Debug and Production OS Commands in SAS - Beyond X Commands

X commands don’t tell you anything about the success of an OS command; use FileName Pipe to read the text from and debug your commands; use SysTask to get the return code, then you can exit if something went wrong.

Note: This post is based on a Windows environment where OS commands are allowed. If your admins have disallowed them in your config, then you’re on your own! Those new to OS commands can check out some fundamentals here.

If you’re a SAS programmer with processes involving a manual file deletions or renames, then you could absolutely be using OS commands in your SAS programs. Having a good grasp of scripting is a great career skill, and if you’re anything like me, saves your sanity when doing repetitive file system tasks.

Writing OS commands for SAS to execute can seem daunting, but often the key is knowing how to debug the command and not writing it blind. In my opinion, you should avoid the X command in SAS and stick with the two below; one for debugging and one for production.

CMD.exe

Before you jump into writing your SAS code, fire up CMD. Get your CMD environment as close to that on your server as possible. That means mapping all the same drives and moving CMD into the same directory location you’re working with in SAS. You can use your local CMD to quickly check syntax and that your desired outcome is actually possible.

If you don’t know what network drives are mapped on the server, submit a plain net use command using the FileName Pipe method we’ll discuss now.

Filename Pipe - Debug

The FileName statement should be familiar to all SAS programmers, but just in case; the FileName statement assigns a logical link to a file in SAS, which can then be called upon in other statements. Generally the other statements will be reading from, or writing to, the location specified in the FileName statement.

The addition of the pipe in a FileName statement, tells SAS that the following text (in quotes) does not point to a file on disk, but it is an OS command. At the appropriate time, SAS will throw this command at the OS, then optionally try to read the textual output generated. This works because SAS is an excellent text parser and CMD, the shell available to SAS, is a textual environment.

Follow the structure below to submit an OS command, then read the generated output and put it in the log.

FileName myCmd Pipe "YOUR COMMAND HERE";
Data _NULL_;
    InFile myCmd Length=lineLength;
    Input line $varying512. lineLength;
    Put line=;
Run;

If you're stuck for ideas, try the above with a plain old `dir` in the quotes of the `FileName` statement. You can get a directory listing into a SAS data set this way, without messy intermediate `.txt` files.

I often encounter SAS programmers who have an OS command that should work through SAS, but doesn’t. They’ve done the right thing and checked it will work using a local CMD, but once it hits the server then it just won’t run.

Using the FileName Pipe method allows them to read what the CMD window would be telling them, if they were executing the command at the server themselves. Now, they can check the SAS log and see what CMD is complaining about. This takes away the issue of writing the command blind (like with X); no more throwing it into the dark and hoping!

SysTask - Production

FileName Pipe is excellent for crafting time saving OS commands, when they’re ready then SysTask is usually the command you want to switch to. This is especially true when you’re using a third party tool with its own command line interface (CLI) that will give you a return code (RC). Utilising the RC of an executable, you can much more easily tell if it ran successfully than by parsing its text output.

The following template will run an OS command (or other executable), wait for it to finish and store the return code in a macro variable called rc.

SysTask Command "YOUR COMMAND HERE" wait status=rc;

Again, chuck in a dir if you just want to see it work; use %put rc=&rc.; to see the return code in the log.

You can call the status macro variable something more specific to the task your completing, and then in a macro inspect it for the outcome. I like to use this technique when zipping (7zip) or copying data, then I can do a simple %if and %abort cancel; the macro if rc indicates something went wrong.