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

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

我有以下 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)

我面临的问题是,当存档不再有 space 时,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 命令时,我得到了这个错误)。这有可能吗?我假设 gzip 是 tar 中的另一个进程。我错了吗?请记住,升级到 Python 3 是不可能的。

编辑:我也尝试使用 subprocess.check_output() 并打印 e.output 的内容,但这也没有用

Python 3 种适合正常人的解决方案

在 Python 3 上,解决方案很简单,无论如何你都应该使用 Python 3 来编写新代码(Python 2.7 在将近一年前结束了所有支持):

问题是程序将错误回显到 stderr,因此 check_output 没有捕获它(通常,或在 CalledProcessError 中)。最好的解决方案是使用 subprocess.runcheck_call/check_output 只是一个薄包装)并确保您同时捕获 stdoutstderr。最简单的方法是:

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 为喜欢不受支持的软件的人提供的解决方案

如果您 必须 在 Python 2 上执行此操作,则您必须通过手动调用 Popen 自行处理这一切,因为 none那里可用的高级功能的一部分将覆盖你(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)