简体   繁体   English

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

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

I used Python's subprocess.Popen to execute a command and capture its output: 我使用Python的subprocess.Popen执行命令并捕获其输出:

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

I want to use stderr to tell users when there was an error and exit my script: 我想使用stderr告诉用户何时出现错误并退出我的脚本:

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

But now I've found that stderr can contain warnings that could be safely ignored, so my script should not exit, but continue to finish the job. 但是现在我发现stderr可以包含可以安全忽略的警告,因此我的脚本不应退出,而是继续完成工作。

Is there a way to separate warnings from errors in stderr ? 有没有办法将警告与stderr错误分开?

univerio is correct, in that there is no specific meaning for any bytes you discover in stderr ... think of it as "standard not -output" instead of "standard error". univerio是正确的,因为您在stderr发现的任何字节都没有特定的含义……可以将其视为“标准输出”而不是“标准错误”。 However, on most operating systems, you can use the process's exit status (or "return code") to skip most of the progress bars and other non-error output. 但是,在大多数操作系统上,您可以使用进程的退出状态(或“返回代码”)来跳过大多数进度条和其他非错误输出。

A Popen object has a field called returncode , which is used to store whatever value the subprocess returned when it exited. Popen对象具有一个称为returncode的字段,该字段用于存储子进程退出时返回的任何值。 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). 直到1)进程终止,以及2)使用pollwait方法收集其退出状态(至少在类似Unix的系统上),该值才为None Since you're using communicate , which always does both 1 and 2, p.returncode should always be an integer by the time you care about it. 由于您使用的是communicate ,它总是同时执行1和2, p.returncode在您关心它时, p.returncode应该始终是整数。

As a general rule, a 0 exit status indicates success, while any other value indicates failure. 通常,退出状态为0表示成功,而其他任何值表示失败。 If you trust the programs you're calling to return proper values, you can use this to skip most of the junk output on stderr : 如果您信任要调用的程序以返回正确的值,则可以使用它跳过stderr上的大多数垃圾输出:

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

If the bytes found in stderr weren't important enough to produce a non- 0 exit status, they're not important enough for you to report, either. 如果在stderr中找到的字节不足以产生非0退出状态,则它们对于报告也不是足够重要。

To test this, you can write a few tiny scripts that produce stderr output and then exit , either successfully or not. 为了测试这一点,您可以编写一些微型脚本来生成stderr输出,然后成功exitexit

warnings.py : warnings.py

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

errors.py : errors.py

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

This still leaves the task of separating spinning batons and other progress-report spam from actual error messages, but you'll only have to do that for processes that failed... and maybe not even then, since the "not dead yet!" 这仍然需要将旋转的警棍和其他进度报告垃圾邮件与实际错误消息分开,但是您只需要为失败的进程执行此操作……也许甚至没有这样做,因为“还没有死!” messages might actually be useful in those cases. 在这些情况下,消息实际上可能很有用。

PS: In Python 3, stdout and stderr will be bytes objects, so you'll want to decode them before treating them like strings. PS:在Python 3中, stdoutstderr将是bytes对象,因此您需要先decode它们进行decode然后再将它们视为字符串。

No. If all you have to go on is the data from stderr, you'll have to parse it to see if there are warnings. 否。如果您要做的只是来自stderr的数据,就必须解析它以查看是否有警告。 This is unfortunately specific to each program and fragile. 不幸的是,这是每个程序特有的,并且很脆弱。

An example of how you can do this: 有关如何执行此操作的示例:

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

You'll have to adapt this heuristic for your particular program. 您必须针对特定程序调整此启发式方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM