2009-02-09 10 views
21

Se questo è il mio sottoprocesso:Intercettare stdout di un sottoprocesso mentre è in esecuzione

import time, sys 
for i in range(200): 
    sys.stdout.write('reading %i\n'%i) 
    time.sleep(.02) 

E questo è lo script di controllare e modificare l'uscita del sottoprocesso:

import subprocess, time, sys 

print 'starting' 

proc = subprocess.Popen(
    'c:/test_apps/testcr.py', 
    shell=True, 
    stdin=subprocess.PIPE, 
    stdout=subprocess.PIPE ) 

print 'process created' 

while True: 
    #next_line = proc.communicate()[0] 
    next_line = proc.stdout.readline() 
    if next_line == '' and proc.poll() != None: 
     break 
    sys.stdout.write(next_line) 
    sys.stdout.flush() 

print 'done' 

Perché readline e communicate in attesa che il processo sia terminato? C'è un modo semplice per passare (e modificare) il subprocesso 'stdout in tempo reale?

BTW, ho visto this, ma non ho bisogno delle funzionalità di registrazione (e non mi sono preoccupato di capirlo molto).

Sono su Windows XP.

+0

correlati: [? Come svuotare l'uscita di Python print] (http://stackoverflow.com/q/230751/95735) –

risposta

14

Come già detto, il problema è il buffering. Mi sono imbattuto in un problema simile durante la scrittura di alcuni moduli per SNMPd e risolto risolvendo stdout con una versione di auto-flushing.

ho usato il seguente codice, ispirato da alcuni messaggi su ActiveState:

class FlushFile(object): 
    """Write-only flushing wrapper for file-type objects.""" 
    def __init__(self, f): 
     self.f = f 
    def write(self, x): 
     self.f.write(x) 
     self.f.flush() 

# Replace stdout with an automatically flushing version 
sys.stdout = FlushFile(sys.__stdout__) 
+0

Non vedo come sia diverso dal chiamare sys.stdout.flush() dopo ogni sys.stdout.readline(), che è quello che faccio. Ho anche provato a impostare bufsize = 0 per il sottoprocesso. – Paul

+9

Lo svuotamento è necessario nel sottoprocesso, non nel processo principale. – bobince

+0

Sì, nell'esempio il sottoprocesso è anche uno script python. Quindi sostituire lo stdout nel sottoprocesso. Chiamare sys.stdout.flush() nel processo padre non fa nulla. –

7

L'uscita del processo è memorizzata nel buffer. Su più sistemi operativi UNIXy (o Cygwin), è disponibile il modulo pexpect, che recita tutti gli incantesimi necessari per evitare problemi relativi al buffer. Tuttavia, questi incantesimi richiedono un lavoro pty module, che non è disponibile su build Win32 native di Win32 (non cygwin).

Nel caso di esempio in cui si controlla il sottoprocesso, è sufficiente chiamare lo sys.stdout.flush() se necessario, ma per i sottoprocessi arbitrari tale opzione non è disponibile.

Vedere anche the question "Why not just use a pipe (popen())?" nelle domande frequenti di pexpect.