I'm trying to create a read-only macro variable. I can create a non-read-only macro variable that does what I need to do, but I prefer that the variable be read-only. This is what I have that works:
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 55 56 *works; 57 %LET path1=%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete 57 ! Guide to the SAS Macro Language); 58 %LET path1test=&path1/test/location; 59 %PUT &=path1test; PATH1TEST=/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language/test/location 60 61 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 73
I'm unable to create a read-only variable using the following %GLOBAL statement however:
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 55 56 *doesn't work; 57 %GLOBAL / READONLY path2=%STR(%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 57 ! 9/Carpenter's Complete Guide to the SAS Macro Language)); 58 %LET path2test=&path2/test/location; 59 %PUT &=path2test; 60 61 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 62 ODS HTML CLOSE; 63 &GRAPHTERM; ;*';*";*/;RUN;QUIT; 64 QUIT;RUN; 65 ODS HTML5 (ID=WEB) CLOSE; 66 67 ODS RTF (ID=WEB) CLOSE; 68 ODS PDF (ID=WEB) CLOSE; 69 FILENAME _GSFNAME; 70 DATA _NULL_; 71 RUN; 72 OPTIONS NOTES STIMER SOURCE SYNTAXCHECK;
Does anybody know what I'm doing wrong?
Vic
It is definitely NOT storing the macro quoting. You can see this for yourself by looking at the value you can see in the dictionary tables.
%let x=%bquote(Don't);
%global /readonly y=%bquote(Don't);
data _null_;
set sashelp.vmacro;
where scope='GLOBAL' and name in ('X','Y');
put name= value = $hex20. ;
run;
Results
name=X value=04446F6E117408202020
name=Y value=446F6E27742020202020
You will need to just be careful where you REFERENCE the value of the global macro variable you have created that has unbalanced quotes.
Or you could take more care in defining the global macro variable so that the stored value does not require macro quoting.
1 %global /readonly a=%qsysfunc(dequote('%bquote(Don''t)')) ;
2 %put Actual value = |%superq(a)| ;
Actual value = |%bquote(Don't)|
3 %put Resolves to = |&a| ;
Resolves to = |Don't|
PS I'm running SAS University Edition.
There is no readonly option for macro variables. Macro variables can be set anytime/anywhere.
@rararayayayay wrote:
See: https://support.sas.com/resources/papers/proceedings15/SAS1575-2015.pdf
I stand corrected. Well, we're finally upgrading from 9.2 to 9.4 next month. READONLY was introduced with 9.3, so I never encountered it.
When you make a macro variable read only, after that you cannot change the value of that macro variable.
But in your test code, you are not testing whether you can change the value of of a read only macro variable. First you make PATH2 and it is read only. Then you make PATH2TEST and happen to resolve PATH2 in that assignment statement. That is all allowed. If you tried to change the value of PATH2, it should error.
So, this works:
33 %GLOBAL / READONLY path2=/some/location ;
34 %LET path2test=&path2/with/subdirectory ;
35 %put &=Path2 &=Path2test ;
PATH2=/some/location PATH2TEST=/some/location/with/subdirectory
But if you try to assign a new value to path2 it fails:
37 %let path2=/some/other/location ;
ERROR: The variable PATH2 was declared READONLY and cannot be modified or re-declared.
Sorry, I didn't make my problem easy to reproduce.
No, I'm not trying to change the value of a read-only variable, and I can get the %GLOBAL statement with the READONLY option to work for most strings. But when I use a particaular string that has an unmatched apostrophe, I have problems. The string in question is
/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language
What's strange is that I don't have any problems when using a %LET statement. I mask the string with a macro quoting function and it works.
%LET path1=%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language);
%PUT &=path1;
%LET path1test=&path1/test/location;
%PUT &=path1test;
yields
56 %LET path1=%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete
56 ! Guide to the SAS Macro Language);
57 %PUT &=path1;
PATH1=/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language
58 %LET path1test=&path1/test/location;
59 %PUT &=path1test;
PATH1TEST=/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language/test/location
But if I use the same string with a %GLOBAL / READONLY macro-variable=value; statement
%GLOBAL / READONLY path2=%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro Language);
%PUT &=path2;
%LET path2test=&path2/test/location;
%PUT &=path2test;
it doesn't work, and I get this junk:
56 %GLOBAL / READONLY path2=%NRBQUOTE(/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS
56 ! 9/Carpenter's Complete Guide to the SAS Macro Language);
57 %PUT &=path2;
58 %LET path2test=&path2/test/location;
59 %PUT &=path2test;
60
61 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
62 ODS HTML CLOSE;
63 &GRAPHTERM; ;*';*";*/;RUN;QUIT;
PATH2=/folders/myfolders/sasuser.v94/2 SAS Certified Advanced Programmer for SAS 9/Carpenter's Complete Guide to the SAS Macro
Language;%LET path2test=&path2/test/location;%PUT &=path2test;OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;ODS HTML
CLOSE;&GRAPHTERM; ;*'
64 QUIT;RUN;
65 ODS HTML5 (ID=WEB) CLOSE;
66
67 ODS RTF (ID=WEB) CLOSE;
68 ODS PDF (ID=WEB) CLOSE;
NOTE: ODS PDF(WEB) printed no output.
(This sometimes results from failing to place a RUN statement before the ODS PDF(WEB) CLOSE statement.)
69 FILENAME _GSFNAME;
NOTE: Fileref _GSFNAME has been deassigned.
70 DATA _NULL_;
71 RUN;
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
72 OPTIONS NOTES STIMER SOURCE SYNTAXCHECK;
73
Does that make any sense to you?
Vic
Okay, came back to playing with it, and I think you should send this in to tech support. Looks like /readonly is not honoring the macro quoting.
I ran this in EG with SAS 9.4M3, and didn't work:
%global /readonly y=%str(Carpenter%'s) ;
%put y=&y ;
Reaching for straws, I tried %SUPERQ, but it didn't help:
%let x=%str(Carpenter%'s) ;
%put x=&x ;
%global /readonly y=%superq(x);
%put y=&y ;
And trying it in a macro caused an ugly "CALL tech support" error:
%macro try(dummy) ;
%global /readonly Z=%str(Carpenter%'s) ;
%mend try ;
%try()
Perhaps because EG gets tripped up by the unmatched quote and then not seeing the %mend and even EG's magic string doesn't save it.
Seems buggy to me. Unless of course it's documented somewhere that you can't use quoting functions with /readonly.
It is definitely NOT storing the macro quoting. You can see this for yourself by looking at the value you can see in the dictionary tables.
%let x=%bquote(Don't);
%global /readonly y=%bquote(Don't);
data _null_;
set sashelp.vmacro;
where scope='GLOBAL' and name in ('X','Y');
put name= value = $hex20. ;
run;
Results
name=X value=04446F6E117408202020
name=Y value=446F6E27742020202020
You will need to just be careful where you REFERENCE the value of the global macro variable you have created that has unbalanced quotes.
Or you could take more care in defining the global macro variable so that the stored value does not require macro quoting.
1 %global /readonly a=%qsysfunc(dequote('%bquote(Don''t)')) ;
2 %put Actual value = |%superq(a)| ;
Actual value = |%bquote(Don't)|
3 %put Resolves to = |&a| ;
Resolves to = |Don't|
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.