BookmarkSubscribeRSS Feed

&SYSRC holds the return code of the last external command executed. But it is not set when a filename pipe is used as input (and therefore runs the command included in the physical name if the fileref).

See this:

filename oscmd pipe "ls /garbage 2>&1";

%put &=sysrc.;

data _null_;
infile oscmd;
input;
put _infile_;
run;

%put &=sysrc.;

x "ls /garbage 2>&1";

%put &=sysrc.;

Log:

27         filename oscmd pipe "ls /garbage 2>&1";
28         
29         %put &=sysrc.;
SYsrc=0
30         
31         data _null_;
32         infile oscmd;
33         input;
34         put _infile_;
35         run;

NOTE: The infile OSCMD is:
      Pipe-Kommando="ls /garbage 2>&1"

ls: 0653-341 The file /garbage does not exist.
NOTE: 1 record was read from the infile OSCMD.
      The minimum record length was 46.
      The maximum record length was 46.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds
      

36         
37         %put &=sysrc.;
SYsrc=0
38         
39         x "ls /garbage 2>&1"
39       !                     ;
40         
41         %put &=sysrc.;
SYsrc=2

I therefore suggest that SYSRC is also updated when external commands are run via the filename pipe mechanism, as it would enhance the communication with the host OS.

4 Comments
Quentin
Super User

Good suggestion.  Currently with SYSTASK it is done differently.  You need to specify a STATUS macro variable be created, and then check both &sysrc (to see that SYSTASK statement executed without errors) and the status macro variable (to see that the OS command executed without errors):

The SYSRC macro variable contains the return code for the SYSTASK statement. The status variable that you specify with the STATUS option contains the return code of the process started with SYSTASK COMMAND. To ensure that a task executes successfully, you should monitor both the status of the SYSTASK statement and the status of the process that is started by the SYSTASK statement.

 

For the sake of backwards compatibility, SAS might not want to change the behavior of SYSRC returned by filename pipe.  I guess another option would be to implement something like a STATUS option for filename pipe.  You definitely need some way to get a return code from the OS command.

 

data_null__
Jade | Level 19

You can get the command status as part of the PIPE and set SYSRC.

 

filename oscmd pipe "/usr/bin/ls /etc/groupx 2>&1; echo STATUS=$?";
/*filename oscmd pipe "/usr/bin/find /etc/group ; echo STATUS=$?";*/
%let sysrc=0;
%put INFO: &=sysrc;
data _null_;
   infile oscmd;
   input @;
   put _infile_;
   if _infile_ eq: 'STATUS' then do;
      input status=;
      putlog 'INFO: ' status=;
      call symputx('SYSRC',status);
      end;
   run;
%put INFO: &=sysrc;
44         filename oscmd pipe "/usr/bin/ls /etc/groupx 2>&1; echo STATUS=$?";
45         /*filename oscmd pipe "/usr/bin/find /etc/group ; echo STATUS=$?";*/
46         %let sysrc=0;
47         %put INFO: &=sysrc;
INFO: SYsrc=0
2                                                          The SAS System                              16:16 Monday, August 17, 2020

48         data _null_;
49            infile oscmd;
50            input @;
51            put _infile_;
52            if _infile_ eq: 'STATUS' then do;
53               input status=;
54               putlog 'INFO: ' status=;
55               call symputx('SYSRC',status);
56               end;
57            run;

NOTE: The infile OSCMD is:
      Pipe command="/usr/bin/ls /etc/groupx 2>&1; echo STATUS=$?"

/usr/bin/ls: cannot access /etc/groupx: No such file or directory
STATUS=2
INFO: status=2
NOTE: 2 records were read from the infile OSCMD.
      The minimum record length was 8.
      The maximum record length was 65.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      

58         %put INFO: &=sysrc;
INFO: SYsrc=2
PhilC
Rhodochrosite | Level 12

Suppose there were two FILENAME and two INFILE statements used in one data step?

 

filename oscmd1 pipe "dir \temp 2>&1";
filename oscmd2 pipe "dir \tmp 2>&1";

%put &=sysrc.;

data _null_;
do until (eo1);
  infile oscmd1 end=eo1;
  input;
  put _infile_;
end;
put "*************************";
do until (eo2);
  infile oscmd2 end=eo2;
  input;
  put _infile_;
end;

run;

Which of the two file reference's statuses gets to be prioritized to be placed in SYSRC?

 

What if we ask for a column in dictionary.extFiles? This is less clean than your one macro variable solution, but, would it not better enhance our communication with the host OS?

PROC SQL;
   SELECT sysrc /*hypothetical variable*/
      FROM dictionary.extFiles
      WHERE fileref="OSCMD" ;
QUIT;
Kurt_Bremser
Super User

Rethinking it, I come to the conclusion that a STATUS= option for the FILE/INFILE statement would be the most practicable solution, as it allows to query multiple FILE/INFILE statements, or a statement with the FILEVAR= option dynamically while the DATA step is running. Kudos to @Quentin and @PhilC for alerting me to that.

 

Such an option could also be used without PIPE to deal gracefully with certain conditions (missing permission to read/write, no space left etc).

 

I contemplate creating a new ballot idea for this.