Hello,
when I launch this code in an included program, via a main program it works, I mean the log of the main program displays ===>"XXX"
but by replacing "XXX" by &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME it doesn't ,only / is displayed. I woud like to obtain the folder and program of the included prog.
thanks in advance for your help
regards
Nasser
%macro mc_get_program_name ; %let v_path_prog =; %let v_path_prog = "XXX" ; %mend ; %mc_get_program_name ; %let path_prog = &v_path_prog ; %put ===>&path_prog ;
A slight modification to my solution: you can also put the RUN statement inside the macro, as log as you do not put the final semicolon.
%macro mc_get_program_name;
data _null_;
call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
run
%mend;
Then, in your %INCLUDE program, just use the macro call with a semicolon:
%mc_get_program_name;
and things should work as you want, the datastep does not get executed before SAS encounters the semicolon (which is outside the macro).
You need to define the macrovariable as a global one to use it outside the macro-program:
%macro mc_get_program_name ;
%global v_path_prog; /*add this statement*/
%let v_path_prog =;
%let v_path_prog = "XXX" ;
%mend ;
%mc_get_program_name ;
%let path_prog = &v_path_prog ;
%put ===>&path_prog ;
Best,
I don't see how the subject relates to the code you posted. There are no references to either of those system generated macro variables in the code you posted. There is no %INCLUDE command in the code you posted.
Note those variables are only populated while you are including the file.
Example to try:
filename code temp;
data _null_;
file code ;
put
'%global mypath;'
/'%let mypath=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;'
;
run;
%include code / source2;
%put &mypath;
@Nasser_DRMCP wrote:
Sorry,
I launch a prog that only contains %include '/sbsas/ALBERTNA/include/nm_workshop_batch_inc.sas' ;
wich contains the code of the macro i posted
If the file only includes the macro definition then including it will only DEFINE the macro, not run it. So there is no place where those two system macro variables would be evaluated while they reflect that include file. You need to either run the macro as part of the code included. Or as in my example above just create a global macro variable in the open code in the include file that you can then reference later after the code that was included as finished running.
To test make two files to include. One with a macro definition that references the system macro variables. The second with a call to that macro. Include them in order and you should see that the path to the file with the call to macro is displayed.
Please post CODE. Like this:
filename code 'C:\downloads\test1.sas';
data _null_;
file code ;
put
'%macro test1;'
/'%put macroname=&sysmacroname. includepath=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;'
/'%mend test1;'
/'%test1;'
;
run;
%include code / source2;
Looks like SAS is treating the execution of the macro as not part of the inclusion process, so the macro variables are not populated.
Use one of the work arounds.
@Nasser_DRMCP wrote:
I tried the code you proposed. it works very well. but I would like to get the result via macro.
Explain more what the use case actually is. Some alternatives:
1) If you are using SAS autocall there are options to have SAS display in the log the name of the file where a macro is compiled from.
2) If you are using a version control system they usually have a method to modify the text of the file when you check in the updates to include the filename (and other version control metadata). I know we used to use this feature in RCS to keep comment sections of macro definitions up to date.
3) You could make a naming convention for your own global macro variables and use the open code %LET method in my example.
%global location_mymacro;
%let location_mymacro= &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;
%macro mymacro;
%put This macro was defined from source file &location_mymacro;
%mend mymacro;
Here is a slightly dirty way to accomplish your goal. Define your macro like this:
%macro mc_get_program_name;
data _null_;
call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
%mend ;
Then, the data step will not be executed immediately, but only when SAS encounters a RUN statement or a step boundary.
In your %INCLUDE program, you should then (just to be safe) put a RUN after the macro call:
%mc_get_program_name;
run;
And your macro variable will have the right value.
The main challenge here is what happens during macro compilation and macro execution time.
During macro compilation time (that's what happens when you execute your %include statement) any macro variable used within a macro definition does NOT get resolved. SAS just compiles your macro "as is". In below example SAS will compile statement "%put &=someMacroVar;" and not the resolved value of the macro variable.
%symdel someMacroVar/nowarn;
/** macro compilation **/
%let someMacroVar=ABC;
%macro demo();
%put &=someMacroVar;
%mend;
During macro execution time SAS will resolve the macro variable. Because in below example the macro variable doesn't exist anymore during execution time SAS will throw a warning.
%symdel someMacroVar/nowarn;
/** macro execution **/
%demo();
38 %demo(); WARNING: Apparent symbolic reference SOMEMACROVAR not resolved.
The only way I can think of to compile a macro with a resolved macro variable (like &SYSINCLUDEFILEDIR in your case) would be to have a data step which dynamically creates the macro code and then execute (compile) the generated code.
Having said all that: If you just want in the log an indication from where the macro has been compiled from whenever you call (execute) it then much simpler would be to store the macro definition in a .sas file in a folder that is part of the autocall facility. If you do so then you don't need the %include statement anymore. You just call the macro - and if you set option MAUTOLOCDISPLAY then you'll get in the SAS log where the macro has been compiled from.
@Nasser_DRMCP wrote:
Hello,
when I launch this code in an included program, via a main program it works, I mean the log of the main program displays ===>"XXX"
but by replacing "XXX" by &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME it doesn't ,only / is displayed. I woud like to obtain the folder and program of the included prog.
thanks in advance for your help
regards
Nasser
%macro mc_get_program_name ; %let v_path_prog =; %let v_path_prog = "XXX" ; %mend ; %mc_get_program_name ; %let path_prog = &v_path_prog ; %put ===>&path_prog ;
Not sure what the purpose of this is, but if you want to record the name of the file you including just move the %LET statements to OUTSIDE of the macro definition.
You can place it either before or after the code that defines a macro, but if you want to use the new macro variable inside the body of the macro then make sure the macro variable you create is defined before you call the macro.
%let v_path_prog=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME ;
%put Before macro definition: &=v_path_prog;
%macro my_functional_macro;
* This macro does something actually useful ;
%put &=sysmacroname &=v_path_prog;
%mend my_functional_macro;
%put After macro definition: &=v_path_prog;
%my_functional_macro;
%put After macro execution: &=v_path_prog;
Results:
1 %include 'c:\downloads\code.sas' / source2 ; NOTE: %INCLUDE (level 1) file c:\downloads\code.sas is file c:\downloads\code.sas. 2 +%let v_path_prog=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME ; 3 +%put Before macro definition: &=v_path_prog; Before macro definition: V_PATH_PROG=c:\downloads/code.sas 4 +%macro my_functional_macro; 5 +* This macro does something actually useful ; 6 +%put &=sysmacroname &=v_path_prog; 7 +%mend my_functional_macro; 8 +%put After macro definition: &=v_path_prog; After macro definition: V_PATH_PROG=c:\downloads/code.sas 9 +%my_functional_macro; SYSMACRONAME=MY_FUNCTIONAL_MACRO V_PATH_PROG=c:\downloads/code.sas 10 +%put After macro execution: &=v_path_prog; After macro execution: V_PATH_PROG=c:\downloads/code.sas 11 + NOTE: %INCLUDE (level 1) ending.
A slight modification to my solution: you can also put the RUN statement inside the macro, as log as you do not put the final semicolon.
%macro mc_get_program_name;
data _null_;
call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
run
%mend;
Then, in your %INCLUDE program, just use the macro call with a semicolon:
%mc_get_program_name;
and things should work as you want, the datastep does not get executed before SAS encounters the semicolon (which is outside the macro).
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!
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.