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!

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 8 replies
  • 1182 views
  • 0 likes
  • 5 in conversation