Monday, February 27, 2017

Hack 4.14 Running System Commands from a SAS Program


SAS Programming Professionals,

Did you know that you can execute Windows operating system commands from within a SAS Data step?

You can do this by using the CALL SYSTEM call routine.  Unlike its blunt cousin the X statement, CALL SYSTEM can be executed conditionally within a DATA step.  This makes it much more flexible and useful.  Here is an example:

/* Rename directory on Mondays*/
data _null_;

if weekday(today()) = 2 then do;

      call system("rename c:\temp\mikedir mikedir_old");
      call system("md c:\temp\mikedir");

end;

run;

ods rtf file="c:\temp\mikedir\classlist.rtf";

proc print noobs data=sashelp.class;
title1 "List of Subjects in Weight/Height Study";
run;

ods rtf close;

In the example, the DATA _NULL_ step houses the CALL SYSTEM call routines.  They are only executed when the current day of the week is Monday.  When they are executed, the first CALL SYSTEM sends a command to Windows to rename the MIKEDIR directory to MIKEDIR_OLD.  The second CALL SYSTEM sends a command to Windows to create a new directory named MIKEDIR.  The subsequent PROC PRINT creates an RTF file in the new MIKEDIR directory.

Obviously, the Windows system commands must be syntactically correct for the CALL SYSTEM call routine to work properly.  Here is one of the many online sources for looking up Windows system commands:


The previously mentioned X command executes unconditionally.  That means that if we were to replace both CALL SYSTEM’s with X commands in the program above, they would executed no matter what day of the week it is.  They just barge right in.  That is why I prefer the CALL SYSTEM call routine for shelling out operating system commands from within my SAS programs.

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, February 20, 2017

Hack 4.13 Reversing Character Strings with the REVERSE Function


SAS Programming Professionals,

Did you know that: the REVERSE function can be very useful and also a lot of fun to use?

The REVERSE function can be used to return a character string in reverse order.  For instance, consider the following example:

data testit;

x = "SAS";
Y = reverse(x);

put "x= " x;
put "y= " y;

run;

As you can see from the log:

1    data testit;
2
3    x = "SAS";
4    Y = reverse(x);
5
6    put "x= " x;
7    put "y= " y;
8
9    run;

x= SAS
y= SAS

… Y is the exact reverse of X!

A more practical application of this can be found when you need to pluck out the last node in something, such as a full-path file name.  Here is an example from a SAS program that I use to get the name of previously executed SAS programs from the LOGFILE variable in LOGPARSE SAS data sets:

/**********************************/
/* Determine the SAS program name */
/**********************************/
logtemp = reverse(strip(logfile));

