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

时间:2016-02-10 03:02:51

标签: python subprocess popen

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

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

我想使用stderr告诉用户何时出错并退出我的脚本:

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

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

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

2 个答案:

答案 0 :(得分:3)

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}

如果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)

这仍然需要将旋转警棍和其他进度报告垃圾邮件与实际错误消息分开,但是您只需对那些失败的进程执行此操作...甚至可能不会这样做,因为& #34;还没死!"在这些情况下,消息实际上可能很有用。

PS:在Python 3中,stdoutstderr将是bytes个对象,所以在将它们视为字符串之前,您需要decode个。{ / p>

答案 1 :(得分:1)

没有。如果您只需要继续使用stderr中的数据,那么您必须解析它以查看是否有警告。不幸的是,这对每个项目都是特定的,而且很脆弱。

如何执行此操作的示例:

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

您必须针对您的特定计划调整此启发式方法。