Saltar al contenido principal

Una Introducción al Subproceso Python: Conceptos básicos y ejemplos

Explora nuestra guía paso a paso para ejecutar comandos externos utilizando el módulo de subprocesos de Python, completa con ejemplos.
29 ene 2024  · 15 min de lectura

Puedes utilizar el módulo de subprocesos de Python para crear nuevos procesos, conectarte a su entrada y salida, y recuperar sus códigos de retorno y/o salida del proceso. En este artículo, exploraremos los aspectos básicos del módulo de subprocesos, incluyendo cómo ejecutar comandos externos, redirigir la entrada y la salida y gestionar los errores. Tanto si eres un principiante como un desarrollador experimentado de Python, este tutorial te proporcionará los conocimientos que necesitas para utilizar el módulo de subprocesos de forma eficaz en tus proyectos.

Qué es el subproceso Python

El módulo subproceso de Python es una herramienta que te permite ejecutar otros programas o comandos desde tu código Python. Se puede utilizar para abrir nuevos programas, enviarles datos y obtener resultados.

Es como dar órdenes a tu ordenador utilizando Python en lugar de escribirlas directamente en el símbolo del sistema. Este módulo facilita la automatización de tareas y la integración de otros programas con tu código Python.

Por ejemplo, puedes utilizar el módulo subproceso para ejecutar un comando shell, como "ls" o "ping", y obtener la salida de ese comando en tu código Python. También puedes utilizarlo para ejecutar otros scripts o ejecutables de Python, como archivos .exe en Windows.

Además, el módulo de subproceso puede redirigir la entrada y la salida del proceso, lo que significa que puedes controlar qué datos se envían al proceso y qué datos se reciben de él.

Una de las capacidades más útiles del módulo subproceso es que permite al usuario manejar las entradas, salidas e incluso los errores que genera el proceso hijo desde dentro del código Python.

Esta función se considera uno de los aspectos más potentes del módulo. Gracias a esta función, ahora es posible hacer que el proceso de llamada a subprocesos sea más potente y versátil. Por ejemplo, ahora es posible utilizar la salida del subproceso como variable en el resto del script Python.

En este tutorial aprenderemos a utilizar el módulo subproceso para ejecutar otros programas desde nuestro código Python, a enviarles datos y a obtener resultados. Será útil tanto para principiantes como para desarrolladores experimentados de Python.

Cuándo utilizar el Subproceso Python

Automatizar las tareas del sistema

El módulo de subprocesos puede utilizarse para automatizar diversas tareas del sistema, como ejecutar copias de seguridad, iniciar y detener servicios y programar trabajos cron. Por ejemplo, puedes utilizar el módulo de subprocesos para ejecutar el comando "cp" para crear una copia de seguridad de un archivo o el comando "service" para iniciar y detener servicios en sistemas Linux.

También puedes utilizar el módulo de subprocesos para programar tareas que se ejecuten a intervalos específicos utilizando cron u otras herramientas de programación.

Ejecutar herramientas de línea de comandos

El módulo subproceso puede utilizarse para ejecutar herramientas de línea de comandos como grep, sed y awk, y procesar su salida en tu código Python. Por ejemplo, puedes utilizar el módulo subproceso para ejecutar el comando "grep" para buscar un patrón específico en un archivo y luego procesar la salida en tu código Python. Esto puede ser útil para tareas como el análisis de registros, el procesamiento de datos y la manipulación de textos.

Ejecutar ejecutables externos

El módulo subproceso puede ejecutar otros ejecutables, como archivos .exe en Windows, y controlar su comportamiento. Por ejemplo, puedes utilizar el módulo de subproceso para ejecutar un ejecutable que realice una tarea específica y luego utilizar la salida de ese ejecutable en tu propio código. Esto puede ser útil para el procesamiento de imágenes, el análisis de datos y las tareas de aprendizaje automático.

Ejecutar scripts como procesos en segundo plano

