在Windows中从SAS捕获stdout和stderr?

oob*_*oob 5 python sas

我想从Windows上的另一个程序调用SAS程序.我有一些在批处理模式下从命令行调用SAS的经验,但没有真正的经验从它接收消息并处理这些消息.我已经google了一下,发现了很多关于从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;
Run Code Online (Sandbox Code Playgroud)

调用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()
Run Code Online (Sandbox Code Playgroud)

我在控制台上的结果是:

('', '')
Run Code Online (Sandbox Code Playgroud)

Rob*_*dge 2

据我所知,这是不可能直接实现的。您可以通过使用 -sysparm 命令行参数将唯一的文件名传递到 sas 并将 STDOUT 输出保存到其中来模拟这一点。然后,您可以使用 -log 命令行参数将 sas 日志发送到不同的文件。SAS 程序完成后,您将能够使用您选择的程序来解析生成的每个文件。不幸的是,日志文件被锁定,直到 SAS 程序完成为止,因此如果您想使用 SAS 处理日志文件,您将需要启动辅助后续程序来执行此操作。(即,您无法从创建日志文件的 SAS 程序中读取该日志文件)。

阅读日志后,您可以查找以 ERROR: 或 WARNING: 开头的行,并采取适当的操作(在我的情况下,它会向我发送一封电子邮件)。您可能想添加一些适合您的编码风格的逻辑。例如,SAS 视为注释的某些内容我认为是错误。另外,有些 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;
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。