BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
JordiGC
Obsidian | Level 7

I have written the following test code. The goal is to send an e-mail with the content of some variables which my contain any character (in this example, an &):

 

%macro WriteInLog(Text1, Text2);
	data _null_;
		%put "Text1 is &Text1";
		%put "Text2 is &Text2";
	run;
%mend WriteInLog;

%macro SendMail(Text1, Text2);
	filename msg email
		to = "moretest@sas.com"
		from = "test@sas.com"
		subject = "Test mail";

	data _null_;
		file msg;
		put "Text1: &Text1"; put '0D0A'x;
		put "Text2: &Text2"; 
	run;
%mend SendMail;

data test;
	Text1 = 'Test';
	Text2 = 'Text&MoreText';
run;

data _null_;
	set test;
	call execute(cats('%WriteInLog(',Text1,',%nrstr(',Text2,'))'));
	call execute(cats('%SendMail(',Text1,',%nrstr(',Text2,'))'));
run;

The execution of the macro WriteInLog shows no error and the following text in the log, as expected:

"Text1 is Test"
"Text2 is Text&MoreText"

The execution of the macro SendMail shows a warning when trying to resolve the variable &MoreText, even if I have called the macro using %nrstr in order to avoid that:

2   + filename msg email   to = "moretest@sas.com"   from = "test@sas.com"   subject = "Test mail";
2   +                                                                                                 data _null_;   file msg;   
put "Text1: Test"; put '0D0A'x;   put "Text2: Text&MoreText";   run;
WARNING: Apparent symbolic reference MORETEXT not resolved.

What am I missing?

 

Thank you

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Just add the extra level when writing the strings to CALL EXECUTE().

data test;
	Text1 = 'Test';
	Text2 = 'Text&MoreText';
run;

data _null_;
	set test;   
	call execute(cats('%nrstr(%WriteInLog)(%nrstr(%nrstr(',Text1,')),%nrstr(%nrstr(',Text2,')))'));
run;
1    + %WriteInLog(%nrstr(Test),%nrstr(Text&MoreText))
MPRINT(WRITEINLOG):   data _null_;
MPRINT(WRITEINLOG):   put "Text1=Test";
MPRINT(WRITEINLOG):   put "Text2=Text&MoreText";
MPRINT(WRITEINLOG):   run;

Text1=Test
Text2=Text&MoreText

View solution in original post

11 REPLIES 11
PaigeMiller
Diamond | Level 26

Macro variable &MoreText has not been assigned a value.

--
Paige Miller
JordiGC
Obsidian | Level 7

MoreText is not intended to be a macro variable; it is part of text string assigned to a variable. I'm trying to show the text &MoreText as text in the email. Think of &MoreText as a company called Text &MoreText or Dallas&Sally, for example.

Quentin
Super User

Interesting problem.  Note that this isn't about emailing.  In your first test of %WriteInLog you don't get the problem because you use a %PUT statement, instead of a PUT statement.  If you get change to PUT, you'll get the same attempted resolution.  

 

Call Execute timing, and automatic unquoting, is always tricky.

 

Could you settle for using:

data test;
	Text1 = 'Test';
	Text2 = '%nrstr(Text&MoreText)';
run;

That would allow to use your current code, e.g.:

 

%macro WriteInLog(Text1, Text2);
	data _null_;
		put "Text1 is &Text1. Text2 is Text2";
	run;
%mend WriteInLog;

data test;
	Text1 = 'Test';
	Text2 = '%nrstr(Text&MoreText)';
run;

data _null_;
	set test;   
	call execute(cats('%WriteInLog(',Text1,',',Text2,')'));
run;

I would probably use:

data _null_;
	set test;   
	call execute(cats('%nrstr(%%)WriteInLog(',Text1,',%nrstr(',Text2,'))'));
run;

because delaying the macro execution gives a clearer log:

 

277  data _null_;
278    set test;
279    call execute(cats('%nrstr(%%)WriteInLog(',Text1,',%nrstr(',Text2,'))'));
280  run;

NOTE: There were 1 observations read from the data set WORK.TEST.

NOTE: CALL EXECUTE generated line.
1   + %WriteInLog(Test,%nrstr(Text&MoreText))

Text1 is Test Text2 is Text2

 

The Boston Area SAS Users Group is hosting free webinars!
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
Quentin
Super User

Sorry, my answer is wrong.  Haven't woken up yet!

The Boston Area SAS Users Group is hosting free webinars!
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
Quentin
Super User

Tom's answer is (as usual) better than mine.  But here is a corrected version of my prior approach, which requires adding quoting inside the text string, which looks weird, but works:

 

%macro WriteInLog(Text1, Text2);
  data _null_;
    put "Text1=&Text1";
    put "Text2=&Text2";
  run;
