Frage

Ich versuche, das Makro unten zu ändern, für einen Befehl dir einen Makro Parameter als ‚Standort‘ Argument zu akzeptieren. Allerdings kann ich nicht bekommen es aufgrund der verschachtelten Anführungszeichen Problem richtig zu lösen. Mit% str (%) nicht funktioniert, auch nicht zitiert Funktionen aus irgendeinem Grund.

Das Makro fein funktioniert, wenn der Dateipfad hat keine Leerzeichen (zB C: \ temp \ withnospace) als die mittleren Anführungszeichen sind nicht erforderlich. Allerdings muss ich dieses Makro für Dateipfade arbeiten mit Leerzeichen (zB 'C: \ temp \ mit Leerzeichen \').

Bitte um Hilfe!

%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 */
War es hilfreich?

Lösung

Hier ist ein weiterer Weg, um das gleiche Ergebnis zu erzielen, ohne dass ein Rohr 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));

Andere Tipps

Nehmen Sie die folgenden mehrere Änderungen und Ihr Code funktioniert.

%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 Sie die %macro Anweisung mit einem Semikolon;

(2) umgibt die Makro mit variabler Auflösung mit verdoppelt-up doppelten Anführungszeichen und %unquote;

(3) Lassen Sie die Datei-Handle durch Clearing; und

(4) Nicht Apostroph Ihre Eingabeparameter. stattdessen Makro Zitat, falls erforderlich.

auf der letzten Probe Basierend auf diese 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 habe auch versucht Makro zitiert, konnte aber nicht an der Arbeit.

Hier ist eine schnelle Makro setzen Windows-basierte Verzeichnislisten in eine sas Daten 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 aufgerufen

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

Hinweis gibt es keinen Backslash, wenn das Basisverzeichnis angeben. C: nicht C:\.

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

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

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

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

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

Hier ist eine reine Makrocode-Version. Es erlaubt Ihnen auch festlegen, dass Sie nur über Dateien (und nicht die Ordner) und können Sie einen Basisfilter angeben wissen wollen. Es gibt die Liste der Dateien in einem Format mit Trennzeichen, aber Sie können diese in einem Datensatz mit SQL-Insert leicht einfügen, wenn Sie (zB enthalten, aber nicht getestet - keine SAS Zugang atm) wollte. innerhalb eines anderen Makros, einen Datensatz, eine SQL-Anweisung ... wo auch immer - es kann von überall aufgerufen werden. Fügen Sie einfach diese beiden Makros das Makro Autocall Bibliothek und Sie haben Recht zu gehen.

Es gibt 2 Makros unten. Das% isdir Makro wird durch den% file_list Makro erforderlich. Die Makros sind ein bisschen größer und komplexer als die oben, aber sie sind viel flexibler. Und sie bieten 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;

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;

Dabei gilt Makrovariable basedir kann Leerzeichen enthalten und kann so die Dateinamen. Diese Kombination aus %unquote und %str(%') ist eine häufig vorkommende Makro Idiom.

"Was ist, wenn ich Apostroph in meinem dir haben?"

Diese Situation Handhabung erfordert eine Makro unter Angabe Funktion, wie %bquote(); Fortsetzung des obigen Beispiels, folgt aus:

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

sollte es tun.

unendliche Wiederholungen dieser Art von Fragen zu vermeiden, sehen Sie Ian Whitlocks Papier, ein ernsthafter Blick auf Makro Zitiert, die verfügbar ist, hier ;

Es gibt (viele) andere, aber dies ist die am häufigsten zitierte. Eine kleine Anmerkung: etwas von Ian Whitlock ist wahrscheinlich lohnt sich. Er schreibt klar und sein Verständnis von SAS Ausgaben ist genial.

Wir verwenden diese kleine 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 der Job auf dem Server für einen Bediener Antwort zu warten hängen wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top