【发布时间】:2013-08-01 13:27:53
【问题描述】:
我有一个使用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...
附言我知道shell=True 的安全警告。
【问题讨论】:
-
暂时忘记
shell=True的安全警告;它也使事情变得更加复杂,因为您实际上根本没有将ls传递给grep;您正在将一个sh传递给另一个sh。你这样做有什么原因吗? -
在我的应用程序中
ls和grep是更有趣的命令行程序(它们在文件输入等中使用shell 功能,因此需要shell=True)。上述方法有什么问题?我将 ls 的输出从 shell 传送到 grep,从而实现了 grep ls 输出的正确结果 -
另外,
result没有returncode;是p1和p2。 -
@abarnet:是的,这是错字,已修复
-
还有几个问题。 (1) 调用 p1.wait() 即使 p2 成功,因为这会从进程表中清除僵尸进程。 (2) 如果 p1 向 stderr 写入过多,它将挂起,因为您没有阅读它。查看 Popen.communicate 代码,看看它是如何创建 theads 来读取管道并自己为 p1.stderr 执行此操作的。
标签: python unix subprocess pipe