%mend WriteInLog;

data test;
	Text1 = 'Test';
	Text2 = '%nrstr(Text&MoreText)';
run;

data _null_;
	set test;   
	call execute(cats('%nrstr(%%)WriteInLog(',Text1,',%nrstr(',Text2,'))'));
run;

Log:

13   data _null_;
14     set test;
15     call execute(cats('%nrstr(%%)WriteInLog(',Text1,',%nrstr(',Text2,'))'));
16   run;

NOTE: There were 1 observations read from the data set WORK.TEST.

NOTE: CALL EXECUTE generated line.
1   + %WriteInLog(Test,%nrstr(Text&MoreText))

Text1=Test
Text2=Text&MoreText

 

The Boston Area SAS Users Group is hosting free webinars!
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
Tom
Super User Tom
Super User

Just add the extra level when writing the strings to CALL EXECUTE().

data test;
	Text1 = 'Test';
	Text2 = 'Text&MoreText';
run;

data _null_;
	set test;   
	call execute(cats('%nrstr(%WriteInLog)(%nrstr(%nrstr(',Text1,')),%nrstr(%nrstr(',Text2,')))'));
run;
1    + %WriteInLog(%nrstr(Test),%nrstr(Text&MoreText))
MPRINT(WRITEINLOG):   data _null_;
MPRINT(WRITEINLOG):   put "Text1=Test";
MPRINT(WRITEINLOG):   put "Text2=Text&MoreText";
MPRINT(WRITEINLOG):   run;

Text1=Test
Text2=Text&MoreText
Quentin
Super User

@Tom wrote:

Just add the extra level when writing the strings to CALL EXECUTE().

 Thanks Tom, agree, that's better.

The Boston Area SAS Users Group is hosting free webinars!
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
JordiGC
Obsidian | Level 7

Thanks everyone for your help. Just adding an extra level in the string processing did the trick for me, even when other characters as commas could cause trouble adding (apparently) extra parameters to the macro function. 

No more annoying warnings in the log 🙂 

Tom
Super User Tom
Super User

You need to quote the string with the macro triggers if you don't want the macro processor to process them.

 

Many times it is much easier to just use actual quotes, like you did in the DATA step, than macro quoting.  So if you just write the macro so it expects the quotes around the values.

%macro testing(Text1, Text2);
%put &=text1 &=text2 ;
data _null_;
  put "Text1: " &text1 ;
  put "Text2: " &text2 ;
run;
%mend testing;

options mprint;
data test;
  Text1 = 'Test';
  Text2 = 'Text&MoreText';
  call execute(cats('%nrstr(%testing)(',quote(trim(text1),"'"),',',quote(trim(text2),"'"),')'));
run;

It works fine

NOTE: CALL EXECUTE generated line.
1    + %testing('Test','Text&MoreText')
TEXT1='Test' TEXT2='Text&MoreText'
MPRINT(TESTING):   data _null_;
MPRINT(TESTING):   put "Text1: " 'Test' ;
MPRINT(TESTING):   put "Text2: " 'Text&MoreText' ;
MPRINT(TESTING):   run;

Text1: Test
Text2: Text&MoreText
Kurt_Bremser
Super User

Use this:

call execute(cats('%nrstr(%SendMail(',Text1,',',Text2,'))'));

to delay the execution of macro statements and references.

If that does not do it, try a macro quoting function.

yabwon
Onyx | Level 15

In addition to what already have been said [especially by @Kurt_Bremser about adding %nrstr()] I would add: your input looks like an arbitrary string of text to me, in such case I would, instead using the "&" macro variable call, use the symget() function. It is more safe in such situations:

 

%macro WriteInLog(Text1, Text2);
	data _null_;
    length t1 t2 $ 32767;
    t1=symget('Text1');
    t2=symget('Text2');
		put "Text1 is " T1;
		put "Text2 is " T2;
	run;
%mend WriteInLog;

%macro SendMail(Text1, Text2);
	filename msg email
		to = "moretest@sas.com"
		from = "test@sas.com"
		subject = "Test mail";

	data _null_;
		file msg;

    length t1 t2 $ 32767;
    t1=symget('Text1');
    t2=symget('Text2');
		put "Text1: " T1;put '0D0A'x;
		put "Text2: " T2;
	run;
%mend SendMail;

data test;
	Text1 = 'Test';
	Text2 = 'Text&MoreText';
run;

data _null_;
	set test;
	call execute(cats('%nrstr(%WriteInLog(',Text1,',%nrstr(',Text2,')))'));
	call execute(cats('%nrstr(%SendMail(',Text1,',%nrstr(',Text2,')))'));
run;

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 11 replies
  • 1846 views
  • 2 likes
  • 6 in conversation