stdin, stdout y stderr: los tres canales de todo proceso

Cuando un proceso arranca en Linux, el sistema operativo le entrega tres canales de comunicación ya abiertos, sin que el programa tenga que pedirlos. Se llaman stdin, stdout y stderr, y están identificados por los números 0, 1 y 2 respectivamente. Son file descriptors, es decir, referencias numéricas a recursos de I/O que el kernel gestiona por cada proceso. No son ficheros en disco, aunque se comporten como si lo fueran: son abstracciones que pueden apuntar al teclado, a la pantalla, a un pipe, a un socket, o a cualquier cosa que el sistema operativo sepa leer o escribir.

El diseño de tres canales separados no es arbitrario. stdin (fd 0) es la entrada: por defecto apunta al teclado, y el proceso lee de ahí cuando espera datos del usuario o de otro programa. stdout (fd 1) es la salida normal: por defecto apunta a la terminal, y el proceso escribe ahí sus resultados, sus datos, lo que quiere comunicar hacia afuera. stderr (fd 2) es la salida de errores y diagnóstico: también apunta a la terminal por defecto, pero es un canal completamente independiente de stdout.

Esa independencia es el punto clave. Si stdout y stderr fueran el mismo canal, no podrías encadenar programas de forma fiable. Cuando escribes programa_a | programa_b, el shell conecta el stdout de programa_a al stdin de programa_b. Si programa_a mezcla errores con datos en el mismo stream, programa_b recibiría basura entre los datos útiles. Al tener stderr separado, los mensajes de error van directamente a tu terminal sin contaminar el pipe. stdout es para datos. stderr es para mensajes al operador.

¿Cuándo te importa saber esto? En cuanto empieces a redirigir salida, a encadenar comandos con pipes, o a escribir scripts que otros programas van a consumir. Si no entiendes que un mensaje de error aparece en pantalla aunque hayas redirigido la salida a un fichero, pasarás un buen rato desconcertado. Y si mezclas los dos streams sin querer en un script, el programa siguiente en la cadena leerá mensajes de error como si fueran datos válidos.

# Ejecutamos un comando que produce salida normal Y un error
# ls lista el directorio actual (stdout) y falla con el que no existe (stderr)
ls /tmp /directorio_que_no_existe

# Para ver que son canales distintos, redirigimos solo stdout a un fichero
# El error sigue apareciendo en la terminal porque stderr no está redirigido
ls /tmp /directorio_que_no_existe > /tmp/salida_normal.txt

# Comprobamos qué capturó el fichero: solo los datos de stdout
cat /tmp/salida_normal.txt

# Ahora redirigimos solo stderr a otro fichero
# La salida normal aparece en la terminal; el error va al fichero
ls /tmp /directorio_que_no_existe 2> /tmp/solo_errores.txt

# Verificamos el fichero de errores
cat /tmp/solo_errores.txt

# echo siempre escribe en stdout
echo "este mensaje va a stdout"

# Para escribir en stderr desde bash hay que redirigir explícitamente al fd 2
echo "este es un error" >&2

Fíjate en lo que pasa con el primer ls: ves tanto la lista de /tmp como el mensaje de error, y visualmente parecen lo mismo porque los dos van a la terminal. Esa ilusión es exactamente lo que lleva a confusión. El shell los está escribiendo por separado, en canales distintos, pero tu emulador de terminal los mezcla en pantalla porque ambos terminan apuntando al mismo destino físico.

Cuando añades > /tmp/salida_normal.txt, le dices al shell que conecte el fd 1 de ls a ese fichero. El fd 2 no se toca: sigue apuntando a la terminal. Por eso el error aparece en pantalla aunque hayas redirigido la salida. No es que la redirección falle, es que redirigiste el canal correcto y el error viaja por el canal que no tocaste.

La sintaxis 2> hace lo mismo pero para el fd 2: conecta stderr al fichero indicado, dejando stdout intacto apuntando a la terminal. El número antes del > es literalmente el número del file descriptor.

La última línea del ejemplo, echo "este es un error" >&2, muestra cómo un script puede escribir deliberadamente en stderr. La notación >&2 significa “redirige mi stdout al mismo destino al que apunta el fd 2”. En un script bien escrito, los mensajes de diagnóstico, advertencias y errores van a stderr, y los datos que otro programa va a consumir van a stdout. Así cualquiera que use tu script puede separar unos de otros sin adivinar nada.

40

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio