subprocess.popen, capturar stdout

Arnau Sanchez arnau en ehas.org
Mar Oct 30 16:55:50 CET 2007


Oswaldo Hernández escribió:

> Para capturar la salida he probado:
>     retorno=None
>     while retorno is None:
>         out, error = pr.communicate()
>         retorno = pr.poll(50)
> 
> Esto funciona, pero communicate() espera a que termine el proceso y da 
> toda la salida de una vez.

Es lo que se espera de communicate():

communicate(input=None)
     Interact with process: Send data to stdin. Read data from stdout 
and stderr, until end-of-file is reached. Wait for process to terminate.

Salió algo parecido en este hilo:

http://listas.aditel.org/archivos/python-es/2007-September/018638.html

Todo lo que te diga en este mensaje está sólo probado en UNIX, no sé si 
el comportamiento en Windows será el mismo. En fin, la solución más 
simple que se me ocurre:

import subprocess

def get_popen(command):
     sp = subprocess
     return subprocess.Popen(command, stdout=sp.PIPE, stderr=sp.STDOUT)

command = "top -b"
popen = get_popen(command.split())
for line in popen.stdout:
     print line,
popen.wait()

Fíjate que, al menos en UNIX, es necesario enviar a subprocess el 
comando como lista (por eso hago el split()), no como cadena como hacías 
en tu ejemplo.

Ahora bien, no siempre el comando a ejecutar hará un flush para cada 
línea que escriba, y entonces nuestra situación no habrá mejorado: la 
lectura en popen.stdout se quedará igualmente parada. Si te ocurre esto, 
tienes que crear un generador que llame explícitamente al readline() del 
descriptor hasta agotar los datos:

def readlines(fd):
     while 1:
         line = fd.readline()
         if not line:
             break
         yield line

Si estás familiarizado con las itertools, esta función también puede 
escribirse de forma más compacta, así:

import itertools
def readlines(fd):
     genlines = (fd.readline() for _ in itertools.repeat(None))
     return itertools.takewhile(bool, genlines)

Cualquiera de las dos se usaría de este modo:

for line in readlines(popen.stdout):
     print line,

Prueba y nos dices si algo de esto te funciona.

arnau
_______________________________________________
Lista de correo Python-es 
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes





Más información sobre la lista de distribución Python-es