the do while is not working.
What's wrong ?
data paths;
length path $200;
input path $;
datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;
%macro process;
proc sql noprint;
select path into :path_list separated by ' '
from paths;
quit;
%put &=path_list;
%let i = 1;
%do %while (%scan(&path_list, &i. , ' ') ne '');
%let current_path = %scan(&path_list, &i. , ' ');
%put &=current_path;
%let i = %eval(&i. + 1);
%end;
%mend process;
%process;
data paths; length path $200; input path $; datalines; /dwh_actuariat/sasprocess/prodmens/HYFIprep/output /dwh_actuariat/sasprocess/prodmens/HYFIp/output ; run; %macro process; proc sql noprint; select path into :path_list separated by ' ' from paths; quit; %put &=path_list; %let i = 1; %do %while (%qscan(&path_list, &i. ,%str( )) ne ); %let current_path = %scan(&path_list, &i. , %str( )); %put &=current_path; %let i = %eval(&i. + 1); %end; %mend process; %process;
data paths; length path $200; input path $; datalines; /dwh_actuariat/sasprocess/prodmens/HYFIprep/output /dwh_actuariat/sasprocess/prodmens/HYFIp/output ; run; %macro process; proc sql noprint; select path into :path_list separated by ' ' from paths; quit; %put &=path_list; %let i = 1; %do %while (%qscan(&path_list, &i. ,%str( )) ne ); %let current_path = %scan(&path_list, &i. , %str( )); %put &=current_path; %let i = %eval(&i. + 1); %end; %mend process; %process;
In its current form, the macro does nothing but write values to the log, which can easily be achieved in a single DATA step without any macro language.
What is your real task?
Oh, sorry, that should have been a reply to @alepage's original post.
@alepage wrote:
Why did you replace the %scan by %pscan and the '' by %str() and ne )
Please explain.
Your script work perfectly
%QSCAN() adds macro quoting to the path so that %EVAL() does not see the / as division symbols.
You do not need to enclose strings in quotes for the macro processor. The reason you need the quotes in SAS code is so SAS knows what to treat as strings and what to treat as variable names or keywords. But to the macro processor everything is a string. So the quotes become part of the string.
1)Actually, @Tom has already answered your question.
The secret hided in operator "NE".
When sas meet "NE" ,would put %eval() around "/dwh_actuariat/sasprocess/prodmens/HYFIp/output"
and since "/" is a divided operator in sas ,sas would take it as a divided operator, and lead to this error.
Here I use %QSCAN() is to mask "/" operator to avoid this error as Tom show you detailly .
2)A white blank is a special character in MACRO language, so I use %str( ) to mask it to let MACRO know it as I use %qscan() to mask "/“ divided operator.
3)As @Tom pointed out MACRO take everything as a STRING , you don't need to put quote around it just leave it as a blank . Otherwise, MACRO would take it as "a blank", not a NULL character(empty).
Why did you tell SQL to use space as the delimiter and tell %SCAN() to also include single quote as a delimiter? And why did you compare the value to something that does contain single quote characters? That will never match as the result of the %SCAN() function could never contain any single quotes since they are being used as delimiters.
Note since you want to use %SCAN() to split the macro variable it will work better to use some character that cannot appear in a path as the delimiter, such as a | character.
Also SAS will not like those / characters in the strings generated by the %SCAN() call.
PATH_LIST=/dwh_actuariat/sasprocess/prodmens/HYFIprep/output /dwh_actuariat/sasprocess/prodmens/HYFIp/output ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: %scan(&path_list, &i. , ) ne ERROR: The condition in the %DO %WHILE loop, %scan(&path_list, &i. , ) ne, yielded an invalid or missing value, . The macro will stop executing. ERROR: The macro PROCESS will stop executing.
If you want to get your complex looping code to work make sure to use the right delimiter and compare to and actual empty value and use macro quoting to protect the value of the path from confusing the %EVAL() used by the %WHILE().
%do %while (%qscan(&path_list, &i. , %str( )) ne );
But why would you use such a complex loop when you can just use a NORMAL iterative do loop?
%macro process;
%local path_list i n current_path;
proc sql noprint;
select path into :path_list separated by '|'
from paths;
quit;
%let n=&sqlobs;
%do i=1 %to &n;
%let current_path = %scan(&path_list, &i. ,|);
%put &=i &=current_path;
%end;
%mend process;
Results
I=1 CURRENT_PATH=/dwh_actuariat/sasprocess/prodmens/HYFIprep/output I=2 CURRENT_PATH=/dwh_actuariat/sasprocess/prodmens/HYFIp/output
And if you want to loop over a delimited list where you don't know the number of items in advance just count them.
%do i=1 %to %sysfunc(countw(&path_list,|));
%let current_path = %scan(&path_list, &i. ,|);
%put &=i &=current_path;
%end;
From my point of view the first error is moving data from a dataset into macro variables, which is not necessary in most cases.
How about using macroArray packge and create a macro variable array?
1) Documentation.
2) Article describing the package.
Example:
/* load package to your SAS session */
%loadPackage(macroArray)
/* data */
data paths;
length path $200;
input path $;
datalines;
/dwh_actuariat/sasprocess/prodmens/HYFIprep/output
/dwh_actuariat/sasprocess/prodmens/HYFIp/output
;
run;
/* create m.v.a. Path */
%array(ds=paths,vars=path,macarray=Y)
/*
optionally preview:
%put %do_over(path);
*/
/* use macro variable array */
%macro test(i);
%do i = 1 %to &i.;
%put &=i. #%path(&i.)#; /* call %path() macro to get values one by one */
%end;
%mend;
%test(&pathN.) /* pathN macro variable keep size */
/* clean up */
%deleteMacArray(path,macarray=Y)
Log:
1 2 3 data paths; 4 length path $200; 5 input path $; 6 datalines; NOTE: The data set WORK.PATHS has 2 observations and 1 variables. NOTE: DATA statement used (Total process time): real time 0.00 seconds user cpu time 0.00 seconds system cpu time 0.00 seconds memory 404.96k OS Memory 25908.00k Timestamp 08/21/2025 09:24:43 AM Step Count 289 Switch Count 0 9 ; 10 run; 11 12 13 /* create */ 14 %array(ds=paths,vars=path,macarray=Y) NOTE:[ARRAY] 2 macrovariables created 15 16 /* 17 optionally preview: 18 %put %do_over(path); 19 */ 20 21 /* use macro variable array */ 22 %macro test(i); 23 24 %do i = 1 %to &i.; 25 %put &=i. #%path(&i.)#; 26 %end; 27 28 %mend; 29 30 %test(&pathN.) I=1 #/dwh_actuariat/sasprocess/prodmens/HYFIprep/output# I=2 #/dwh_actuariat/sasprocess/prodmens/HYFIp/output# 31 32 /* clean up */ 33 %deleteMacArray(path,macarray=Y)
Bart
P.S. How to install MacroArray package?
1) Create a directory of your convenience, for example:
C:\users\myuser\Desktop\Packages
2) In your SAS session, run the following line of code:
filename packages "C:\users\myuser\Desktop\Packages";
For Linux change the path accordingly
3) To install the SAS Packages Framework, execute the code (only one time):
/* enable a temporary version of the framework */
filename SPFinit url
"https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit;
/* install the framework */
%installPackage(SPFinit)
filename SPFinit clear;
4) To install the package macroArray
run the following code:
%installPackage(macroArray)
5) In order to use the SPF and packages in a SAS session, they must be enabled and loaded first. This is very straightforward, all we need to do is to assign the packages
filename to the packages directory, then include the framework code, and load a package we need. To do so execute 3 lines of code:
filename packages "/path/to/my/packages";
%include packages(SPFinit.sas);
%loadPackage(macroArray)
See SAS packages tutorial for more details.
Agreeing with @Kurt_Bremser , there is no point in using macros for this task. So @alepage what is the real problem you are trying to solve?
Well I want to use the macro process to passed as parameter the two different paths. Then I will replace the %put statement by another macro function that is loading all the txt files into that folder into a sas dataset.
@alepage wrote:
Well I want to use the macro process to passed as parameter the two different paths. Then I will replace the %put statement by another macro function that is loading all the txt files into that folder into a sas dataset.
So skip the macro and the macro variables and just use a data step to generate the calls to the macro.
So if your macro is named %MYMACRO() and takes the path as the first positional argument you could generate one call to the macro for each observation in the data PATHS with this data step:
data _null_;
set paths;
call execute(cats('%nrstr(%mymacro)(',path,')'));
run;
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!
Check out this tutorial series to learn how to build your own steps in SAS Studio.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.