【问题标题】:How to pipe the content of a variable through two chained pipes in python?python - 如何通过python中的两个链式管道传递变量的内容?
【发布时间】: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


【解决方案1】:

一种可能性是将整个命令设置为由 shell 执行(shell=True 到您的 Popen() 调用的关键字 args 中......并且只有 .communicate() 带有整个管道的末端(您的输入将进入 command1 的标准输入,而您的 stdout/stderr 来自 command2 的 stdout/stderr)。

一种更复杂但更精细的方法是使用os.fork() 以及os.pipe()os.dup2() 以及可能的一些os.fcntl() 调用来设置您自己的子流程,并使用您自己的自定义填充,以及您在文件描述符上需要的任何所需的阻塞/非阻塞特性,然后最后在每个函数中使用您自己的 os.exec* 函数。

显然,后一种方法会复制subprocess 模块中已有的大量代码。但是,它为您提供了以不通过 subprocess.Popen 类公开的方式以不同方式执行其中一些步骤的选项。

中间道路是创建一个继承自subprocess.Popen的子类

当然,最好通过 Python 代码和模块(例如 tar、gzip 和拆分操作)执行此管道的某些部分。

【讨论】:

  • 谢谢,我选择了 shell=True 的简单解决方案。不幸的是,安全性有点低,但我希望不向命令中添加任何用户可控制的字符串时会没问题...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 2016-04-05
  • 2021-01-11
  • 1970-01-01
相关资源
最近更新 更多