2013-05-15 3 views
5

Sto utilizzando uno script python per eseguire un processo utilizzando subprocess.Popen e contemporaneamente memorizzo l'output in un file di testo e lo stampo sulla console. Questo è il mio codice:Ottenere l'output di un processo in fase di esecuzione

result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
for line in result.stdout.readlines(): #read and store result in log file 
    openfile.write("%s\n" %line) 
    print("%s" %line) 

Sopra codice funziona bene, ma ciò che fa è in primo luogo completa il processo e memorizza l'output in risultato variabile. Dopodiché, lo per il ciclo memorizza l'output e lo stampa.

Ma voglio l'output in fase di esecuzione (dato che il mio processo può richiedere ore per essere completato, non ottengo alcun output per tutte queste ore).

Quindi c'è qualche altra funzione che mi dà l'uscita dinamicamente (in fase di esecuzione), significa che non appena il processo dà la prima riga, dovrebbe essere stampato.

+1

non ho mai provato, ma penso che si suppone di inviare il proprio Python 'file' oggetto per l'argomento' stdout' (o 'stdin', o' stderr'). Quindi devi eseguire il polling di quel file. "Subprocesso" è stato inventato per risparmiarti quel dolore, ma sembra che tu non abbia altra scelta. In bocca al lupo. –

+1

_ "prima completa il processo e memorizza l'output nel risultato" _ - non è vero. – Eric

+0

"prima completa il processo e memorizza l'output nel risultato" - non è vero. Bene, quando sto eseguendo il comando Popen, continua a funzionare fino al termine del processo e quindi esegue ulteriore codifica. Se funziona in qualche altro modo, non vedo l'ora di saperlo. – Niyojan

risposta

5

Il problema qui è che .readlines() ottiene l'intero output prima di tornare, in quanto crea un elenco completo. Basta iterare direttamente:

for line in result.stdout: 
    print line 
+1

nota: ['per la linea nel risultato.stdout' non restituisce le linee in "real time" su Python 2, usa 'per line in iter (result.stdout.readline, b '')' invece] (http://ideone.com/8KFawl) (il tuo 'print l'istruzione line' suggerisce che ti aspetti che funzioni su Python 2. [Su Python 3 funziona bene] (http://ideone.com/EUpeGV) – jfs

+0

Sì, funziona, sto ricevendo l'output in tempo reale, grazie. – Niyojan

1

È possibile iterare le linee una per una utilizzando readline sul tubo:

while True: 
    line = result.stdout.readline() 
    print line.strip() 
    if not line: 
     break 

Le linee contengono una finale \n che ho messo a nudo per la stampa. Quando il processo termina, readline restituisce una stringa vuota, in modo da sapere quando fermarsi.

+1

Mi dispiace ma non hai ricevuto la mia domanda. Quello che hai suggerito lo sto già facendo utilizzando for loop, quello che voglio è l'output riga per riga mentre il processo è ancora in esecuzione. – Niyojan

+1

ci hai provato? Stai usando 'readlines', che restituisce tutte le linee. Questo è possibile solo dopo la risoluzione. Con 'readline', ottieni solo il successivo –

+0

result.stdout funziona bene per me, ma le tue funzioni line.strip() sono utili perché avevo già troppi" b "\ r \ n" "prima, Grazie – Niyojan

3

.readlines() restituisce un elenco di tutti le linee il processo tornerà mentre aperta, vale a dire, che non restituisce nulla fino a quando ricevuto tutti uscita dal sottoprocesso. Per leggere riga per riga in "tempo reale":

import sys 
from subprocess import Popen, PIPE 

proc = Popen(cmd, shell=True, bufsize=1, stdout=PIPE) 
for line in proc.stdout: 
    openfile.write(line) 
    sys.stdout.buffer.write(line) 
    sys.stdout.buffer.flush() 
proc.stdout.close() 
proc.wait() 

Nota: se il sottoprocesso utilizza blocco-buffering quando viene eseguito in modalità non interattiva; potrebbe essere necessario pexpect, pty modules o stdbuf, unbuffer, script commands.

Nota: su Python 2, potrebbe anche essere necessario usare iter(), per ottenere l'output "tempo reale":

for line in iter(proc.stdout.readline, ""): 
    openfile.write(line) 
    print line,