Puedes utilizar el módulo de subprocesos para ejecutar scripts como procesos en segundo plano, de modo que sigan ejecutándose después de que salga el programa principal. Por ejemplo, puedes utilizar el módulo de subproceso para ejecutar un script que realice una tarea específica y salir del programa principal sin esperar a que el script finalice. Esto puede ser útil para la supervisión, el registro y la recopilación de datos.

Ejecutar guiones con un intérprete que no sea Python

El módulo subproceso puede ayudarte a ejecutar scripts escritos en otros lenguajes como Perl, Ruby y Bash. Por ejemplo, puedes utilizar el módulo de subproceso para ejecutar un script Perl que realice una tarea específica y luego utilizar la salida de ese script en tu propio código. Esto puede ser útil para el tratamiento de datos, la manipulación de textos y la administración del sistema.

Procesamiento paralelo

El módulo de subprocesos puede utilizarse para ejecutar varios procesos en paralelo, lo que puede ser útil para tareas como el procesamiento de imágenes, el análisis de datos y el aprendizaje automático. Por ejemplo, puedes utilizar el módulo de subprocesos para ejecutar varias instancias del mismo script, cada una procesando una parte diferente de los datos y luego combinar los resultados.

Ejecute y edite el código de este tutorial en línea

Ejecutar código

Ejemplos de subprocesos en Python 

subproceso python ejecutar

En subprocess.run() es una forma cómoda de ejecutar un subproceso y esperar a que se complete. Te permite elegir el comando a ejecutar y añadir opciones como argumentos, variables de entorno y redirecciones de entrada/salida. Una vez iniciado el subproceso, el run() se bloquea hasta que el subproceso finaliza y devuelve un objeto CompletedProcess, que contiene el código de retorno y la salida del subproceso.

En subprocess.run() toma varios argumentos, algunos de los cuales son:

  • args: El comando a ejecutar y sus argumentos, pasados como una lista de cadenas.
  • capture_output: Si se establece en Verdadero, capturará la salida estándar y el error estándar.
  • text: Si se establece en Verdadero, devolverá la salida estándar y la salida estándar como cadena, si no, como bytes.
  • check: un valor booleano que indica si se comprueba el código de retorno del subproceso, si la comprobación es verdadera y el código de retorno es distinto de cero, entonces se lanza el subproceso `CalledProcessError`.
  • timeout: Un valor en segundos que especifica cuánto tiempo hay que esperar a que el subproceso finalice antes de que se agote el tiempo de espera.
  • shell: Un valor booleano que indica si se debe ejecutar el comando en un intérprete de comandos. Esto significa que la orden se pasa como una cadena, y se pueden utilizar funciones específicas del shell, como la expansión de comodines y la sustitución de variables.

El método subprocess.run() también devuelve un objeto CompletedProcess, que contiene los siguientes atributos:

  • args: El comando y los argumentos que se ejecutaron.
  • returncode: El código de retorno del subproceso.
  • stdout: La salida estándar del subproceso, como objeto bytes.
  • stderr: El error estándar del subproceso, como objeto bytes.

Ejemplo 1: Ejecutar comandos shell:

import subprocess

result = subprocess.run(["dir"], shell=True, capture_output=True, text=True)

print(result.stdout)

Salida: 

Volume in drive C has no label.

Volume Serial Number is E414-A41C

 Directory of C:\Users\owner

01/25/2023  10:56 AM    <DIR>          .

01/25/2023  10:56 AM    <DIR>          ..

07/19/2021  01:19 PM    <DIR>          .anaconda

07/19/2021  01:19 PM    <DIR>          .astropy

07/19/2021  01:19 PM    <DIR>          .aws

09/12/2022  08:48 AM               496 .bash_history

03/27/2022  03:08 PM    <DIR>          .cache

09/26/2021  06:58 AM    <DIR>          .conda

09/26/2021  06:59 AM                25 .condarc

