2009-09-07 19 views
34

Quiero que la salida ejecute Test_Pipe.py, traté de seguir el código en Linux pero no funcionó.Cómo obtener salida del subproceso.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 línea proc.stdout.readline() estaba bloqueado, así que no hay datos grabados fuera.

+0

Duplicado: 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 –

Respuesta

39

Obviamente puedes usar subprocess.communicate pero creo que estás buscando entrada y salida en tiempo real.

readline se bloqueó porque el proceso probablemente esté esperando su entrada. Usted puede leer carácter por carácter para superar este como el siguiente:

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

[no es necesario 'process.poll()' en este caso] (http: // stackoverflow.com/a/17701672/4279). – jfs

12

Para evitar los muchos problemas que siempre pueden surgir con capacidad para amortiguar las tareas como "conseguir la salida del subproceso al proceso principal en tiempo real", me siempre se recomienda usar pexpect para todas las plataformas que no sean de Windows, wexpect en Windows, en lugar de subprocess, cuando tales tareas sean deseadas.

+0

Enlace actualizado a pexpect: https://github.com/pexpect/pexpect –

20

El fragmento de Nadia funciona, pero la invocación de lectura con un búfer de 1 byte es muy desaconsejable. La mejor manera de hacer esto sería establecer el descriptor de archivo de salida estándar a no bloqueante usando fcntl

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

y luego usando seleccione para probar si los datos están listos

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

Ella tenía razón en que su problema debe ser diferente de lo que publicó como Caller.py y Test_Pipe.py funcionan según lo previsto.

+0

No producirá el resultado más rápido que el código en la pregunta debido a [el problema del bloqueo de bloques.Ver mi respuesta] (http://stackoverflow.com/a/17701672/4279). – jfs

+0

El código produce salida en tiempo real. ¿Tuviste un problema con eso? –

+0

siga el enlace en el comentario. – jfs

7

Test_Pipe.py buffers en su salida estándar por defecto, así proc en Caller.py no ven ninguna salida hasta que el buffer del niño está lleno (si el tamaño del búfer es de 8 KB a continuación, se tarda alrededor de un minuto para llenar Test_Pipe.py 's stdout buffer).

Para hacer que la salida esté sin búfer (línea de búfer para las secuencias de texto) puede pasar -u flag al script de Python secundario. Permite leer la línea de salida de subproceso por línea en 'tiempo real':

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

ver los enlaces en Python: read streaming input from subprocess.communicate() sobre cómo resolver el problema de bloque de amortiguación para los procesos secundarios no Python.

+1

Nuevamente estás usando un buffer de 1 byte que es increíblemente ineficiente. –

+4

@DerrickPetzold: mal. 'bufsize = 1' significa" línea amortiguada ". Utiliza el mismo tamaño de búfer que 'bufsize = -1'. Podría haber descubierto que sus dos comentarios son incorrectos si fuera a ejecutar el código (compare el rendimiento del tiempo y mida el tiempo antes de leer el primer byte) – jfs

+1

me gusta esta forma de hacerlo porque puede imprimir directamente en la pantalla y también almacenar los resultados del popen para hacer algo con, y más tarde comprobar el código de error, etc ... thumbs up =) lo ejecuto sin el bufsize y funciona bien para mí en mi código. – pelos

Cuestiones relacionadas