BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
desertsp
Obsidian | Level 7

I have a macro which, when executed, sets a global variable (named &SearchResult) to a 1 or 0. I would instead prefer the macro itself evaluate to 1 or 0, without having to set a global variable.

 

BTW - this will be used for program control. The macro is checking whether a log file contains the word SUCCESS, and if so, the main program is allowed to continue processing.

 

Here is what I have now:

%macro CheckFileForString(FilenameAndPath=,
                          SearchString=);
%global SearchResult; %let SearchResult = 0; /* default unless the string is found */

/* scan FilenameAndPath for SearchString */ filename finp ("&FilenameAndPath"); data result; infile finp filename = _filepath truncover; input a_line $1000.; /* read first 1000 bytes of each line */ if find(a_line,"&SearchString") then do;  call symput('SearchResult',1); /* set the return code */ end; run; %mend; %macro main_program; /* search a log file for the string SUCCESS */ %CheckFileForString(FilenameAndPath=C:\TEMP\LOGFILE.LOG, SearchString= SUCCESS);
%IF &SearchResult = 1 %THEN
%PUT NOTE: Processing can continue;
%ELSE %PUT ERROR: The log file does not contain the word SUCCESS. Processing must halt; %mend; %main_program;

Here is how I would prefer to setup %main_program. %CheckFileForString needs to evaluate to a 1 or 0, but I'm not sure how to accomplish that.

%macro main_program;
/* check if a log file contains the word SUCCESS */ %IF %CheckFileForString(FilenameAndPath=C:\TEMP\LCM_PYLOG.LOG, SearchString= SUCCESS) = 1 %THEN
%PUT NOTE: Processing can continue; %ELSE %PUT ERROR: The log file does not contain the word SUCCESS. Processing must halt; %mend; %main_program;

 

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

So, you may want to combine what @andreas_lds and @ballardw have suggested:

  1. Avoid SAS code in macro CheckFileForString.
  2. Let the macro code end with a (local) macro variable reference.

The result, a (preliminary) function-style version of CheckFileForString, could look something like this:

%macro CheckFileForString(FilenameAndPath=,
                          SearchString=);
%local SearchResult filrf rc fid c;
%let SearchResult = 0; /* default unless the string is found */
%let filrf=srcf;
%let rc=%sysfunc(filename(filrf, &FilenameAndPath));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
  %do %while(%sysfunc(fread(&fid))=0);
    %let rc=%sysfunc(fget(&fid, c, 1000)); /* read first 1000 bytes of each line */
    %if %index(%superq(c), &SearchString) %then %let SearchResult=1; /* set the return code */
  %end;
  %let rc=%sysfunc(fclose(&fid));
%end;
%let rc=%sysfunc(filename(filrf));
&SearchResult
%mend CheckFileForString;

View solution in original post

8 REPLIES 8
EEng
Obsidian | Level 7

You don't want to use SYSCC?

 

You can add this in the beginning of your code

%Let syscc=0; ** Operating Environment Condition Code **;

 

And after each macro, you can add this into your code:

if &syscc>0 then your log message.

 

From SAS notes (Usage Note 35553)

:

SYSCC is a read/write automatic macro variable that enables you to reset the job condition code and to recover from conditions that prevent subsequent steps from running. The values for SYSCC are:

  • 0 is no errors no warnings
  • 4 is warnings
  • > 4 is an error occurred
desertsp
Obsidian | Level 7

I was not aware of SYSCC - it sounds very useful for trapping unexpected errors. Thank you!

 

If you don't mind, could you please demonstrate how I would incorporate this logic? If I'm not mistaken, my %CheckFileForString macro does not generate an "error" per se, even if the string isn't found.

 

Or are you simply suggesting that I replace my own &SearchResult with &SYSCC?

ballardw
Super User

Here is one way to expose a single value without a global macro variable:

%macro dummy (value);
   %if &value=10 %then %let result=1;
   %else %let result=0;
   &result
%mend;

%macro main_program;
   /* search a log file for the string SUCCESS */
 
 %IF %dummy(10) = 1 %THEN 
   %PUT NOTE: Processing can continue;
 %ELSE 
   %PUT ERROR: The value is not 10. Processing must halt;
%mend;

%main_program;

The local macro variable result exposed as a single statement without any ; to end the statement.

 

Test other values with something like:

%put %dummy(5);

 

You might want to include a LRECL parameter on our INFILE statement.

desertsp
Obsidian | Level 7

Thank you! I don't have much experience working with infile (usually, I work with existing SAS datasets)

 and I appreciate you pointing out my omission of LRECL.

 

andreas_lds
Jade | Level 19

Macros returning values can't use data-steps or procs, only macro-code is allowed. In the following example sashelp.class is not printed, but the code is returned to the calling macro.

 

%macro dummy;
   %local z;
   %let z = 100;
  
   proc print data=sashelp.class;
   run;

   &z.

%mend;

%macro testbox;
   %local result;
   %let result = %dummy;
   %put -----------;
   %put &result.;
   %put -----------;
%mend;

%testbox;
desertsp
Obsidian | Level 7

I definitely need to learn more about when macros resolve to "text" and when they resolve to "executetable code". Your example helps with that understanding. Thanks!

 

 

FreelanceReinh
Jade | Level 19

So, you may want to combine what @andreas_lds and @ballardw have suggested:

  1. Avoid SAS code in macro CheckFileForString.
  2. Let the macro code end with a (local) macro variable reference.

The result, a (preliminary) function-style version of CheckFileForString, could look something like this:

%macro CheckFileForString(FilenameAndPath=,
                          SearchString=);
%local SearchResult filrf rc fid c;
%let SearchResult = 0; /* default unless the string is found */
%let filrf=srcf;
%let rc=%sysfunc(filename(filrf, &FilenameAndPath));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
  %do %while(%sysfunc(fread(&fid))=0);
    %let rc=%sysfunc(fget(&fid, c, 1000)); /* read first 1000 bytes of each line */
    %if %index(%superq(c), &SearchString) %then %let SearchResult=1; /* set the return code */
  %end;
  %let rc=%sysfunc(fclose(&fid));
%end;
%let rc=%sysfunc(filename(filrf));
&SearchResult
%mend CheckFileForString;
desertsp
Obsidian | Level 7

Thank you - I see you also improved how the macro works with the file, which I appreciate!

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

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!

Register Now

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
  • 8 replies
  • 2832 views
  • 0 likes
  • 5 in conversation