@Ksharp OH! It depends where you define the filename! If it's outside of the macro then the code won't get generated but if it's inside of the macro then the code will get generated. Have a play with below and you'll see.
Sooo... How would you redirect the log to "_null_" all done within the SAS macro? Is there any pre-defined libref we could use?
filename _null_ dummy;
%macro secure(val)/secure;
/* filename _null_ dummy;*/
/* data _null_;*/
/* _rc=filename('_null_',,'dummy');*/
/* run;*/
proc printto log=_null_ new;
run;
data T;
X="&val";
putlog "This data step was generated from a secure macro with value &val..";
run;
proc print data=sashelp.class;
run;
proc printto;
run;
%mend secure;
options MPRINT MLOGIC SYMBOLGEN SOURCE SOURCE2;
data _null_;
infile datalines truncover;
input val $;
call execute(cats('%secure(',val,')'));
datalines;
abc
;
@Ksharp Strange. For below case with the filename within the macro my SAS log shows the generated SAS code.
/*filename _null_ dummy;*/
%macro secure(val)/secure;
filename _null_ dummy;
proc printto log=_null_ new;
run;
data T;
X="&val";
putlog "This data step was generated from a secure macro with value &val..";
run;
proc print data=sashelp.class;
run;
proc printto;
run;
%mend secure;
options MPRINT MLOGIC SYMBOLGEN SOURCE SOURCE2;
data _null_;
infile datalines truncover;
input val $;
call execute(cats('%secure(',val,')'));
datalines;
abc
;
NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds NOTE: CALL EXECUTE generated line. 60 ; 1 + filename _null_ dummy; data _null_; _rc=filename('_null_',,'dummy'); run; proc printto log=_null_ new; run; data T; X="abc"; putlog "This data step was generated from a secure macro with value abc."; run; proc print NOTE: DATA statement used (Total process time): real time 0.00 seconds 3 The SAS System 23:34 Tuesday, October 12, 2021
@Ksharp So you created a file named _null_.log in the current working directory.
962 proc printto log=_null_ new; run; NOTE: PROCEDURE PRINTTO used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 965 data _null_; 966 infile '_null_.log'; 967 input; 968 list; 969 run; NOTE: The infile '_null_.log' is: Filename=c:\downloads\_null_.log, RECFM=V,LRECL=32767,File Size (bytes)=206, Last Modified=12Oct2021:19:28:21, Create Time=12Oct2021:19:27:25 RULE: ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0 1 NOTE: PROCEDURE PRINTTO used (Total process time): 50 2 real time 0.00 seconds 38 3 cpu time 0.00 seconds 38 4 6 5 0 6 963 %put hello; 18 7 hello 5 8 964 proc printto log=log; run; 33 9 0 NOTE: 9 records were read from the infile '_null_.log'. The minimum record length was 0. The maximum record length was 50. NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds
Honestly, I was surprised that @Ksharp 's PROC PRINTTO worked (it worked when I tested it as well), as I thought the call execute timing wouldn't allow it to hide the code generated by the macro. Curious in the environment where PROC PRINTTO alone doesn't work, does my DOSUBL approach with PROC PRINTTO running inside the DUSUBL block work?
@Quentin Can't find a dosubl() example in this discussion but I've tried tons of options dosubl() included and could never make things work with everything defined within the macro only.
More than happy for you to give it a go.
@Patrick my suggestion relating to DOSUBL is (I think this link will work): https://communities.sas.com/t5/SAS-Programming/How-to-hide-SAS-macro-source-code/m-p/773394/highligh...
It worked for me, so I thought DOSUBL was helping with the timing (allowing the PROC PRINTTO to execute before the DATA step executes). But then @Ksharp 's dosubl-less PROC PRINTTO worked for me, so it's possible DOSUBL isn't helping. Just curious what the result would be from that code in your environment, if the DOSUBL-less PROC PRINTTO isn't working for you there.
The silver bullet for Windows is destination nul. I wasn't aware that something like /dev/null exists under Windows. Learned something new and very useful 🙂
Already in my previous tests proc printto executed immediately IF the destination pre-existed. So now with nul that's the case and things just work even without dosubl().
/*filename _null_ dummy;*/
%macro secure(val)/secure;
proc printto log="nul" new;
run;
data T;
X="&val";
putlog "This data step was generated from a secure macro with value &val..";
run;
proc print data=sashelp.class;
run;
proc printto;
run;
%mend secure;
/*options MPRINT MLOGIC SYMBOLGEN SOURCE SOURCE2;*/
data _null_;
infile datalines truncover;
input val $;
call execute(cats('%secure(',val,')'));
datalines;
abc
;
NOTE: CALL EXECUTE generated line. 55 ; 1 + proc printto log="nul" new; run;
It'd be useful that the null device existed to access the null device of the OS, so we don't have to test whether nul (DOS) or /dev/null (Unix) are to be used. Request created.
You could replace the "temp" filename (which stores code in a file) with a "dummy" filename (which works like /dev/null).
filename x DUMMY;
proc printto log=x new;run;
Bart
You could try to use the GSM package if you want, here is the doc: https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md
Bart
@yabwon Very clever and clean!!
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.