BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
WesBarris
Obsidian | Level 7

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?

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

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

14 REPLIES 14
Peter_C
Rhodochrosite | Level 12

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

art297
Opal | Level 21

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

WesBarris
Obsidian | Level 7

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.

Ksharp
Super User

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

WesBarris
Obsidian | Level 7

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.

art297
Opal | Level 21

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.

WesBarris
Obsidian | Level 7

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.

Tom
Super User Tom
Super User

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));

WesBarris
Obsidian | Level 7

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.

ballardw
Super User

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";

WesBarris
Obsidian | Level 7

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.

Peter_C
Rhodochrosite | Level 12

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.

Tom
Super User Tom
Super User

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;

WesBarris
Obsidian | Level 7

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

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 14 replies
  • 14379 views
  • 6 likes
  • 6 in conversation