DATA Step, Macro, Functions and more

How to do a relative include?

Accepted Solution Solved
Reply
Contributor
Posts: 44
Accepted Solution

How to do a relative include?

I have a number of directories each containing the same sas program.  I would like to

set some macro variables in a small sas file in each of these directories and then

include it in the main sas program.  Because the main sas program can be copied

to a number of directories I don't want to use an absolute path in the include statement.

Is there a way to use relative paths?   For example, if I had this include statement in

my main sas program:

%include 'linemg.sas';

and then tried to run the main sas program from within the sas application window, I get

an error stating that it cannot open the file.  If I specify the absolute path in the include

statement it works but I don't want to have to do that.  Does the concept of a current working

directory exist in sas?


Accepted Solutions
Solution
‎10-04-2011 06:47 PM
Super User
Posts: 10,500

Re: How to do a relative include?

If the relative path you need is relative to the location of the currently executing SAS program I think you are looking for the automatic SAS variables SAS_EXECFILEPATH and SAS_EXECFILENAME.

This requires the executing code to have been saved. The macro variable PATH should be

%let a=%sysget(SAS_EXECFILEPATH);
%let b=%sysget(SAS_EXECFILENAME);

%let path= %sysfunc(tranwrd(&a,&b,''));
%put &path;

The macro variable PATH should be ready to use as %include "&path.codefile.sas";

View solution in original post


All Replies
Valued Guide
Posts: 2,175

How to do a relative include?

There is a 'current folder'. Set or change it with SAS statement:

X CD "your preferred folder";

The default is set by the current folder in which SAS is launched.

Relative folders can be defined in the normal way

Here is  ./

Parent ../

Child folder ./childfolder

Cousin folder ../cousin

Use \ if not on unix (only sometimes do we get away with / on windows)

Peter

PROC Star
Posts: 7,363

How to do a relative include?

Take a look at the various options expressed throughout the following sas-l thread:

http://listserv.uga.edu/cgi-bin/wa?A2=ind1010a&L=sas-l&D=0&O=D&m=22408&P=13821

Contributor
Posts: 44

Re: How to do a relative include?

Hi Art,

This is exactly what I was looking for.  However, I can't seem to get it to work.  I tried this piece of code:

* ConCheck.sas ;

%include 'c:\SASUtils\dissectionIO20110912.sas';

%include 'c:\SASUtils\Current.sas';

%Current;

%include "&Current\linemg.sas"';

The output log shows this:

1    * ConCheck.sas ;

2    %include 'c:\SASUtils\dissectionIO20110912.sas';

22   %include 'c:\SASUtils\Current.sas';

38   %Current;

NOTE: The infile PRESENT is:

      Unnamed Pipe Access Device,

      PROCESS=CD,RECFM=V,LRECL=256

Stderr output:

The handle is invalid.

NOTE: 0 records were read from the infile PRESENT.

NOTE: DATA statement used (Total process time):

      real time           0.14 seconds

      cpu time            0.03 seconds

NOTE: Libref CURRENT was successfully assigned as follows:

      Engine:        V9

      Physical Name: C:\Users\barrisw\

39   %include "&Current\linemg.sas";

WARNING: Physical file does not exist, C:\linemg.sas.

ERROR: Cannot open %INCLUDE file \linemg.sas.

Super User
Posts: 9,681

Re: How to do a relative include?

Here is a workaround. Assuming all of your directories which contains SAS code are under c:\temp.

