BookmarkSubscribeRSS Feed
Babloo
Rhodochrosite | Level 12

I've  a requirement to pass file names as argument to create a dataset. As of now, I've the code where I read file names from .txt file and then calling macro, but my managements wants me to pass file names as argument by considering the future requirements.

 

My Existing code will be like,

 

data log.output_file ;
  infile "&path/output_file.txt" firstobs=2 truncover ;
  input fname $400. ;
run;

%macro log_analysis;

data log.log_analysis;
set log.output_file;
filename=fname;
length fname $400;
infile dummy dsd truncover FILEVAR = fname END = end_of_file LRECL=32000;
DO WHILE (not end_of_file);
input var : $ 3000.;
..........
..........
%mend log_analysis;

data _null_;
  set log.output_file;
  if fname =: '/usr/sas/SASApp_STPServer' then call execute ('%log_analysis;');
else put 'no log files';
run;

 

With this code, I'm calling the macro based on the filename. Instead of that, I need to create a macro and then pass file names as argument.

 

Although I've referred the example 2 from the following,I could not suceed.

 

https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000210819.htm

 

Kindly seeking someon'e help to achive this task.

 

Thanks!

 

18 REPLIES 18
arodriguez
Lapis Lazuli | Level 10

If I have understood it properly, you want to use a macro with a parameter. To do that you must do something like that

 


%macro import_file(parameter1);

*to use it you must do something like that; "&path/&parameter1..TXT"; %mend;

%import_file(TEST);

or


%macro import_file(parameter1=);

*to use it you must do something like that;
"&path/&parameter1..TXT";

%mend;

%import_file(parameter1=TEST);

They look really similar, the first if you put multiples parameters, they must be given in the same order of the definition. In the second you could give values to parameter without matter about the order.

 

I recomend use the second one, because if you have a macro with 10 parameters is very difficult to remmember order.

Babloo
Rhodochrosite | Level 12

In your second example, how will you give the filenames to parameter without hardcoding? Can't we get the file reference and file name from .txt file and pass it to the macro parameter?

arodriguez
Lapis Lazuli | Level 10

