I'm trying to create a folder with the character "&" in the name
I've tried the %superq function which seems to interpret correctly the macro variable
x "cd c:\Users\avibe_000\Dropbox\htdocs\Landa2018\LDPdepartments\";
data _null_;
call symput('mv1','Smith&Jones');
run;
%let testmv1=%superq(mv1);
%put &testmv1 ;
x "mkdir &testmv1";
The code works but creates a folder "Smith" and not "Smith&Jones" as expected
The DCREATE function will create a sub-folder. In macro use nrstr to pass a non-resolved value to the function. %SUPERQ is not, pre se, for value assignment, but for as-is value retrieval based on macro variable name.
filename parent 'C:\Temp';
%put NOTE: parent(path)=%qsysfunc(pathname(parent));
%let rc = %qsysfunc(DCREATE(%nrstr(Smith&Jones),parent));
filename sj 'C:\Temp\Smith&Jones';
%put NOTE: sj(path)=%qsysfunc(pathname(sj));
The macro processor tries to process macro triggers inside of double quotes. But it doesn't inside of single quotes. Also the Windows command line will need quotes around the value with an & in it.
>mkdir a&b
'b' is not recognized as an internal or external command,
operable program or batch file.
>mkdir "a&b"
So change your process to enclose the command in single quotes and the directory name in double quotes.
data _null_;
call symputX('command',quote('mkdir "Smith&Jones"',"'"));
run;
x &command ;
#Tom Nice answer.
And you just been so closed to your own way:
data _null_;
call symput('mv1','d:\Users\avibe_000\Dropbox\htdocs\Landa2018\LDPdepartments\Smith&Jones');
run;
%let testmv1=%str(%")%superq(mv1)%str(%");
%put &testmv1;
x mkdir &testmv1;
You can use the mf_mkdir macro in the SASjs macrocore library - this also uses dcreate() and recursively creates any subdirectories that are needed. It is also delivered as a macro function (so can be used pretty much anywhere in your code).
/* import and compile (or go there and copy paste into your code */
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/base/mf_mkdir.sas";
%inc mc;
/* execute */
%mf_mkdir(/tmp/this %nrstr(&) that)
result:
Related
I have to scan a target directory, and import every CSV file there into SAS. I am to use separated macros to fix names of those files (they are intentionaly problematic for SAS) and actually import them. I have XCMD disabled, so pipe solution isn't usable for me (the only solution my course provided me, so several exercises are a bit problematic for me). My attempt so far is this:
%let path=my_dir
%macro fixname(badname);
%if %datatyp(%qsubstr(&badname,1,1))=NUMERIC
%then %let badname=_&badname;
%let badname=
%sysfunc(compress(
%sysfunc(translate(&badname,_,%str( ))),,kn));
%substr(&badname,1,%sysfunc(min(%length(&badname),32)))
%mend fixname;
%macro importcsv(file);
options nonotes nosource;
proc import
datafile="%superq(file)"
out=%fixname(%scan(&file,-2,.\)) replace
dbms=csv;
run;
options notes source;
%mend importcsv;
filename folder "&path";
data FilesInFolder;
length Line 8 File $300;
List = dopen('folder');
do Line = 1 to dnum(List);
File = trim(dread(List,Line));
output;
end;
drop list line;
run;
proc sql noprint;
select * into :file1-
from FilesInFolder
where File like '%.csv'
;
quit;
%macro loop;
%do i=1 %to &sqlobs;
call execute(cats('%importcsv('&path.\&&file&i')'));
%end;
%mend loop;
%loop;
Looking at logs there seems to be something wrong with call execute line, but for the life of me I cannot fix it.
As regards the requested call execute line, this will not work.
call execute(cats('%importcsv('&path.\&&file&i')'));
The cats is not properly constructed. It's unclear why you're even using cats, as you aren't really concatenating anything. It's clear why you need to use it, but not why you're currently using it.
First: you have single quotes around the string, which means it won't resolve the macro variables. That is a problem for you. In particular, you want &i to resolve. You also, though, don't want %importcsv itself to resolve.
Second: you have single quotes inside single quotes, or else you have unquoted text.
The right way to do this is:
call execute(cats('%importcsv(',"&path.\&&file&i.",')'));
The goal here is to make sure %importcsv doesn't resolve - so we wrap it in single quotes - but get the macro variables to resolve - wrapped in double quotes. It would be okay for &path not to resolve (as it's a global variable), but &&file&i absolutely needs to, since it's what you are looping over.
The final ')' is unnecessary (it could be included inside the double quotes), but I like it for readability (it makes it obvious that it's the end of the macro invocation). In this case it's unimportant, but sometimes the middle bits have more parentheses in them, and it becomes unclear when you have the right number.
All this aside, you're making this much too complicated. Here:
proc sql noprint;
select * into :file1-
from FilesInFolder
where File like '%.csv'
;
quit;
Why not simply put the macro invocation itself?
proc sql noprint;
select cats('%importcsv(',"&path.\",file,')')
into :filelist separated by ' '
from FilesInFolder
where File like '%.csv'
;
quit;
&filelist
Now you have &filelist which contains all of the macro invocations, and you can just invoke them, no macro loop needed.
You can check out my presentation on Writing Code With Your Data if you want to know more about how that works.
Of course, if this is homework and you have to do the first way, it's fine, but in the real world the second way is superior unless you have > 60k characters worth of macro calls.
I use this bit outside of any DATA step.
%let sth = 20191111;
%let sthelse=SUBSTR(INPUT(&sth.,12.),1,4);
%put &sthelse.;
It does not yield '2019', which I would expect but rather
SUBSTR(INPUT(20191111,12.),1,4)
What goes wrong here?
Use the macro function %SUBSTR to extract a portion of its argument. Remember, macro values are only character values (not to be confused with data step character variables and values) and have no explicit numeric value, even when the macro value is comprised of all digits.
%let sth = 20191111;
%let first4 = %substr(&sth,1,4);
You are not understanding how the macro pre-processor works. It is just a text replacement tool. It looks for two trigger character, % and & to see where it needs to do work. You can see both at work in your statement:
%let sthelse=SUBSTR(INPUT(&sth.,12.),1,4);
So the % will trigger the macro processor and it will recognize %let as a macro statement. Then the & trigger will cause it to treat &sth. as a macro variable reference to be replaced. So it replaces that and you end up with this statement.
%let sthelse=SUBSTR(INPUT(20191111,12.),1,4);
Since there are no more macro triggers SAS happily stores that text into the macro variable sthelse.
You also seem confused about how numbers and character strings work. If you write this code:
data x;
x=INPUT("20191111",12.);
run;
You would be asking SAS to convert the string 20191111 into the number 20,191,111. So X would be a numeric variable. So it would have the same effect as if you ran this statement instead.
x=20191111;
Now if you then ask SAS to try to use the SUBSTR() function on that NUMERIC value by doing this:
y=substr(x,1,4);
SAS will need to first convert X into a character string. It will happily do that for you, but it will use the BEST12. format to make the conversion. So your number 20,191,111 will become the string
20191111
So it will have 4 leading spaces. Then if you take the first four characters you end up with four spaces.
Did you intend to run this code instead?
%let sth = 20191111;
%let sthelse=%substr(&sth,1,4);
That will use the MACRO function %SUBSTR() to take the first four characters of the string you have given it. Since you gave it the string 20191111 (to the macro processor everything is a string, no quotes needed) the result will be the string 2019.
SUBSTR is datastep function.
Try to use it into macro function:
%let sth = 20191111;
%let sthelse=%sysfunc(SUBSTR(%sysfunc(INPUTn(&sth.,12.)),1,4));
%put &sthelse.;
There isn't macro function named substr and input, this function is "data step functions". You should use %sysfunc statement. And macro variables stores as text, so you shouldn't use input function on it.
%let sth = 20191111;
%let sthelse=%sysfunc(SUBSTR(&sth.,1,4));
%put &=sthelse.;
STHELSE=2019
UPDATE(thanks #Tom):
There is macro function %substr, so you can use %SUBSTR(&sth.,1,4) instead of %sysfunc(SUBSTR(&sth.,1,4)).
I am trying to write a macro that creates a text file using parameter value. I understand all SAS parameters are passed as text, so i need to convert the text to numeric. Using INPUT for this but still getting a syntax error. Appreciate the help. Thank you.
code:
%macro test(n_var);
data _null_;
file"c:/temp/test.txt" TERMSTR=crlf;
put ;
put "(numeric variable passed = "input(&n_var,8.)")";
put ;
run;
%mend;
%test(n_var=100);
Log:
SYMBOLGEN: Macro variable N_VAR resolves to 100
NOTE: Line generated by the macro variable "N_VAR".
39 100
___
22
76
MPRINT(TEST): put "(numeric variable passed = "input(100,8.)")";
MPRINT(TEST): put ;
MPRINT(TEST): run;
ERROR 22-322: Syntax error, expecting one of the following: a name, arrayname, _ALL_, _CHARACTER_, _CHAR_, _NUMERIC_.
ERROR 76-322: Syntax error, statement will be ignored.
All SAS macro symbols (aka variables) are text. SAS macro parameters are text.
Your use case probably does not need to convert text to numeric.
Consider:
%let x = 100;
data _null_;
my_num_var = &x;
run;
The resolution of the macro variable (or perhaps better understood as 'symbol') are the letters 1 0 0, but with respect to text to be interpreted as SAS code. The data step compiler infers my_num_var is numeric from the line it sees as
my_num_var = 100;
There are some use cases where you may want to test that a macro parameter can be interpreted as a numeric value. Such use cases are probably beyond your needs at this time.
The INPUT function is one of those special DATA Step functions that is not available for use in SAS macro via the %sysfunc function. When you must 'input' a value in a 'pure' manner outside a DATA step, you will want to invoke the INPUTN or INPUTC functions via %sysfunc
%let evaluatedRepresentation = %sysfunc(inputn(&x,best8.));
The numeric evaluation of the inputn is converted to text and assigned to symbol evaluatedRepresentation.
If you are not in control of the callers to you macros in which you do ampersand evaluations the safer approach is to evaluate via SUPERQ to break code injections and other anamolies
%let evaluatedRepresentation = %sysfunc(inputn(%superq(x),best8.));
I'm creating a text file with SAS and I'm using a macro variable with a date in my text file's name to make it distinct from other similar files.
The problem I'm experiencing:
SAS is adding two unwanted spaces in the middle of the file name. The unwanted spaces are placed directly before the text generated by my macro variable
I'm certain this has everything to do with my macro variable being used, but on its own, the variable doesn't contain any spaces. Below is my code:
proc format;
picture dateFormat
other = '%Y%0m%0d%0H%0M' (datatype=datetime);
run;
data _null_;
dateTime=datetime();
call symput('dateTime', put(dateTime,dateFormat.));
run;
%LET FILE = text_text_abc_&dateTime..txt;
filename out "/location/here/&FILE" termstr=crlf;
data _null_; set flatfile;
/*file content is created in here*/
run;
The exported file name will look like this:
NOTE: The file OUT is:
Filename=/location/here/text_text_abc_ 201702010855.txt
If it helps, I'm using SAS E-Guide 7.1.
Any help is appreciated! Thanks, all!
You need to assign an appropriate default length to your picture format. SAS is applying a default default length of 14 but you need 12, e.g.
proc format;
picture dateFormat (default=12)
other = '%Y%0m%0d%0H%0M' (datatype=datetime);
run;
Use call symputx() instead of call symput(), then SAS will automatically strip the leading and trailing blanks from the value written to the macro variable. You should really only use call symput() in the rare cases where you want the macro variable value to have leading or trailing blanks.
Run this little program to see the difference.
data _null_;
str=' XX ';
call symput('var1',str);
call symputX('var2',str);
run;
%put |&var1|;
%put |&var2|;
I am in the process of creating dynamic webfiles via a stored process. The ouput file are generated via proc stream. However I am doing something wrong whilest creating the dynamic file paths.
The following simplified example works:
FILENAME hello 'D:\test\hello.html';
proc stream outfile=hello; begin
hello world
;;;;
However when I try to dynamically create files using a do loop, I am not getting any output at all. (no errors as well)
%do i=1 %to 3;
%let outputFileName = D:\test\&i%str(.html);
FILENAME hello '&outputFileName';
proc stream outfile=hello; begin
Hello world
;;;;
%end;
If I put the outputFileName variable, I can see my path is the way it is supposed to be.
Any ideas?
Macro variable reference won't resolve inside single quotes. Use double quotes:
FILENAME hello "&outputFileName";