如何使用Python子进程捕获子进程的错误?
我有以下Python(2.7)代码: 我面临的问题是,当没有更多的存档空间时,如何使用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中的另一个进程。我错了吗?请
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)