Pregunta

Tengo algunos datos que me gustaría gzip, uuencode y luego imprimir en formato estándar. Lo que básicamente tengo es:

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

La forma en que envío los datos al compresor es a través de compressor.stdin.write (material).

Lo que realmente necesito hacer es enviar un EOF al compresor, y no tengo idea de cómo hacerlo.

En algún momento, probé compressor.stdin.close () pero eso no funciona; funciona bien cuando el compresor escribe directamente en un archivo, pero en el caso anterior, el proceso no finaliza y se detiene. en compressor.wait ().

Sugerencias? En este caso, gzip es un ejemplo y realmente necesito hacer algo para canalizar la salida de un proceso a otro.

Nota: los datos que necesito comprimir no caben en la memoria, por lo que la comunicación no es una buena opción aquí. Además, si acabo de ejecutar

compressor.communicate("Testing") 

después de las 2 líneas anteriores, aún se cuelga con el error

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

Solución

Sospecho que el problema está relacionado con el orden en el que abres las tuberías. UUEncode es gracioso es que se quejará cuando lo lances si no hay una canalización entrante de la manera correcta (intenta lanzar la maldita cosa por sí sola en una llamada de Popen para ver la explosión con solo PIPE como stdin y stdout)

Prueba esto:

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

Tienes razón, por cierto ... no hay manera de enviar un EOF genérico por una tubería. Después de todo, cada programa realmente define su propio EOF. La forma de hacerlo es cerrar la tubería, como intentabas hacer.

EDITAR: Debería ser más claro sobre uuencode. Como programa shell, su comportamiento predeterminado es esperar la entrada de la consola. Si lo ejecutas sin un " live " tubería entrante, bloqueará la espera de entrada de consola. Al abrir el codificador en segundo lugar, antes de que enviara material por el tubo del compresor, el codificador estaba bloqueando a la espera de que comience a escribir. Jerub tenía razón en que había algo bloqueando.

Otros consejos

Este no es el tipo de cosas que deberías hacer directamente en python, hay excentricidades con respecto a cómo funcionan las cosas que hacen que sea una mejor idea hacer esto con una cáscara. Si solo puede usar subprocess.Popen (" foo | bar " ;, shell = True), entonces todo lo mejor.

Lo que podría estar sucediendo es que gzip no ha podido emitir toda su entrada aún, y el proceso no se cerrará hasta que sus escrituras estándar hayan finalizado.

Puedes ver en qué sistema está bloqueando una llamada del proceso si usas strace. Use ps auxwf para descubrir qué proceso es el proceso gzip, luego use strace -p $ pidnum para ver qué llamada del sistema está realizando. Tenga en cuenta que stdin es FD 0 y stdout es FD 1, probablemente lo verá leyendo o escribiendo en esos descriptores de archivo.

si solo quiere comprimir y no necesita los contenedores de archivos, considere usar el módulo zlib

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

¿Alguna razón por la que las sugerencias de Shell = True y Unix Pipes no funcionen?

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top