Macro系列导读
SAS Macro作为SAS高手不可或缺的一项技能,是因为它功能足够强大,能极大的提升程序开发效率;使你的时间和精力投入在更有价值的事情上。
Macro系列文章,将会逐一奉上SAS Macro的点点滴滴,带你踏上从认识Macro到熟练使用Macro之路。掌握SAS Macro,将会使你的SAS编程能力更上一层楼。
上期文章“”这一主题进行了介绍。在每种编程语言中都有一些字符具有特殊的含义,但是在某些情况下我们不需要他们有特殊的含义,只是单纯的当作一个字符来使用。在宏语言中也不例外,如果想要将具有特殊含义字符当作普通字符来使用,这时候局需要用到Macro Quoting。所以,简单来说Macro Quoting就是将宏语言中具有特殊功能字符的功能隐藏掉。
Macro系列(13)—Macro Storing
本期文章对Macro Storing这一主题进行介绍,如何将宏程序存储起来,方便每次调用。也可以将其共享给团队内部,使得整个团队提升工作效率。同时,也可以将有些核心的程序编译存储,在分享给他人使用的同时,对源代码也起到保护的作用。
一般情况下,我们在调用某个自定义的宏程序时,需要先对该宏程序的定义部分(即%MACRO语句和%MEND语句部分)运行一次。运行完这部分宏程序定义后,SAS会将该宏程序编译并存在WORK.SASMACR这个catalog中。如果不先运行自定义宏程序的定义部分,而直接调用该宏程序,SAS会提示没有该宏程序。
当关闭SAS,再次打开后。如果想要再次调用该自定义的宏程序,同样需要再次运行该宏程序的定义部分。那么,有没有办法可以比较方便的重复使用宏程序呢?
1.
最直接的方法
最为常用的方法也就是上面所讲的手动执行。将所有的宏程序定义保存在一个SAS程序中,在SAS中打开这个程序,运行整个程序编译所有的宏程序;或者选择性的运行部分宏程序的定义,编译部分需使用的宏程序。被编译后的宏程序会存储在WORK.SASMACR这个catalog中。例如:
2.
相对正规的方法
此种方法需要用到一个宏语句
%INCLUDE
。首先同样需要将所有的宏程序定义放在一个SAS程序中。在需要调用其中的宏之前,使用
%INCLUDE
语句将该程序文件包含到当前的SAS会话中。其本质与上面的方法是一样的,只不过相对简单。但是使用这种方法,就只能运行编译整个程序文件。
其用法如下:
%include
"D:sasmacrosmacro_programexample.sas"
;
运行后日志如下:
可以看到,日志当中只显示了这一段代码,并无其他信息。
但其实SAS会运行程序文件中的所有程序。因为该程序中只有宏程序的定义,因此并无日志显示出来
。在WORK逻辑库可以看到的确生成了该程序文件中定义的3个宏。
接下来,就可以直接调用其中的宏使用了。在实际工作中此种方式也最为普遍,因为最为简单、方便。针对一个团队,可以将一些公共宏程序统一放到共享路径,由专门的人负责维护管理,他人负责使用即可。
3.
使用Autocall Macro
上面两种方法其实可以归结为同一种方法,只不过实现的路径不同。但都存在一个缺点:如果程序文件中包含很多宏程序的定义,而往往有时候只需要调用其中的一个宏,那么其他宏程序的编译其实就是多余的。
Autocall Macro就可以解决这个问题,通过使用这种方式,会在调用宏的时候,SAS自动搜索相对应宏程序的代码,然后对其进行编译(
在同个SAS会话中,只在第一次调用时编译,第二次调用会跳过编译过程
),进而运行该宏。所以称之为Autocall。
此种方式又可以根据存储方式的不同分为两种,下面分别进行介绍。
3.1. 将目录作为Autocall库
要实现此种方式,需要以下三个步骤:
将所有的宏程序分别存储到一个SAS程序文件中,
并且以宏程序的名字命名该程序文件
。然后将所有的宏程序文件放到一个特定的目录下;
使用FILENAM语句将存储所有宏程序文件的目录关联一个FILEREF;
使用MAUTOSOURCE系统选项打开Autocall机制(默认打开),并且通过SASAUTO=系统选项将该FILEREF指定为Autocall库;
在完成上面三个步骤后就可以直接调用其中的宏使用,在调用的时候SAS会自动搜索该宏对应的宏程序文件(这也是为什么要求程序文件名必须跟宏的名字一致的原因);然后进行编译,存储到WORK.SASMACR中。
将宏程序分别存储到不同程序文件中
使用FILENAME语句
filename
mymacros
"D:sasmacrosautocall_macros_directory"
;
使用系统选项
options
mautosource
sasautos
=(sasautos mymacros);
接下来,就可以直接调用宏程序使用了。例如:
需要注意SASAUTOS=系统选项,因为SAS在启动时会初始化自带的一些Autocall库,所以SASAUTOS会有默认的值。如果直接覆盖SASAUTOS的值,那么SAS系统自带的宏将会不可用。因此在赋值的时候,要加上默认的SASAUTOS值。
SASAUTOS的默认值可在SAS启动的配置文件“sasv9.cfg”中找到。若默认语言为中文,则该配置文件位于:
{SASHOME}SASFoundation9.4nlszh
打开该文件夹下的sasv9.cfg文件,即可找到默认的SASAUTOS对应的路径(
也可以直接将自己的存储宏程序的路径添加在此处,就省去以上的2、3步
)。
3.2. 将SAS Catalog作为Autocall库
此种方式与上面的方式基本一样,只是宏程序存储的方式不同。上面是将其存储在某个目录下的分散的程序文件中。而此种方式是将程序源码存储在SAS catalog中。需要以下四个步骤:
使用LIBNAME语句将用于存储catalog的目录分配一个逻辑库;
使用FILENAM语句在该逻辑库下创建一个catalog;
将各宏程序的定义源码以SOURCE ENTRY的形式分别存入该catalog下,
每
个SOURCE ENTRY的名字与宏程序的名字保持一致
;
使用MAUTOSOURCE系统选项打开Autocall机制(默认打开),并且通过SASAUTO=系统选项将该CATALOG指定为Autocall库;
在完成上面四个步骤后就可以直接调用其中的宏使用,在调用的时候SAS会自动搜索该宏对应的SOURCE ENTRY(这也是为什么要求SOURCE ENTRY名必须跟宏的名字一致的原因);然后进行编译,存储到WORK.SASMACR中。
分配逻辑库
libname
mylib
"D:sasmacrosautocall_macros_catalog"
;
创建CATALOG
filename
mymacros
catalog
'mylib.myautos'
;
将宏程序源码存入CATALOG
filename
macro1
catalog
'mylib.myautos.proc_print.source'
;
data
_null_
;
infile
datalines
truncover
;
file
macro1;
input
str
$50.
;
put
str $;
datalines4
;
%macro proc_print(dsn, var);
proc print data=&dsn;
var &var;
%mend proc_print;
run
;
filename
macro2
catalog
'mylib.myautos.proc_means.source'
;
data
_null_
;
infile
datalines
truncover
;
file
macro2;
input
str
$50.
;
put
str $;
datalines4
;
%macro proc_means(dsn, var);
proc means data=&dsn;
var &var;
%mend proc_means;
run
;
filename
macro3
catalog
'mylib.myautos.proc_freq.source'
;
data
_null_
;
infile
datalines
truncover
;
file
macro3;
input
str
$50.
;
put
str $;
datalines4
;
%macro proc_freq(dsn, var);
proc freq data=&dsn;
table &var;
%mend proc_freq;
run
;
运行完毕后,即可再MYLIB逻辑库下看到MYAUTOS这个CATALOG,及该CATALOG下的三个宏程序对应的SourceEntry。
使用系统选项
options
mautosource
sasautos
=(sasautos mymacros);
接下来,就可以直接调用了:
4.
存储编译宏
Autocall的方式虽然能够自动搜索相应的宏程序进行编译运行,但是每次首次调用宏时仍然需要对宏程序源码进行编译,然后执行宏。
但是通过存储编译后的宏,就可以在调用时省去宏程序编译的时间,提高效率。要实现存储编译宏,需要以下四步:
使用LIBNAME语句定义存储编译宏的逻辑库;
使用系统选项MSTORED打开存储编译宏功能,使用系统选项SASMSTORE=指定存储编译宏的逻辑库;
在%MACRO语句中增加STORE选项;
提交%MACRO-%MEND宏程序定义代码,编译并将其存储至指定逻辑库中;
分配逻辑库
libname
macrolib
"D:sasmacrosstored_macros"
;
使用系统选项
option
mstored
sasmstore
=macrolib;
增加STORE选项
%macro
proc_print(dsn, var) / store;
proc print data=&dsn;
var &var;
%mend
proc_print;
提交运行代码
提交上述代码,运行后日志如下:
打开MACROLIB逻辑库,可以看到编译后的宏程序存储在MACROLIB.SASMACR中。
利用以上方式存储有一个缺点,就是需要备份宏程序的源代码,因为存储的是编译后的宏,并不能从编译的宏得到源代码。如果后期对源代码升级优化后,需要重新编译存储。
除了备份源代码,也可以在%MACRO语句中增加一个
SOURCE
选项,使其在存储编译宏的同时将源代码也一并存储。这样就可以不用手动备份源代码了。通过%COPY语句就可以将源代码读取出来,例如:
%macro
proc_means(dsn, var) / store source;
proc means data=&dsn;
var &var;
%mend
proc_means;
%
copy
proc_means / source;
运行后,日志如下:
除此之外,还有一种需求,就是封装核心代码。他人只能使用,却看不到其中的源代码。通过存储编译宏的方式也可以达到,只需在%MACRO语句中增加
SECURE
选项即可。通过%COPY语句就无法查看其源代码。
例如:
%macro
proc_freq(dsn, var) / store secure;
proc freq data=&dsn;
table &var;
%mend
proc_freq;
%
copy
proc_freq / source;
运行后日志文件:
可以看到日志显示因为SECURE的缘故,是无发显示源码的。
即使是使用MPRINT、MLOGIC选项,也不会将相关的代码及宏变量显示出来
,只会显示运行的日志:
本期文章到这里就结束了,主要针对Macro Storing这一主题进行了说明。在日常工作中比较多用的是%INCLUDE语句,因为最为方便。如果需要对某些敏感信息进行封装,可通过加密编译存储的方式,这样使用者就无法看到源码
。
更多内容,请持续关注SAS中文论坛——“SAS岩论-Macro系列”。
作者:辛岩,从事了多年的SAS数据分析挖掘工作,担任过项目经理、技术顾问、培训讲师等职务,拥有丰富的项目实战经验。
剑指SAS,尽在今朝。欢迎各位技术达人交流,可以长按下面群二维码入SAS中文论坛微信群@Slash,也可以发邮件:slash.xin@hotmail.com。
更多SAS岩论系列文章