Cuando un programa arranca en Linux, el sistema le abre automáticamente tres canales de comunicación: stdin (entrada estándar, descriptor de archivo 0), stdout (salida estándar, descriptor 1) y stderr (error estándar, descriptor 2). Por defecto los tres apuntan a la terminal: el programa lee lo que tecleas y escribe todo —mensajes normales y errores— en la misma pantalla. La redirección es el mecanismo por el que le dices al shell que cambie el destino o el origen de uno o varios de esos descriptores antes de lanzar el proceso.
El diseño es intencionado: los programas no saben ni les importa si están hablando con un terminal, un archivo o una tubería. Solo escriben en el descriptor 1 o en el 2, y el sistema operativo se encarga del resto. Eso es lo que hace posible componer herramientas pequeñas entre sí.
Usas redirección cuando quieres guardar la salida de un comando para revisarla después, cuando un programa necesita leer datos de un archivo en lugar del teclado, o cuando quieres separar —o reunir— los mensajes de error del resto de la salida. Si te equivocas en el orden de los operadores, el resultado puede ser exactamente el contrario de lo que buscas, y la salida acaba en la terminal cuando esperabas que fuera al archivo, o viceversa.
El caso más peligroso de equivocarse es usar > sobre un archivo que ya existe y que no querías machacar: el shell lo trunca a cero bytes antes de que el programa escriba la primera línea, sin preguntar. Si tus datos no estaban respaldados, desaparecieron.
# Instalar un paquete guardando TODO lo que produce el comando: # stdout y stderr juntos en un mismo archivo de log. apt install curl > /tmp/instalacion.log 2>&1 # Verificar qué quedó en el log (stdout del install más cualquier error) cat /tmp/instalacion.log # Añadir una segunda instalación al mismo log sin borrar la anterior apt install wget >> /tmp/instalacion.log 2>&1 # Hacer que un programa lea su entrada desde un archivo # en lugar de esperar que escribas en el teclado. # wall lee stdin y manda el mensaje a todos los terminales activos. wall < /etc/motd # Separar errores: solo stderr va a un archivo aparte; # stdout sigue apareciendo en la terminal. find /etc -name "*.conf" 2> /tmp/errores_find.txt # Silenciar completamente un comando: descartar stdout y stderr. # Útil en scripts cuando solo te interesa el código de salida. apt install curl > /dev/null 2>&1 echo "Código de salida: $?" # TRAMPA CLÁSICA — este orden es incorrecto: # stderr va a la terminal, no al archivo. # apt install curl 2>&1 > /tmp/mal.log # ← NO hagas esto si quieres capturar stderr
Vamos línea por línea por lo que realmente ocurre.
En apt install curl > /tmp/instalacion.log 2>&1, el shell procesa las redirecciones de izquierda a derecha. Primero ejecuta > /tmp/instalacion.log: abre el archivo y apunta el descriptor 1 hacia él. Después ejecuta 2>&1: copia el descriptor 1 —que en este momento ya apunta al archivo— al descriptor 2. Resultado: ambos van al archivo. Si invirtieras el orden (2>&1 > /tmp/instalacion.log), cuando el shell procesa 2>&1 el descriptor 1 todavía apunta a la terminal, así que el descriptor 2 queda atado a la terminal. Luego redirige el 1 al archivo, pero el 2 ya se movió antes y no se actualiza. Stderr sigue en pantalla.
El operador >> en apt install wget >> /tmp/instalacion.log 2>&1 abre el archivo en modo append: el cursor se posiciona al final antes de cada escritura. El contenido anterior no se toca. Usa > cuando quieres empezar limpio, >> cuando quieres acumular.
La línea wall < /etc/motd ilustra la redirección de stdin. El shell abre /etc/motd y conecta su descriptor de lectura al descriptor 0 de wall. El programa nunca sabe que no está leyendo del teclado; simplemente lee stdin y encuentra el contenido del archivo.
En find /etc -name "*.conf" 2> /tmp/errores_find.txt, solo el descriptor 2 se redirige. Los resultados normales —las rutas encontradas— siguen saliendo en la terminal. Los mensajes “Permission denied” van al archivo. Esto es útil cuando quieres ver el output en tiempo real pero registrar los errores para revisarlos después.
/dev/null es un archivo especial del kernel que descarta todo lo que escribas en él y devuelve EOF inmediatamente si intentas leerlo. > /dev/null 2>&1 es el patrón canónico para silenciar un comando completamente en scripts: ni stdout ni stderr aparecen en ningún sitio, pero $? te dice si el comando tuvo éxito o falló.
El atajo &> que ofrece bash (comando &> archivo) es equivalente a > archivo 2>&1 y más difícil de confundir porque no tiene orden interno, pero no está disponible en shells POSIX como dash —que es /bin/sh en Debian— así que evítalo en scripts que empiecen con #!/bin/sh.
N° 41