Estoy tratando de escribir un script de contenedor para un programa de línea de comando (svnadmin verificar) que mostrará un buen indicador de progreso para la operación. Esto requiere que pueda ver cada línea de salida del programa envuelto tan pronto como salga.
Pensé que simplemente ejecutaría el programa usando subprocess.Popen
, use stdout=PIPE
, luego leería cada línea tal como venía y actuaría en consecuencia. Sin embargo, cuando ejecuté el siguiente código, la salida parecía estar almacenada en algún lugar, haciendo que apareciera en dos fragmentos, líneas 1 a 332, luego 333 a 439 (la última línea de salida)
from subprocess import Popen, PIPE, STDOUT
p = Popen('svnadmin verify /var/svn/repos/config', stdout = PIPE,
stderr = STDOUT, shell = True)
for line in p.stdout:
print line.replace('\n', '')
Después de mirar un poco la documentación sobre el subproceso, descubrí el bufsize
parámetro Popen
, así que intenté establecer bufsize en 1 (buffer cada línea) y 0 (sin buffer), pero ninguno de los valores parecía cambiar la forma en que se entregaban las líneas.
En este punto, comenzaba a comprender las pajillas, así que escribí el siguiente ciclo de salida:
while True:
try:
print p.stdout.next().replace('\n', '')
except StopIteration:
break
pero obtuve el mismo resultado.
¿Es posible obtener la salida del programa 'en tiempo real' de un programa ejecutado usando un subproceso? ¿Hay alguna otra opción en Python que sea compatible con versiones anteriores (no exec*
)?
fuente
sydout=PIPE
para que el subproceso escriba directamente en tu consola, sin pasar por el proceso principal?Respuestas:
Intenté esto, y por alguna razón mientras el código
amortigua agresivamente, la variante
no. Aparentemente, este es un error conocido: http://bugs.python.org/issue3907 (El problema ahora está "cerrado" a partir del 29 de agosto de 2018)
fuente
while p.poll() is None
lugar dewhile True
, y eliminar elif not line
print(line.decode('utf-8').rstrip())
.PYTHONUNBUFFERED=1
. Esto es especialmente útil para salidas que son infinitasfuente
p.stdout.close()
no está claro.Puede dirigir la salida del subproceso a las secuencias directamente. Ejemplo simplificado:
fuente
.communicate()
? ¿O los contenidos se pierden en las secuencias stderr / stdout padre?communicate()
método en la devoluciónCompletedProcess
. Además,capture_output
es mutuamente exclusivo constdout
ystderr
.Puedes probar esto:
Si usa readline en lugar de read, habrá algunos casos en los que el mensaje de entrada no se imprime. Pruébelo con un comando que requiera una entrada en línea y compruébelo usted mismo.
fuente
El subproceso Streaming stdin y stdout con asyncio en la publicación de blog de Python de Kevin McCarthy muestra cómo hacerlo con asyncio:
fuente
import nest_asyncio; nest_asyncio.apply()
y usar el comando de shell, es decir, enprocess = await create_subprocess_shell(*command, stdout=PIPE, stderr=PIPE, shell=True)
lugar deprocess = await create_subprocess_exec(...)
. ¡Salud!Problema de salida en tiempo real resuelto: Encontré un problema similar en Python, mientras capturaba la salida en tiempo real del programa c. Agregué " fflush (stdout) "; en mi código C. Funcionó para mi. Aquí está el fragmento del código
<< Programa C >>
<< Programa Python >>
<< SALIDA >> Imprimir: Cuenta 1 Imprimir: Cuenta 2 Imprimir: Cuenta 3
Espero eso ayude.
~ sairam
fuente
flush(stdout)
) en C ++. ¡Gracias!Me encontré con el mismo problema hace un tiempo. Mi solución fue deshacerme de la iteración del
read
método, que regresará de inmediato incluso si su subproceso no ha terminado de ejecutarse, etc.fuente
Dependiendo del caso de uso, es posible que también desee deshabilitar el almacenamiento en búfer en el propio subproceso.
Si el subproceso será un proceso de Python, puede hacer esto antes de la llamada:
O, alternativamente, pase esto en el
env
argumento aPopen
.De lo contrario, si está en Linux / Unix, puede usar la
stdbuf
herramienta. Por ejemplo, como:Ver también aquí sobre
stdbuf
u otras opciones.(Ver también aquí para la misma respuesta).
fuente
Utilicé esta solución para obtener resultados en tiempo real en un subproceso. Este ciclo se detendrá tan pronto como se complete el proceso, dejando de lado la necesidad de una declaración de interrupción o un posible ciclo infinito.
fuente
if out=='': break
despuésout = sub_process...
Encontré esta función "plug-and-play" aquí . ¡Trabajado como un encanto!
fuente
stderr=subprocess.STDOUT
realmente ayuda mucho en la captura de datos de transmisión. Lo estoy votando.Puede usar un iterador sobre cada byte en la salida del subproceso. Esto permite la actualización en línea (las líneas que terminan con '\ r' sobrescriben la línea de salida anterior) del subproceso:
fuente
En Python 3.x, el proceso puede bloquearse porque la salida es una matriz de bytes en lugar de una cadena. Asegúrate de decodificarlo en una cadena.
A partir de Python 3.6, puede hacerlo utilizando el parámetro
encoding
en Popen Constructor . El ejemplo completo:Tenga en cuenta que este código redirecciones
stderr
astdout
y controla los errores de salida .fuente
El uso de pexpect [ http://www.noah.org/wiki/Pexpect ] con líneas de lectura sin bloqueo resolverá este problema. Se deriva del hecho de que las tuberías están almacenadas en búfer, por lo que la salida de su aplicación está siendo almacenada por la tubería, por lo tanto, no puede llegar a esa salida hasta que el búfer se llene o el proceso muera.
fuente
Solución completa:
fuente
universal_newlines=True
laPopen()
llamada, probablemente no necesite poner su propio manejo de ellos, ese es el punto central de la opción.Este es el esqueleto básico que siempre uso para esto. Facilita la implementación de tiempos de espera y es capaz de lidiar con los inevitables procesos de bloqueo.
fuente
(Esta solución ha sido probada con Python 2.7.15)
Solo necesita sys.stdout.flush () después de cada línea de lectura / escritura:
fuente
Pocas respuestas sugiriendo python 3.xo pthon 2.x, el siguiente código funcionará para ambos.
fuente