Let’s consider the following ubiquitous scenario. You have created a SAS program that you want to run automatically on schedule on a SAS server under the Microsoft Windows operating system.
But even if you only have SAS Foundation installed on a Windows server (or any Windows machine), you can automate/schedule your SAS program to run in batch using Windows Task Scheduler. In order to do that you would need a Windows batch file.
What are Windows batch files?
A Windows batch file (or batch script) is a text file consisting of a series of Windows commands executed by the command-line interpreter. It can be created using a plain text editor such as Notepad or Notepad++ and saved as a text file with the .bat file name extension. (Do not use a word processor like Microsoft Word for batch script writing!)
Historically, batch files originated in DOS (Disk Operating System), but modern versions of Windows continually support them. Batch files get executed when you double click on them in Windows File Explorer or type & enter their name in the Command Prompt window.
Besides simply running a bunch of OS commands sequentially one after another, batch scripts can be more sophisticated. For example, they can use environment variables (which are similar to SAS macro variables). They can use functions and formats. They can capture exit code from one command (or SAS program) and then, depending on its value, conditionally execute a command or a group of commands (which might include another SAS program or another batch script). They can even do looping.
They can submit a SAS program to run by the SAS System in batch mode and pass a parameter string to this program.
They can dynamically generate a unique log file name suffixed with a datetime stamp, as well as control where the SAS program saves its log file.
Windows batch script examples
Let’s explore a couple of examples.
Example 1. Simple script running SAS program in batch mode
set sas=D:\SAS94\sashome\SASFoundation\9.4\sas.exe set proj=C:\Projects\SAS_to_Excel set name=mysasprogram set pgm=%proj%\%name%.sas set log=%proj%\logs\%name%.log %sas% -sysin %pgm% -log %log% -nosplash -nologo -icon
Here, we define several environment variables (proj, name, pgm, log) and reference these variables by surrounding their names with %-sign as %variable-name% (analogous to SAS macro variables which are defined by %let mvar-name = mvar-value; and referenced as &mvar-name).
This script will initiate SAS session in batch mode which executes your SAS program mysasprogram.sas and outputs SAS log as mysasprogram.log file.
Example 2. Running SAS program in batch and date/time stamping SAS log
Batch scripts are often used to run a SAS programs repeatedly at different times. In order to preserve SAS log for each run, we can assign unique names for the log files by suffixing their names with a date/time. For example, instead of saving SAS log with the same name mysasprogram.log we can dynamically generate unique names for SAS log, e.g. mysasprogram_YYYYMMDD_HHMMSS, where YYYYMMDD_HHMMSS indicates the date (YYYYMMDD) and time (HHMMSS) of run. This will effectively keep all SAS logs and indicate when (date and time) each log file was created. Here is a Windows batch script that does it:
: generate suffix dt=YYYYMMDD_HHMMSS, pad HH with leading 0 set z=%time: =0% set dt=%date:~-4%%date:~4,2%%date:~7,2%_%z:~0,2%%z:~3,2%%z:~6,2% set sas=D:\SAS94\sashome\SASFoundation\9.4\sas.exe set proj=C:\Projects\SAS_to_Excel set name=mysasprogram set pgm=%proj%\%name%.sas set log=%proj%\logs\%name%_%dt%.log %sas% -sysin %pgm% -log %log% -nosplash -nologo -icon
Windows batch scripts with conditional execution
Let’s enhance our script by adding the following functionality:
- Captures exit code from the mysasprogram.sas (exit code 0 mean there are no ERRORs or WARNINGs)
- If exit code is not equal to 0, conditionally execute another SAS program my_error_email.sas which sends out an email to designated recipients informing them that mysasprogram.sas failed (successful execution email can be sent from mysasprogram.sas itself).
One would expect that it can be achieved by adding the following scripting code to the above example 2:
: capture exit code from sas set exitcode=%ERRORLEVEL% : generate email if ERROR and/or WARNING if not %exitcode% == 0 ( set ename=my_error_email set epgm=%proj%\Programs\%ename%.sas set elog=%proj%\SASLogs\%ename%_%dt%.log %sas% -sysin %epgm% -log %elog% -nosplash -nologo -icon -sysparm %log% )
However, you might be in for a big surprise (I was!) when you discover that my_error_email.sas program runs regardless of whether exitcode is equal on not equal to 0. How is that possible!
It turned out that Windows script environment variable references in form of %variable-name% do not resolve at execution time like SAS macro variable references &mvar-name or Unix/Linux script variable references $variable-name . They resolve during the initial script parsing before the run-time exitcode is evaluated. As a result, all the commands within the parentheses of the IF-command (including SAS session kickoff) are resolved and executed unconditionally.
Initially, DOS (and later Windows) scripts were implemented without conditional execution (IF command) and looping (FOR command) functionality and their environment variable references were resolving during script parsing. Later, when scripting language was brought to a higher standard that did include conditional execution and looping, the developers decided to keep the original behavior of the %variable-name% references intact, but added a new form of the environment variable references !variable-name! surrounding variable names with exclamation marks. They called it "delayed expansion" and cardinally altered the variable references behavior causing them to resolve (expand) during execution time rather than parse time.
The following scripting command enables delayed expansion:
We can place this SetLocal command right before the IF section and replace variable references in it with !variable-name! . Alternatively, for consistency, we can place SetLocal EnableDelayedExpansion at the beginning of the script and replace all environment variable references with !variable-name! . In the latter case, all our variables will be resolved at execution time. Here is the final script:
SetLocal EnableDelayedExpansion : generate suffix dt=YYYYMMDD_HHMMSS, pad HH with leading 0 set z=!time: =0! set dt=!date:~-4!!date:~4,2!!date:~7,2!_!z:~0,2!!z:~3,2!!z:~6,2! set sas=D:\SAS94\sashome\SASFoundation\9.4\sas.exe set proj=C:\Projects\SAS_to_Excel set name=mysasprogram set pgm=!proj!\!name!.sas set log=!proj!\logs\!name!_!dt!.log !sas! -sysin !pgm! -log !log! -nosplash -nologo -icon : capture exit code from sas set exitcode=!ERRORLEVEL! : generate email if ERROR and/or WARNING if not !exitcode! == 0 ( set ename=my_error_email set epgm=!proj!\Programs\!ename!.sas set elog=!proj!\SASLogs\!ename!_!dt!.log !sas! -sysin !epgm! -log !elog! -nosplash -nologo -icon -sysparm !log! )
Notice, how we pass in to the my_error_email.sas program the log name of failed mysasprogram.sas:
This log name can be captured in the my_error_email.sas program by using the SYSPARM automatic macro variable:
%let failed_log = &sysparm;
Then, it can be used either to attach that log file to the automatically generated email or at least provide its path and name in the email body.
With Windows batch script file in place, you can easily schedule and run your SAS program in batch mode on a SAS machine that have just SAS Foundation installed using Microsoft Windows Task Scheduler. In order to do that you would need to specify your script’s fully qualified name in the Windows Task Scheduler (Create Task → New Action → Program/script field) as shown below:
Then you would need to specify (add) new Trigger(s) that ultimately define the scheduling rules:
That’s all. You can now sleep well while your job runs at 3:00 am.
Questions? Thoughts? Comments?
Do you have questions, concerns, comments or use other ways of automating SAS jobs? Please share with us below in the Comments section.