81

我阅读了 subprocess 提供的函数 - call、check_call、check_output,并了解了每个函数的工作原理和功能上的不同。我目前正在使用check_output,所以我可以访问stdout,并使用“try block”来捕获异常,如下所示:

# "cmnd" is a string that contains the command along with it's arguments. 
try:
    cmnd_output = check_output(cmnd, stderr=STDOUT, shell=True, timeout=3, universal_newlines=True);                         
except CalledProcessError:                                                                                                   
    print("Status : FAIL")                                                                                                   
print("Output: \n{}\n".format(cmnd_output))                                                                                  

我遇到的问题是抛出异常时,“cmnd_output”未初始化并且无权访问stderr,并且我收到以下错误消息:

print("Output: \n{}\n".format(cmnd_output))
UnboundLocalError: local variable 'cmnd_output' referenced before assignment

我认为那是因为异常导致“check_output”立即退出,没有任何进一步的处理,也就是在 try 块中分配给“cmnd_output”。如果我错了,请纠正我。

有什么方法可以访问 stderr (如果发送到 stout 就可以了)并可以访问退出代码。我可以根据退出代码手动检查通过/失败,而不会抛出异常。

谢谢你,艾哈迈德。

4

5 回答 5

124

试试这个版本:

import subprocess
try:
    output = subprocess.check_output(
        cmnd, stderr=subprocess.STDOUT, shell=True, timeout=3,
        universal_newlines=True)
except subprocess.CalledProcessError as exc:
    print("Status : FAIL", exc.returncode, exc.output)
else:
    print("Output: \n{}\n".format(output))

这样,只有在调用成功时才会打印输出。如果是,CalledProcessError您打印返回码和输出。

于 2013-04-24T17:38:26.783 回答
74

接受的解决方案涵盖了您可以混合stdoutstderr的情况,但是在子进程(无论出于何种原因)决定使用stderrIN ADDITION 来stdout进行非失败输出(即输出非关键警告)的情况下,然后给定的解决方案可能并不理想。

例如,如果您将对输出进行额外的处理,例如转换为 JSON,并且您stderrstderr.

我发现在这种情况下可以使用以下方法:

cmd_args = ... what you want to execute ...

pipes = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#If you are using python 2.x, you need to include shell=True in the above line
std_out, std_err = pipes.communicate()

if pipes.returncode != 0:
    # an error happened!
    err_msg = "%s. Code: %s" % (std_err.strip(), pipes.returncode)
    raise Exception(err_msg)

elif len(std_err):
    # return code is 0 (no error), but we may want to
    # do something with the info on std_err
    # i.e. logger.warning(std_err)

# do whatever you want with std_out
# i.e. json.loads(std_out)
于 2014-12-26T20:09:57.750 回答
15

两种建议的解决方案要么混合标准输出/标准错误,要么使用Popen不像check_output. check_output但是,如果您只是使用管道捕获 stderr,则可以在使用时完成相同的事情,并保持 stdout/stderr 分开:

import sys
import subprocess

try:
    subprocess.check_output(cmnd, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
    print('exit code: {}'.format(e.returncode))
    print('stdout: {}'.format(e.output.decode(sys.getfilesystemencoding())))
    print('stderr: {}'.format(e.stderr.decode(sys.getfilesystemencoding())))

在此示例中,由于我们捕获了 stderr,因此它在异常的stderr属性中可用(不使用管道捕获,它只是None)。

于 2018-02-15T17:45:04.563 回答
0

我有类似的要求,以下对我有用:

    try:
        with open ("vtcstderr.out", "w") as file:
            rawOutput = subprocess.check_output(
                command,
                stderr=file,
                shell=True
            )
    except subprocess.CalledProcessError as error:
        # this is the stdout
        rawOutput = error.output

    with open ("vtcstderr.out", "r") as file:
        # this is the stderr
        errorLines = file.readlines()

于 2020-06-19T13:47:26.897 回答
-2

为什么不在 try 语句之前初始化变量 cmnd_output 呢?这样,它将按照您期望的方式工作。以下行将起作用,只需将其添加到 try 语句上方:

cmnd_output = ''
于 2013-04-24T17:36:22.557 回答