在Windows中从SAS捕获stdout和stderr?
我想在Windows上从一个程序调用一个SAS程序。我之前有一些在命令行中以批处理模式调用SAS的经验,但对于如何接收来自SAS的消息和处理这些消息,我没有太多经验。我在网上查了一些资料,发现了很多关于如何在SAS程序中从标准输入(stdin)读取的内容,但我似乎搞不清楚如何让我的SAS程序输出到标准输出(stdout)或标准错误(stderr)。在Windows上我能做到这一点吗?
在SAS程序中,我想做以下几件事:
- 把警告信息和错误信息重定向到标准错误(stderr),而不是打印到日志文件里
- 在SAS程序内部,手动检测错误或其他问题,并将它们输出到标准错误(stderr)或标准输出(stdout)
这是我尝试过的:
SAS
data test;
attrib i length=8;
do i = 1 to 10;
put 'putting'; *how can i make this go to stdout?;
putlog 'putting to log'; *this can go to the log - that is okay;
if i = 5 then do;
*pretend this is an error I am manually detecting - how can i make this go to stderr?;
put 'we found 5';
end;
output;
end;
run;
data _null_;
1 = y; *this is an error detected by SAS. How can I make this go to stderr?;
run;
调用SAS的Python代码:
import subprocess
import os
if __name__ == '__main__':
filename = os.path.normpath(r'C:\Users\oob\Desktop\sas_python_test.sas')
sas_executable = os.path.normpath(r'C:\Program Files\SAS\SASFoundation\9.2\sas.exe')
cmd = r'"' + sas_executable + r'"' + " " + r'"' + filename + r'"'
p = subprocess.Popen(cmd,shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print p.communicate()
从这个代码在控制台上得到的结果是:
('', '')
3 个回答
我在网上查了一下,关于如何把日志重定向到错误输出(STDERR)给你找到了资料:
proc printto log=STDERR;
run;
data _null_;
1=x;
run;
我手头没有Windows版本的SAS,但在UNIX系统上,我是这样把输出重定向到标准输出(STDOUT)的:
data _null_;
file STDOUT;
do i=1 to 10;
put i=;
end;
run;
我不太确定怎么把错误日志重定向到标准错误(STDERR),不过打印到STDERR的方式看起来是这样的:
ods listing file=STDERR;
proc print data=sashelp.class;
run;
据我所知,这个直接实现是不可能的。不过你可以通过传递一个独特的文件名给sas,使用 -sysparm 这个命令行参数来模拟这个过程,并把你的标准输出(STDOUT)保存到那个文件里。然后,你可以用 -log 这个命令行参数把sas日志发送到另一个文件。等到SAS程序运行完毕后,你就可以用你喜欢的程序来解析这些生成的文件。不幸的是,日志文件在SAS程序完成之前是锁定的,所以如果你想用SAS来处理日志文件,你需要启动一个后续的程序来完成这个任务。(也就是说,你不能在创建日志文件的SAS程序内部读取它。)
一旦你读取了日志,你可以查找以 ERROR: 或 WARNING: 开头的行,并采取适当的措施(在我的情况下,它会给我发一封邮件)。你可能想添加一些符合你编码风格的逻辑。例如,SAS认为的一些NOTES我认为是错误,而SAS认为的一些错误我并不在意。以下是我使用的逻辑:
data problems log;
length line $1000;
infile "&logfile";
input;
logfile = "&logfile";
line_no = _n_;
line = _infile_;
problem = 0;
if
(
line =: "ERROR:"
or line =: "WARNING:"
or line =: "NOTE: Numeric values have been converted to character values"
or line =: "NOTE: Character values have been converted to numeric values"
or line =: "NOTE: Missing values were generated as a result of performing an operation on missing values"
or line =: "NOTE: MERGE statement has more than one data set with repeats of BY values"
or line =: "NOTE: Invalid (or missing) arguments to the INTNX function have caused the function to return"
or line =: "INFO: Character variables have defaulted to a length of 200"
or line =: "NOTE: Invalid"
)
and not
(
line =: "WARNING: Your system is scheduled to expire"
or line =: "WARNING: The Base Product product with which Session Manager is associated"
or line =: "WARNING: will be expiring soon, and is currently in warning mode to indicate"
or line =: "WARNING: this upcoming expiration. Please run PROC SETINIT to obtain more"
or line =: "WARNING: information on your warning period."
or line =: "WARNING: This CREATE TABLE statement recursively references the target table. A consequence"
or line =: "WARNING: Unable to copy SASUSER registry to WORK registry. Because of this, you will not see registry customizations during this"
or line =: "WARNING: Estimates did not improve after a ridge was encountered in the objective function."
or line =: "WARNING: Estimates may not have converged."
or line =: "ERROR: A lock is not available for"
or line =: "ERROR: Errors printed on pages"
)
then do;
problem = 1;
output problems;
end;
output log;
run;
希望这对你有帮助。