2009-09-11 4 views
7

Ich versuche, das Makro unten zu ändern, um einen Makroparameter als 'Speicherort' Argument für einen Befehl dir zu akzeptieren. Ich kann jedoch nicht erreichen, dass es aufgrund des Problems mit verschachtelten Anführungszeichen korrekt aufgelöst wird. Die Verwendung von% str (% ') funktioniert nicht, auch nicht aus irgendeinem Grund.Verwenden von SAS-Makro zum Pipe einer Liste von Dateinamen aus einem Windows-Verzeichnis

Das Makro funktioniert gut, wenn der Dateipfad keine Leerzeichen (z. B. C: \ temp \ withnospace) wie die mittleren Anführungszeichen nicht benötigt wird. Ich brauche dieses Makro jedoch für Dateipfade mit Leerzeichen (zB 'C: \ temp \ with space \').

Bitte helfen!

%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 */ 

Antwort

13

Hier ist eine andere Möglichkeit, um das gleiche Ergebnis ohne eine PIPE zu verwenden.

%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)); 
+0

Obwohl dies die Frage nicht wirklich beantwortet, ist dieser Code weit überlegen, da er in Umgebungen verwendet werden kann - und erfüllt den gleichen Zweck. danke ... –

1

Wir verwenden diesen kleinen Makro

%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; 

Beispielaufruf

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

Wenn Sie im Batch laufen und nicht über die option noxwait xsync den Job auf dem Server für eine Warte hängen Bedienerantwort.

3

Basierend auf der letzten Probe auf this page anstelle der Dateiname Anweisung, versuchen

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

und rufen Sie das Makro ohne Anführungszeichen:

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

Ich zitiere auch Makro versucht, aber couldn‘ t es zur Arbeit bringen.

+0

+1 - nett. Sie können auch lrecl als Host-Option an dieses übergeben, so dass es genau wie sein Original ist: % let rc =% sysfunc (Dateiname (filrf,% bquote (dir "& location"/b), Pipe, lrecl = 32767)); – cmjohns

2

es funktioniert für mich, wenn ich die ursprüngliche Makro diese Weise

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

natürlich nenne ich das Semikolon am Ende der Anweisung %macro hatte hinzuzufügen.

Wenn Ihr Verzeichnis ein Komma enthält, passieren schlimme Dinge. zu beheben, verwenden Sie die %str() Makro

 %get_filenames(%str(C:\temp\comma, fail))

6

Nehmen Sie die folgenden Änderungen vor und Ihr Code wird funktionieren.

%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) beenden %macro Anweisung mit einem Semikolon;

(2) Umkreisen Sie die Auflösung der Makrovariablen mit doppelten Anführungszeichen und %unquote;

(3) Geben Sie das Dateihandle frei, indem Sie es löschen; und

(4) Geben Sie nicht Ihren Eingangsparameter an. Makro Zitat, wenn nötig.

+0

das funktioniert - aber hinterlässt eine Fehlermeldung (WARNUNG: Keine logische Zuweisung für den Dateinamen PIPE.) –

+2

Ändern Sie einfach den Dateinamen pipe clear; zu Dateiname pipedir klar; um die Warnung zu unterdrücken. – cmjohns

3

Hier ist ein schnelles Makro, um Windows-basierte Verzeichnislisten in eine sas-Datei zu ziehen.

 
%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; 

und hier ist, wie sie

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

Mitteilung dort aufgerufen ist kein Backslash, wenn das Basisverzeichnis angeben. C: nicht C:\.

+0

Ich mag das, aber ich musste ein paar Änderungen vornehmen, damit es auf meinem System funktioniert (win xp). Ich habe die Zeile re_subd = in re_subd = prxparse ("/ (\ d \ d \/\ d \ d \/\ d \ d \ d \ d) \ s + (\ d \ d: \ d \ d [A |)) geändert P] M) \ s +

\ s + (\ S * *)/"); wie jede Zeile wurde sonst wie ein Unterverzeichnis für mich behandelt. Auch entfernte ich die% If & SUBDIR eq% dann% let subdir =/s; Zeile seit & subdir Makrovariable ist nicht definiert und wird nicht an anderer Stelle verwendet. – cmjohns

+0

Ich erinnere mich daran, die Änderung an re_subd Regex-Muster zu machen, wenn os aktualisiert wurde, aber nie gedacht, die vorherige Version zu speichern. Der Parameter SUBDIR dient zum Angeben der Option/s für rekursive Unterverzeichnissen. irgendwann mal. – rkoopmann

2

Hier ist eine, die die Reihenfolge der Angebotserstellung und unquoting entschlüsselt:

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

filename datain pipe &command; 

wo Makrovariable basedir kann Leerzeichen enthalten und kann so die Dateinamen. Diese Kombination von %unquote und %str(%') ist ein häufig vorkommendes Makroidiom.

"Was ist, wenn ich ein einzelnes Zitat in meinem Verzeichnis habe?"

diese Situation Handhabung erfordert ein Makro unter Angabe Funktion, wie %bquote(); Fortsetzung des obigen Beispiels, das:

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

sollte es tun.

Um unendliche Wiederholungen dieser Art von Frage zu vermeiden, siehe Ian Whitlocks Papier, ein seriöser Blick auf Macro Quoting, die here verfügbar ist;

Es gibt (viele) andere, aber das ist die am häufigsten zitierte. Eine kleine Anmerkung: irgendetwas von Ian Whitlock ist wahrscheinlich lohnenswert. Er schreibt klar und sein Verständnis von SAS-Themen ist großartig.

2

Hier ist eine reine Makrocodeversion. Sie können auch angeben, dass Sie nur über Dateien (und nicht über Ordner) informiert werden möchten und einen Basisfilter angeben können. Es gibt die Liste der Dateien in einem begrenzten Format zurück, aber Sie können diese einfach mit SQL-Einfügung in ein Dataset einfügen, wenn Sie möchten (Beispiel enthalten, aber nicht getestet - kein SAS-Zugriff atm). Es kann von überall aufgerufen werden - innerhalb eines anderen Makros, eines Datasets, einer SQL-Anweisung ... wo auch immer. Fügen Sie einfach diese beiden Makros zu Ihrer Makroautokall-Bibliothek hinzu und Sie haben Recht.

Es gibt 2 Makros unten. Das Makro% isdir wird vom Makro% file_list benötigt. Die Makros sind ein bisschen größer und komplexer als die oben genannten, aber sie sind viel flexibler. Außerdem bieten sie eine Fehlerprüfung.

/****************************************************************************** 
** 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; 
Verwandte Themen