…

Los usuarios de Linux o mac sustituyen "dir" por "ls" y se deshacen del argumento `shell`.

Ejemplo 2: Ejecutar scripts de Python:

También puedes ejecutar un script python utilizando el método subproceso.ejecutar(). Empecemos creando un sencillo script Python en un archivo .py

print(“This is the output from subprocess module”)

Guarda este archivo como `mi_archivo_python.py`.

Ahora puedes utilizar el módulo de subproceso para ejecutar este archivo:

import subprocess

result = subprocess.run(["python", "my_python_file.py"], capture_output=True, text=True)

print(result.stdout)

Salida:

This is the output from subprocess module

Ejemplo 3: Ejecutar código Python directamente desde una función:

Para casos de uso sencillos, puedes pasar directamente un comando python en la función subproceso.ejecutar(). He aquí cómo:

result = subprocess.run(["C:/Users/owner/anaconda3/python", "-c", "print('This is directly from a subprocess.run() function')"], capture_output = True, text = True)

print(result.stdout)

Salida:

This is directly from a subprocess.run() function

En el args el primer elemento `C:/Usuarios/propietario/anaconda3/python` es una ruta al Python ejecutable (tu ruta puede ser diferente). El segundo elemento, `-c` es una etiqueta Python que permite al usuario escribir código Python como texto en la línea de comandos. El tercer elemento, `print(...)` es el propio comando Python.

Ejemplo 4: Utilizar el argumento de comprobación

El argumento comprobar es un argumento opcional de la función subproceso.ejecutar() del módulo subproceso de Python. Es un valor booleano que controla si la función debe comprobar el código de retorno del comando que se está ejecutando.

Cuando la comprobación se establece en True, la función comprobará el código de retorno del comando y lanzará una excepción CalledProcessError si el código de retorno es distinto de cero. La excepción tendrá como atributos el código de retorno, stdout, stderr y comando.

Cuando la comprobación se establece en Falso (por defecto), la función no comprobará el código de retorno y no lanzará una excepción, aunque la orden falle.

import subprocess

result = subprocess.run(["python", "file_donot_exist.py"], capture_output=True, text=True, check=True)

print(result.stdout)

print(result.stderr)

Salida:

---------------------------------------------------------------------------

CalledProcessError                        Traceback (most recent call last)

<ipython-input-81-503b60184db8> in <module>

      1 import subprocess

----> 2 result = subprocess.run(["python", "file_donot_exist.py"], capture_output=True, text=True, check=True)

      3 print(result.stdout)

      4 print(result.stderr)

~\anaconda3\lib\subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)

    514         retcode = process.poll()

    515         if check and retcode:

--> 516             raise CalledProcessError(retcode, process.args,

    517                                      output=stdout, stderr=stderr)

    518     return CompletedProcess(process.args, retcode, stdout, stderr)

CalledProcessError: Command '['python', 'file_donot_exist.py']' returned non-zero exit status 2.

Observa que el comando ha fallado porque "archivo_no_existe.py" no existe. A diferencia de cuando estableces `check=True`, tu proceso no fallará; en su lugar, obtendrás el mensaje de error en `stdout`. 

import subprocess

result = subprocess.run(["python", "my_python_file2.py"], capture_output=True, text=True, check=False)

print(result.stdout)

print(result.stderr)

Salida:

python: can't open file 'my_python_file2.py': [Errno 2] No such file or directory

subproceso python Popen

`subprocess.Popen` es una interfaz de nivel inferior para ejecutar subprocesos, mientras que subprocess.run es una envoltura de nivel superior alrededor de Popen que pretende ser más cómoda de usar.

Popen te permite iniciar un nuevo proceso e interactuar con sus flujos estándar de entrada, salida y error. Devuelve un "handle" del proceso en ejecución que puede utilizarse para esperar a que el proceso finalice, comprobar su código de retorno o terminarlo.

