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;
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
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.