filename fname pipe 'dir c:\temp\*.sas /S /b';
data _null_;
infile fname;
input;
call symputx(scan(_infile_,-2,'.\'),_infile_);
run;
%put _user_;
%include "&a1";










86   %put _user_;
GLOBAL A1 c:\temp\a\a1.sas
GLOBAL A2 c:\temp\a\a2.sas
GLOBAL B1 c:\temp\b\b1.sas
GLOBAL B2 c:\temp\b\b2.sas
87   %include "&a1";

Ksharp

消息编辑者为:xia keshan

Contributor
Posts: 44

Re: How to do a relative include?

Hi Ksharp,

Thanks for the advice.  However, when I tried to run this I got errors.  Perhaps I'm not doing this correctly:

Plus, I dont' want to have to specify the directory in the sas program.

filename fname pipe 'dir m:\L01mg300\*.sas /S /b';

data _null_;

infile fname;

input;

call symputx(scan(_infile_,-2,'.\'),_infile_);

run;

%put _user_;

%include "&a1";

Log output:

NOTE: Copyright (c) 2002-2008 by SAS Institute Inc., Cary, NC, USA.

NOTE: SAS (r) Proprietary Software 9.2 (TS2M3)

NOTE: This session is executing on the X64_DSRV08  platform.

NOTE: SAS initialization used:

      real time           1.96 seconds

      cpu time            0.79 seconds

1    filename fname pipe 'dir m:\L01mg300\*.sas /S /b';

2    data _null_;

3    infile fname;

4    input;

5    call symputx(scan(_infile_,-2,'.\'),_infile_);

6    run;

NOTE: The infile FNAME is:

      Unnamed Pipe Access Device,

      PROCESS=dir m:\L01mg300\*.sas /S /b,RECFM=V,

      LRECL=256

Stderr output:

There is not enough space on the disk.

NOTE: 0 records were read from the infile FNAME.

NOTE: DATA statement used (Total process time):

      real time           0.15 seconds

      cpu time            0.03 seconds

7    %put _user_;

8    %include "&a1";

WARNING: Apparent symbolic reference A1 not resolved.

WARNING: Physical file does not exist, C:\Users\barrisw\&a1.

ERROR: Cannot open %INCLUDE file &a1.

PROC Star
Posts: 7,363

Re: How to do a relative include?

Wes, Do you happen to have the name(s) current and/or present reserved for something else?  It worked perfectly on my machine.

You shouldn't end the macro call with a semi-colon, but that wouldn't cause the error you received.

Contributor
Posts: 44

Re: How to do a relative include?

Hi Art,

I don't think that Current or Present are defined anywhere else.  I've found that if I navigate inside Windows Explorer to the sas file and double-click on it, it opens the SAS environment window.  If I then click on the "run" icon it works.  However, if I first start the SAS environment and then use File-> Open Program and then navigate to that same sas file, and then run it, it issues the errors I mentioned.

Successful run (double clicking on sas file in windows explorer):

1    * ConCheck.sas ;

2    %include 'c:\SASUtils\dissectionIO20110912.sas';

22   %include 'c:\SASUtils\Current.sas';

38   %Current;

NOTE: The infile PRESENT is:

      Unnamed Pipe Access Device,

      PROCESS=CD,RECFM=V,LRECL=256

NOTE: 1 record was read from the infile PRESENT.

      The minimum record length was 11.

      The maximum record length was 11.

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.00 seconds

NOTE: Libref CURRENT was successfully assigned as follows:

      Engine:        V9

      Physical Name: M:\L01mg300

39   %include "&Current\linemg.sas";

Failed run (navigating to file from sas environment):

1    * ConCheck.sas ;

2    %include 'c:\SASUtils\dissectionIO20110912.sas';

22   %include 'c:\SASUtils\Current.sas';

38   %Current;

NOTE: The infile PRESENT is:

      Unnamed Pipe Access Device,

      PROCESS=CD,RECFM=V,LRECL=256

Stderr output:

The handle is invalid.

NOTE: 0 records were read from the infile PRESENT.

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.00 seconds

NOTE: Libref CURRENT was successfully assigned as follows:

      Engine:        V9

      Physical Name: C:\Users\barrisw\

39   %include "&Current\linemg.sas";

WARNING: Physical file does not exist, C:\linemg.sas.

ERROR: Cannot open %INCLUDE file \linemg.sas.

Super User
Super User
Posts: 6,500

Re: How to do a relative include?

It looks like your CURRENT macro is just creating a LIBREF and is not assigning anything to the CURRENT macro variable.

If it does assign a value to the CURRENT macro variable without first defining it as local then if you define it first the macro will be able to return a value.  (Look at the concept of LOCAL and GLOBAL macro variables).

So try:

%let current=;

%current;

%put current="&current";

To see if that works.

Another idea is just use . as the current directory.  This will reference whatever your SAS process considers the current working directory.

Also you can use the PATHNAME function to get the path to the CURRENT library that the macro is creating.

%current;

%let current=%sysfunc(pathname(current));

Contributor
Posts: 44

Re: How to do a relative include?

Thanks Tom.

Attempting your first suggestion:

1774  %let Current=;

1775  %Current;

NOTE: The infile PRESENT is:

      Unnamed Pipe Access Device,

      PROCESS=CD,RECFM=V,LRECL=256

Stderr output:

The handle is invalid.

NOTE: 0 records were read from the infile PRESENT.

NOTE: DATA statement used (Total process time):

      real time           0.03 seconds

      cpu time            0.01 seconds

NOTE: Libref CURRENT was successfully assigned as follows:

      Engine:        V9

      Physical Name: C:\Users\barrisw\

1776  %put Current="&Current";

Current=""

1777  %include "&Current\linemg.sas";

WARNING: Physical file does not exist, C:\linemg.sas.

ERROR: Cannot open %INCLUDE file \linemg.sas.

I've already tried usine ./linemg.sas but the current working directory inside the SAS environment is not the same as where the .sas file sits in the filesystem.

using sysfunc and pathname...

looks like it is picking up my home directory and not the directory where the .sas program exists.

NOTE: Libref CURRENT was successfully assigned as follows:

      Engine:        V9

      Physical Name: C:\Users\barrisw

1341  %let Current=%sysfunc(pathname(Current));

1342  %include "&Current\linemg.sas";

WARNING: Physical file does not exist, C:\Users\barrisw\linemg.sas.

ERROR: Cannot open %INCLUDE file C:\Users\barrisw\linemg.sas.

Solution
‎10-04-2011 06:47 PM
Super User
Posts: 10,500

Re: How to do a relative include?

If the relative path you need is relative to the location of the currently executing SAS program I think you are looking for the automatic SAS variables SAS_EXECFILEPATH and SAS_EXECFILENAME.

This requires the executing code to have been saved. The macro variable PATH should be

%let a=%sysget(SAS_EXECFILEPATH);
%let b=%sysget(SAS_EXECFILENAME);

%let path= %sysfunc(tranwrd(&a,&b,''));
%put &path;

The macro variable PATH should be ready to use as %include "&path.codefile.sas";

Contributor
Posts: 44

Re: How to do a relative include?

Thanks ballardw, that is exactly what I was looking for.  I only had to make one small modification to get it working.  That was to remove the empty quotes:

%let path= %sysfunc(tranwrd(&a,&b,));

tranwrd was replacing the filename with the two adjacent quotes.  Removing them made it do what I needed.

Valued Guide
Posts: 2,175

How to do a relative include?

Wes

looks like you need to set the current folder, then relative paths will work from there. Double click on the folder/address in the status-bar aat the foot of the SAS environment (assuming that you are not running sas in enterprise guide)

status.bar.JPG

or  submit statement

   x cd 'required current folder' ;

Peter.

Super User
Super User
Posts: 6,500

Re: How to do a relative include?

IF you are using the "enhanced" editor in Windows then you can take advantage of environment variables that it sets. That's a big IF for those of us using SAS on other operating systems or who just prefer the normal program editor.

I prefer to use SUBSTR and LENGTH to deal with pulling just the path from the beginning of a string.  Using a translate function runs the risk of confusion if some friendly programmer happended to have created a subdirectory that matches your filename.

data _null_;

  p1=sysget('sas_execfilepath');

  p2=sysget('sas_execfilename');

  dir=substr(p1||' ',1,length(p1)-length(p2));

  call system('cd ' || quote(trim(dir)));

  put 'Running program: ' p1 / 'Switching to directory: ' dir ;

run;

Contributor
Posts: 44

Re: How to do a relative include?

Thanks Tom.  That is a good point about the lenght and substring.  I'll probably implement something like that.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 14 replies
  • 5875 views
  • 4 likes
  • 6 in conversation