简体   繁体   English

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

[英]How to catch the errors of a child process using Python subprocess?

I have the following Python(2.7) code:我有以下 Python(2.7) 代码:

try:    
  FNULL = open(os.devnull,'w')
  subprocess.check_call(["tar", "-czvf", '/folder/archive.tar.gz', '/folder/some_other_folder'], stdout=FNULL, stderr=subprocess.STDOUT)
except Exception as e:
  print str(e)

The problem which I face is that, when there is no more space for the archive, print str(e) prints Command '['tar', '-czvf', '/folder/archive.tar.gz', '/folder/some_other_folder']' returned non-zero exit status 1 , which is true, but I want to catch the real error here, that is gzip: write error: No space left on device (I got the this error when I ran the same tar comand manually).我面临的问题是,当存档没有更多空间时, print str(e)打印Command '['tar', '-czvf', '/folder/archive.tar.gz', '/folder/some_other_folder']' returned non-zero exit status 1 ,这是真的,但我想在这里捕获真正的错误,即gzip: write error: No space left on device (当我运行相同的tar 命令手动)。 Is that possible somehow?这有可能吗? I assume that gzip is another process within tar.我假设 gzip 是 tar 中的另一个进程。 Am I wrong?我错了吗? Please keep in mind that upgrading to Python 3 is not possible.请记住,无法升级到 Python 3。

EDIT: I also tried to use subprocess.check_output() and print the contents of e.output but that also didn't work编辑:我也尝试使用e.output subprocess.check_output()并打印e.output的内容,但这也不起作用

Python 3 solution for sane people适用于理智人士的 Python 3 解决方案

On Python 3, the solution is simple, and you should be using Python 3 for new code anyway (Python 2.7 ended all support nearly a year ago):在 Python 3 上,解决方案很简单,无论如何你应该使用 Python 3 来编写新代码(Python 2.7 几乎在一年前结束了所有支持):

The problem is that the program is echoing the error to stderr , so check_output doesn't capture it (either normally, or in the CalledProcessError ).问题是程序将错误回显到stderr ,因此check_output不会捕获它(通常或在CalledProcessError )。 The best solution is to use subprocess.run (which check_call / check_output are just a thin wrapper over) and ensure you capture both stdout and stderr .最好的解决办法是使用subprocess.run (其中check_call / check_output只是一个瘦包装过),并确保你同时捕获stdoutstderr The simplest approach is:最简单的方法是:

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 solution for people who like unsupported software适用于喜欢不受支持的软件的人的 Python 2 解决方案

If you must do this on Python 2, you have to handle it all yourself by manually invoking Popen , as none of the high level functions available there will cover you ( CalledProcessError didn't spawn a stderr attribute until 3.5, because no high-level API that raised it was designed to handle stderr at all):如果您必须在 Python 2 上执行此操作,则必须通过手动调用Popen自己处理这一切,因为那里可用的任何高级函数都不会覆盖您( CalledProcessError直到 3.5 才产生stderr属性,因为没有高级函数提出它的 API 旨在完全处理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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM