Imprima constantemente la salida del subproceso mientras el proceso se está ejecutando

Resuelto Wolkenarchitekt asked hace 14 años • 17 respuestas

Para iniciar programas desde mis scripts de Python, estoy usando el siguiente método:

def execute(command):
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise ProcessException(command, exitCode, output)

Entonces, cuando inicio un proceso como Process.execute("mvn clean install"), mi programa espera hasta que finaliza el proceso, y solo entonces obtengo el resultado completo de mi programa. Esto es molesto si estoy ejecutando un proceso que tarda un poco en finalizar.

¿Puedo dejar que mi programa escriba la salida del proceso línea por línea, sondeando la salida del proceso antes de que termine en un bucle o algo así?

Encontré este artículo que podría estar relacionado.

Wolkenarchitekt avatar Dec 11 '10 23:12 Wolkenarchitekt
Aceptado

Puede usar iter para procesar líneas tan pronto como las genere el comando: lines = iter(fd.readline, ""). Aquí hay un ejemplo completo que muestra un caso de uso típico (gracias a @jfs por ayudar):

from __future__ import print_function # Only Python 2.x
import subprocess

def execute(cmd):
    popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True)
    for stdout_line in iter(popen.stdout.readline, ""):
        yield stdout_line 
    popen.stdout.close()
    return_code = popen.wait()
    if return_code:
        raise subprocess.CalledProcessError(return_code, cmd)

# Example
for path in execute(["locate", "a"]):
    print(path, end="")
tokland avatar Dec 11 '2010 16:12 tokland

Para imprimir la salida del subproceso línea por línea tan pronto como se vacía su buffer de salida estándar en Python 3:

from subprocess import Popen, PIPE, CalledProcessError

with Popen(cmd, stdout=PIPE, bufsize=1, universal_newlines=True) as p:
    for line in p.stdout:
        print(line, end='') # process line here

if p.returncode != 0:
    raise CalledProcessError(p.returncode, p.args)

Aviso: no es necesario p.poll(): el ciclo finaliza cuando se alcanza eof. Y no es necesario iter(p.stdout.readline, ''): el error de lectura anticipada se solucionó en Python 3.

Consulte también Python: lea la entrada de transmisión desde subprocess.communicate() .

jfs avatar Feb 04 '2015 10:02 jfs