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

Python 当使用Popen.communicate时,如何将警告与在stderr中发现的错误区分开来?,python,subprocess,popen,Python,Subprocess,Popen,我使用Python执行命令并捕获其输出: p = Popen(cmd, stdout=PIPE, stderr=PIPE,shell=True) stdout, stderr = p.communicate() 我想使用stderr告诉用户何时出现错误并退出我的脚本: if stderr !='': return {'error':stderr} 但是现在我发现stderr可以包含可以安全忽略的警告,因此我的脚本不应该退出,而是继续完成任务 是否有一种方法可以将stderr中的警告和

我使用Python执行命令并捕获其输出:

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

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

一般情况下,
0
退出状态表示成功,而任何其他值表示失败。如果您信任正在调用的程序返回正确的值,则可以使用此选项跳过
stderr上的大多数垃圾输出:

# ...same as before...
stdout, stderr = p.communicate()
if p.returncode and stderr:
    return {'error': stderr}
如果在
stderr
中找到的字节不够重要,无法生成非
0
退出状态,则它们也不够重要,无法报告

为了测试这一点,您可以编写一些小脚本,生成
stderr
输出,然后,不管成功与否

warnings.py

import sys
print('This is spam on stderr.', file=sys.stderr)
sys.exit(0)
import sys
print('This is a real error message.', file=sys.stderr)
sys.exit(1)
错误。py

import sys
print('This is spam on stderr.', file=sys.stderr)
sys.exit(0)
import sys
print('This is a real error message.', file=sys.stderr)
sys.exit(1)
这仍然留下了将旋转警棍和其他进度报告垃圾邮件与实际错误消息分离的任务,但您只需对失败的进程执行此操作。。。甚至可能不会,因为“还没死!”消息在这些情况下可能真的很有用


PS:在Python3中,
stdout
stderr
将是
bytes
对象,因此在将它们视为字符串之前,您需要先对它们进行处理。

THX,您的答案似乎简单且有希望,我可以添加它。但不幸的是,我不能再重复这个警告了。也许程序解决了这个问题。这仍然是我脚本中的一个bug,它总是很高兴看到修复的方法it@milowang:我添加了两个脚本,您可以使用它们来测试此操作。“当它退出时”并不完全正确:如果您使用
.wait()
.communicate()
(间接),
.poll()
(进程退出后)即“它退出”是不够的——您必须读取它的状态(直到您读取它的状态;它是)@J.F.Sebastian:我已经更新了我的答案。但是,这不会真正改变这个用户的任何东西,因为他或她正在使用
通信
,它将始终收集子进程的退出状态。我认为
任何
应该是
所有
:“如果所有行都没有“警告”这个词,那么这是一个真正的错误。”@Chase假设每行包含一条日志消息,如果该行包含“警告”一词,则该消息不应计算在内。因此,如果任何一行没有“警告”,这意味着这是一条错误消息,应该会导致一个错误。当然,这是一个毫无意义的争论,因为它取决于假想程序的输出。明白了。我认为这是一条单独的大消息,所以任何“警告”的出现都会将整个事件降级为可忽略的状态。