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

How to separate warnings from errors found in stderr when using Popen.communicate?

我使用 Python 的 subprocess.Popen 执行命令并捕获其输出:

p = Popen(cmd, stdout=PIPE, stderr=PIPE,shell=True)
stdout, stderr = p.communicate()

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

if stderr !='':
    return {'error':stderr}

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

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

没有。如果您要做的只是来自 stderr 的数据,则必须解析它以查看是否有警告。不幸的是,这对每个程序都是特定的并且很脆弱。

如何执行此操作的示例:

if any("warning" not in l.lower() for l in stderr.splitlines()):
     return {'error':stderr}

您必须针对您的特定程序调整此试探法。

univerio 是正确的,因为您在 stderr 中发现的任何字节都没有特定含义...将其视为 "standard not-output" 而不是 "standard error"。但是,在大多数操作系统上,您可以使用进程的退出状态(或"return code")来跳过大部分进度条和其他非错误输出。

一个 Popen 对象有一个名为 returncode, which is used to store whatever value the subprocess returned when it exited. This value is None until 1) the process terminates, and 2) you collect its exit status with either the poll or wait methods (at least on Unix-like systems). Since you're using communicate 的字段,总是 做 1 和 2,p.returncode 应该总是一个整数到你关心它的时候。

作为一般规则,0 退出状态表示成功,而任何其他值表示失败。如果你相信你正在调用的程序 return 正确的值,你可以使用它来跳过 stderr:

上的大部分垃圾输出
# ...same as before...
stdout, stderr = p.communicate()
if p.returncode and stderr:
    return {'error': stderr}

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

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

warnings.py:

import sys
print('This is spam on stderr.', file=sys.stderr)
sys.exit(0)

errors.py:

import sys
print('This is a real error message.', file=sys.stderr)
sys.exit(1)

这仍然留下了将旋转警棍和其他进度报告垃圾邮件与实际错误消息分开的任务,但您只需为失败的进程执行此操作...甚至可能不需要,因为 "not dead yet!" 消息在这些情况下可能真的有用。

PS:在 Python 3 中,stdoutstderr 将是 bytes 个对象,因此您需要 decode在像字符串一样对待它们之前。