我最近继承了一个看起来像这样的 SAS 程序:
%MACRO ComplicatedStuff( GroupId= );
%LET FileId = %SYSFUNC( OPEN( Work.BigDataSet ) );
%PUT 'Doing something really difficult with ' &GroupId.;
%LET CloseRC = %SYSFUNC( CLOSE( &FileId. ) );
%MEND ComplicatedStuff;
%ComplicatedStuff(GroupId=ABC1);
%ComplicatedStuff(GroupId=DEF2);
%ComplicatedStuff(GroupId=3GHI);
%ComplicatedStuff(GroupId=J4KI);
作为一个多面的程序员,我看着这个并想“我当然可以让它至少更动态一点”。果然,我能够使用以下方法开发我认为的简单解决方案CALL EXECUTE
:
DATA Work.IDs;
INPUT ID $4.
;
DATALINES;
ABC1
DEF2
3GHI
J4KI
RUN;
DATA Work.CommandDebug;
SET Work.IDs;
Command = CATS(
'%ComplicatedStuff(GroupId=', ID, ');'
);
CALL EXECUTE( Command );
RUN;
我对这个解决方案很满意,直到需要将 ComplicatedStuff 生成的文件通过 FTP 传输到不同的服务器。我们的 SAS 服务器在 Unix 上运行,SAS 管理员为我们创建了一个有用的小宏来命名%sas_sftp
(因为有人告诉我,x
代码变得非常丑陋)。不幸的是,我无法发布%sas_sftp
代码 - 它属于我的公司,我认为他们不希望它出现在 SO 上。
我尝试像调用%sas_sftp
宏一样调用%ComplicatedStuff
宏(CALL EXECUTE
在同一数据步骤中作为第二个,作为第二个数据步骤),但只有第一个文件(大约 30 个)会到达目的地。当我查看日志时,看起来第二个宏在 ftp 完成之前开始执行(ftp 管道或其他任何东西在下一个 ftp 开始之前还没有被释放),所以随后的 ftp 只是默默地失败了由于资源不可用(我想)。
我认为 EXECUTE 基本上会将我的宏调用排队,然后像它们按顺序位于代码中一样执行它们(就像它们最初一样) - 一次一个。显然还有其他事情正在发生,因为虽然上面的第一种方法没有问题,但我的动态解决方案失败了。我倾注了CALL EXECUTE: How and Why和SAS 文档,但恐怕我只是不明白他们在说什么。
我最终确实找到了一个解决方法(或者更确切地说,一位同事找到了一个),我在下面发布了一个“答案”,但我真的很想有人解释 EXECUTE 函数及其工作原理。
为什么我的第一次尝试,使用CALL EXECUTE
,没有工作?