2

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

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

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

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

在某些时候,我尝试了compressor.stdin.close() 但这不起作用——当压缩器直接写入文件时效果很好,但在上述情况下,进程不会终止并在压缩器上停止。等待()。

建议?在这种情况下,gzip 就是一个例子,我真的需要做一些事情,将一个进程的输出通过管道传输到另一个进程。

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

compressor.communicate("Testing") 

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

  文件“/usr/lib/python2.4/subprocess.py”,第 1041 行,在通信中
    rlist, wlist, xlist = select.select(read_set, write_set, [])
4

3 回答 3

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(24TL3@4`;2O+"!(`````
`
end

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

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

于 2009-03-06T01:37:43.090 回答
3

这不是你应该直接在 python 中做的事情,关于事情的工作方式有一些怪癖,这使得用 shell 来做这件事是一个更好的主意。如果您可以只使用 subprocess.Popen("foo | bar", shell=True),那就更好了。

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

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

于 2009-03-06T00:49:17.887 回答
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()

似乎工作

于 2009-03-06T00:34:00.420 回答