ejecutar es una función más cómoda que te permite ejecutar una orden y capturar su salida en una sola llamada, sin tener que crear un objeto Popen y gestionar tú mismo los flujos. También te permite especificar varias opciones para ejecutar el comando, como si se debe lanzar una excepción si el comando falla.

En general, debes utilizar ejecutar si sólo necesitas ejecutar una orden y capturar su salida y Popen si necesitas más control sobre el proceso, como interactuar con sus flujos de entrada y salida.

La clase Popen toma los mismos argumentos que run(), incluidos los argumentos que especifican la orden que se va a ejecutar y otros argumentos opcionales como stdin, stdout, stderr, shell, cwd y env.

La clase Popen tiene varios métodos que te permiten interactuar con el proceso, como communicate(), poll(), wait(), terminate() y kill().

import subprocess

p = subprocess.Popen(["python", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

output, errors = p.communicate()

print(output)

Salida:

usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...

Options and arguments (and corresponding environment variables):

-b     : issue warnings about str(bytes_instance), str(bytearray_instance)

         and comparing bytes/bytearray with str. (-bb: issue errors)

-B     : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x

-c cmd : program passed in as string (terminates option list)

-d     : debug output from parser; also PYTHONDEBUG=x

-E     : ignore PYTHON* environment variables (such as PYTHONPATH)

…

Esto ejecutará el comando `python -help` y creará un nuevo objeto Popen, que se almacena en la variable p. La salida estándar y el error del comando se capturan mediante el método communicate() y se almacenan en las variables output y errors, respectivamente.

El `subproceso.Popen` es útil cuando quieres tener más control sobre el proceso, como enviarle entradas, recibir salidas de él o esperar a que termine.

llamada al subproceso python

`subprocess.call()` es una función del módulo de subprocesos de Python que se utiliza para ejecutar una orden en un proceso separado y esperar a que se complete. Devuelve el código de retorno de la orden, que es cero si la orden ha tenido éxito, y distinto de cero si ha fallado.

La función call() toma los mismos argumentos que run(), incluidos los argumentos que especifican la orden que se va a ejecutar, y otros argumentos opcionales, como stdin, stdout, stderr, shell, cwd y env.

La salida estándar y el error del comando se envían a las mismas stdout y stderr que el proceso padre, a menos que los redirijas utilizando los argumentos stdout y stderr.

import subprocess

return_code = subprocess.call(["python", "--version"])

if return_code == 0:

    print("Command executed successfully.")

else:

    print("Command failed with return code", return_code)

Salida:

Command executed successfully.

Esto ejecutará el comando `python -version` en un proceso separado y esperará a que se complete. El código de retorno de la orden se almacenará en la variable código_de_retorno, que será cero si la orden ha tenido éxito, y distinto de cero si ha fallado.

subproceso.llamar() es útil cuando quieres ejecutar una orden y comprobar el código de retorno, pero no necesitas capturar la salida.

subproceso python comprobar_salida

check_output es una función del módulo subproceso que es similar a run(), pero sólo devuelve la salida estándar del comando, y lanza una excepción CalledProcessError si el código de retorno es distinto de cero.

La función check_output toma los mismos argumentos que run(), incluidos los argumentos que especifican la orden que se va a ejecutar, y otros argumentos opcionales, como stdin, stderr, shell, cwd y env.

La función check_output devuelve la salida estándar del comando como un objeto bytes o una cadena, si se pasa text=True.

import subprocess

try:

    output = subprocess.check_output(["python", "--version"], text=True)

    print(output)

except subprocess.CalledProcessError as e:

    print(f"Command failed with return code {e.returncode}")

Salida:

Python 3.8.8

Tubería de subproceso Python

El módulo de subprocesos de Python proporciona una forma de crear e interactuar con procesos hijos, que pueden utilizarse para ejecutar otros programas o comandos. Una de las características del módulo de subprocesos es la posibilidad de crear tuberías, que permiten la comunicación entre los procesos padre e hijo.

Una tubería es un canal de comunicación unidireccional que conecta la salida estándar de un proceso con la entrada estándar de otro. Una tubería puede conectar la salida de un comando a la entrada de otro, permitiendo que la salida del primer comando se utilice como entrada del segundo.

Las tuberías pueden crearse utilizando el módulo subproceso con la clase Popen, especificando el argumento stdout o stdin como subproceso.PIPE.

Por ejemplo, el siguiente código crea una tubería que conecta la salida del comando ls con la entrada del comando grep, que filtra la salida para mostrar sólo las líneas que contienen la palabra "archivo":

import subprocess

ls_process = subprocess.Popen(["ls"], stdout=subprocess.PIPE, text=True)

grep_process = subprocess.Popen(["grep", "sample"], stdin=ls_process.stdout, stdout=subprocess.PIPE, text=True)

output, error = grep_process.communicate()

print(output)

print(error)

Salida:

sample_data

En este ejemplo, la clase Popen se utiliza para crear dos procesos hijos, uno para el comando ls y otro para el comando grep. La salida estándar del comando ls se conecta a la entrada estándar del comando grep mediante subproceso.PIPE, que crea una tubería entre los dos procesos. El método communicate() se utiliza para enviar la salida del comando ls al comando grep y recuperar la salida filtrada.

Conclusión

El módulo `subproceso` de Python proporciona una forma potente y flexible de crear e interactuar con procesos hijo, permitiéndote ejecutar otros programas o emitir comandos desde dentro de tu script de Python. Desde comandos sencillos como subprocess.call() hasta funciones más avanzadas como tuberías, redireccionamiento de entrada y salida, y paso de variables de entorno, el módulo subproceso tiene algo que ofrecer para casi todos los casos de uso. Es una forma estupenda de automatizar tareas repetitivas, ejecutar comandos del sistema e incluso interactuar con otros lenguajes y plataformas de programación.

Cuando trabajes con el módulo de subprocesos, es importante que recuerdes que ejecutar comandos externos supone un riesgo para la seguridad, sobre todo si utilizas el parámetro shell=True o pasas una entrada no desinfectada. Siempre es una buena práctica utilizar la función subproceso.ejecutar(), que te permite especificar varias opciones sobre cómo debe ejecutarse el comando, como por ejemplo si debe lanzar una excepción si el comando falla. 

Si te interesa profundizar en las infinitas posibilidades de automatización de la línea de comandos mediante Python, consulta nuestro curso Automatización de la línea de comand os en Python. En este curso, aprenderás a escribir un código de automatización que recorrerá un sistema de archivos, buscará archivos que sigan un patrón y, a continuación, determinará si los archivos son duplicados en uno de los numerosos casos. Al finalizar el curso, serás capaz de gestionar e interactuar con procesos Unix, así como de automatizar diversas actividades rutinarias del sistema de archivos. 

Preguntas frecuentes sobre subprocesos en Python

¿Cuál es la diferencia entre subproceso.llamar() y subproceso.ejecutar()?

subprocess.call() es una función que ejecuta una orden y espera a que se complete, devolviendo el código de retorno de la orden. subprocess.run() es una función más potente que te permite ejecutar una orden, capturar su salida y especificar varias opciones sobre cómo debe ejecutarse la orden, como por ejemplo si debe lanzar una excepción si la orden falla.

¿Cómo puedo ejecutar un comando y capturar su salida en Python utilizando un subproceso?

Puedes utilizar la función subproceso.ejecutar() para ejecutar una orden y capturar su salida en una sola llamada. Por ejemplo, el siguiente código ejecuta el comando "ls" y captura su salida en la variable "resultado":

importar subproceso

resultado = subproceso.ejecutar(["ls"], stdout=subproceso.PIPE)

print(result.stdout.decode())

¿Cómo puedo pasar variables como argumentos a un comando en un subproceso?

Puedes pasar variables como argumentos a un comando del subproceso incluyéndolas en la lista que se pasa a las funciones subprocess.run() o subprocess.Popen(). Por ejemplo, el siguiente código ejecuta el comando "echo" y pasa el valor de la variable "mensaje" como argumento:

importar subproceso

mensaje = "¡Hola, mundo!"

subprocess.run(["echo", message])

¿Cómo puedo redirigir la salida de un comando a un archivo utilizando un subproceso?

Puedes redirigir la salida de un comando a un archivo utilizando el operador ">" en el comando. Por ejemplo, el siguiente código ejecuta el comando "ls" y redirige su salida a un archivo llamado "ls.txt":

importar subproceso

subprocess.run("ls > ls.txt", shell=True)

¿Cómo puedo ejecutar un comando en segundo plano utilizando un subproceso?

Puedes ejecutar un comando en segundo plano estableciendo el parámetro start_new_session a True al crear un nuevo proceso mediante subprocess.Popen(). Esto creará un nuevo grupo de procesos, permitiéndote ejecutar el comando en segundo plano.

importar subproceso

subprocess.Popen(["ls"], start_new_session=True)

¿Cómo puedo comprobar el código de retorno de una orden ejecutada mediante subproceso?

Puedes comprobar el código de retorno de una orden accediendo al atributo returncode del objeto subproceso.CompletedProcess devuelto por subproceso.run(). Por ejemplo, el siguiente código ejecuta el comando "ls" y comprueba su código de retorno:

importar subproceso

result = subprocess.run(["ls"])

if result.returncode == 0:

    print("Comando ejecutado correctamente")

si no:

    print("Comando fallido con código de error", result.returncode)

¿Cómo puedo pasar variables de entorno a un comando ejecutado mediante subproceso?

Puedes pasar variables de entorno a un comando incluyéndolas en un diccionario y pasando ese diccionario como parámetro env al crear un nuevo proceso mediante subproceso.Popen() o subproceso.run(). Por ejemplo, el siguiente código establece la variable de entorno "TEST_VAR" y ejecuta el comando "printenv":

importar subproceso

env = {'TEST_VAR': 'test_value'}

subprocess.run(["printenv", "TEST_VAR"], env=env)
Temas
Relacionado

tutorial

Tutorial sobre cómo ejecutar scripts en Python

Aprenda cómo puede ejecutar un script Python desde la línea de comandos, y también cómo puede proporcionar argumentos de línea de comandos a su script.
Aditya Sharma's photo

Aditya Sharma

10 min

tutorial

Tutorial de multiprocesamiento en Python

Descubra los fundamentos del multiprocesamiento en Python y las ventajas que puede aportar a sus flujos de trabajo.
Kurtis Pykes 's photo

Kurtis Pykes

6 min

tutorial

Tutorial sobre cómo trabajar con módulos en Python

Los módulos te permiten dividir partes de tu programa en archivos diferentes para facilitar el mantenimiento y mejorar el rendimiento.

Nishant Kumar

8 min

tutorial

Configurar VSCode para Python: Guía completa

Experimenta una forma sencilla, divertida y productiva de desarrollar en Python conociendo VSCode y sus extensiones y funciones.
Abid Ali Awan's photo

Abid Ali Awan

16 min

tutorial

Desarrollo de backend en Python: Guía completa para principiantes

Esta completa guía te enseña los fundamentos del desarrollo backend en Python. Aprende conceptos básicos, marcos de trabajo y buenas prácticas para empezar a crear aplicaciones web.
Oluseye Jeremiah's photo

Oluseye Jeremiah

26 min

tutorial

Tutorial de funciones de Python

Un tutorial sobre funciones en Python que cubre cómo escribir funciones, cómo invocarlas y mucho más.
Karlijn Willems's photo

Karlijn Willems

14 min

See MoreSee More