You mean how to give a array of files to import and avoid to execute proc import for each parameter? You could define a character as separator of the array (I use to use # because sometimes files have spaces in names).

Uou could do something like

 

%macro import_files(File_names=);

%local i actual_file;
%do i=1 %to %sysfunc(countw(&File_names));
  %let actual_file=%scan(&File_names,&i,%str(#));
*Now you have a parameter Actual_file with the i-th file that could be use as macro parameter in a
data _null_ or proc import; %end; %mend;

%import_files(File_names=File1#File2#OtherFile);

 

Babloo
Rhodochrosite | Level 12

 

Thanks for your coninued support.

 

I can import the file via data step and I've the code to do that. I need to pass file names as parameter while I reading the file to create a dataset.

 

In the code below, could you please tell me the folder where it will search for the file?

arodriguez
Lapis Lazuli | Level 10
%macro import_files(File_names=);

%local i actual_file;
%do i=1 %to %sysfunc(countw(&File_names));
  %let actual_file=%scan(&File_names,&i,%str(#));  *Now you have a parameter Actual_file with the i-th file that could be use as macro parameter in a  data _null_ or proc import;

data log.output_file ;
  infile "&path/&actual_file..txt" firstobs=2 truncover ;
  input fname $400. ;
run;

%end;

%mend;%import_files(File_names=File1#File2#OtherFile);

I think that you want to do something like that, since it use the &path macro variable, it depend on want you put in this macro var

Babloo
Rhodochrosite | Level 12

From the following line, it seems you're hard coding the file names.

 

%import_files(File_names=File1#File2#OtherFile);

If so, I would like to have a macro without any hardcoding.

arodriguez
Lapis Lazuli | Level 10

You coud use the macro of http://support.sas.com/kb/45/805.html This macro search all files in a directory


%macro drive(dir,ext); 

	%local filrf rc did memcnt name;
                                                                                                                                        
  %let filrf=mydir;                                                                                                                      
                                                                                                                                        
  /* Assigns the fileref of mydir to the directory and opens the directory */                                                                    
  %let rc=%sysfunc(filename(filrf,&dir));                                                                                                
  %let did=%sysfunc(dopen(&filrf));                                                                                                              
  /* Returns the number of members in the directory */                                                                   
  %let memcnt=%sysfunc(dnum(&did));                                                                                                      
                                                                                                                                        
   /* Loops through entire directory */                                                                                                  
   %do i = 1 %to &memcnt;                                                                                                                
    
     /* Returns the extension from each file */                                                                                                                                    
     %let name=%qscan(%qsysfunc(dread(&did,&i)),-1,.);                                                                                   
                                                                                                                                        
     /* Checks to see if file contains an extension */                                                                                     
     %if %qupcase(%qsysfunc(dread(&did,&i))) ne %qupcase(&name) %then %do;                                                                  
                                                                                                                                        
     /* Checks to see if the extension matches the parameter value */                                                                      
     /* If condition is true prints the full name to the log       */                                                                      
      %if (%superq(ext) ne and %qupcase(&name) = %qupcase(&ext)) or                                                                       
         (%superq(ext) = and %superq(name) ne) %then %do;                                                                                     
         		%qsysfunc(dread(&did,&i))                  
      %end;                                                                               
     %end;                                                                                                                               
   %end;                                                                                                                                                                                                                                                                   
  /* Closes the directory  */                                                                                                            
  %let rc=%sysfunc(dclose(&did));                                                                                                        
                                                                                                                                        
%mend drive; 

%let FILES=%drive(&path);;

This macro return names separated by spaces not by #, so adapt the file

Babloo
Rhodochrosite | Level 12

Thanks a ton.

 

If I'm not wrong, I need to place the code at the begining, before I call the macro %log_analysis from my intial post. I think this time I need to call that macro with parameters something like below.

 

macro %log_analysis (&files);

 Am I right?

arodriguez
Lapis Lazuli | Level 10
yes, something like
%macro %log_analysis(parameter1=&files);
Steelers_In_DC
Barite | Level 11

Does this get you what you are looking for?

 

proc sql noprint;
select distinct memname into :namelist separated by ' '
from dictionary.columns
where libname = 'WORK' and memname ne '_PRODSAVAIL';

%put &namelist;

Tom
Super User Tom
Super User

One of the nice features of SAS macros is that you can define parameters as positional and still call them by name.  You just can't do the reverse.

 

So if I had a macro defined like this:

%macro divide(numerator,denominator);
...
%mend divide;

I could call it many ways:

 

%divide(10,5);
%divide(numerator=10,denominator=5);
%divide(denominator=5,numerator=10);
%divide(10,denominator=5);
Babloo
Rhodochrosite | Level 12
I agree with you Tom.

However intially I don't know to dynamically pass the filenames as per my initial. I.e. without hardcoding the macro parameter values like yours.

You have any other solutions for my intial post before I try the solution suggested by others?
Tom
Super User Tom
Super User

I really am not sure I understand the original question.  

 

If you have an existing piece of code and you want to change to a macro with parameters then just additify the pieces that change and make them parameters. Then in the code replace the original hardcoded text with the macro variable reference to the parameter.

 

So if you are talking about the adding a parameter to your original macro then the change should look like this.

 

%macro log_analysis(filename);

data log.log_analysis;
  length fname $400;
   infile "&filename" dsd truncover END = end_of_file LRECL=32000;
   fname="&filename" ;
  DO WHILE (not end_of_file);
    input var : $ 3000.;
..........
..........
%mend log_analysis;

Now this program will have a problem when called multiple times since the name of the data set is now hard coded.  But you could also convert that to a parameter.  Or you could add more complex logic to read thie current file and then append the result to a master dataset that would accumulate the data over multiple macro calls.

Babloo
Rhodochrosite | Level 12
Thanks for your prompt reply.

May I request you to tell me to append the datasets after I modify the datasets names as parameters? E.g. I will get three datasets if the macro is called three times. How to append these three datasets as one master dataset?

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 18 replies
  • 5437 views
  • 8 likes
  • 4 in conversation