I often create temporary ODS output files - and getting rid of those files after I'm done is an extra chore I don't relish. For example, if I want to generate a PDF-only report and email it from SAS (see "Jedi SAS Tricks: Email from the Front – Part 2") there's no need to leave a copy of the PDF file cluttering up my hard drive after it's been sent. Or perhaps you generated a report to some other ODS destination, and closed the default HTML destination to avoid unnecessary output.
In SAS versions before the SAS9.4 M5 maintenance release, re-opening the default HTML destination directs all of the temporary HTML files created for reports to the SAS default directory. These "temporary" files will persist on the hard drive unless cleaned up. I need an easy way of placing my files in the path where the SAS WORK library is located. Files written there are automatically deleted when the SAS session terminates. I need a %PATHNAME macro function to enlighten my code! The DATA step PATHNAME function and a little macro magic should make this about as easy as winning a shootout with Greedo...
Building the %PATHNAME macro function
The PATHNAME function accepts a LIBREF or FILEREF as its first argument. If necessary for disambiguation, a second argument designates the name as a FILREF or LIBREF. Our macro will use the %qsysfunc() macro function to execute PATHNAME. The entire macro code is included in the ZIP file for this post. As the majority of the macro program text consists of self-documentation and parameter validation, we'll show just the working parts here:
%macro pathname(ref,mod); %if %superq(mod)= %then %let path=%qsysfunc(pathname(%superq(ref))); %else %let path=%qsysfunc(pathname(%superq(ref),%superq(mod))); %superq(path) %mend;
If I save the pathname.sas program in my SAS session's autocall path, I can use the new macro "function" in-line with my SAS code to provide the path to the WORK library whenever I need it.
Using the %PATHNAME macro function
Here is an example of how to use our new %PATHNAME function:
ods _all_ close; ods PDF file="%pathname(work)\myfile.pdf"; proc FedSQL; title "This is a test"; select * from sasuser.acities limit 10 ; quit; ods pdf close; ods html path="%pathname(work)";
You can use this technique to turn just about any SAS DATA step function into a macro function, making your everyday programming quicker and easier. As usual, you can download the %pathname macro and testing code from this link.
Until next time, may the SAS be with you!
What if a concatenated library is passed
The %PATHNAME macro will return the full concatenated path, just as the PATHNAME function in BASE SAS would do. And, of course, you wouldn't want to use a concatenated library path in this particular application - the code produced wouldn't make sense. In that case, the calling process might search the text returned for the presence of a parenthesis '(' to detect a concatenated library and, if detected, take appropriate action.
Great use of quoting functions! Of course, like any utility macro, there are many ways it can be enhanced.. One might be to test that the library is indeed a BASE engine (V9), as other engines (such as ODBC) are not directory based. A macro for this is referenced below, which might be used as follows:
%if &engine=V9 %then %do;
%if %superq(mod)= %then %let path=%qsysfunc(pathname(%superq(ref)));
%else %let path=%qsysfunc(pathname(%superq(ref),%superq(mod)));
%else %put Library has engine type &engine;
Thanks, Allan! An elegant and useful addition - I'm going to add this to the personal copy in my autocall path :-)
Extra tip: use the forward slash when building your file paths. SAS will make that work on Windows (where backslash is the usual delimiter) and on UNIX systems, so your program remains portable across different operating systems. Ex:
ods PDF file="%pathname(work)/myfile.pdf";
An EXCELLENT point, Chris! Windows is agnostic about which slash you use ("/" or "\"), as long as you are consistent. UNIX and LINUX only accept the forward slash (/). I'm a big fan of making my SAS programs as platform-independent as possible, and this is a good habit to get into. Unfortunately, I developed the habit of using "\"on Windows long before I learned to code in SAS, and breaking a bad habit is so much harder than learning it right the first time ;-)