Salida en tiempo real de la secuencia de comandos de python utilizando subprocess.Popen ()

Después de buscar alrededor, definí una función para ejecutar un comando como en la terminal:

import shlex import subprocess def execute_cmd(cmd): p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) for line in iter(p.stdout.readline, b''): # b'' here for python3 sys.stdout.write(line.decode(sys.stdout.encoding)) error = p.stderr.read().decode() if error: raise Exception(error) 

Funciona bien (la salida es en tiempo real), cuando yo

 execute_cmd('ping -c 5 www.google.com') 

Sin embargo, cuando uso execute_cmd para ejecutar un script de python, la salida se imprimirá hasta que el proceso haya finalizado.

 execute_cmd('python test.py') 

script: test.py

 #!/usr/bin/env python # -*- coding: utf-8 -*- import time print('hello') time.sleep(2) print('hello, again') 

¿Cómo puedo arreglarlo? ¡Gracias!


Lo siento por no explicar por qué ‘captura la salida estándar y luego escríbela de nuevo a la salida estándar’. Aquí lo que realmente quiero hacer es capturar los resultados del script para el registrador, el registrador los envía a la pantalla (StreamHandler) y al archivo de registro (FileHandler). Construí y probé la parte del registrador, ahora la parte ‘ejecutar’. E ignorar el parámetro stdout= parece no funcionar.

tubería:

  1. logger de configuración;
  2. redirigir STDOUT, STDERR al registrador;
  3. ejecutar scripts;

Debido al paso 2, si ignoro el parámetro stdout= , las salidas de los scripts seguirán saliendo a STDOUT y no se registrarán en el archivo.

Tal vez puedo configurar stdout= para el registrador?

Este es un problema común del sistema de salida subyacente, especialmente en Linux u otros sistemas similares a Unix. La biblioteca io es lo suficientemente inteligente como para vaciar la salida en cada \n cuando detecta que la salida se dirige a un terminal. Pero esta descarga automática no se produce cuando la salida se redirige a un archivo o una canalización, probablemente por motivos de rendimiento. No es realmente un problema cuando solo importan los datos, pero conduce a un comportamiento extraño cuando el tiempo también importa.

Desafortunadamente, no conozco una forma sencilla de solucionarlo desde el progtwig de llamadas (*). La única posibilidad es tener el lavado de la fuerza del usuario en cada línea / bloque o usar una salida sin búfer:

 #!/usr/bin/env python # -*- coding: utf-8 -*- import time import sys print('hello') sys.stdout.flush() time.sleep(2) print('hello, again') 

(*) La forma a prueba de balas sería usar un pseudo-terminal. La persona que llama controla el lado maestro y pasa el lado del cliente al destinatario. La biblioteca detectará un terminal y se vaciará automáticamente en cada línea. Pero ya no es portátil fuera del mundo Unix y no es realmente una forma simple .