subprocess.Popen管道如何在Python中工作?

时间:2014-12-10 00:39:58

标签: python python-2.7 subprocess

我完全清楚相关问题的存在,但所有问题都非常模糊,无法清楚地解释每一步的发生情况。提供的示例通常未经过测试,也未提供有关如何使其适应不同场景的信息。以下是问题以及Python的文档:

这基本上是我想要实现的,但在Python中:

curl http://asdf.com/89asdf.gif | convert -resize 80x80 - - | icat -k -

以下是我在几个小时之后将上述答案中的部分和部分内容进行坦诚相关的内容:

import requests
import subprocess
from subprocess import Popen, PIPE, STDOUT
url = 'http://asdf.com/89asdf.gif'
img = requests.get(url)
p1 = subprocess.Popen(['convert', '-resize', '80x80', '-', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p2 = subprocess.Popen(['icat', '-k', '-'], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.communicate(img.content)
print p2.stdout

这是我的代码,这一次根据你的答案进行了改进:

import requests
from subprocess import Popen, PIPE, STDOUT
url = 'http://asdf.com/89asdf.gif'
img = requests.get(url)
p1 = Popen(['convert', '-resize', '80x80', '-', '-'], stdin=PIPE, stdout=PIPE)
p2 = Popen(['icat', '-k', '-'], stdin=p1.stdout, stdout=PIPE)
p1.stdin.write(img.content)
p1.stdin.close()
p1.stdout.close()
output = p2.communicate()[0]
print output

注意:icat以256色终端输出图像。我已经设法在another question成功打印输出。一个典型的图像在icat处理后的终端中看起来像这样:

icat doing what it does best

请纠正我错在哪里,但这是我目前的理解:

  • p1.communicate(img.content):这会设置p1的STDIN。
  • p1的STDIN是subprocess.PIPE,这是p1.communicate(mg.content)提供的。
  • p2的STDIN是p1的STDOUT,即由convert调整大小的图片。
  • 我然后print p2的STDOUT,它应该是由icat提供的ASCII颜色的图像。

问题:

  1. 我见过stdin=subprocess.PIPEstdin=PIPE。有什么区别?
  2. 为什么在定义其他子进程后提供第一个STDIN?
  3. 有人可以解释一下这个过程中实际发生了什么以及我的代码有什么问题吗?整个管道业务必须比看起来更简单,我很想了解它是如何运作的。

2 个答案:

答案 0 :(得分:1)

Q1。在subprocess.PIPEPIPE的任何一种情况下,它们都引用相同的符号,即PIPE模块中的subprocess。以下是相同的:

# Version 1
import subprocess
proc = subprocess.Popen(['ls'], stdout=subprocess.PIPE)
output = proc.communicate()[0]

# Version 2
from subprocess import PIPE, Popen
proc = Popen(['ls'], stdout=PIPE)
output = proc.communicate()[0]

Q2。 communicate()实际上做的是将输入发送到p1的STDIN流。尽管在调用Popen构造函数时子进程确实存在且正在运行,但在您的特定情况下,convert实用程序似乎在它实际通过STDIN接收内容之前不会执行任何操作。如果它是一个交互性较低的命令(例如ls),则它不会等到communicate()做任何事情。

更新的内容 在您的情况下,不要使用communicate将输入发送到p1,而是尝试以下内容:

p1.stdin.write(img.content)
p1.stdin.close()
p1.stdout.close() # Protect against the busted pipe condition when p2 finishes before p1
output = p2.communicate()[0]
print output

看看你是否有更好的运气。

答案 1 :(得分:0)

Q1。它们都是subprocess.PIPE ....

没有区别

Q2。你不必这样做就可以轻松做到

p1.stdin.write(img.content)

(事实上,这正是沟通的那部分所做的......)

使用了

communicate,因为它会阻塞直到进程完成(在这种情况下,它的stdout可以被p2.stdin(可能是?))用,因为write只是写入管道并且继续到文件

中的下一行python