Entrada y salida estándar — Redirección de stdin/stdout
Al finalizar este tema
Podrás explicar las funciones de stdin, stdout y stderr, y conectar la entrada y salida de programas mediante redirección (>, <) y tuberías (|) en la terminal.
Tres canales
Cuando se ejecuta un programa, el sistema operativo abre automáticamente tres canales:
| Nombre | Dirección | Uso | Python |
|---|---|---|---|
| stdin (entrada estándar) | Externo → Programa | Entrada del teclado | input(), sys.stdin |
| stdout (salida estándar) | Programa → Externo | Resultado normal | print(), sys.stdout |
| stderr (error estándar) | Programa → Externo | Errores/advertencias | sys.stderr |
Por defecto, stdin está conectado al teclado y stdout y stderr a la pantalla (terminal).
print() escribe en stdout
# hello.pyprint("Hola") # salida a stdout$ python hello.pyHolaprint() llama internamente a sys.stdout.write(). También se puede usar directamente:
import sys
sys.stdout.write("salida a stdout\n")sys.stderr.write("salida a stderr\n")Ambas líneas aparecen en la pantalla, pero a través de canales diferentes. Esta diferencia se manifiesta en la redirección.
Redirección — canalizar a un archivo
En la terminal, > y < permiten cambiar la dirección de entrada/salida.
stdout a un archivo (>)
$ python hello.py > output.txtNo se muestra nada en la pantalla. El resultado de print() se guarda en el archivo output.txt.
$ cat output.txtHola>> continúa el contenido anterior:
$ python hello.py >> output.txt # agregar al final del contenido existenteEntrada estándar desde un archivo (<)
# count.pyimport syslines = sys.stdin.readlines()print(f"Total {len(lines)} líneas")$ python count.py < data.txtTotal 42 líneasEl contenido de data.txt se ingresa a través de stdin en lugar de la entrada del teclado.
Separar solo stderr
# process.pyimport sysprint("Resultado del procesamiento: éxito")sys.stderr.write("Advertencia: algunos datos faltan\n")$ python process.py > result.txt 2> error.txt> redirige únicamente la salida estándar (stdout), mientras que 2> redirige únicamente la salida de error estándar (stderr). Esto permite separar los resultados y los errores en archivos distintos.
Tubería — Conectar programas
| (tubería) conecta la salida estándar (stdout) del programa anterior con la entrada estándar (stdin) del programa siguiente:
$ cat data.csv | python process.py | python report.py > final.txtcat → (stdout) → | → (stdin) → process.py → (stdout) → | → (stdin) → report.py → final.txtCada programa recibe y procesa únicamente los datos que provienen de su entrada inmediata, y luego transfiere el resultado al siguiente paso. Este es el principio fundamental de la filosofía Unix, que consiste en combinar programas pequeños para realizar tareas complejas.
Lectura línea por línea desde stdin en Python
# upper.py — Convierte la entrada a mayúsculasimport sys
for line in sys.stdin: print(line.strip().upper())$ echo "hello world" | python upper.pyHELLO WORLD
$ cat names.txt | python upper.pyALICEBOBCHARLIEsys.stdin es iterable. Al leerlo línea por línea con un bucle for, se utiliza la memoria de manera eficiente.
La relación entre input() y stdin
name = input("Nombre: ") # Prompt → stderr? No, stdoutinput() internamente:
- imprime la cadena de entrada en stdout
- lee una línea desde stdin y la devuelve
Por lo tanto, se debe tener cuidado al usarlo con tuberías (pipes):
$ echo "Cheolsu" | python -c "name = input(); print(f'Hola, {name}')"Hola, CheolsuEn Pipe, los prompts carecen de significado; por lo tanto, al crear herramientas CLI, es preferible leer directamente sys.stdin en lugar de input().
Ejemplos de uso práctico
# csv_filter.py — Imprime solo las filas que cumplen una condición específicaimport sysimport csv
reader = csv.reader(sys.stdin)header = next(reader)print(",".join(header))
for row in reader: if float(row[2]) > 100: # La tercera columna es mayor que 100 print(",".join(row))$ cat sales.csv | python csv_filter.py > filtered.csvEl uso de stdin/stdout permite evitar codificar nombres de archivos en el código. Al poder conectar cualquier archivo mediante tuberías, se incrementa la reutilización del código.
Encadenamiento de tuberías — Filosofía UNIX
# Busca solo ERROR en los registros y ordénalos por frecuencia$ cat server.log | grep "ERROR" | sort | uniq -c | sort -rn | head -5Cada programa realiza una sola tarea de manera eficiente y se conecta mediante tuberías (pipes). Los scripts de Python también pueden formar parte de esta cadena:
# word_count.py — Calcula la frecuencia de palabrasimport sysfrom collections import Counter
words = []for line in sys.stdin: words.extend(line.strip().split())
for word, count in Counter(words).most_common(10): print(f"{count:>5} {word}")$ cat article.txt | python word_count.py 42 the 31 and 28 toMostrar el progreso mediante stderr
import sys
total = 1000for i in range(total): # Lógica de procesamiento... if i % 100 == 0: print(f'Progreso: {i}/{total}', file=sys.stderr)
print(f'Resultado: {i * 2}') # Salida real → stdout$ python process.py > results.txtProgreso: 0/1000 ← Visible en la pantalla (stderr)Progreso: 100/1000...La salida estándar (stdout) se redirige a un archivo y se guarda en results.txt, mientras que la salida de error estándar (stderr) sigue mostrándose en la pantalla. Este es un patrón práctico para separar los mensajes de progreso de los datos resultantes.
Resumen clave
| Sintaxis | Significado |
|---|---|
> | stdout a archivo (sobrescribir) |
>> | stdout a archivo (añadir al final) |
< | archivo como entrada estándar (stdin) |
2> | stderr a archivo |
| | stdout → stdin del siguiente programa |
2>&1 | fusionar stderr con stdout |
/dev/null — Descartar la salida
# Descartar stdout (solo ver errores)$ python noisy_script.py > /dev/null
# Descartar stderr (solo ver resultados)$ python noisy_script.py 2> /dev/null
# Descartar ambos (silencio total)$ python noisy_script.py > /dev/null 2>&1/dev/null es el "papelera". Se utiliza para suprimir la salida innecesaria en scripts automatizados.
# El mismo patrón en Pythonimport os, sys
if os.environ.get("QUIET"): sys.stdout = open(os.devnull, "w")subprocess — Configuración de tuberías en Python
import subprocess
# Ejecutar comando externo + capturar stdoutresult = subprocess.run( ["ls", "-la"], capture_output=True, text=True)print(result.stdout)print(result.stderr)
# Encadenamiento de tuberíasp1 = subprocess.Popen(["cat", "data.txt"], stdout=subprocess.PIPE)p2 = subprocess.Popen(["grep", "ERROR"], stdin=p1.stdout, stdout=subprocess.PIPE)output = p2.communicate()[0].decode()En Python, es posible conectar programáticamente la entrada estándar (stdin) y la salida estándar (stdout) de un comando del shell.
print() corresponde a stdout, mientras que los mensajes de error van a stderr. Comprender esta separación hace que la redirección y el uso de tuberías resulten más naturales.