如何使用Python子进程捕获子进程的错误?

如何使用Python子进程捕获子进程的错误?,python,python-2.7,subprocess,Python,Python 2.7,Subprocess,我有以下Python(2.7)代码: 我面临的问题是,当没有更多的存档空间时,print str(e)prints命令'['tar','-czvf','/folder/archive.tar.gz','/folder/some_other_folder']'返回非零退出状态1,这是真的,但我想在这里抓住真正的错误,这就是gzip:write error:device上没有剩余的空间(我在手动运行相同的tar-com时得到了这个错误)。这有可能吗?我假设gzip是tar中的另一个进程。我错了吗?请

我有以下Python(2.7)代码:

我面临的问题是,当没有更多的存档空间时,
print str(e)
prints
命令'['tar','-czvf','/folder/archive.tar.gz','/folder/some_other_folder']'返回非零退出状态1
,这是真的,但我想在这里抓住真正的错误,这就是
gzip:write error:device上没有剩余的空间(我在手动运行相同的tar-com时得到了这个错误)。这有可能吗?我假设gzip是tar中的另一个进程。我错了吗?请记住,升级到Python 3是不可能的

编辑:我还尝试使用
子流程。检查_output()
并打印
e.output
的内容,但对于正常人来说,这也不起作用 在Python3上,解决方案很简单,无论如何,您都应该使用Python3来编写新代码(Python2.7几乎在一年前就停止了所有支持):

问题是程序正在将错误回显到
stderr
,因此
check\u output
不会捕获它(正常情况下,或者在
调用的过程错误中)。最好的解决方案是使用
子流程。运行
(其中
检查调用
/
检查输出
只是一个薄薄的包装)并确保捕获
标准输出
标准输出
。最简单的方法是:

try:
    subprocess.run(["tar", "-czvf", '/folder/archive.tar.gz', '/folder/some_other_folder'],
                   check=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
                             # ^ Ignores stdout           ^ Captures stderr so e.stderr is populated if needed
except CalledProcessError as e:
    print("tar exited with exit status {}:".format(e.returncode), e.stderr, file=sys.stderr)

Python 2解决方案,适用于喜欢不受支持软件的人 如果必须在Python2上执行此操作,则必须通过手动调用
Popen
来自行处理,因为那里的高级函数都无法覆盖您(
CalledProcessError
直到3.5版本才产生
stderr
属性,因为没有设计用于处理
stderr
属性的高级API):

为理智的人提供的Python3解决方案 在Python3上,解决方案很简单,无论如何,您都应该使用Python3来编写新代码(Python2.7几乎在一年前就停止了所有支持):

问题是程序将错误回显到
stderr
,因此
check\u output
无法捕获它(正常情况下,或者在
调用的进程错误中)。最好的解决方案是使用
子进程。运行
(这
check\u call
//code>check\u output
只是一个薄薄的包装)并确保同时捕获
stdout
stderr
。最简单的方法是:

try:
    subprocess.run(["tar", "-czvf", '/folder/archive.tar.gz', '/folder/some_other_folder'],
                   check=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
                             # ^ Ignores stdout           ^ Captures stderr so e.stderr is populated if needed
except CalledProcessError as e:
    print("tar exited with exit status {}:".format(e.returncode), e.stderr, file=sys.stderr)

Python 2解决方案,适用于喜欢不受支持软件的人 如果必须在Python2上执行此操作,则必须通过手动调用
Popen
来自行处理,因为那里的高级函数都无法覆盖您(
CalledProcessError
直到3.5版本才产生
stderr
属性,因为没有设计用于处理
stderr
属性的高级API):


一般来说,“退出状态1”是唯一一个真正明确的机器可读错误。stderr内容可以包含任何诊断日志或人类可读的信息内容,而不仅仅是错误——因此,按照@ShadowRanger编写的答案,虽然没有错误,但可能会导致错误之前的日志消息被视为错误的一部分因此,当您编写
if tar-czvf folder.archive.gz/folder时,…;else回显“有一个错误”>&2;fi
在shell中,它是shell用来知道发生了什么错误并遵循
else
分支的退出状态。@CharlesDuffy:我的答案仅在退出状态为非零时回显
stderr
,因此,可以肯定的是,当出现错误时,您可能会看到诊断输出,但在正常情况下它将保持沉默(成功)条件。绝对不依赖于
stderr
是否为空/非空。@ShadowRanger,如果你检查空/非空的stderr,你会投反对票;我的立场是谨慎、有条件的支持。一般来说,“退出状态1”是唯一一个真正明确的机器可读错误。stderr内容可以包含任何诊断日志或人类可读的信息内容,而不仅仅是错误——因此,按照@ShadowRanger编写的答案,虽然没有错误,但可能会导致错误之前的日志消息被视为错误的一部分因此,当您编写
if tar-czvf folder.archive.gz/folder时,…;else回显“有一个错误”>&2;fi
在shell中,它是shell用来知道发生了什么错误并遵循
else
分支的退出状态。@CharlesDuffy:我的答案仅在退出状态为非零时回显
stderr
,因此,可以肯定的是,当出现错误时,您可能会看到诊断输出,但在正常情况下它将保持沉默(成功)条件。绝对不依赖于
stderr
是否为空/非空。@ShadowRanger,如果你检查空/非空stderr,你会投反对票;我的立场是谨慎、有条件的支持。
with open(os.devnull, 'wb') as f:
    proc = subprocess.Popen(["tar", "-czvf", '/folder/archive.tar.gz', '/folder/some_other_folder'],
                 stdout=f, stderr=subprocess.PIPE)
    _, stderr = proc.communicate()
if proc.returncode != 0:
    # Assumes from __future__ import print_function at top of file
    # because Python 2 print statements are terrible
    print("tar exited with exit status {}:".format(proc.returncode), stderr, file=sys.stderr)