我想修改下面的宏接受宏参数作为一个dir命令的“位置”的说法。 不过,我不能让它正确地解决由于嵌套的报价问题。 使用%STR(%')不工作,也不做报价功能出于某种原因。
宏将正常工作时的文件路径没有空格 (如C:\ TEMP \ withnospace)因为不需要中间报价。 不过,我需要这个宏与空间工作的文件路径(如“C:\ TEMP \与空间\”)。
请帮忙!
%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 */
Answer 1:
下面是实现同样的结果,而无需使用管道的另一种方式。
%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));
Answer 2:
做以下一些变化,你的代码将工作。
%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)--*;
(1)结束%macro
用分号语句;
(2)围绕所述宏可变分辨率具有双式双引号和%unquote
;
(3)通过清除它松开文件句柄; 和
(4)不要单引号的输入参数。 宏观报价相反,如果需要的话。
Answer 3:
基于对最后一个样本此页面 ,而不是文件名的语句,尝试
%let filrf=pipedir;
%let rc=%sysfunc(filename(filrf,%bquote(dir "&location" /b),pipe));
和调用宏不使用引号:
%get_filenames(c:\temp\with spaces);
我也试过宏引用,但不能让它开始工作。
Answer 4:
这里有一个快速的宏观拉基于Windows的目录列表到SAS数据集。
%macro DirList(dir);
/* %if &SUBDIR eq %then %let subdir=/s; */ /*** &SUBDIR not defined ****/
filename dirpipe pipe "dir &DIR.\*.* /s /-c";
data dir_list(label="Directory Listing [&DIR.]" drop=re_: _line_ date time);
format Path
File $250.
ModDT datetime19.
Size 16.
_line_ $32000. ;
if _N_ = 1 then do;
re_path=prxparse("/Directory of (.+)/");
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.*)/");
retain re_: path;
end;
infile dirpipe lrecl=32000; input; _line_ = _infile_;
if lengthn(_line_)=0 then delete;
else
if prxmatch(re_path, _line_) then do;
path=prxposn(re_path, 1, _line_);
end;
else
if prxmatch(re_subd, _line_) then do;
date=input(prxposn(re_subd, 1, _line_), mmddyy10.);
time=input(prxposn(re_subd, 2, _line_), time6.);
ModDT=dhms(date, 0, 0, time);
File=prxposn(re_subd, 3, _line_);
size = .D; /*mark subdirectory records*/
if file not in ('.', '..') then output;
end;
else
if prxmatch(re_file, _line_) then do;
date=input(prxposn(re_file, 1, _line_), mmddyy10.);
time=input(prxposn(re_file, 2, _line_), time6.);
ModDT=dhms(date, 0, 0, time);
size=input(prxposn(re_file, 3, _line_), 16.);
file=prxposn(re_file, 4, _line_);
output;
end;
run;
filename dirpipe clear;
%mend;
这里是他们是如何被称为
%dirlist(c:);
%dirlist(c:\temp);
注意到没有指定基目录时斜杠。 C:
不是C:\
。
Answer 5:
它的工作对我来说,如果我叫原来的宏这样
%get_filenames(""C:\Program Files"")
当然,我不得不在末尾添加分号%macro
声明。
如果您的目录中包含一个逗号,不好的事情发生。 以固定,使用%str()
宏
%get_filenames(%STR(C:\ TEMP \逗号,失败))
Answer 6:
这是一个纯粹的宏代码的版本。 它还允许你指定你只是想知道文件(而不是文件夹),并允许您指定一个基本的过滤器。 它返回一个分隔格式文件的列表,但你可以很容易地使用SQL插入插入到这些数据集,如果你想(包括例如,未经测试 - 无SAS接入ATM)。 它可以从任何地方被称为 - 另一个宏,数据集,SQL语句......无论内。 只要这两个宏添加到您的宏自动调用库,你就到了。
下面有2个宏。 在%ISDIR宏由file_list中%所需的宏。 宏都有点比上述更大和更复杂的,但他们更灵活。 再加上他们提供错误检查。
/******************************************************************************
** 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;
Answer 7:
这里有一个解读报价和unquoting的顺序:
%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(%'));
应该这样做。
为了避免这种问题的无限重复,看伊恩·惠特洛克的文件,认真的看宏引用,这是可以在这里 ;
有(许多)人,但是这是最被广泛引用。 一张小纸条:由伊恩·惠特洛克东西可能是值得的。 他清楚地写他的SAS问题的理解是真棒。
Answer 8:
我们用这个小宏
%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
的作业将挂起服务器等待操作的响应上。
文章来源: Using SAS Macro to pipe a list of filenames from a Windows directory