El subproceso de Python lee la salida estándar mientras se ejecuta
-
El subproceso de Python lee
stdout
mientras se ejecuta -
Enfoque 1: use
check_call
para leerstdout
de unsubprocess
mientras se ejecuta en Python -
Enfoque 2: sondee el proceso para leer
stdout
de un “subproceso” mientras se ejecuta en Python
El objetivo principal de este artículo es demostrar cómo leer el stdout
de un subprocess
que se está ejecutando en Python.
El subproceso de Python lee stdout
mientras se ejecuta
Al igual que con muchos otros módulos integrados, Subprocess
también es un módulo integrado que viene preinstalado con una instalación de Python “normal”.
Se usa principalmente cuando desea ejecutar tareas, procesos y programas en un nuevo proceso, realizar un conjunto específico de tareas y devolver el resultado.
Una de las muchas razones de su amplio uso es que permite la ejecución de programas externos y ejecutables directamente desde el programa como un proceso separado.
Al ejecutar un programa utilizando la biblioteca subprocess
, puede ser necesario que la salida de ese programa externo se muestre en tiempo real. Esto puede ser un requisito por muchas razones, como cuando un programa puede ser en tiempo real y depende de los cálculos después de un corto período de tiempo.
Considere el siguiente programa:
import subprocess
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 Exception(command, exitCode, output)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
Producción :
Folder PATH listing
Volume serial number is 0213-B7F2
C:.
+---DRIVERS
¦ +---bluetooth
¦ +---U1BLT07AVVASDSAP
¦ +---Custom
¦ ¦ +---EULA
¦ +---Win64
¦ +---LD
¦ +---svcpack
+---flutter
¦ +---.git
¦ ¦ +---hooks
¦ ¦ +---info
¦ ¦ +---logs
¦ ¦ ¦ +---refs
¦ ¦ ¦ +---heads
¦ ¦ ¦ +---remotes
¦ ¦ ¦ +---origin
¦ ¦ +---objects
¦ ¦ ¦ +---info
¦ ¦ ¦ +---pack
¦ ¦ +---refs
¦ ¦ +---heads
¦ ¦ +---remotes
¦ ¦ ¦ +---origin
¦ ¦ +---tags
¦ +---.github
¦ ¦ +---ISSUE_TEMPLATE
¦ ¦ +---workflows
¦ +---.idea
¦ ¦ +---runConfigurations
...
Podemos ver la salida en el programa pero no en tiempo real. La salida solo se mostrará después de que todo el comando (árbol
en nuestro caso) haya terminado de ejecutarse.
La salida no mostrará nada hasta que el programa (o comando) se ejecute en un proceso separado usando el comando subprocess
.
En nuestro caso, dado que se requiere que obtengamos la salida en tiempo real, necesitamos crear otra solución, la que muestra la salida del programa tal como está escrita en el stdout
.
La solución se puede abordar de múltiples maneras, algunas de las cuales se mencionan a continuación.
Enfoque 1: use check_call
para leer stdout
de un subprocess
mientras se ejecuta en Python
Considere el siguiente código:
import subprocess
import sys
def execute(command):
subprocess.check_call(
command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT
)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
Producción :
Folder PATH listing
Volume serial number is 0213-B7F2
C:.
├───DRIVERS
│ └───bluetooth
│ └───U1BLT0720US14CMP
│ ├───Custom
│ │ └───EULA
│ └───Win64
│ ├───LD
│ └───svcpack
├───flutter
│ ├───.git
│ │ ├───hooks
│ │ ├───info
│ │ ├───logs
│ │ │ └───refs
│ │ │ ├───heads
│ │ │ └───remotes
│ │ │ └───origin
│ │ ├───objects
│ │ │ ├───info
│ │ │ └───pack
│ │ └───refs
│ │ ├───heads
│ │ ├───remotes
│ │ │ └───origin
│ │ └───tags
│ ├───.github
│ │ ├───ISSUE_TEMPLATE
│ │ └───workflows
│ ├───.idea
│ │ └───runConfigurations
│ ├───.pub-cache
│ │ ├───hosted
│ │ │ └───pub.dartlang.org
│ │ │ ├───.cache
...
Si el requisito principal es imprimir la salida del programa en tiempo real, se puede usar check_call
para lograrlo. Esta solución simple, limpia y elegante es concisa y “simplemente perfecta” para programas muy simples, como cuando solo se necesita imprimir la salida.
El check_call
también admite el paso de parámetros, por lo que si su programa necesita argumentos para funcionar, se pueden pasar fácilmente a la función sin problemas. Este método espera a que el programa se complete.
Según la finalización del programa, el método regresa; de lo contrario, genera una excepción CalledProcessError
. El CalledProcessError
tendrá el código de retorno de falla, al que se puede acceder usando el atributo returncode
.
En el código mencionado anteriormente, el comando
se pasa al método check_call
, que contiene el comando (o el programa) a ejecutar.
El parámetro shell
se configuró en true
para ejecutar el proceso usando un shell, y la stdout
del proceso se configuró en la stdout
de nuestro programa, por lo que escribe directamente en nuestra stdout
, y podemos ver los cambios a medida que ocurren en nuestro stdout
.
Por último, el stderr
se establece en el stdout
del proceso generado.
Enfoque 2: sondee el proceso para leer stdout
de un “subproceso” mientras se ejecuta en Python
Considere el siguiente código:
import subprocess
import sys
def execute(command):
process = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
# Poll process for new output until finished
while True:
nextline = process.stdout.readline().decode("unicode_escape")
if nextline == "" and process.poll() is not None:
break
sys.stdout.write(nextline)
sys.stdout.flush()
output = process.communicate()[0]
exitCode = process.returncode
if exitCode == 0:
return output
else:
raise Exception(command, exitCode, output)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
Producción :
...
¦ ¦ ¦ ¦ ¦ +---UuidUtil
¦ ¦ ¦ ¦ +---example
¦ ¦ ¦ ¦ +---lib
¦ ¦ ¦ ¦ +---test
¦ ¦ ¦ +---vector_math-2.1.2
¦ ¦ ¦ ¦ +---benchmark
¦ ¦ ¦ ¦ +---bin
¦ ¦ ¦ ¦ +---lib
¦ ¦ ¦ ¦ ¦ +---src
¦ ¦ ¦ ¦ ¦ +---vector_math
¦ ¦ ¦ ¦ ¦ ¦ +---third_party
¦ ¦ ¦ ¦ ¦ +---vector_math_64
¦ ¦ ¦ ¦ ¦ ¦ +---third_party
¦ ¦ ¦ ¦ ¦ +---vector_math_geometry
¦ ¦ ¦ ¦ ¦ ¦ +---filters
¦ ¦ ¦ ¦ ¦ ¦ +---generators
¦ ¦ ¦ ¦ ¦ +---vector_math_lists
¦ ¦ ¦ ¦ ¦ +---vector_math_operations
¦ ¦ ¦ ¦ +---test
¦ ¦ ¦ ¦ +---tool
¦ ¦ ¦ +---video_player-2.2.11
¦ ¦ ¦ ¦ +---android
¦ ¦ ¦ ¦ ¦ +---gradle
...
Para asegurarnos de que la salida del programa generada usando el subprocess
se imprima tan pronto como se escriba en la stdout
, debemos sondear el proceso para ver la salida y continuar leyendo la última línea de la stdout
de la stdout
del programa.
En un ciclo “infinito”, continuamos leyendo la salida del proceso generado usando readline()
. Dado que la salida está codificada, necesitamos decodificarla (utf-escape
en nuestro caso) para que se represente adecuadamente.
Esto se puede hacer utilizando el método decode
y pasando el esquema de codificación correspondiente.
Una vez que el programa ha terminado de ejecutarse, también debemos escapar del bucle “infinito”. Podemos hacerlo comprobando dos cosas:
- La línea
stdout
actual está vacía. - El proceso ha terminado o muerto.
Esto se puede hacer de forma bastante sencilla, con una simple comparación de cadenas para la primera condición y el método poll()
para comprobar si el proceso ha terminado o no. Si el programa ha terminado, devuelve el returncode
; en caso contrario, devuelve Ninguno
.
Una simple comparación con Ninguno
también nos puede dar información de si el programa ha terminado de ejecutarse o no.
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn