An interesting puzzle was raised by this question. https://communities.sas.com/t5/SAS-Programming/Changing-SAS-System-options-within-a-macro-which-does...
If I try to run a line of code with single quotes around it then SAS will rightly throw an error message because you cannot have a free floating string literal in the middle of a block of SAS code.
Why does SAS remove the quotes around values passed to the DOSUBL() function when called via the %SYSFUNC() macro call?
So if I make a program file with this value:
>more qstring.sas 'data _null_; string=symget("sysjobid"); put string;run;'
and run it with SAS I get this LOG.
NOTE: SAS initialization used: real time 0.27 seconds cpu time 0.03 seconds 1 'data _null_; string=symget("sysjobid"); put string;run;' ___________________________________________________________ 180 ERROR 180-322: Statement is not valid or it is used out of proper order. ERROR: Errors printed on page 1. NOTE: SAS Institute Inc., SAS Campus Drive, Cary, NC USA 27513-2414 NOTE: The SAS System used: real time 0.28 seconds cpu time 0.03 seconds
But if I make a macro variable with that value.
%let string='data _null_; string=symget("sysjobid"); put string;run;';
And run it through %SYSFUNC(DOSUBL()) it runs.
174 %put BEFORE; BEFORE 17548 NOTE: DATA statement used (Total process time): real time 0.01 seconds cpu time 0.01 seconds 175 %let rc=%sysfunc(dosubl(&string)); 176 %put &=rc; RC=0 177 %put AFTER; AFTER
The way I see it:
Function DOSUBL does a lot behind the scenes and is not at all a regular function.
It starts a new SAS thread and passes code to that thread.
It looks that, as part of the code-passing, surrounding single quotes are removed.
This could be considered a feature or a bug.
Note that surrounding double quotes are not removed.
It's not only when called via a macro that the surrounding single quotes are removed.
This runs fine:
data _null_;
RC=dosubl(" 'data _null_; string=symget(""sysjobid""); put string;run;' ");
run;
[Edit: This code does NOT run as expected.]
Hi @ChrisNZ
Interesting. When I run your code, id doesn't run
NOTE: SAS initialization used: real time 4.01 seconds cpu time 1.17 seconds 1 data _null_; 2 RC=dosubl(" 'data _null_; string=symget(""sysjobid""); put string;run;' "); 3 run; ERROR 180-322: Statement is not valid or it is used out of proper order. NOTE: DATA statement used (Total process time): real time 0.67 seconds cpu time 0.18 seconds
Mmmm. You are right. I did a few tests and got confused on the way. This code does generate an error.
Apologies for wasting your time.
Hi @ChrisNZ
Far from wasting my time, I had a very interesting evening experimenting with dosubl. I was aware of it from "What's new in SAS x.x.x", but have never used it. So it is like when I got a Dremel as a birthday present many years back. I had never missed it before, but now I'm on my third.
I got confused on the way too, I have some examples here. It makes sense that both 1.2 and 1.3 works, but why does 2.2 not work, when 2.3 does? - Any ideas?
******* without surrounding quotes *******;
%let cmd = %str(data _null_; string=symget("sysjobid"); put string; run;);
* 1.1 - works;
%let rc = %sysfunc(dosubl(&cmd));
* 1.2 - works;
data _null_;
cmd = symget('cmd');
put cmd;
RC = dosubl(cmd);
run;
* 1.3 - works;
data _null_;
cmd = 'data _null_; string=symget("sysjobid"); put string; run;';
put cmd;
RC = dosubl(cmd);
run;
******* with surrounding quotes ********;
%let cmd = %str('data _null_; string=symget("sysjobid"); put string; run;');
* 2.1 - works;
%let rc = %sysfunc(dosubl(&cmd));
* 2.2 - DOES NOT WORK;
data _null_;
cmd = symget('cmd');
put cmd;
RC = dosubl(cmd);
run;
* 2.3 - works;
data _null_;
cmd = "'" || 'data _null_; string=symget("sysjobid"); put string; run;' || "'";
put cmd;
RC = dosubl(cmd);
run;
@ErikLund_Jensen wrote:
It makes sense that both 1.2 and 1.3 works, but why does 2.2 not work, when 2.3 does? - Any ideas?
Good question. It seems that DOSUBL doesn't like the trailing blanks after the closing single quote in CMD (character variable of length 200) in 2.2, which are not present in 2.3 where CMD is a variable of length 60. As it turns out, it doesn't like leading blanks before the opening single quote either:
* 2.4 - DOES NOT WORK;
%let cmd1 = %str( 'data _null_; string=symget("sysjobid"); put string; run;');
%let cmd2 = %str('data _null_; string=symget("sysjobid"); put string; run;' );
%let rc = %sysfunc(dosubl(&cmd1));
%let rc = %sysfunc(dosubl(&cmd2));
> It seems that DOSUBL doesn't like the trailing blanks [...] it doesn't like leading blanks before the opening single quote either
Ah! That explains it! I added the spaces in my code after pasting it here, to making it more legible. This runs:
data _null_;
RC=dosubl("'data _null_; string=symget(""sysjobid""); put string;run;'");
run;
In light of the comments by @FreelanceReinh, this
* 2.2 - DOES NOT WORK;
data _null_;
cmd = symget('cmd');
put cmd;
RC = dosubl(cmd);
run;
can run like this:
* 2.2 - DOES WORK;
data _null_;
cmd = symget('cmd');
put cmd;
RC = dosubl(trim(cmd));
run;
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.