使用 Popen.communicate 时,如何将警告与 stderr 中发现的错误分开?

mil*_*ang 3 python subprocess popen

我使用 Pythonsubprocess.Popen来执行命令并捕获其输出:

p = Popen(cmd, stdout=PIPE, stderr=PIPE,shell=True)
stdout, stderr = p.communicate()
Run Code Online (Sandbox Code Playgroud)

我想stderr在出现错误时告诉用户并退出我的脚本:

if stderr !='':
    return {'error':stderr}
Run Code Online (Sandbox Code Playgroud)

但是现在我发现stderr可以包含可以安全忽略的警告,所以我的脚本不应该退出,而是继续完成工作。

有没有办法将警告与错误分开stderr

Kev*_*ase 6

univerio 是正确的,因为您在stderr...中发现的任何字节都没有特定含义......将其视为“标准输出”而不是“标准错误”。但是,在大多数操作系统上,您可以使用进程的退出状态(或“返回代码”)来跳过大多数进度条和其他非错误输出。

一个Popen对象有一个名为 的字段returncode,用于存储子进程退出时返回的任何值。这个值None直到 1) 进程终止,以及 2) 你用pollwait方法收集它的退出状态(至少在类 Unix 系统上)。由于您正在使用communicate,它总是同时执行 1 和 2,p.returncode因此在您关心它时应该始终是一个整数。

作为一般规则,0退出状态表示成功,而任何其他值表示失败。如果您相信您正在调用的程序会返回正确的值,您可以使用它来跳过大部分垃圾输出stderr

# ...same as before...
stdout, stderr = p.communicate()
if p.returncode and stderr:
    return {'error': stderr}
Run Code Online (Sandbox Code Playgroud)

如果在 中找到的字节stderr不够重要,无法产生非0退出状态,那么它们也不够重要,无法报告。

要对此进行测试,您可以编写一些生成stderr输出的小脚本,然后exit无论成功与否。

warnings.py

import sys
print('This is spam on stderr.', file=sys.stderr)
sys.exit(0)
Run Code Online (Sandbox Code Playgroud)

errors.py

import sys
print('This is a real error message.', file=sys.stderr)
sys.exit(1)
Run Code Online (Sandbox Code Playgroud)

这仍然留下了将旋转警棍和其他进度报告垃圾邮件与实际错误消息分开的任务,但您只需要对失败的进程执行此操作……甚至可能不会,因为“还没有死!” 在这些情况下,消息实际上可能很有用。

PS:在 Python 3 中,stdout并且stderr将是bytes对象,因此在将decode它们视为字符串之前,您需要先使用它们。