02-19-2016 12:13 PM
Is it possible to bring only a portion of a text from another program using %include statement? I want to only bring the macro I use and a certain dataset I created, rather than the entire program that also includes exporting/regressions, etc...
02-19-2016 12:34 PM - edited 02-19-2016 12:35 PM
I don't believe there is any direct option do what you are contemplating.
You might consider moving your Macro code to an AUTOCALL library. Then the macro is always available.
If the data set is created in a permanent library you might not need to reference the code just make sure the permanent library is available when you need it with a LIBNAME statement.
Or create separate files for those bits of code and then use %include statements as needed to directly access them.
You might consider what would happen if you have a reference to lines 50 to 100 and then someone, possibly not you, edits the code and adds or removes lines before the current line 50.
02-19-2016 12:49 PM - edited 02-19-2016 12:50 PM
You could use CALL EXECUTE to run selected portions of the external program:
data _null_; infile 'C:\Temp\test.sas' firstobs=17 obs=116; input; call execute(_infile_); run;
The above example would execute a block of 100 lines from line 17 to line 116 of program C:\Temp\test.sas.
As @ballardw pointed out, the line numbers may not be reliable. So, you may want to omit the FIRSTOBS= and OBS= options and instead use IF conditions or other data step logic to select those lines which you want to execute selectively. Example (for executing a one-line macro call):
if upcase(left(_infile_))=:'%MYMACRO' then call execute(_infile_);
02-19-2016 02:01 PM - edited 02-20-2016 11:58 AM
@FreelanceReinhard but it won't work.
33 options generic=1; 34 filename FT15F001 temp; 35 data _null_; 36 infile FT15F001; 37 input; 38 call execute(_infile_); 39 parmcards4; 48 ;;;; NOTE: The infile FT15F001 is: (system-specific pathname), (system-specific file attributes) ERROR: The %IF statement is not valid in open code. NOTE: ARG is blank ERROR: The %END statement is not valid in open code. ERROR: The %ELSE statement is not valid in open code. WARNING: Apparent symbolic reference ARG not resolved. NOTE: arg NOTE: DATA statement used (Total process time): real time 0.02 seconds cpu time 0.01 seconds ERROR: The %END statement is not valid in open code. ERROR: No matching %MACRO statement for this %MEND statement. NOTE: 8 records were read from the infile (system-specific pathname). The minimum record length was 9. The maximum record length was 33. NOTE: The SAS System stopped processing this step because of errors. NOTE: CALL EXECUTE generated line. NOTE: Line generated by the CALL EXECUTE routine. 1 + $macro test(arg); _ 180 ERROR 180-322: Statement is not valid or it is used out of proper order. WARNING: Apparent invocation of macro TEST not resolved. 49 run; 50 %test(Hello my friend); _ 180 ERROR 180-322: Statement is not valid or it is used out of proper order.
Here is program.
options generic=1; filename FT15F001 temp; data _null_; infile FT15F001; input; call execute(_infile_); parmcards4; %macro test(arg); %if %superq(arg) eq %then %do; %put NOTE: ARG is blank; %end; %else %do; %put NOTE: &=arg; %end; %mend; ;;;; run; %test(Hello my friend);
02-19-2016 03:33 PM
Thanks, @data_null__, well spotted!
So, I'm sorry it seems my original suggestion has limitations when the code to be selectively executed contains a macro definition. (It worked, however, with open code I had used for a quick test. It also worked with a one-line macro call. This was the situation where I had used this technique in practice.)
I've never seen the apparently undocumented system option GENERIC. At least with my SAS 9.4 it did not prevent the error due to starting the macro definition with $macro rather than %macro (not sure if this was the purpose of setting this option).
@dl0324: Here's a new suggestion, using %INCLUDE, as you had requested:
data _null_; infile 'C:\Temp\test.sas' firstobs=17 obs=116; file 'C:\Temp\temp.sas'; input; put _infile_; run; %include 'C:\Temp\temp.sas';
Again, you are free to use other data step techniques (also in addition to FIRSTOBS= and OBS=) to select the lines of code to be written to temp.sas, the program which is eventually included. It would even be possible, to execute only part of a line of the original program or to modify a line before it's written to temp.sas.
Also, it would be possible to use a temporary location for temp.sas (e.g. in the WORK directory) rather than C:\Temp. To avoid the risk of a name conflict, one could create a unique file name rather than hardcoding "temp.sas."
Let's see if someone comes up with a counterexample to this one. :-)
02-19-2016 04:13 PM
GENERIC is an internal option that causes SAS to print infile/file info in a "generic" way. You may notice this in SAS documention examples.
NOTE: The infile FT15F001 is: (system-specific pathname), (system-specific file attributes)
02-19-2016 04:49 PM
@data_null__: Thanks for the explanation. I've just noticed (while working on another post) that this option modifies the format of PROC CONTENTS output as well.
02-20-2016 12:20 PM
@FreelanceReinhard I reckon it is generally everywhere a host specific file path would be displayed.
If you can fit the entire macro definition on one line you compile with a CALL EXECUTE.
data _null_; infile FT15F001; input; call execute(_infile_); parmcards4; %macro test(arg); %if %superq(arg) eq %then %do; %put NOTE: ARG is blank; %end; %else %do; %put NOTE: &=arg; %end; %mend; ;;;;
02-21-2016 02:45 PM
@data_null__: Thanks again. As another example of the impact of option GENERIC, in PROC COMPARE output the "Created" and "Modified" timestamps are replaced by missing values (which makes sense). At the same time, however, the familiar text "All values compared are exactly equal" is replaced by "NOTE: The data sets ... and ... compare equal" (including the dataset names).
@dl0324: Inspired by data_null__'s remarks I was able to fix the issue with my original suggestion:
If the selected code (which may include a macro definition) fits into a character variable (of maximum length 32767) and the line breaks in the code may be replaced by single blanks, the following technique should work (tested with a macro definition of about 100 lines):
filename test 'C:\Temp\testprog.sas'; data _null_; length code $32767; retain code; infile test firstobs=17 obs=116 end=last; /* 17 and 116 are only examples */ input; code=catx(' ', code, _infile_); /* IF conditions and character functions may be applied to _infile_ */ if last then call execute(code); run;
But I would rather prefer the %INCLUDE technique. The selected code written to temp.sas will be helpful for debugging and documentation purposes.
02-22-2016 03:21 AM