7月 10, 2011

Posted by in | 3 条评论

使用%nowpath宏获取当前SAS路径

前几天学习了一个叫mypath的宏,其实现了将当前sas程序的路径定义为一个宏变量、以方便后续调用路径的功能。查了下相关资料,在《Generating Program-Stamped Output in an Interactive SAS Session》中,也有个叫fullpath的宏,是提取当前路径为宏变量后进行应用。

个人觉得这2个实现路径提取功能的宏及其中的编程技巧挺有用的,拿出来分享一下。

 

1.%nowpath

1.1

将%mypath和%fullpath作了小小改动、整合成了下面的宏%nowpath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%macro nowpath;
	%global fullpath nowpath;   /*定义为global,为后续调用准备*/
 
	proc sql noprint;
		select xpath into : fullpath   /*选取全路径*/
			from  dictionary.extfiles  /*dictionary.extfiles包含SAS路径信息*/
			where substr(fileref,4) eq
				(	select max(substr(fileref,4))   /*max()保证选取最新(当前)路劲*/
					from dictionary.extfiles
					where substr(fileref,1,1) eq "#" and index(xpath,".sas") gt 0  	);
	quit;
 
        /*选取当前路径*/
	%let nowpath=%substr(&fullpath,1,%eval(%length(&fullpath)-%length(%scan(&fullpath,-1,\)))); 
 
	%put The Full Path is: &fullpath;
	%put The Now Path is: &nowpath;
 
%mend nowpath;

这里面有一大关键点,就是dictionary.extfiles的使用。

关于dictionary.extfiles,个人没能查到详细的资料,下面是个人结合各种零碎介绍及一些测试做的理解(如有不对或不祥的地方,非常感谢大家能指出或补充):

  1. dictionary.extfiles会记录一些SAS的路径,包括系统、人为定义的路径,及运行(存储)的SAS文件的路径,fileref分别标记为SASAUTOS、MYAUTOS及#LN00000类型,并将路径名其存储于xpath变量中。
  2. 对于#LN类型,其后五位数字按时间依次递增,最新的一个路径的数字标号最大。

所以找出最大的#LN路径即为当前SAS文件的路径。

下图是引用《Generating Program-Stamped Output in an Interactive SAS Session》中的图:

再来看%nowpath:

  1. 使用“where substr(fileref,1,1) eq “#” and index(xpath,”.sas”) gt 0”来保证选取的类型#LN
  2. 使用“max(substr(fileref,4)”找出最新(即当前)路径

从而得到全路径:fullpath; 然后在通过substr和length函数的使用得到当前路径:nowpath

所以运行

1
%nowpath;

log中得到:

The Full Path is: F:\1.SAS\0.My SAS\0.My Blog_Statistics with SAS\12.宏nowpath\nowpath.sas
The Now Path is: F:\1.SAS\0.My SAS\0.My Blog_Statistics with SAS\12.宏nowpath\

1.2

而如《Generating Program-Stamped Output in an Interactive SAS Session》介绍,使用dictionary.extfiles是SAS V8的主要办法,SAS 9提供了2个environment variables:sas_execfilename和sas_execfilepath可以直接获取当前SAS文件名和路径。

于是可用下面的代码:

1
2
3
4
5
6
7
8
9
10
11
 %macro nowpath2;
	%global fullpath2 nowpath2;
 
	%let name=%sysget(sas_execfilename);
	%let fullpath=%sysget(sas_execfilepath);
	%let nowpath = %substr(&fullpath,1,%eval(%length(&fullpath) - %length(&name) ) );
 
	%put fullpath2=&fullpath;
	%put nowpath2=&nowpath;
 
%mend nowpath2;

2.宏nowpath的作用

上述宏就是实现将当前路径存储为宏变量,有哪些可取之处呢?

  1. 方便高效。在后续程序中若要使用当前路径的话,只需“&nowpath”,既省时省力又准确。
  2. 规范、可移植性强。对于一个常用的标准的宏程序来说,其需要保证很强的可移植性和稳健性,当将程序转移到其他文件位置或设备时,使用此种方法便不需人为的对路径进行改动,而能直接运行。

举个简单的例子:

以后我写某个博客,数据及现有程序路径如下:

利用现有Example_data要生成:
一些SAS数据集文件(.sas7bdat)、一些图形文件(.png)、一些结果数据(.xls),并将其相应的存储到datasets、plot、out_data文件夹下。

代码中就会有许多需要定义路径的过程,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
data _null_;
datap=dcreate("datasets","&nowpath"); /*在“&nowpath”路径下建立文件夹datasets*/
run; 
 
data _null_;
out_p=dcreate("out_data","&nowpath"); /*在“&nowpath”路径下建立文件夹out_data*/
run; 
 
libname blog "&nowpath\datasets\";
 
proc import  datafile="&nowpath.example_data.xls" out=blog.eg_data replace;
	getnames=yes;
run;

这样,路径调用很方便,而且即使以后如果中间的路径有所更改,或者在其他机器上运行,只要有数据和程序,不必修改仍可保证无误运行。

3.题外话:关于DICTIONARY tables(词典表)

从这个样例宏,再次可以看出使用DICTIONARY tables能实现很好的功能。

  1. DICTIONARY tables在PROC SQL中使用,通过其可以获取SAS系统信息,包括逻辑库、数据集、系统选项等等详细信息。
  2. 经常会用到的是dictionary.columns,dictionary.tables等,读取其中关于我们所需的数据及变量等信息进入宏变量中,再做进一步的后续批量处理的工作。
  3. 另外,DICTIONARY tables对应于SASHELP views(如dictionary.columns对应于sashelp.vcolumn),这样,在data step中我们也可以进行类似操作,十分方便、有效。

关于其详细介绍可以参见SASHELP文档及《SAS SQL 9.2 Procedure User Guide》中的“Accessing SAS System Information by Using DICTIONARY Tables”有关内容。

 

参考文献:
http://cos.name/cn/topic/103604
《Generating Program-Stamped Output in an Interactive SAS Session》
《SAS SQL 9.2 Procedure User Guide》

  1. data _null_;
    datap=dcreate(“datasets”,”&nowpath”); /*在“&nowpath”路径下建立文件夹datasets*/
    run;
    如何先判断文件夹是否存在,如没有再创建?

    [回复]

  2. 别担心,没有它会创建,有了它也不会删除重建,也不报错。

    [回复]

    hssnow 回复:

    呵呵,谢谢解答啊~

    [回复]

发表评论

返回顶部