Domanda

Ho alcuni dati che vorrei gzip, uuencode e quindi stampare su standard out. Quello che fondamentalmente ho è:

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

Il modo in cui invio i dati al compressore è tramite compressore.stdin.write (roba).

Quello che devo davvero fare è inviare un EOF al compressore e non ho idea di come farlo.

Ad un certo punto, ho provato compressore.stdin.close () ma non funziona: funziona bene quando il compressore scrive direttamente su un file, ma nel caso sopra, il processo non termina e si blocca su compressore.wait ().

Suggerimenti? In questo caso, gzip è un esempio e ho davvero bisogno di fare qualcosa con il piping dell'output di un processo a un altro.

Nota: i dati che devo comprimere non si adattano alla memoria, quindi comunicare non è davvero una buona opzione qui. Inoltre, se corro solo

compressor.communicate("Testing") 

dopo le 2 righe sopra, si blocca ancora con l'errore

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

Soluzione

Sospetto che il problema sia nell'ordine in cui apri i tubi. UUEncode è divertente è che gemerà quando lo lancerai se non ci sono pipe in entrata nel modo giusto (prova a lanciare la cosa maledetta da sola in una chiamata Popen per vedere l'esplosione con solo PIPE come stdin e stdout)

Prova questo:

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

Hai ragione, a proposito ... non c'è modo di inviare un EOF generico in una pipe. Dopotutto, ogni programma definisce davvero il proprio EOF. Il modo per farlo è chiudere la pipa, come stavi cercando di fare.

EDIT: dovrei essere più chiaro su uuencode. Come programma shell, il suo comportamento predefinito è quello di prevedere l'input della console. Se lo esegui senza " live " pipe in entrata, bloccherà in attesa dell'input della console. Aprendo il secondo encoder, prima di aver inviato materiale lungo il tubo del compressore, l'encoder si stava bloccando in attesa di iniziare a digitare. Jerub aveva ragione nel dire che c'era qualcosa che bloccava.

Altri suggerimenti

Questo non è il tipo di cosa che dovresti fare direttamente in Python, ci sono eccentricità riguardo al modo in cui funzionano le cose che rendono l'idea molto migliore di farlo con una shell. Se puoi semplicemente usare subprocess.Popen (" foo | bar " ;, shell = True), allora tanto meglio.

Ciò che potrebbe accadere è che gzip non è stato ancora in grado di produrre tutti i suoi input, e il processo non si chiuderà fino a quando le sue scritture stdout non saranno terminate.

Puoi vedere su quale chiamata di sistema sta bloccando un processo se usi strace. Usa ps auxwf per scoprire quale processo è il processo gzip, quindi usa strace -p $ pidnum per vedere quale chiamata di sistema sta eseguendo. Nota che stdin è FD 0 e stdout è FD 1, probabilmente lo vedrai leggere o scrivere su quei descrittori di file.

se vuoi solo comprimere e non hai bisogno dei wrapper di file, considera l'utilizzo del modulo zlib

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

qualsiasi motivo per cui i suggerimenti shell = True e unix pipe non funzioneranno?

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

sembra funzionare

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top