我有一个使用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)
所以我不知道返回码在这里有什么帮助吗?
感谢@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...
P.S。为了安全起见,我知道shell=True
的警告。
答案 0 :(得分:2)
不,你不能;我可以查看result.returncode并查看它不是0,但这可能意味着p2失败。
result
只是一个元组(stdoutdata, stderrdata)
。
具有Popen
值的returncode
个对象。
这就是你的答案:
如果此管道出错,我该如何专门检查p1是否失败或p2是否失败?
只需检查p1.returncode
。
但是,请注意虽然p2.communicate
确实保证p2
已wait
,但它不保证同样适用于p1
。幸运的是,它应该保证p1
至少wait
能够,wait
不能if p2.returncode:
if p1.wait():
# p2 failed, probably because p1 failed
else:
# p2 failed for some other reason
,所以:
p1.stdout.close()
除了你几乎肯定想在communicate
之前做p1.wait()
。否则,进程2中的错误可能会导致进程1被阻止,因此p1.poll()
可能会永久阻塞。 (你可以在这里使用p1.stderr
解决这个问题,如果还没有完成就杀掉它,但实际上,最好不要创建问题而不是解决问题。)
最后一件事:您已将subprocess.PIPE
设置为{{1}},它永远不会附加到任何内容,因此进程1也可能阻止尝试写入溢出的stderr管道。您可能也希望解决这个问题。