%SYSFUNC: A powerful SAS® tool.
Foster Kerrison
NJSUG,
ABSTRACT
%SYSFUNC
is a very powerful and flexible component of the SAS ® system. This BASUG
presentation is designed to teach you how to understand the basic elements of
%SYSFUNC, and how to apply it to your daily tasks. %SYSFUNC is a macro
function, but you don’t need to be a macro guru to use it. %SYSFUNC allows you
to undertake a wide range of tasks related to your data by using consistent
syntax. Understanding how to use %SYSFUNC is the key to success, and this
presentation will teach you how.
INTRODUCTION
After
reading this paper, and the programs attatched, you should be able to incorporate
%SYSFUNC into your daily tasks. Over time, and with experience, you will learn
to add new and more complex features of %SYSFUNC, until you become adept at all
the options in %SYSFUNC.
%SYSFUNC
%SYSFUNC
was added in one of the version 6 enhancements, and is now available in all
current versions. %SYSFUNC runs on all systems, so you can use it anywhere.
%SYSFUNC
is a SAS ® utility which allows a programmer access to almost all SAS
functions, and 61 SCL functions.
MACROS
The
use of %SYSFUNC does not require that you know how to write macros,
although a few macro basics will help you get the best out of %SYSFUNC. The
primary macro statement to understand is the %LET statement. The syntax for
this is %LET name = value
;
This
is a macro language statement that assigns a value to a macro variable name. If
you use the %LET statement in open code it will automatically create a global macro variable (meaning you can
use it anywhere in that SAS ® session). If
you use it inside a macro, then it creates a local macro variable (meaning you can use it within the macro). To
illustrate:
%let
country =
To
use the assigned value we call it by putting an ampersand (&) in front of
it, like this: &country.
I
could then add it to a title statement anywhere:
TITLE “It is green in &country “;
And
the title would print like this:
It is green in
So
the value of the macrovar is assigned by the %LET statement, and called by
&country.
Being
able to pass values around like this is very convenient because we will see
that many of the %SYSFUNC operations can be assigned in open code and we can
pass their values around.
WHERE TO USE %SYSFUNC
%SYSFUNC can be used with: SAS
DATASETS, EXTERNAL FILES, SAS CATALOGS, and FILE DIRECTORIES.
%SYSFUNC
can be used in: open code (outside a datastep or macro), in a datastep, or
inside a macro. It is, therefore, very adabtable and of course very powerful.
%SYSFUNC with
Functions
First,
let’s have a look at how %SYSFUNC works with regular SAS® functions.
%SYSFUNC can access all SAS® functions, other than, DIF,
DIM, INPUT, PUT, LAG, RESOLVE, HBOUND, LBOUND, MISSING, IORCMSG and SYMGET.
%SYSFUNC
should not be confused with the SAS® %functions (e.g. %upcase(var)).
BASIC %SYSFUNC SYNTAX:
%SYSFUNC(FUNCTION(ARGUMENT<,FORMAT>)
;
To illustrate its use with
functions, I used a datastep to assign a value:
DATA NOM ;
NAMED = '
PADDIE ' ;
NEWNAME = TRANSLATE(NAMED,"X","
") ;
CALL SYMPUT('NOMAMA',NEWNAME)
;
RUN ;
%PUT &NOMAMA
;
XXXPADDIEXXX
Then I used %SYSFUNC to drop the X:
%let MAMA = %SYSFUNC(COMPRESS(&NOMAMA,X));
%PUT &MAMA
;
PADDIE
And then I added the X back
again:
%let MAMA = %sysfunc(TRANSLATE(&NOMAMA,X, ));
%PUT &MAMA ;
XXXPADDIEXXX
So I used a SAS function with
%SYSFUNC to flip over and back between:
PADDIE
XXXPADDIEXXX
Of course, we don’t really
need the datastep, because we can assign the value using a %let statement in
open code:
%let BENIGN = '
PADDIE ' ;
%put BENIGN = &BENIGN ;
BENIGN = ' PADDIE
'
Then use %sysfunc to change
it:
%let NASTY =
%SYSFUNC(translate(&BENIGN,X, )) ;
%put NASTY = &NASTY;
NASTY = 'XXXPADDIEXXX'
Now change it back again:
%let BENIGN2 =
%SYSFUNC(translate(&NASTY, ,X)) ;
%put BENIGN2 = &BENIGN2;
BENIGN2 = ' PADDIE
'
and finally, clean up the
value (remove the quotation marks):
%let BENIGN2 = %SYSFUNC(compress(&benign2,’’))
;
%put BENIGN2 = &BENIGN2;
BENIGN2 = PADDIE
You are probably wondering if
%SYSFUNC can be nested. The answer is: “of course!” The key is to nest each
%SYSFUNC. Like this:
%let ONELINE=
%SYSFUNC(compress(%SYSFUNC(translate((%SYSFUNC(translate(&BENIGN,"X","
")))," ","X")),"'() ")) ;
I
just used two functions here for illustration: translate, and compress, but you
have a vast array of functions available to you.
One other common use of
%SYSFUNC is in reformatting dates. First assign the date:
%let txtdate = 120403 ; * MMDDYY6 ;
%let trydate =
Using a macro approach:
%macro change_date (redate,sasfmt) ;
%let txtdate = %sysfunc(inputn(&&redate,&sasfmt)) ;
%mend change_date ;
%change_date
(&txtdate,mmddyy6) ;
or %SYSFUNC in open code:
%let trydate =
%sysfunc(inputn(&trydate,mmddyy8)) ;
gives us the SAS® date:
MACRO CONVERTED THE
TXTDATE TO: 16043 ;
OPEN
CODE CONVERTED THE DATE TO: 16043 ;
You can also use your own user created formats or
SAS® formats with %SYSFUNC.
%SYSFUNC with datasets
Another
powerful, and useful, operation is to use %SYSFUNC with a dataset. %SYSFUNC offers
an extensive range of dataset operations.
For
illustration, so that they are easier to follow, I like to break them into two
elements:
This
may be a little simplistic, because in many cases you will want to mix
different operations, so the differentiation does not always hold.
The
two major functions in 1. to look at dataset information are ATTRN and ATTRC.
The difference is that one returns a numeric code (ATTRN) and the other returns
a character (ATTRC). I have identified codes for the major functions in
appendix1. Check more of them yourself, by trying the code.
To
illustrate how this works, I want to check to see if a datasets exists. Then I
want to know various bits of information about it such as how many observations
and variables it has, how long the record is, when it was modified, if it is
password protected, whether it is sorted and so on. Could I get this from PROC
CONTENTS?
To
answer the first question: does the dataset exist?
%LET OK = %SYSFUNC(EXIST(<dataset name>)) ;
If
the dataset exists then the value for &OK is 1, but if it does not exist
then &OK will be 0.
It
is always a good idea to use IF statements to check if certain steps took
place. Because you use %IF statements you need to enclose the code in a macro.
Assuming
that the dataset exists, I want to have a look at it.
The
first key, and critical, step
is to open the dataset. An equally
critical step is to close it when you are finished, otherwise it will
not be available. So, putting these all together:
%IF %SYSFUNC(EXIST(&DS))
= 1 %THEN %DO ;
/* ASSIGN THE DATASET NAME */
%LET DSNAME = &DS ;
/* OPEN THE DATASET */
%LET DSID = %SYSFUNC(OPEN(&DSNAME)) ;
/* IF THE DATASET OPENED ...*/
%IF &DSID %THEN %DO ;
/* DOES IT HAVE OBS? */
%LET ANY = %SYSFUNC(ATTRN(&DSID,ANY)) ;
/* HOW MANY OBS DOES IT HAVE? */
%LET OBS = %SYSFUNC(ATTRN(&DSID,NOBS)) ;
/* HOW MANY VARS DOES IT HAVE? */
%LET VAR =
%SYSFUNC(ATTRN(&DSID,NVARS)) ;
/* WHAT IS THE LRECL? */
%LET LREC=
%SYSFUNC(ATTRN(&DSID,LRECL)) ;
/* WHEN WAS IT CREATED? */
%LET DTEC = %SYSFUNC(ATTRN(&DSID,CRDTE));
/* WHEN WAS IT MODIFIED? */
%LET DTE = %SYSFUNC(ATTRN(&DSID,MODTE)) ;
/* IS IT PASSWORD PROTECTED? */
%LET PWD= %SYSFUNC(ATTRN(&DSID,ALTERPW))
;
/* WHAT ENGINE WAS USED TO CREATE IT? NOTE: ATTRC, NOT ATTRN*/
%LET ENG = %SYSFUNC(ATTRC(&DSID,ENGINE)) ;
/* HAS IT BEEN SORTED? */
%LET SRT=%SYSFUNC(ATTRC(&DSID,SORTEDBY));
/* WHAT TYPE OF DATASET IS IT? */
%LET MDE = %SYSFUNC(ATTRC(&DSID,MODE));
/* CLOSE THE DATASET - A CRITICAL
STEP!*/
%LET RC = %SYSFUNC(CLOSE(&DSID)) ;
/* END THE DO STATEMENT */
%END ;
Feel free to modify this to
meet your own needs.
%SYSFUNC with files and directories
%SYSFUNC
is also a very powerful tool with files and directories.
The
basic syntax structure remains the same as we saw in datasets, but the
commands, as you would expect, are different.
The
process is also similar to what we saw in looking at datasets, 1. open the
file, 2. investigate the contents, and 3. close the file.
SAS®
uses the file data buffer (FDB) to
read the file contents.
The
first thing to do is to check if the file exists. So, create a fileref:
FILENAME TEST2
"C:\TESTS\TESTER.TXT" ; RUN
;
Then check for the file
(inside a macro):
%LET RC = %SYSFUNC(FEXIST(TESTER)) ;
%IF &RC = 1 %THEN %PUT THE
FILE EXISTS ;
Then open it, and work with it:
%LET FILRF = TEST2 ;
%LET RC = %SYSFUNC(FILENAME(FILRF,
C:\TESTS\TESTER.TXT)) ;
%IF &RC = 0 %THEN %PUT FILE
REF SUCCESSFUL ;
%LET FID = %SYSFUNC(FOPEN(&FILRF,I)) ;
%IF &FID = 1 %THEN %PUT
FILE OPEN WAS A SUCCESS ;
%IF &FID = 0 %THEN %PUT
%SYSFUNC(SYSMSG()) ;
%IF &FID > 0 %THEN %DO ;
%LET RC = %SYSFUNC(FREAD(&FID))
;
%LET RC = %SYSFUNC(FGET(&FID,MYSTRING,10));
%PUT
;
%PUT
THE DATA STRING IS: &MYSTRING ;
%PUT
;
%LET
INFOS = %SYSFUNC(FOPTNUM(&FID))
;
%PUT THE NUMBER OF FILE OPTIONS ARE: &INFOS AS FOLLOWS: ;
%DO
I = 1 %TO &INFOS ;
%LET NAME = %SYSFUNC(FOPTNAME(&FID,&I)) ;
%LET VALUE =
%SYSFUNC(FINFO(&FID,&NAME)) ;
%PUT %UPCASE(&NAME) HAS A VALUE OF
&VALUE ;
%END
;
%PUT
;
%LET
RC = %SYSFUNC(FCLOSE(&FID)) ;
%IF
&RC = 0 %THEN
%PUT THE FILE WAS CLOSED SUCCESSFULLY
;
%END ;
In this
case, we opened the file (FOPEN), then looked at the data in the first record
(FREAD) which I forced to read the first 10 characters - the default is to read
to the first token - and then identify the number of options (FOPTNUM), then I
created a loop to run through the names of each of the options (FOPTNAME),
outputting those values to the log, and then closed (FCLOSE) the file.
There are
many file manipulation options available, including appending data, identifying
various records within the file, moving the cursor around in the file to read
data, and so on.
We can also
work with the files themselves. Let’s say that we want to delete a file, we
call the fileref and in one line of code delete
the file:
%let rd = %sysfunc(fdelete(tester)) ;
In a directory, we can do similar
operations. First, let’s see how many
files are in a directory:
%LET DIR = C:\TEST ;
%LET DREF = TSTDIR ;
%LET RC = %SYSFUNC(FILENAME(DREF,&DIR))
;
%LET DID = %SYSFUNC(DOPEN(&DREF)) ;
%LET MEMBERS = %SYSFUNC(DNUM(&DID)) ;
%LET RC = %SYSFUNC(DCLOSE(&DID)) ;
%PUT FILES = &MEMBERS ;
Here, we
opened the directory (DOPEN), and checked to see how many members there were
(DNUM), closed the directory (DCLOSE), and then printed the number of members
in the log.
That’s a
useful thing to know, but you might also want to look at the names of the members.
If you do, then try this macro:
%MACRO MEMBER ;
%LET DIRECTORY = C:\TEST ;
%LET DREF = TSTDIR ;
%LET RC=%SYSFUNC(FILENAME(DREF,&DIRECT));
%LET DID = %SYSFUNC(DOPEN(&DREF)) ;
%LET MEMBERS = %SYSFUNC(DNUM(&DID)) ;
%DO I = 1 %TO &MEMBERS ;
%LET NAMED&I =
%SYSFUNC(DREAD(&DID,&I)) ;
%END ;
%LET RC = %SYSFUNC(DCLOSE(&DID)) ;
%PUT ;
%PUT THE NUMBER OF MEMBERS IN &DIRECT IS: = &MEMBERS ;
%DO T = 1 %TO &MEMBERS ;
%PUT FILENAME&T = &&NAMED&T
;
%END ;
%MEND MEMBER ;
%MEMBER ;
This will
produce a listing in your log of the number of files in the directory, and
their names. If you have a library on MVS, you can use this code to read the
number of members, and their names; just change the directory name to suit your
library name. If you have hundreds of files in your directory you might not
want to print them in your log, but that’s up to you. Remember, the basic steps
are, 1. open the directory, 2. check the contents, and 3. close.
So can we
mix these operations to pick individual files, read them and manipulate them in
one step? Yes you can, and how you do it is a matter of how adept and creative
you can become using %SYSFUNC.
RETURN CODES
I
mentioned earlier that I was including return codes for the major functions,
and I recommend that you become familiar with these return codes. Knowing what
code is returned - they are not always 1 for success and 0 for unsuccessful -
will make your life much easier.
I created a
table of codes with the associated %SYSFUNC code, which you might find useful
as a start point in becoming familiar with return codes.
DO IT YOURSELF
%SYSFUNC
has so many options to work with that you really have to build your own
approach and technique. Build your own, “homemade,” solutions to undertake
complex tasks to reconfigure data, or files.
For more
information about %SYSFUNC within the SAS® system look in online docs, and
drill down to find %SYSFUNC, or check the references below for examples.
Hopefully
this paper will give you the basics that allow you to use %SYFUNC. You are the
best person to determine your own needs, and you are the best person to build
on the basics in this paper, so I encourage you to test and use %SYSFUNC
approaches to make your life easier, and add to your SAS® skillsets.
CONTACT INFORMATION
Foster Kerrison
Phone: 603-520-7520
Email: kerrison@metrocast.net
REFERENCES:
SAS Institute Inc., SAS ® Macro
Language : Reference, first edition, SAS Institute,
Burlew, Michele M. SAS® MACRO Programming
Made Easy, Cary, NC SAS Institute Inc., 2001. 208pp.
Ysidra, Chris, “%SYSFUNC – The brave
new macro world”, SUGI23, 1998.
SAS Institute Inc.,
TS-DOC:TS-544-Base Language Changes for release 6.09E Maintenance, SAS Institute,