2009-03-06 76 views
2

我有一些数据,我想gzip,uuencode,然后打印到标准输出。我基本上有:Python Popen,关闭流和多个进程

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

我给压缩机提供数据的方式是通过compressor.stdin.write(东西)。

我真的需要做的是发送一个EOF到压缩机,我不知道该怎么做。

在某些时候,我尝试了压缩机.stdin.close(),但不起作用 - 它压缩机直接写入文件时效果很好,但在上述情况下,过程不会终止并且在compressor.wait()上停顿。

对此提出建议?在这种情况下,gzip就是一个例子,我真的需要将一个进程的输出管道连接到另一个进程。

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

compressor.communicate("Testing") 
上面的两行之后

,它仍然与错误

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

尽管cobbal的答案将适用于gzip,但这实际上只是一个例子 - 我确实需要管道... – bsdfish 2009-03-06 00:36:33

回答

4

我怀疑问题出在您打开管道的顺序。 UUEncode很有意思的是,如果没有正确的输入管道,它会发出呜呜声(尝试在Popen调用中自行启动补丁程序,以PIPE作为标准输入和标准输出来看爆炸)

试试这个:

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([email protected]`;2O+"!(````` 
` 
end 

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

编辑:我应该更清楚uuencode。作为一个shell程序,它的默认行为是期望控制台输入。如果您在没有“实时”传入管道的情况下运行它,它将阻止等待控制台输入。第二次打开编码器,在压缩机管道下传送材料之前,编码器阻止了您等待您开始输入。耶鲁是对的,因为有阻碍。

+0

不幸的是,它仍然需要将整个输出存储在内存中,如果您尝试读取()编码器stdout它似乎仍然挂起 – cobbal 2009-03-06 01:48:08

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() 

似乎工作

3

这不是之类的事情,你应该直接在Python做,有关于事物是如何工作的怪癖,使其成为一个更好的主意了壳里做这个。如果你可以使用subprocess.Popen(“foo | bar”,shell = True),那么一切都会好一些。

可能发生的情况是,gzip尚未能够输出其所有输入,并且在stdout写入完成之前,该进程将不会退出。

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