【发布时间】:2011-05-25 08:29:26
【问题描述】:
我已经成功地通过这种方式将一个变量传递给一个没有进一步传递的命令:
from subprocess import Popen, PIPE
def exec_command(command, some_input):
proc = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
(stdout, stderr) = proc.communicate(input=some_input)
...但是当尝试将其通过管道传输到另一个管道命令时(例如管道传输到 tar,然后进一步管道拆分),它似乎不起作用:
from subprocess import Popen, PIPE
def exec_piped_command(command1, command2, some_input):
proc1 = Popen(command1, stdout=PIPE, stdin=PIPE)
proc2 = Popen(command1, stdin=proc1.stdout, stdout=PIPE)
(stdout, stderr) = proc2.communicate(input=some_input)[0]
那么,第二个变体的正确方法是什么?上面代码的问题似乎是“proc2.communicate()”命令中的输入没有到达proc1的stdin管道? (虽然不确定......不幸的是我对子进程语法有点困惑......)。
【问题讨论】:
-
proc2.communicate 正在尝试将一些输入提供给 PIPE,但 proc2 的输入 PIPE 已与 proc1 的输出 PIPE 一起提供 --- Unix 管道不适用于多个写入器/读取器进程(它们不像队列对象;也不像套接字)。这可能会导致您的代码出现死锁。
-
是的,没错,所以我的问题是,如何将变量提供给 proc1 的输入,并且仍然执行整个链式命令? ...做 proc1.communicate(input=some_input) 也不起作用...
-
文体问题;
from x import *真的很糟糕,并且一直都气馁。 -
您可以尝试 proc1.stdin.write(...) ... 但是这可能会在一个完整的缓冲区上死锁。您可以尝试 fnctl 操作将 proc1.stdin 设置为非阻塞模式(并将尝试的 write() 调用包装在适当的异常处理套件中以处理“EWOULDBLOCK”结果)。如果你这样做,那么你可能会在 proc2 的标准输出上做类似的非阻塞操作并使用 read() 调用而不是调用 .communicate() 。至于 proc1 和 proc2 之间的 PIPE ...您的 Python 进程保留了一份对您无用的副本,应该关闭。
-
注意:你不能对 proc1 和 proc2 之间的阻塞语义做任何有用的事情......但只要你在两端没有阻塞和完整的缓冲区,它们就不应该死锁的管道。如果您需要进程之间更复杂的交互(例如,使它们成为协同进程),那么您必须插入自己的(Python)进程以主动将数据从一个输出管道中继到另一个输入管道,依此类推—— - 或者你必须有记录的方法来限制这些过程适应彼此的缓冲语义。
标签: python subprocess pipe