Python 从子进程调用中获取退出代码和 stderr
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16198546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get exit code and stderr from subprocess call
提问by Ahmed A
I read up on the functions provided by subprocess - call, check_call, check_output, and understand how each works and differs in functionality from one another. I am currently using check_output, so I can have access to the stdout, and used "try block" to catch the exception, as follows:
我阅读了 subprocess 提供的函数 - call、check_call、check_output,并了解每个函数的工作原理和彼此的功能不同。我目前正在使用 check_output,因此我可以访问 stdout,并使用“try 块”来捕获异常,如下所示:
# "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))
The issue I am running into is when an exception is thrown, "cmnd_output" is not initialized and don't have access to stderr, and I get the following error message:
我遇到的问题是抛出异常时,“cmnd_output”未初始化且无法访问 stderr,并且我收到以下错误消息:
print("Output: \n{}\n".format(cmnd_output))
UnboundLocalError: local variable 'cmnd_output' referenced before assignment
I think thats because the exception causes the "check_output" to bail immediately without any further processing, aka assignment to "cmnd_output", in the try block. Please correct me if I am wrong.
我认为那是因为异常导致“check_output”在没有任何进一步处理的情况下立即保释,也就是在 try 块中分配给“cmnd_output”。如果我错了,请纠正我。
Is there any way I can get access to stderr (it's ok if it's sent to stout) and have access to the exit code. I can manually check for pass/fail based on exit code with out the exception being throuwn.
有什么方法可以访问stderr(如果它被发送到stout就可以)并可以访问退出代码。我可以根据退出代码手动检查通过/失败,而不会抛出异常。
Thank you, Ahmed.
谢谢你,艾哈迈德。
采纳答案by warvariuc
Try this version:
试试这个版本:
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))
This way you will print the output only if the call was successful.
In case of a CalledProcessErroryou print the return code and the output.
这样,您将仅在调用成功时打印输出。如果CalledProcessError您打印返回代码和输出。
回答by n3rV3
why not initialize the varible cmnd_output before the try statement? That way it will work the way you expect it to. Following line would work, just add it above try statement :
为什么不在 try 语句之前初始化变量 cmnd_output?这样它就会按照你期望的方式工作。以下行可以工作,只需将其添加到 try 语句上方:
cmnd_output = ''
回答by oarevalo
The accepted solution covers the case in which you are ok mixing stdoutand stderr, but in cases in which the child process (for whatever reason) decides to use stderrIN ADDITION to stdoutfor a non failed output (i.e. to output a non-critical warning), then the given solution may not desirable.
接受的解决方案涵盖了您可以混合stdout和的情况stderr,但是在子进程(无论出于何种原因)决定使用stderrIN ADDITION 来stdout进行非失败输出(即输出非严重警告)的情况下,然后给定的解决方案可能并不理想。
For example, if you will be doing additional processing on the output, like converting to JSON, and you mix in the stderr, then the overall process will fail since the output will not be pure JSON because of the added stderroutput.
例如,如果您将对输出进行额外处理,例如转换为 JSON,并且您混入了stderr,则整个过程将失败,因为由于添加了输出,输出将不是纯 JSON stderr。
I've found the following to work in that case:
在这种情况下,我发现以下内容有效:
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)
回答by Kyle
Both of the proposed solutions either mix the stdout/stderr, or use Popenwhich isn't quite as simple to use as check_output. However, you can accomplish the same thing, and keep stdout/stderr separate, while using check_outputif you simply capture stderrby using a pipe:
两个提议的解决方案要么混合 stdout/stderr,要么Popen使用不像check_output. 但是,您可以完成同样的事情,并保持 stdout/stderr 分开,而check_output如果您只是通过使用管道捕获 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())))
In this example, since we captured stderr, it's available in the exception's stderrattribute (without capturing with the pipe, it would just be None).
在这个例子中,因为我们捕获了 stderr,它在异常的stderr属性中可用(不用管道捕获,它只是None)。

