7

我正在尝试修改下面的宏以接受宏参数作为 dir 命令的“位置”参数。但是,由于嵌套引号问题,我无法正确解决它。使用 %str(%') 不起作用,由于某种原因引用函数也不起作用。

当文件路径没有空格(例如 C:\temp\withnospace)时,宏将正常工作,因为不需要中间引号。但是我需要这个宏来处理带有空格的文件路径(例如'C:\temp\with space\')。

请帮忙!

%macro get_filenames(location)
   filename pipedir pipe   "dir &location. /b " lrecl=32767;
   data filenames;
     infile pipedir truncover;
     input line $char1000.;
   run;
%mend;

%get_filenames(C:\temp\)              /* works */
%get_filenames('C:\temp\with space')  /* doesnt work */
4

8 回答 8

14

这是无需使用 PIPE 即可获得相同结果的另一种方法。

%macro get_filenames(location);
filename _dir_ "%bquote(&location.)";
data filenames(keep=memname);
  handle=dopen( '_dir_' );
  if handle > 0 then do;
    count=dnum(handle);
    do i=1 to count;
      memname=dread(handle,i);
      output filenames;
    end;
  end;
  rc=dclose(handle);
run;
filename _dir_ clear;
%mend;

%get_filenames(C:\temp\);           
%get_filenames(C:\temp\with space);
%get_filenames(%bquote(C:\temp\with'singlequote));
于 2009-09-11T19:53:27.360 回答
6

进行以下几项更改,您的代码将起作用。

%macro get_filenames(location);  %*--(1)--*;
   filename pipedir pipe "dir ""%unquote(&location)"" /b" lrecl=32767; %*--(2)--*;
   data filenames;
     infile pipedir truncover;
     input filename $char1000.;
     put filename=;
   run;
   filename pipedir clear;  %*--(3)--*;
%mend;

%get_filenames(d:\)          
%get_filenames(d:\your dir)  %*--(4)--*;

%macro(1)以分号结束语句;

(2) 用双引号和 将宏变量分辨率括起来%unquote

(3) 通过清除文件句柄来释放文件句柄;和

(4) 不要单引号你的输入参数。如有必要,请改为使用宏引用。

于 2009-09-11T20:23:00.657 回答
3

基于此页面上的最后一个示例,而不是文件名语句,尝试

%let filrf=pipedir;
%let rc=%sysfunc(filename(filrf,%bquote(dir "&location" /b),pipe));

并在不使用引号的情况下调用宏:

%get_filenames(c:\temp\with spaces);

我也尝试过宏引用,但无法正常工作。

于 2009-09-11T13:35:43.770 回答
3

这是一个快速宏,用于将基于 Windows 的目录列表拉入 sas 数据集。

%宏目录列表(目录);

/* %if &SUBDIR eq %then %let subdir=/s; */ /*** &SUBDIR 未定义 ****/
文件名 dirpipe 管道 "dir &DIR.\*.* /s /-c";

data dir_list(label="目录列表 [&DIR.]" drop=re_: _line_ date time);
  格式路径
         提交 250 美元。
         ModDT 日期时间19。
         尺寸 16。
         _行_ $32000。;

  如果 _N_ = 1 则执行;
    re_path=prxparse("/目录(.+)/");
    re_subd=prxparse("/(\d\d\/\d\d\/\d\d\d\d)\s+(\d\d:\d\d [A|P]M)\s+\ s+(\S.*)/");
    re_file=prxparse("/(\d\d\/\d\d\/\d\d\d\d)\s+(\d\d:\d\d [A|P]M)\s+( \d+)\s+(\S.*)/");
    保留re_:路径;
    结尾;

  infile dirpipe lrecl=32000; 输入; _line_ = _infile_;

  如果 lengthn(_line_)=0 则删除;
  别的
  如果 prxmatch(re_path, _line_) 然后做;
    路径=prxposn(re_path,1,_line_);
    结尾;
  别的
  如果 prxmatch(re_subd, _line_) 然后做;
    日期=输入(prxposn(re_subd,1,_line_),mmddyy10。);
    时间=输入(prxposn(re_subd,2,_line_),time6。);
    ModDT=dhms(日期, 0, 0, 时间);
    文件=prxposn(re_subd, 3, _line_);
    大小 = .D; /*标记子目录记录*/
    如果文件不在 ('.', '..') 中,则输出;
    结尾;
  别的
  如果 prxmatch(re_file, _line_) 然后做;
    日期=输入(prxposn(re_file,1,_line_),mmddyy10。);
    时间=输入(prxposn(re_file,2,_line_),time6。);
    ModDT=dhms(日期, 0, 0, 时间);
    大小=输入(prxposn(re_file,3,_line_),16。);
    文件=prxposn(re_file,4,_line_);
    输出;
    结尾;
跑;
文件名 dirpipe 清除;
%修补;

这就是他们被称为的方式

%dirlist(c:);
%dirlist(c:\temp);

请注意,指定基本目录时没有尾部反斜杠。C:不是C:\

于 2009-09-14T19:56:04.130 回答
2

如果我以这种方式调用原始宏,它对我有用

%get_filenames(""C:\Program Files"")

当然,我必须在语句末尾添加分号%macro

如果您的目录包含逗号,则会发生不好的事情。修复,使用%str()

%get_filenames(%str(C:\temp\comma, 失败))

于 2009-09-11T15:26:30.183 回答
2

这是一个解读引用和取消引用顺序的内容:

%let command =%unquote(%str(%')dir "&baseDir.data\*txt"%str(%'));

filename datain pipe &command;

其中宏变量 basedir 可以包含空格,文件名也可以。%unquote和的这种组合 %str(%')是一个经常出现的宏习语。

“如果我的目录中有单引号怎么办?”

处理这种情况需要一个宏引用函数,比如%bquote(); 继续上面的例子,这样:

%let command =%unquote(%str(%')dir "%bquote(&baseDir.data\*txt)"%str(%'));

应该这样做。

为避免此类问题的无限迭代,请查看 Ian Whitlock 的论文,A Serious Look at Macro Quoting,可在此处获得;

还有(很多)其他的,但这是引用最广泛的。一点提示:Ian Whitlock 的任何作品都可能是值得的。他写得很清楚,他对 SAS 问题的理解很棒。

于 2010-03-15T18:35:56.380 回答
2

这是一个纯宏代码版本。它还允许您指定您只想了解文件(而不是文件夹),并允许您指定基本过滤器。它以分隔格式返回文件列表,但如果您愿意,您可以使用 SQL 插入轻松地将这些文件插入数据集(包括但未测试的示例 - 无 SAS 访问 atm)。它可以从任何地方调用 - 在另一个宏、数据集、sql 语句中......任何地方。只需将这两个宏添加到您的宏自动调用库中即可。

下面有2个宏。%file_list 宏需要 %isdir 宏。宏比上面的宏更大更复杂,但它们更加灵活。此外,它们还提供错误检查。

/******************************************************************************
** 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;
于 2010-04-18T02:52:23.610 回答
1

我们使用这个小宏

%macro getdir(dir=,redirect=, switch=);
    options noxwait xsync;
    %if %length(&switch)=0 %then %let switch=b;
    data _null_; 
      xcmd='dir "' || "&dir" || '"' || "/&switch " || ">" || "&redirect";
      put 'generated the following command: ' xcmd=; 
      rc=system(xcmd);
      put 'result code of above command: ' rc=;
    run;
%mend getdir;

样品电话

%getdir(dir=c:\temp\,redirect=c:\temp\dir.txt) *run;

如果您批量运行并且没有作业,则option noxwait xsync该作业将挂在服务器上等待操作员响应。

于 2009-09-11T13:15:06.253 回答