SAS 매크로를 사용하여 Windows 디렉토리에서 파일 이름 목록을 파이프
문제
DIR 명령에 대한 '위치'인수로 매크로 매개 변수를 수락하기 위해 아래 매크로를 수정하려고합니다. 그러나 중첩 인용문 문제로 인해 올바르게 해결할 수 없습니다. %str ( %')를 사용하는 것은 작동하지 않으며 어떤 이유로 든 인용 기능도하지 않습니다.
매크로는 FilePath가있을 때 잘 작동합니다 공간이 없습니다 (예 : C : temp withnospace) 중간 따옴표가 필요하지 않습니다. 그러나 나는이 매크로가 FilePaths를 위해 일해야합니다 공간과 함께 (예 : 'c : temp 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 */
해결책
파이프를 사용할 필요없이 동일한 결과를 달성하는 또 다른 방법이 있습니다.
%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));
다른 팁
다음 몇 가지 변경 사항을 작성하면 코드가 작동합니다.
%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) 입력 매개 변수를 단일 견적하지 마십시오. 대신 마크로 견적, 필요한 경우.
마지막 샘플을 기반으로합니다 이 페이지, 파일 이름 명령문 대신 시도해보십시오
%let filrf=pipedir;
%let rc=%sysfunc(filename(filrf,%bquote(dir "&location" /b),pipe));
인용문을 사용하지 않고 매크로에 전화하십시오.
%get_filenames(c:\temp\with spaces);
나는 또한 매크로 인용을 시도했지만 그것을 작동시킬 수 없었습니다.
다음은 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:\
.
이 방법으로 원래 매크로를 호출하면 저에게 효과적입니다.
%get_filenames(""C:\Program Files"")
물론 나는 끝에 세미콜론을 추가해야했다. %macro
성명.
디렉토리에 쉼표가 포함되어 있으면 나쁜 일이 발생합니다. 수정하려면 사용하십시오 %str()
매크로
%get_filenames(%str(C:\temp\comma, fail))
순수한 매크로 코드 버전이 있습니다. 또한 파일 (폴더가 아닌 파일)에 대해서만 알고 싶다는 것을 지정하고 기본 필터를 지정할 수 있습니다. 파일 목록을 구분 형식으로 반환하지만 원하는 경우 SQL Insert를 사용하여 데이터 세트에 쉽게 삽입 할 수 있습니다 (예제 포함이지만 테스트되지 않음 -SAS 액세스 ATM). 다른 매크로, 데이터 세트, SQL 명령문 내에서 어디서나 호출 할 수 있습니다. 이 두 매크로를 매크로 Autocall 라이브러리에 추가하면 가야합니다.
아래에는 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;
다음은 인용 및 인용문의 명령을 방해하지 않는 것입니다.
%let command =%unquote(%str(%')dir "&baseDir.data\*txt"%str(%'));
filename datain pipe &command;
매크로 변수 기반에 공백이 포함될 수 있으며 파일 이름도 마찬가지입니다. 이 조합%unquote
그리고 %str(%')
자주 발생하는 매크로 관용구입니다.
"내 딥에 단일 인용문이 있다면 어떨까요?"
이 상황을 처리하려면 매크로 인용 기능이 필요합니다. %bquote();
위의 예를 계속하면 다음과 같습니다.
%let command =%unquote(%str(%')dir "%bquote(&baseDir.data\*txt)"%str(%'));
해야합니다.
이런 종류의 질문에 대한 무한한 반복을 피하려면 이안 휘트 록 (Ian Whitlock)의 논문, 매크로 인용문을 진지하게 살펴보십시오. 여기;
다른 사람들이 많지만 이것은 가장 널리 인용됩니다. 약간의 메모 : Ian Whitlock의 모든 것이 가치가있을 것입니다. 그는 명확하게 글을 쓰고 SAS 문제에 대한 그의 이해는 대단합니다.
우리는이 작은 매크로를 사용합니다
%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
작업은 운영자 응답을 기다리는 서버에 매달려 있습니다.