Python Popen,关闭流和多个进程

时间:2009-03-06 00:30:09

标签: python stream popen eof

我有一些数据,我想gzip,uuencode然后打印到标准输出。我基本上拥有的是:

compressor = Popen("gzip", stdin = subprocess.PIPE, stdout = subprocess.PIPE)
encoder    = Popen(["uuencode", "dummy"], stdin = compressor.stdout)

我向压缩器提供数据的方式是通过compress.stdin.write(stuff)。

我真正需要做的是将EOF发送到压缩器,我不知道该怎么做。

在某些时候,我尝试了compress.stdin.close()但是这不起作用 - 当压缩器直接写入文件时它很有效,但在上面的情况下,进程不会终止并停止在compress.wait()。

连连呢?在这种情况下,gzip就是一个例子,我真的需要做一些事情来管理一个进程的输出到另一个进程。

注意:我需要压缩的数据不适合内存,所以沟通在这里不是一个好选择。另外,如果我只是运行

compressor.communicate("Testing") 

在上面的2行之后,它仍然会挂起错误

  File "/usr/lib/python2.4/subprocess.py", line 1041, in communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])

3 个答案:

答案 0 :(得分:4)

我怀疑问题在于您打开管道的顺序。 UUEncode很有趣的是,如果你没有以正确的方式传入管道,它会发出呜呜声(尝试在Popen调用中自己启动darn的东西,只用PIPE作为stdin和stdout看爆炸)

试试这个:

encoder = Popen(["uuencode", "dummy"], stdin=PIPE, stdout=PIPE)
compressor = Popen("gzip", stdin=PIPE, stdout=encoder.stdin)

compressor.communicate("UUencode me please")
encoded_text = encoder.communicate()[0]
print encoded_text

begin 644 dummy
F'XL(`%]^L$D``PL-3<U+SD])5<A-52C(24TL3@4`;2O+"!(`````
`
end

你是对的,顺便说一句......没有办法向管道发送通用EOF。毕竟,每个程序都确实定义了自己的EOF。这样做的方法是关闭管道,就像你想要的那样。

编辑:我应该更清楚uuencode。作为shell程序,它的默认行为是期望控制台输入。如果在没有“实时”传入管道的情况下运行它,它将阻止等待控制台输入。通过打开编码器,在压缩机管道中发送材料之前,编码器阻止等待您开始键入。 Jerub是对的,因为有阻塞的东西。

答案 1 :(得分:3)

这不是你应该直接在python中做的事情,关于如何工作的怪癖使得用shell做这个更好的主意。如果你可以使用subprocess.Popen(“foo | bar”,shell = True),那就更好了。

可能发生的事情是gzip还无法输出所有输入,并且在stdout写入完成之前,进程不会退出。

如果使用strace,您可以查看进程阻止的系统调用。使用ps auxwf来发现哪个进程是gzip进程,然后使用strace -p $pidnum查看它正在执行的系统调用。请注意,stdin是FD 0,stdout是FD 1,您可能会看到它在这些文件描述符上读取或写入。

答案 2 :(得分:1)

如果您只想压缩并且不需要文件包装器,请考虑使用zlib模块

import zlib
compressed = zlib.compress("text")

shell = True和unix管道建议的任何原因都不起作用?

from subprocess import *

pipes = Popen("gzip | uuencode dummy", stdin=PIPE, stdout=PIPE, shell=True)
for i in range(1, 100):
    pipes.stdin.write("some data")
pipes.stdin.close()
print pipes.stdout.read()

似乎有用