Hi,
I would like to use a macrovariable in filename in a macro, but it gives error NOTE: Argument 1 to function DNUM(0) at line 41 column 69 is invalid.
ERROR: Invalid DO loop control information, either the INITIAL or TO expression is missing or the BY expression is missing, zero,
or invalid. File doesn't seem to open. pathname is created earlier as C:\Users\ydang\OneDrive - Prinses Maxima Centrum\CDM_share\Briga share\
%macro basefile2 (pathname, haveseq );
%let path=cats(strip("&studypath"),strip("&pathname"));
data have1;
rc=filename('xx','&path');
did=dopen('xx');
do i=1 to dnum(did);
fname=dread(did,i);
output;
end;
rc=dclose(did);
run;
%put path;
%mend basefile2;
%basefile2 (01 Source\20230609,1);
It works fine if I use:
rc=filename('xx',C:\Users\ydang\OneDrive - Prinses Maxima Centrum\CDM_share\Briga share\01 Source\20230609
Add double quotation marks, but still getting same error.
%macro basefile6 ( haveseq, pathname );
data have_&haveseq;
rc=filename("xx",symget("pathname"));
did=dopen("xx");
do i=1 to dnum(did);
fname=dread(did,i);
output;
end;
rc=dclose(did);
rc=filename (did);
run;
%mend basefile6;
Double quotes without using symget worked.
%macro basefile ( haveseq, pathname );
data have_&haveseq;
rc=filename('xx',"&pathname");
did=dopen('xx');
do i=1 to dnum(did);
fname=dread(did,i);
output;
end;
rc=dclose(did);
rc=filename (did);
run;
%mend basefile;
There are several things to fix/understand in your code.
1) Whatever value macrovariable PATH will have in this part:
rc=filename('xx','&path');
macrovariable's value will NOT be resolved because single quoted text strings are not resolved by macroprocesor.
Run this and see what will you get:
%let ABC = 123456789;
data _null_;
x = "&ABC.";
y = '&ABC.';
put x= ;
put y= ;
run;
2) when you are creating macrovariable PATH value you have the following:
%let path=cats(strip("&studypath"),strip("&pathname"));
all that is considered by the macroprocesor as a text, so CATS and STRIP are not considered as functions but just ordinary text strings, so for example if STUDYPATH and PATHNAME would be:
%let studyname=C:\directory1;
%let pathname=\directory2\directory3\;
your final value of macrovariable PATH would be:
cats(strip("C:\directory1"),strip("\directory2\directory3\"))
not as I guess you would like to have:
C:\directory1\directory2\directory3\
BTW. use of STRIP is redundand since CATS already strips blank spaces (that's the "S" at the name)
3) if you really would like to grab macrovariable's value in data step, instead:
rc=filename('xx',"&path");
use SYMGET:
rc=filename('xx',symget('path'));
it's much more robust solution.
And 4) just for clarity, what is your purpose? What do you want the cod to do? If you could describe it maybe the community could share better solution. Trust me SAS is old enough language (50+ years) to have majority of questions already answered (sometimes multiple times).
Bart
I'm now using symget. I would like to run the macro with a call execute, so I will get a list of all the files in the folder. In the end some of these files would need to be deleted.
I've now created the full path in variable pathname in the dataset deletefolders, this also contains the pathname. The deletefolder dataset has multiple folders listed with haveseq as sequence number.
I'm still getting the same error when using symget.
%macro basefile3 ( haveseq, pathname );
data have_&haveseq;
rc=filename('xx',symget('pathname'));
did=dopen('xx');
do i=1 to dnum(did);
fname=dread(did,i);
output;
end;
rc=dclose(did);
run;
%mend basefile3;
data _null_;
set Deletefolders;
call execute(cats('%basefile3(',haveseq||','||pathname,')'));
run;
Use BasePlus package for that task, in particular macro called %DirsAndFiles()
Installation:
filename packages "/a/path/to/store/package";
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit;
filename SPFinit clear;
%installPackage(SPFinit BASEPLUS)
Package use:
/* LOAD PACKAGE: */
filename packages "/a/path/to/store/package"; /* setup directory for packages */
%include packages(SPFinit.sas); /* enable the framework */
%loadPackage(BasePlus)
/* USE PACKAGE: */
%dirsandfiles(C:\your\path\to\search\for,ods=work.result)
Bart
@ydang wrote:
I'm now using symget. I would like to run the macro with a call execute, so I will get a list of all the files in the folder. In the end some of these files would need to be deleted.
I've now created the full path in variable pathname in the dataset deletefolders, this also contains the pathname. The deletefolder dataset has multiple folders listed with haveseq as sequence number.
I'm still getting the same error when using symget.
%macro basefile3 ( haveseq, pathname );
data have_&haveseq;
rc=filename('xx',symget('pathname'));
did=dopen('xx');
do i=1 to dnum(did);
fname=dread(did,i);
output;
end;
rc=dclose(did);
run;
%mend basefile3;
data _null_;
set Deletefolders;
call execute(cats('%basefile3(',haveseq||','||pathname,')'));
run;
First point is fix the CALL EXECUTE call so that the macro execute AFTER the data step. Wrap the macro triggers in %NRSTR() so that the call to the macro is pushed to run instead of the code the macro generates being pushed to run. Also remove the || since you are already using CATS() to do the concatenation.
call execute(cats('%nrstr(%basefile3)(',haveseq,',',pathname,')'));
But why make separate datasets for each folder? Ditch the macro and just put the DOPEN(),DREAD() logic into a data step and make ONE dataset with all of the file names.
data DeleteFiles;
set Deletefolders;
rc = filename('xx',pathname);
did=dopen('xx');
if did then do;
do filenum=1 to dnum(did);
length fname $256 ;
fname=dread(did,filenum);
output;
end;
rc=dclose(did);
end;
else put 'WARNING: Unable to open ' pathname 'as a directory.';
drop rc did;
run;
If you want to use a macro then perhaps use one like https://github.com/sasutils/macros/blob/master/dirtree.sas
data _null_;
set deletefolders end=eof;
if _n_=1 then call execute('%nrstr(%dirtree)(out=deletefiles,directory=');
else call execute('|');
call execute(pathname);
if eof then call execute(')');
run;
Add MAXDEPTH=1 to the macro call if you don't want it to recurse into subdirectories.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.