0

我有一个管道方案subprocess,其中一个进程p2将另一个进程的输出p1作为输入:

p1 = subprocess.Popen("ls -al", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen("grep mytext - ", shell=True, stdin=p1.stdout, stdout=subprocess.PIPE)
result = p2.communicate()

p1或者p2可能由于各种原因而失败,例如错误的输入或格式错误的命令。

此代码在p1没有失败时工作正常。我怎样才能做到这一点,还要检查是否p1特别或p2特别失败?例子:

# p1 will fail since notafile does not exist
p1 = subprocess.Popen("ls notafile", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen("grep mytext - ", shell=True, stdin=p1.stdout, stdout=subprocess.PIPE)
result = p2.communicate()

我可以检查p2.returncode并看到它不是0,但这可能意味着p2失败或 p1 失败。如果此管道出错,我如何专门检查是p1失败还是失败?p2

我不知道如何使用p1.returncode它,这将是理想且明显的解决方案。前任:

p1 = subprocess.Popen("ls foo", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen("grep mytext - ", shell=True, stdin=p1.stdout, stdout=subprocess.PIPE)
# here, p2.returncode not defined yet since we didn't communicate()
assert(p2 is None)
r = p2.communicate()
# now p2 has a returncode
assert(p2.returncode is not None)
# ... but p1 does not!
assert(p1.returncode is None)

所以我看不到 returncode 在这里有什么帮助?

感谢@abarnert 的完整解决方案是这样的:

p1 = subprocess.Popen("ls -al", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen("grep mytext - ", shell=True, stdin=p1.stdout, stdout=subprocess.PIPE)
result = p2.communicate()
if p2.returncode != 0:
  # something failed
  if p1.wait() != 0:
     # p1 failed...
  else: 
     # p2 failed...

ps 我知道shell=True安全的注意事项。

4

1 回答 1

2

我可以检查 result.returncode 并看到它不是 0,但这可能意味着 p2 失败。

不,你不能;result只是一个元组(stdoutdata, stderrdata)

Popen是具有returncode价值的对象。

这就是你的答案:

在此管道出错的情况下,如何专门检查 p1 失败或 p2 失败?

只是检查p1.returncode

但是,请注意,虽然p2.communicate 确实保证p2已被waited on,但保证p1. 幸运的是,它应该保证p1至少wait可以,它不是waited,所以:

if p2.returncode:
    if p1.wait():
        # p2 failed, probably because p1 failed
    else:
        # p2 failed for some other reason

除了你几乎肯定想要p1.stdout.close()communicate. 否则,进程 2 中的错误可能会导致进程 1 被阻塞,因此您p1.wait()可能会永远阻塞。(您可以通过p1.poll()在此处使用然后在未完成时将其杀死来解决此问题,但实际上,最好不要创建问题而不是解决它。)

最后一件事:您已设置p1.stderrsubprocess.PIPE,它永远不会附加到任何东西,因此进程 1 也有可能阻止尝试写入溢出的 stderr 管道。您可能也想解决这个问题。

于 2013-07-31T20:37:18.493 回答