Pergunta

Eu tenho alguns dados que eu gostaria de gzip, uuencode e, em seguida, imprimir para fora padrão. O que tem basicamente é:

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

A forma como eu alimentação de dados para o compressor é através compressor.stdin.write (coisas).

O que eu realmente preciso fazer é enviar um EOF para o compressor, e não tenho idéia de como fazê-lo.

Em algum momento, eu tentei compressor.stdin.close (), mas que não funciona - ele funciona bem quando as gravações compressor para um arquivo diretamente, mas, no caso acima, o processo não termina e barracas em compressor.wait ().

Sugestões? Neste caso, gzip é um exemplo e eu realmente preciso fazer alguma coisa com canalizando a saída de um processo para outro.

Nota: Os dados que eu preciso para comprimir não vai caber na memória, então se comunicar não é realmente uma boa opção aqui. Além disso, se eu simplesmente executar

compressor.communicate("Testing") 

depois das 2 linhas acima, ele ainda trava com o erro

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

Solução

Eu suspeito que o problema é com a ordem em que você abrir os tubos. UUEncode é engraçado é que ele vai lamentar quando você lançá-lo se não há nenhuma tubulação de entrada da maneira certa (tente iniciar o danado, por si própria em uma chamada Popen para ver a explosão com apenas TUBO como o stdin e stdout)

Tente isto:

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

Você está certo, btw ... não há maneira de enviar um EOF genérico para baixo de um tubo. Afinal, cada programa realmente define sua própria EOF. A maneira de fazer isso é para fechar o tubo, como você estava tentando fazer.

EDIT: eu deveria ser mais clara sobre uuencode. Como um programa de shell, é comportamento padrão é esperar a entrada console. Se você executá-lo sem um tubo de entrada "ao vivo", ele irá bloquear aguardando entrada console. Ao abrir o segundo codificador, antes que você tinha enviado o material para baixo o tubo compressor, o codificador estava bloqueando esperando por você para começar a digitar. Jerub estava certo em que havia algo de bloqueio.

Outras dicas

Este não é o tipo de coisa que você deve fazer diretamente em python, existem excentricidades a respeito da coisa como o trabalho que o tornam uma idéia muito melhor de fazer isso com uma concha. Se você pode apenas usar subprocess.Popen. ( "Foo | bar", shell = True), então tanto melhor

O que pode estar acontecendo é que gzip não tem sido capaz de saída de todas as suas entradas ainda, eo processo não vai sair até que suas gravações stdout ter sido concluída.

Você pode olhar para o que chamada de sistema um processo está bloqueando sobre se você usar strace. Use ps auxwf para descobrir qual processo é o processo gzip, então use strace -p $pidnum para ver o que chamada de sistema que está realizando. Note-se que stdin é FD 0 e stdout é FD 1, você provavelmente vai vê-lo lendo ou escrevendo sobre esses descritores de arquivos.

Não se você quiser apenas para comprimir e precisa dos invólucros de arquivo Considere o uso da zlib módulo

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

qualquer razão para que o shell = true e UNIX tubos sugestões não vai funcionar?

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

parece funcionar

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top