BookmarkSubscribeRSS Feed
windlove
Fluorite | Level 6

I have a few programs doing data preparations. One of them has a macro wrap on a %do loop to subset the data. When I try to run all those programs inside another macro with %include and %do loop, that data program with macro would always be skipped. 

 

Here "6. program.sas" is the program with macro wrap., and %run_test always skips it. 

	%let program1 = %str(1. program.sas);
	%let program2 = %str(2. program.sas);
	%let program3 = %str(3. program.sas);
	%let program4 = %str(4. program.sas);
	%let program5 = %str(5. program.sas);

	/* report programs */
	%let program6 = %str(6. program.sas);
	%let program7 = %str(7. program.sas);

	%macro run_test;
		%local i;
		%do i = 1 %to 7;
			%include "%sysfunc(catx(\, &sasDir., &&program&i))";
		%end;

	%mend;
	%run_test;

However, if I have the previous 5 programs run already, and the %do loop start from the 6th program. Then it would run successfully. 

 

	%macro run_test;
		%local i;
		%do i = 6 %to 7;
			%include "%sysfunc(catx(\, &sasDir., &&program&i))";
		%end;

	%mend;
	%run_test;

What would be the reason for this, and how can I resolve this?

10 REPLIES 10
windlove
Fluorite | Level 6

oooops. 

After posting the question here, suddenly problem solved. 

I just move the %include statement  after a %goto. My actual program looks like this

All the programs run successfully, but the 6th program now cannot be resolved in &&program&i. 

I have 1-5, and 7, printed out as in

put #3 @5 " The SAS program '&&program&i.' is in the right place";

, but not the 6th program. 

%macro runProgram();

		%local i ;
		%do i = 1 %to 7;
			%let runfile = %sysfunc(catx(\, &sasDir., &&program&i));
			%if %sysfunc(fileexist("&runfile.")) = 0 %then %do;
				data _null_;
					file print;
					put #1 @5 "Error **************************************************************";
		        	put #3 @5 "Error The SAS programs  '&&program&i.'  does not exist"  ;
					put #4 @5 "Error Please check whether the program name or the the directory is correct";
					put #6 @5 "Error *************************************************************";
				run;
				%goto endRun;	
			%end;
			%else %do;
				data _null_ ;
					file print;
					put #1 @5 "*******************************************************";
					put #3 @5 " The SAS program '&&program&i.' is in the right place";
					put #5 @5 "******************************************************";
				run;
				%goto runProg;
				%runProg:
					%include "&runfile.";
			%end;
		%end;

		%endRun:
	%mend; 
	%runProgram;

 

sbxkoenk
SAS Super FREQ

Hello @windlove ,

 

I have no idea why your macro stumbles upon the 6th program??

 

You can consider alternative code, like this one:

Note the comment sections (they contain some important remarks)!

/* IMPORTANT !! This program assumes that the alphabetical sort order of the     */
/* .sas programs is also the order in which the programs have to be submitted !! */

%LET directory=%STR(C:\abc);

/* Collect all .sas programs (files) in a dataset named WORK.mySASprograms_inDir */
data mySASprograms_inDir;
length fref $8 fnamesas $400;
did = filename(fref,"&directory.");
did = dopen(fref);
do i = 1 to dnum(did);
  fnamesas = dread(did,i);
  fnamesas = "&directory"!!'\'!!strip(fnamesas);
  if upcase(scan(fnamesas,-1,'.')) = 'SAS' then output;
end;
did = dclose(did);
did = filename(fref);
keep fnamesas;
run;

/* delete the .sas programs you do not want */
data mySASprograms_inDir;
 set mySASprograms_inDir;
 where fnamesas NOT CONTAINS 'PATHJSCORECODE.sas';
run;

proc sort data=mySASprograms_inDir; by fnamesas; run;

/* How many SAS programs are there?? */
data _NULL_;
 if 0 then set mySASprograms_inDir nobs=count;
 call symput('numobs',strip(put(count,8.)));
 STOP;
run;
%PUT &=numobs;

/* EXECUTE (SUBMIT) the first 2 .sas programs */
options source2;
data _NULL_;
 set mySASprograms_inDir;
 if _N_ < 3 then call execute('%INCLUDE "' !! strip(fnamesas) !! '";');
