español - ¿Puedes hacer una salida de subproceso python stdout y stderr como de costumbre, pero también capturar la salida como una cadena?
subprocess python español (3)
Cree dos lectores como el anterior, uno para stdout
uno para stderr
y comience cada uno en un nuevo hilo. Esto se adjuntaría a la lista aproximadamente en el mismo orden en que fueron generados por el proceso. Mantén dos listas separadas si quieres.
es decir,
p = subprocess.Popen(["the", "command"])
t1 = thread.start_new_thread(func,stdout) # create a function with the readers
t2 = thread.start_new_thread(func,stderr)
p.wait()
# your logic here
Posible duplicado:
Envolver subproceso ''stdout / stderr
En esta pregunta , hanan-n preguntó si era posible tener un subproceso python que produzca salidas a la salida estándar mientras que también mantiene la salida en una cadena para su posterior procesamiento. La solución en este caso fue recorrer cada línea de salida e imprimirlas manualmente:
output = []
p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''''):
print(line)
output.append(line)
Sin embargo, esta solución no se generaliza en el caso de que desee hacer esto tanto para stdout como para stderr, a la vez que satisface lo siguiente:
- la salida de stdout / stderr debe ir al proceso principal ''stdout / stderr respectivamente
- la salida se debe hacer en tiempo real tanto como sea posible (pero solo necesito acceso a las cadenas al final)
- el orden entre las líneas stdout y stderr no se debe cambiar (no estoy muy seguro de cómo funcionaría si el subproceso vacia sus cachés stdout y stderr a diferentes intervalos; supongamos por ahora que obtenemos todo en buenos trozos que contienen contenido completo ¿líneas?)
Revisé la documentación del subproceso , pero no pude encontrar nada que pudiera lograrlo. Lo más cercano que pude encontrar es agregar stderr=subprocess.stdout
y usar la misma solución que la anterior, pero luego perdemos la distinción entre resultados regulares y errores. ¿Algunas ideas? Supongo que la solución, si la hay, implicará tener lecturas asíncronas en p.stdout
y p.stderr
.
Aquí hay un ejemplo de lo que me gustaría hacer:
p = subprocess.Popen(["the", "command"])
p.wait() # while p runs, the command''s stdout and stderr should behave as usual
p_stdout = p.stdout.read() # unfortunately, this will return '''' unless you use subprocess.PIPE
p_stderr = p.stderr.read() # ditto
[do something with p_stdout and p_stderr]
Este ejemplo parece funcionar para mí:
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
import subprocess
import sys
import select
p = subprocess.Popen(["find", "/proc"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = []
stderr = []
while True:
reads = [p.stdout.fileno(), p.stderr.fileno()]
ret = select.select(reads, [], [])
for fd in ret[0]:
if fd == p.stdout.fileno():
read = p.stdout.readline()
sys.stdout.write(''stdout: '' + read)
stdout.append(read)
if fd == p.stderr.fileno():
read = p.stderr.readline()
sys.stderr.write(''stderr: '' + read)
stderr.append(read)
if p.poll() != None:
break
print ''program ended''
print ''stdout:'', "".join(stdout)
print ''stderr:'', "".join(stderr)
En general, cualquier situación en la que quiera hacer cosas con varios descriptores de archivos al mismo tiempo y no sepa cuál tendrá cosas para leer, debe usar select o algo equivalente (como un reactor retorcido).
Para imprimir en la consola y capturar en una cadena stdout / stderr de un subproceso de una manera portátil:
from StringIO import StringIO
fout, ferr = StringIO(), StringIO()
exitcode = teed_call(["the", "command"], stdout=fout, stderr=ferr)
stdout = fout.getvalue()
stderr = ferr.getvalue()
¿dónde se define teed_call()
en el subproceso de Python para obtener la salida de los niños en el archivo y la terminal?
Podría usar cualquier objeto similar a un archivo .write()
método .write()
).