2009-09-07 8 views
34

Voglio l'output da eseguire Test_Pipe.py, ho provato a seguire il codice su Linux ma non ha funzionato.Come ottenere l'output dal sottoprocesso.Popen()

Test_Pipe.py

import time 
while True : 
    print "Someting ..." 
    time.sleep(.1) 

Caller.py

import subprocess as subp 
import time 

proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE) 

while True : 
    data = proc.stdout.readline() #block/wait 
    print data 
    time.sleep(.1) 

La linea proc.stdout.readline() era bloccata, quindi nessun dato codice stampa.

+0

Duplicato: http://stackoverflow.com/search?q=%5Bpython%5D+subprocess+output, http://stackoverflow.com/questions/803265/getting-realtime-output-using-subprocess, http: //stackoverflow.com/questions/1277866/python-subprocess-module-looping-over-stdout-of-child-process –

risposta

39

È ovviamente possibile utilizzare subprocess.communicate ma penso che si stia cercando input e output in tempo reale.

readline è stato bloccato perché il processo è probabilmente in attesa del tuo input. Si può leggere carattere per carattere per superare questo come il seguente:

import subprocess 
import sys 

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE 
) 

while True: 
    out = process.stdout.read(1) 
    if out == '' and process.poll() != None: 
     break 
    if out != '': 
     sys.stdout.write(out) 
     sys.stdout.flush() 
+2

[non è necessario 'process.poll()' in questo caso] (http: // stackoverflow.com/a/17701672/4279). – jfs

12

per evitare i molti problemi che possono sempre sorgere con il buffering per attività come "ottenere l'uscita del sottoprocesso per il processo principale in tempo reale", mi consiglia sempre di utilizzare pexpect per tutte le piattaforme non Windows, wexpect su Windows, anziché subprocess, quando tali attività sono desiderate.

+0

Link aggiornato a pexpect: https://github.com/pexpect/pexpect –

20

Lo snippet di Nadia funziona ma il richiamo di lettura con un buffer da 1 byte è altamente sconsigliato. Il modo migliore per farlo sarebbe quello di impostare il descrittore di file stdout a non bloccante utilizzando fcntl

fcntl.fcntl(
    proc.stdout.fileno(), 
    fcntl.F_SETFL, 
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK, 
) 

e quindi utilizzando selezionare per verificare se i dati sono pronti

while proc.poll() == None: 
    readx = select.select([proc.stdout.fileno()], [], [])[0] 
    if readx: 
     chunk = proc.stdout.read() 
     print chunk 

Era corretta in quanto il problema deve essere diverso da quello che hai pubblicato come Caller.py e Test_Pipe.py funzionano come previsto.

+0

Non produrrà l'output prima del codice nella domanda a causa di [il problema del buffer di blocco.Vedi la mia risposta] (http://stackoverflow.com/a/17701672/4279). – jfs

+0

Il codice produce output in tempo reale. Hai avuto un problema con esso? –

+0

segui il link nel commento. – jfs

7

Test_Pipe.py tamponi suo standard output di default in modo proc in Caller.py non si vede alcun output fino a quando il buffer del bambino è completo (se la dimensione del buffer è di 8 KB, allora ci vuole circa un minuto per riempire Test_Pipe.py di buffer stdout).

Per rendere l'uscita non bufferizzata (buffer di riga per flussi di testo) è possibile passare -u flag allo script figlio Python. Consente di leggere il sottoprocesso linea uscita per riga in 'tempo reale':

import sys 
from subprocess import Popen, PIPE 

proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1) 
for line in iter(proc.stdout.readline, b''): 
    print line, 
proc.communicate() 

vedere link in Python: read streaming input from subprocess.communicate() su come risolvere il problema del blocco-buffer per i processi figlio non-Python.

+1

Anche in questo caso si utilizza un buffer da 1 byte che è incredibilmente inefficiente. –

+4

@DerrickPetzold: sbagliato. 'bufsize = 1' significa" buffer di riga ". Usa la stessa dimensione del buffer di 'bufsize = -1'. Potresti aver scoperto che entrambi i tuoi commenti sono sbagliati se dovessi effettivamente eseguire il codice (confrontare le prestazioni temporali e misurare il tempo prima che il primo byte venga letto) – jfs

+1

mi piace questo modo di farlo perché puoi stampare direttamente sullo schermo e anche memorizzare i risultati del popen per fare qualcosa, e poi controllare il codice di errore ecc ... thumbs up =) lo eseguo senza bufsize e funziona bene per me nel mio codice. – pelos

Problemi correlati