El módulo subprocess en Python permite ejecutar programas externos y comandos del sistema desde un script. Es útil para automatizar herramientas, consultar versiones, comprimir archivos, ejecutar pruebas, invocar Git o conectar varias etapas de un flujo de trabajo.
La función recomendada para la mayoría de los casos es subprocess.run(). Ofrece control sobre argumentos, salida, errores, códigos de retorno, tiempo máximo y variables de entorno. Esta guía muestra cómo utilizarla de forma segura y portable.
Ejecutar el primer comando
import subprocess
result = subprocess.run(
["python", "--version"],
check=True,
)
print(result.returncode)Los argumentos se pasan como una lista. Cada elemento representa una parte del comando. Este formato evita problemas de espacios y reduce riesgos relacionados con la interpretación de texto por una shell.
La documentación oficial de subprocess recomienda run() para los casos que no necesitan una interacción avanzada con el proceso.
Capturar la salida estándar
import subprocess
result = subprocess.run(
["python", "--version"],
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
print(result.stderr.strip())capture_output=True conserva stdout y stderr. text=True convierte bytes en strings. Sin esa opción, el resultado se recibe como bytes.
La guía de strings en Python explica limpieza, codificación y transformación de texto.
Comprobar errores con check=True
Un comando puede terminar con un código diferente de cero. Sin check=True, Python devuelve el resultado y deja la validación al programa:
import subprocess
try:
result = subprocess.run(
["python", "missing_script.py"],
capture_output=True,
text=True,
check=True,
)
except subprocess.CalledProcessError as error:
print("El comando falló")
print(error.returncode)
print(error.stderr)La guía de try y except en Python explica cómo capturar excepciones específicas y conservar el contexto.
Establecer un tiempo máximo
import subprocess
try:
subprocess.run(
["python", "slow_task.py"],
timeout=10,
check=True,
)
except subprocess.TimeoutExpired:
print("El proceso superó el límite")Un timeout evita que una automatización quede bloqueada indefinidamente. El valor correcto depende de la tarea y del entorno.
Evitar shell=True cuando no sea necesario
El argumento shell=True envía una cadena a la shell del sistema. Puede ser necesario para pipes, redirecciones o comandos internos, pero aumenta el riesgo cuando el texto contiene datos externos:
# Evita construir comandos con entrada del usuario
subprocess.run(
f"tool --file {user_value}",
shell=True,
)Prefiere una lista:
subprocess.run(
["tool", "--file", user_value],
check=True,
)La sección de consideraciones de seguridad de subprocess explica la responsabilidad del desarrollador cuando utiliza una shell.
Ejecutar comandos diferentes según el sistema
import platform
import subprocess
system = platform.system()
if system == "Windows":
command = ["cmd", "/c", "dir"]
else:
command = ["ls", "-la"]
result = subprocess.run(
command,
capture_output=True,
text=True,
check=True,
)
print(result.stdout)Cuando la tarea puede resolverse con la biblioteca estándar, una solución nativa suele ser más portable. Para archivos, consulta pathlib en Python y el módulo os.
Definir el directorio de trabajo
from pathlib import Path
import subprocess
project = Path.home() / "projects" / "demo"
result = subprocess.run(
["git", "status", "--short"],
cwd=project,
capture_output=True,
text=True,
check=True,
)
print(result.stdout)cwd evita depender del directorio desde el que se inició el script.
Pasar variables de entorno
import os
import subprocess
environment = os.environ.copy()
environment["APP_MODE"] = "test"
subprocess.run(
["python", "app.py"],
env=environment,
check=True,
)No reemplaces todo el entorno con un diccionario pequeño, porque el proceso puede necesitar PATH y otras variables. Tampoco incluyas secretos en mensajes de error o logs.
Enviar datos a stdin
import subprocess
result = subprocess.run(
["python", "processor.py"],
input="first line\nsecond line\n",
capture_output=True,
text=True,
check=True,
)
print(result.stdout)input permite alimentar un proceso sin crear un archivo temporal.
Ejecutar una herramienta y convertir su salida
import json
import subprocess
result = subprocess.run(
["tool", "--format", "json"],
capture_output=True,
text=True,
check=True,
)
data = json.loads(result.stdout)
print(data)Valida siempre que la salida exista y tenga el formato esperado. Un proceso puede escribir mensajes de diagnóstico en stdout o stderr según su diseño.
Construir una función reutilizable
import subprocess
def run_command(command, *, cwd=None, timeout=30):
try:
return subprocess.run(
command,
cwd=cwd,
timeout=timeout,
capture_output=True,
text=True,
check=True,
)
except FileNotFoundError as error:
raise RuntimeError(
f"No se encontró el programa: {command[0]}"
) from error
except subprocess.TimeoutExpired as error:
raise RuntimeError(
"El comando superó el tiempo máximo"
) from error
except subprocess.CalledProcessError as error:
message = error.stderr.strip() or "Sin detalles"
raise RuntimeError(
f"El comando falló: {message}"
) from errorLa guía de funciones en Python ayuda a diseñar interfaces pequeñas y comprobables.
Crear una interfaz con argparse
Un script de automatización puede recibir parámetros y después ejecutar otra herramienta:
import argparse
import subprocess
parser = argparse.ArgumentParser()
parser.add_argument("filename")
args = parser.parse_args()
subprocess.run(
["python", "validator.py", args.filename],
check=True,
)La guía de argparse en Python explica opciones, tipos, ayuda y subcomandos.
Cuándo utilizar Popen
subprocess.Popen ofrece control de bajo nivel para procesos que deben continuar activos, intercambiar datos progresivamente o ejecutarse en paralelo. Para un comando que comienza, termina y devuelve un resultado, run() suele ser más claro.
Registrar sin exponer datos
import logging
logger = logging.getLogger(__name__)
logger.info("Ejecutando validación de archivos")Registra la operación general, duración y código de salida. Evita tokens, contraseñas, argumentos privados o contenido completo de archivos.
La guía de automatización de tareas con Python muestra cómo combinar comandos, archivos, validación y registros.
Errores frecuentes
- Construir una cadena con entrada del usuario y
shell=True. - Ignorar el código de retorno.
- No definir timeout para procesos externos.
- Depender del directorio actual.
- Suponer que stdout siempre contiene datos válidos.
- Reemplazar todas las variables de entorno.
- Registrar argumentos sensibles.
- Usar comandos del sistema para tareas que pathlib resuelve mejor.
Conclusión
subprocess.run() permite integrar herramientas externas con un control claro sobre argumentos, salida, errores y tiempo máximo. Utiliza listas de argumentos, activa check=True, captura únicamente lo necesario y evita una shell cuando el comando pueda ejecutarse directamente. Con estas prácticas, los scripts de automatización resultan más seguros, portables y fáciles de diagnosticar.






