استخدام SAS Macro لتوجيه قائمة بأسماء الملفات من دليل Windows

StackOverflow https://stackoverflow.com/questions/1409543

سؤال

أحاول تعديل الماكرو أدناه لقبول معلمة ماكرو كوسيطة "الموقع" لأمر dir.ومع ذلك لا يمكنني حلها بشكل صحيح بسبب مشكلة علامات الاقتباس المتداخلة.استخدام %str(%') لا يعمل، وكذلك وظائف الاقتباس لسبب ما.

سيعمل الماكرو بشكل جيد عندما يكون مسار الملف موجودًا بدون مسافات (على سبيل المثال C: emp\withnospace) نظرًا لعدم الحاجة إلى علامات الاقتباس الوسطى.ومع ذلك أحتاج إلى هذا الماكرو للعمل مع مسارات الملفات مع المساحات (على سبيل المثال 'C: emp\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 */
هل كانت مفيدة؟

المحلول

إليك طريقة أخرى لتحقيق نفس النتيجة دون الحاجة إلى استخدام أنبوب.

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

(١) انتهى %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 إذا كنت تريد ذلك (تم تضمين المثال ولكن لم يتم اختباره - لا يوجد جهاز صراف آلي للوصول إلى SAS).يمكن استدعاؤه من أي مكان - داخل ماكرو آخر، أو مجموعة بيانات، أو عبارة 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;

إليك واحدة تفكك ترتيب الاقتباس وإلغاء الاقتباس:

%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(%'));

يجب القيام به.

لتجنب التكرارات اللانهائية لهذا النوع من الأسئلة ، انظر إلى ورقة إيان وايتلوك ، نظرة جادة على اقتباس الماكرو ، وهو متاح هنا;

وهناك (الكثير) غيرها، ولكن هذا هو الأكثر ذكرا على نطاق واسع.ملاحظة صغيرة:ربما يكون أي شيء من تأليف إيان ويتلوك جديرًا بالاهتمام.يكتب بوضوح وفهمه لقضايا 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 سيتم تعليق المهمة على الخادم في انتظار استجابة المشغل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top