r = index(logtemp,"\");

substr(logtemp,r,length(logtemp) - r + 1) = " ";

SASprogram = tranwrd(strip(reverse(logtemp)),"log","sas");


In the example, I know that logfile has the full path name of a SAS log, such as:  "c:\production\fy02\bigprog.log".  If the name of the log is "bigprog.log", then the program that was executed must be "bigprog.sas".  That is what I want to capture in variable SASprogram.

So, the snippet of code first reverses LOGFILE, then looks for the first "/", which was originally the last "/", but is now the first one since the full path has been reversed.  It turns the rest of the contents of LOGTEMP into blanks.  Then, it sets SASprogram equal to the strip-ed, reverse (again) of LOGTEMP while translating "log" into "sas".  Neat, clean, and effective!

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, February 13, 2017

Hack 4.12 Renaming Files and Directories from A DATA Step


SAS Programming Professionals,

Did you know that you can rename SAS data sets, SAS catalog entries, as well as OS directories and files in directory-based operating systems from inside of a SAS DATA step? 

The RENAME function lets you do exactly that!  It is great for SAS purists who do not want to use the X command or the CALL SYSTEM routine to “shell out” to the operating system to rename files and/or directories.  And, if you have PROC DATASET phobia, you can use the RENAME function to rename SAS files.

Here is a simple example:

data _null_;

rc = rename('c:\temp\test.pdf', 'c:\temp\old.pdf', 'file');

put "*****************";

put "the return code is: " rc;

put "*****************";

run;

The example above renames “test.pdf” to “old.pdf” in a DATA step.  The nice thing about the RENAME function that differentiates it from the X command or the CALL SYSTEM routine is that you get a return code that you can query to make sure that your rename worked.

Intrigued?  Well, then read more about it in the SAS online documentation on support.sas.com

Best of luck in all your SAS endeavors!


---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, February 6, 2017

Hack 4.11 Removing Leading and Trailing Blanks with the STRIP Function


SAS Programming Professionals,

Did you know that there is a function that will effortlessly strip off leading and trailing blanks from a character variable?

The aptly named STRIP function allows you to do just that and is a great replacement for the old TRIM(LEFT(character-variable)) construct many programmers used to use.

Here is an example of using the STRIP function:

data cars;
set  sashelp.cars;

car_statement = "The " || strip(make) ||
                   " " || strip(model)||
              " is a " || strip(type) ||
              ".";

run;

proc print noobs data=cars;                    
      var car_statement;
run;

Which produces, in part:

The Acura MDX is a SUV.
The Acura RSX Type S 2dr is a Sedan.
The Acura TSX 4dr is a Sedan.
The Acura TL 4dr is a Sedan.
The Acura 3.5 RL 4dr is a Sedan.
The Acura 3.5 RL w/Navigation 4dr is a Sedan.
The Acura NSX coupe 2dr manual S is a Sports.
The Audi A4 1.8T 4dr is a Sedan.
The Audi A41.8T convertible 2dr is a Sedan.

In the example, we are constructing variable CAR_STATEMENT by concatenating string constants and concatenating the variables MAKE (13 characters in length), MODEL (40 characters in length) and TYPE (8 characters length).  Without the STRIP function, there would be big gaps in CAR_STATEMENT because many of the MAKEs, MODELs, and TYPEs are not 13, 40, and 8 characters long, respectively.

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, January 30, 2017

Hack 4.10 Removing Leading and Trailing Blanks with the CATX Function


SAS Programming Professionals,

Do you know that you can quickly and easily remove leading and trailing blanks when concatenating character variables together?

If you were thinking “Ah yes, the CATS function!” then give yourself a prize!  However, this tip is really about the CATX function.

The CATX function removes leading and trailing blanks and inserts a separator between the variable values being concatenated.  (The CATS function only removes leading and trailing blanks).   This function is handy for building meaningful character variables from two or more variables—like building a full name from first name, middle name, and last name.

Here is an example:

data names;

firstname  = "       Francis";
middlename = "Scott         ";
lastname   = "   Key        ";

fullname = catx(" ", firstname, middlename, lastname);

run;

proc print noobs data=names;
run;

You can see that FIRSTNAME has leading blanks, MIDDLENAME has trailing blanks, and LASTNAME has both leading and trailing blanks.  The CATX function specifies that the separator should be a blank.  So, the result of the PROC PRINT is:

     firstname    middlename    lastname         fullname

     Francis       Scott         Key       Francis Scott Key

If you like the CATX function, check out its brothers, the CAT, CATT, and CATS functions!

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, January 23, 2017

Hack 4.9 Removing Blanks From Macro Variable Text


SAS Programming Professionals,

Did you know that the CALL SYMPUTX routine can save you keystrokes and lead to leaner, cleaner SAS programs? 

In the past, when we needed to load a SAS macro variable with a character string that might contain blanks, we would do the following:

call symput('MACROVAR',trim(left(charvar)));

This can be reduced by 12 keystrokes by using CALL SYMPUTX in the following manner:

call symputX('MACROVAR',charvar);

Think how happy your tired fingers will feel with a savings like that!

My older programs are littered with "trim(left)" CALL SYMPUT's and I would bet that yours are too.  I plan to replace mine as time and circumstance allows when I open my programs to address other issues.  How about you?

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers

Monday, January 16, 2017

Hack 4.8 Putting Your SAS Programs to Sleep


SAS Programming Professionals,

Did you know that you can actually put your SAS programs to sleep?

The SLEEP function suspends execution of your SAS program (puts it to sleep) for the duration of time that you specify in the function.  This function comes in handy when you need to programmatically pause your SAS programs for various reasons.  One such reason is to wait for an asynchronous system event to occur before your SAS program continues.  For example, if you use an X statement to invoke an operating system command, you could put your program to SLEEP for the duration that it takes for that command to complete.

The general form of the SLEEP function is:  Q = SLEEP(N); …where:

·        Q = any SAS variable

·        N = the number of seconds to wait.  The maximum is 46 days!  See the documentation if you want to specify other intervals, such as micro-seconds.

Here is an example of the SLEEP function in action:

options noxwait noxsync xmin;

x '"C:\Program Files\Microsoft Office\Office11\excel.exe"';

data _null_;
  x=sleep(10);
run;

filename comma1 dde 'excel|system';

data _null_;
 file comma1;
 put '[open("D:\MCR\t_excel.xls")]';
run;

data _null_;
  x=sleep(10);
run;

…Other SAS code to populate the Excel spreadsheet…

The overall thrust of this example is to use DDE to open and populate an Excel spreadsheet from a SAS program.  First, we use the SAS X statement to send a command to Windows to open Excel.  Secondly, we put our program to sleep for 10 seconds in a DATA _NULL_ step to give Windows enough time to complete opening Excel.  Next, the FILENAME statement sets up our DDE “environment” and the second DATA _NULL_ creates our spreadsheet in the opened Excel program.  Then, we put our SAS program to sleep a second time to give Excel enough time to create the t_excel.xls spreadsheet in the opened Excel program in the aforementioned DATA _NULL_ step.

If you are tired of having your programs fail due to SAS-generated asynchronous tasks not completing on time, consider using the SLEEP function!

Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers