Using SAS Macro to pipe a list of filenames from a Windows directory

前端 未结 8 2184
独厮守ぢ
独厮守ぢ 2020-12-03 12:13

I am trying to amend the macro below to accept a macro parameter as the \'location\' argument for a dir command. However I cannot get it to resolve correctly due to the nes

8条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-03 13:01

    Here's a pure macro code version. It also allows you to specify that you only want to know about files (and not folders) and lets you specify a basic filter. It returns the list of files in a delimited format but you can easily insert these into a dataset using SQL insert if you wanted to (example included but not tested - no SAS access atm). It can be called from anywhere - within another macro, a dataset, an sql statement... wherever. Just add these two macros to your macro autocall library and you're right to go.

    There are 2 macros below. The %isdir macro is required by the %file_list macro. The macros are a bit larger and more complex than the above but they are MUCH more flexible. Plus they provide error checking.

    /******************************************************************************
    ** PROGRAM:  ISDIR.SAS
    **
    ** DESCRIPTION: DETERMINES IF THE SPECIFIED PATH EXISTS OR NOT.
    **              RETURNS: 0 IF THE PATH DOES NOT EXIST OR COULD NOT BE OPENED.
    **                       1 IF THE PATH EXISTS AND CAN BE OPENED.
    **
    ** PARAMETERS: iPath: THE FULL PATH TO EXAMINE.  NOTE THAT / AND \ ARE TREATED
    **                    THE SAME SO &SASDIR/COMMON/MACROS IS THE SAME AS
    **                    &SASDIR\COMMON\MACROS.
    **
    ******************************************************************************/
    
    %macro isDir(iPath=,iQuiet=1);
      %local result dname;
    
      %let result = 0;
    
      %if %sysfunc(filename(dname,&iPath)) eq 0 %then %do;
        %if %sysfunc(dopen(&dname)) %then %do;
          %let result = 1;
        %end;
        %else %if not &iQuiet %then %do;
          %put ERROR: ISDIR: %sysfunc(sysmsg());
        %end;
      %end;
      %else %if not &iQuiet %then %do;
        %put ERROR: ISDIR: %sysfunc(sysmsg());
      %end;
    
      &result
    
    %mend;
    
    %put %isDir(iPath=&sasdir/common/macros);
    %put %isDir(iPath=&sasdir/kxjfdkebnefe);
    %put %isDir(iPath=&sasdir/kxjfdkebnefe, iQuiet=0);
    %put %isDir(iPath=c:\temp);
    
    /******************************************************************************
    ** PROGRAM:  FILE_LIST.SAS
    **
    ** DESCRIPTION: RETURNS THE LIST OF FILES IN A DIRECTORY SEPERATED BY THE
    **              SPECIFIED DELIMITER. RETURNS AN EMPTY STRING IF THE THE 
    **              DIRECTORY CAN'T BE READ OR DOES NOT EXIST.
    **
    ** PARAMETERS: iPath      : THE FULL PATH TO EXAMINE.  NOTE THAT / AND \ ARE 
    **                          TREATED THE SAME SO &SASDIR/COMMON/MACROS IS THE 
    **                          SAME AS &SASDIR\COMMON\MACROS. WORKS WITH BOTH UNIX 
    **                          AND WINDOWS.
    **             iFilter    : SPECIFY A BASIC FILTER TO THE FILENAMES, NO REGULAR 
    **                          EXPRESSIONS OR WILDCARDS.
    **             iFiles_only: 0=RETURN FILES AND FOLDERS
    **                          1=RETURN FILES ONLY.
    **             iDelimiter : SPECIFY THE DELIMITER TO SEPERATE THE RESULTS BY.
    ******************************************************************************/
    /*
    ** TODO: DOESNT CATER FOR MACRO CHARS IN FILENAMES. FIX SOMETIME.
    ** TODO: IMPROVE THE FILTER. JUST A SIMPLE IF STATEMENT AT THE MOMENT.
    */
    %macro file_list(iPath=, iFilter=, iFiles_only=0, iDelimiter=|);
      %local result did dname cnt num_members filename;
    
      %let result=;
    
      %if %sysfunc(filename(dname,&iPath)) eq 0 %then %do;
    
        %let did = %sysfunc(dopen(&dname));
        %let num_members = %sysfunc(dnum(&did));
    
        %do cnt=1 %to &num_members;
          %let filename = %sysfunc(dread(&did,&cnt));
          %if "&filename" ne "" %then %do;
            %if &iFiles_only %then %do;
              %if not %isDir(iPath=&iPath/&filename) %then %do;
                %if "&iFilter" ne "" %then %do;
                  %if %index(%lowcase(&filename),%lowcase(&iFilter)) %then %do;
                    %let result = &result%str(&iDelimiter)&filename;
                  %end;
                %end;
                %else %do;
                  %let result = &result%str(&iDelimiter)&filename;
                %end;
              %end;
            %end;
            %else %do;
              %if "&iFilter" ne "" %then %do;
                %if %index(%lowcase(&filename),%lowcase(&iFilter)) %then %do;
                  %let result = &result%str(&iDelimiter)&filename;
                %end;
              %end;
              %else %do;
                %let result = &result%str(&iDelimiter)&filename;
              %end;
            %end;
          %end;
          %else %do;
            %put ERROR: (CMN_MAC.FILE_LIST) FILE CANNOT BE READ.;
            %put %sysfunc(sysmsg());
          %end;
        %end;
    
      %end;
      %else %do;
        %put ERROR: (CMN_MAC.FILE_LIST) PATH DOES NOT EXIST OR CANNOT BE OPENED.;
        %put %sysfunc(sysmsg());
      %end;
    
      /*
      ** RETURN THE RESULT.  TRIM THE LEADING DELIMITER OFF THE FRONT OF THE RESULTS.
      */
      %if "&result" ne "" %then %do;
        %substr(&result,2)
      %end;
    
    %mend; 
    
    
    
    **
    ** EXAMPLES - HAVENT TESTED THE LAST TWO YET BUT THEY SHOULD WORK IF SYNTAX IS CORRECT
    *;
    
    %put %file_list(iPath=c:\temp);
    
    %put %file_list(iPath=c:\xxdffsds);
    
    %put %file_list(iPath=c:\rob\SASDev\, iFilter=a);
    
    %put %file_list(iPath=c:\rob\SASDev\,iFiles_only=1);
    
    %put %file_list(iPath=/tmp/unix_sasdir,iFiles_only=1);
    
    data x;
      file_list = "%file_list(iPath=c:\temp)";
    run;
    
    proc sql noprint;
      insert into my_table values ("%file_list(iPath=c:\temp,iDelimiter=%str(","))");
    quit;
    

提交回复
热议问题