在Windows中从SAS捕获stdout和stderr?

5 投票
3 回答
2244 浏览
提问于 2025-04-17 06:52

我想在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 个回答

-1

我在网上查了一下,关于如何把日志重定向到错误输出(STDERR)给你找到了资料:

   proc printto log=STDERR;
   run;

   data _null_;
      1=x;
   run;
2

我手头没有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;
2

据我所知,这个直接实现是不可能的。不过你可以通过传递一个独特的文件名给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;

希望这对你有帮助。

撰写回答