python - example - leer subproceso stdout línea por línea
subprocess python 3 example (6)
De hecho, si resolvió el iterador, entonces el almacenamiento en búfer podría ser su problema. Podría decirle a python en el subproceso que no almacene en búfer su salida.
proc = subprocess.Popen([''python'',''fake_utility.py''],stdout=subprocess.PIPE)
se convierte en
proc = subprocess.Popen([''python'',''-u'', ''fake_utility.py''],stdout=subprocess.PIPE)
He necesitado esto al llamar a python desde dentro de python.
Mi script de Python usa subproceso para llamar a una utilidad de Linux que es muy ruidosa. Quiero almacenar toda la salida en un archivo de registro y mostrarle algo al usuario. Pensé que lo siguiente funcionaría, pero la salida no aparece en mi aplicación hasta que la utilidad ha producido una cantidad significativa de salida.
#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
print hex(i)*512
i += 1
time.sleep(0.5)
#filters output
import subprocess
proc = subprocess.Popen([''python'',''fake_utility.py''],stdout=subprocess.PIPE)
for line in proc.stdout:
#the real code does filtering here
print "test:", line.rstrip()
El comportamiento que realmente quiero es que el script de filtro imprima cada línea a medida que se recibe del subproceso. A Sorta le gusta lo que tee
hace pero con código python.
¿Qué me estoy perdiendo? ¿Es esto posible?
Actualizar:
Si se agrega sys.stdout.flush()
a fake_utility.py, el código tiene el comportamiento deseado en Python 3.1. Estoy usando Python 2.6. Usted pensaría que usar proc.stdout.xreadlines()
funcionaría igual que py3k, pero no lo hace.
Actualización 2:
Aquí está el código de trabajo mínimo.
#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
print i
sys.stdout.flush()
time.sleep(0.5)
#display out put line by line
import subprocess
proc = subprocess.Popen([''python'',''fake_utility.py''],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''''):
print line.rstrip()
Desea pasar estos parámetros adicionales a subprocess.Popen
:
bufsize=1, universal_newlines=True
Luego puedes iterar como en tu ejemplo. (Probado con Python 3.5)
Ha pasado mucho tiempo desde la última vez que trabajé con Python, pero creo que el problema está en la instrucción for line in proc.stdout
, que lee toda la entrada antes de iterarla. La solución es usar readline()
lugar:
#filters output
import subprocess
proc = subprocess.Popen([''python'',''fake_utility.py''],stdout=subprocess.PIPE)
while True:
line = proc.stdout.readline()
if line != '''':
#the real code does filtering here
print "test:", line.rstrip()
else:
break
Por supuesto, todavía tiene que lidiar con el búfer del subproceso.
Nota: de acuerdo con la documentación, la solución con un iterador debería ser equivalente a usar readline()
, excepto el búfer de lectura anticipada, pero (o exactamente por esto) el cambio propuesto produjo resultados diferentes para mí (Python 2.5 en Windows XP).
La siguiente modificación de la respuesta de Rômulo me funciona en Python 2 y 3 (2.7.12 y 3.6.1):
import os
import subprocess
process = subprocess.Popen(command, stdout=subprocess.PIPE)
while True:
line = process.stdout.readline()
if line != b'''':
os.write(1, line)
else:
break
Poco tarde en la fiesta, pero me sorprendió no ver lo que creo que es la solución más sencilla aquí:
import io
import subprocess
proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): # or another encoding
# do something with line
Probé esto con python3 y funcionó, source
def output_reader(proc):
for line in iter(proc.stdout.readline, b''''):
print(''got line: {0}''.format(line.decode(''utf-8'')), end='''')
def main():
proc = subprocess.Popen([''python'', ''fake_utility.py''],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
t = threading.Thread(target=output_reader, args=(proc,))
t.start()
try:
time.sleep(0.2)
import time
i = 0
while True:
print (hex(i)*512)
i += 1
time.sleep(0.5)
finally:
proc.terminate()
try:
proc.wait(timeout=0.2)
print(''== subprocess exited with rc ='', proc.returncode)
except subprocess.TimeoutExpired:
print(''subprocess did not terminate in time'')
t.join()