【问题标题】:How to catch the errors of a child process using Python subprocess?如何使用 Python 子进程捕获子进程的错误?
【发布时间】:2021-02-22 12:03:36
【问题描述】:

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

我面临的问题是,当档案没有更多空间时,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 的内容,但这也没有用

【问题讨论】:

  • 一般来说,“退出状态 1”唯一真正明确的机器可读错误。 stderr 内容可以包含任何诊断日志记录或人类可读的信息内容,而不仅仅是错误 - 因此遵循@ShadowRanger 所写的答案,虽然不是错误,但可能会导致处理错误之前的日志消息好像它们本身就是错误的一部分。
  • ...所以,f/e,当您在 shell 中写入 if tar -czvf folder.archive.gz /folder; then ...; else echo "There was an error" >&2; fi 时,shell 依靠退出状态来知道出现问题并遵循 else 分支。
  • @CharlesDuffy:我的回答只在退出状态为非零时回显stderr,所以当然,发生错误时您可能会看到诊断输出,但在正常情况下它会保持沉默(成功) 状况。绝对不依赖stderr 是否为空/非空。
  • @ShadowRanger,如果您正在检查空/非空标准错误,您将投反对票;我的立场是谨慎、合格的支持之一。

标签: python python-2.7 subprocess


【解决方案1】:

为理智的人提供 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 自行处理,因为那里没有可用的高级函数(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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 2011-08-04
    • 2017-12-29
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多