run;
/* end of program */

Koen

Tom
Super User Tom
Super User

Most likely program #5 is setting the macro variable I to the value 6 so the %DO loop increments it to 7 and so skips the sixth.

 

The solution is to either fix program number 5 (or your %DO loop) to not modify the macro variable used for the loop.

 

Or don't use a macro for the loop.

data _null_;
  length filename $256 ;
  do i=1 to 7;
    filename=catx('\',symget('sasdir'),symget(cats('program',i)));
    call execute('%include '||quote(trim(filename)));
  end;
run;
windlove
Fluorite | Level 6

Thanks for both suggestions. But unfortunately it's not working.

I think it has something to do with the macro wrapper inside #6 program, in which it has the steps like below. This may cause non-compilation of #6 within another %do loop in another macro.

data steps;
x
y
z
%macro data;
a
b
c
%mend;
%data;

I have fixed the problem by wrapping all 7 programs with a macro, and keep the macro name same as the file name. Such that, I can do something like. Now it is working without any issues. 

%do i = 1 %to 7;
	%let runfile = %sysfunc(catx(\, &sasDir., &&program&i));
    %let macroName = %scan(&&program&i., 2, " .");
	%include "&runfile.";
	%&macroName.;	
%end;

 

ballardw
Super User

@windlove wrote:

Thanks for both suggestions. But unfortunately it's not working.

I think it has something to do with the macro wrapper inside #6 program, in which it has the steps like below. This may cause non-compilation of #6 within another %do loop in another macro.

data steps;
x
y
z
%macro data;
a
b
c
%mend;
%data;

I have fixed the problem by wrapping all 7 programs with a macro, and keep the macro name same as the file name. Such that, I can do something like. Now it is working without any issues. 

%do i = 1 %to 7;
	%let runfile = %sysfunc(catx(\, &sasDir., &&program&i));
    %let macroName = %scan(&&program&i., 2, " .");
	%include "&runfile.";
	%&macroName.;	
%end;

 


Are you attempting to use a MACRO as datalines?

I would think anything as static as your example of the %data macro would be better off in a permanent data set and used from there. Or have you "simplified" past the point of usability?

windlove
Fluorite | Level 6

No, not using macro as datalines. It was just an example to show how my program was structured. The macro is just a part of #6, which is doing some data processing in the middle of the whole program.  

Tom
Super User Tom
Super User

Converting the code inside the include file will only work if you also include a %LOCAL statement to make sure the loop counter used in the calling program not overwritten.

So the %LOCAL I statement in this definition of %PROGRAM5 is what is preventing %PROGRAM6 from being skipped.

%macro program5 ;
   %local i;
....
  %let i=6 ;
...
%mend program5;
...
%do i=5 %to 7;
  %program&i ;
%end;

windlove
Fluorite | Level 6

I did try this in the first instance to include a %local loop in both #6, and the script calling it,  and also made sure the loop index names were different, not using i or j in both.  

SASKiwi
PROC Star

The problems you are having are a good argument for not using nested macros.

 

Why not consider a different approach completely? What about creating a list of the programs you want to run then use a DATA step and then use CALL EXECUTE to do the %INCLUDEs:

 %let Run_Pgm_List = proj1*proj2*proj3;
 %let app_saspgm_dir = C:\temp;

data _null_;
  length Run_Pgm_List 1024;
  Run_Pgm_List = symget('Run_Pgm_List');
  pgm_count = countw(Run_Pgm_List, '*');
  if pgm_count ge 1 then do pgm_num = 1 to pgm_count;
    pgm_name = scan(Run_Pgm_List, pgm_num, '*');
    call execute('%include "&app_saspgm_dir.\' !! strip(pgm_name) !! '.sas";');
  end;
run;
windlove
Fluorite | Level 6

I was thinking about this, but reluctant to do it. As the nested macro is just part of the data flows depending on the previous data processing in #6, and I don't want to make it into a stand-alone macro function or separate it from the data processing.  

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 10 replies
  • 1369 views
  • 1 like
  • 5 in conversation