Introducción a las Redirecciones
En Bash, las redirecciones y pipes son mecanismos fundamentales para manipular el flujo de datos. Permiten dirigir la salida de un comando hacia un archivo, tomar entrada desde un archivo, o conectar múltiples comandos para crear flujos de procesamiento complejos.
Todo proceso en Unix/Linux tiene tres flujos de datos estándar:
- stdin (0): Entrada estándar - donde el proceso lee datos
- stdout (1): Salida estándar - donde el proceso escribe resultados normales
- stderr (2): Error estándar - donde el proceso escribe mensajes de error
Flujos de Datos Estándar
Redirecciones Básicas
Operadores de Redirección
Operador | Significado | Ejemplo | Descripción |
---|---|---|---|
> | Redirigir salida | ls > archivo.txt |
Guarda la salida en archivo (sobrescribe) |
>> | Agregar salida | echo "texto" >> archivo.txt |
Agrega la salida al final del archivo |
< | Redirigir entrada | sort < archivo.txt |
Toma entrada desde archivo |
2> | Redirigir errores | comando 2> errores.txt |
Guarda errores en archivo |
2>> | Agregar errores | comando 2>> errores.txt |
Agrega errores al archivo |
&> | Redirigir todo | comando &> todo.txt |
Redirige stdout y stderr |
# Ejemplos básicos de redirección
$ echo "¡Hola mundo!" > saludo.txt
$ cat saludo.txt
¡Hola mundo!
# Agregar contenido sin sobrescribir
$ echo "Segunda línea" >> saludo.txt
$ cat saludo.txt
¡Hola mundo!
Segunda línea
# Redirigir lista de archivos a archivo
$ ls -la > lista_archivos.txt
$ head -5 lista_archivos.txt
total 24
drwxr-xr-x 2 user user 4096 oct 15 10:30 .
drwxr-xr-x 5 user user 4096 oct 15 10:25 ..
-rw-r--r-- 1 user user 30 oct 15 10:31 lista_archivos.txt
-rw-r--r-- 1 user user 27 oct 15 10:30 saludo.txt
Manejo de Errores
Una de las características más poderosas de las redirecciones es la capacidad de manejar errores de forma independiente de la salida normal:
# Intentar listar un directorio que no existe
$ ls directorio_inexistente
ls: cannot access 'directorio_inexistente': No such file or directory
# Redirigir solo los errores
$ ls directorio_inexistente 2> errores.txt
$ cat errores.txt
ls: cannot access 'directorio_inexistente': No such file or directory
# Redirigir salida normal y errores a archivos diferentes
$ ls /home /directorio_inexistente > salida.txt 2> errores.txt
$ cat salida.txt
/home:
usuario1
usuario2
$ cat errores.txt
ls: cannot access '/directorio_inexistente': No such file or directory
# Redirigir tanto salida como errores al mismo archivo
$ ls /home /directorio_inexistente > todo.txt 2>&1
$ cat todo.txt
ls: cannot access '/directorio_inexistente': No such file or directory
/home:
usuario1
usuario2
Importante
El operador 2>&1
redirige stderr (2) hacia donde ya va stdout (1). El orden importa: > archivo.txt 2>&1
funciona, pero 2>&1 > archivo.txt
no hará lo que esperas.
Pipes: Conectando Comandos
Los pipes (tubería, simbolizada por |) permiten conectar la salida de un comando con la entrada de otro, creando cadenas de procesamiento eficientes.
Funcionamiento de un Pipe
La salida de comando1 se convierte en la entrada de comando2, y así sucesivamente
# Ejemplos básicos de pipes
$ ls -la | grep ".txt"
-rw-r--r-- 1 user user 30 oct 15 10:31 lista_archivos.txt
-rw-r--r-- 1 user user 27 oct 15 10:30 saludo.txt
# Contar líneas de archivos de texto
$ ls -la | grep ".txt" | wc -l
2
# Ver procesos y filtrar por usuario
$ ps aux | grep $USER | head -5
user 1234 0.0 0.1 12345 6789 ? S 10:30 0:00 bash
user 1235 0.0 0.2 23456 7890 ? S 10:30 0:01 firefox
user 1236 0.1 0.3 34567 8901 ? R 10:31 0:02 chrome
# Cadena más compleja: buscar archivos grandes
$ find /home/$USER -type f | xargs ls -la | sort -k5 -nr | head -10
Pipes Comunes y Útiles
Combinaciones Frecuentes
# 1. Análisis de logs
tail -f /var/log/syslog | grep "error"
# 2. Procesos consumiendo más memoria
ps aux | sort -k4 -nr | head -10
# 3. Encontrar archivos duplicados por tamaño
find . -type f | xargs ls -la | sort -k5 -n | uniq -D -f4
# 4. Contar tipos de archivos
find . -type f | grep -E '\.[^.]+$' | sed 's/.*\.//' | sort | uniq -c | sort -nr
# 5. Monitoreo de espacio en disco
df -h | grep -v tmpfs | sort -k5 -nr
# 6. Top 10 de comandos más usados
history | awk '{print $2}' | sort | uniq -c | sort -nr | head -10
# 7. Buscar texto en múltiples archivos
grep -r "función" . | cut -d: -f1 | sort | uniq
# 8. Análisis de conexiones de red
netstat -an | grep ESTABLISHED | wc -l
Tip Profesional
Los pipes son una de las características más poderosas de Unix/Linux. Dominar combinaciones como grep
, sort
, uniq
, cut
, y awk
te convertirá en un usuario mucho más eficiente.
Redirecciones Avanzadas
Here Documents y Here Strings
Bash ofrece métodos avanzados para proporcionar entrada a comandos usando here documents (<<
) y here strings (<<<
):
# Here Document - entrada multilínea
$ cat << EOF > mi_archivo.txt
Esta es la línea 1
Esta es la línea 2
Línea con variable: $USER
EOF
$ cat mi_archivo.txt
Esta es la línea 1
Esta es la línea 2
Línea con variable: usuario
# Here Document sin expansión de variables (EOF entre comillas)
$ cat << 'EOF' > literal.txt
Esta línea contiene $USER literal
No se expande la variable
EOF
# Here String - entrada de una línea
$ grep "bash" <<< "Mi shell favorito es bash"
Mi shell favorito es bash
# Usar here string con variables
$ nombre="Juan"
$ grep "Juan" <<< "El usuario es $nombre"
El usuario es Juan
Redirecciones con Descriptores de Archivo
# Abrir archivo para lectura (descriptor 3)
$ exec 3< mi_archivo.txt
$ read -u 3 linea
$ echo $linea
Esta es la línea 1
# Abrir archivo para escritura (descriptor 4)
$ exec 4> salida_personalizada.txt
$ echo "Escribiendo en descriptor 4" >&4
$ exec 4>&- # Cerrar el descriptor
# Intercambiar stdout y stderr
$ comando 3>&1 1>&2 2>&3 3>&-
Descriptores de Archivo
Los descriptores de archivo son números que el sistema usa para referenciar archivos abiertos. 0, 1, y 2 están reservados para stdin, stdout, y stderr respectivamente. Puedes usar descriptores del 3 al 9 para tus propios propósitos.
Trucos y Técnicas Avanzadas
Tee: Duplicar el Flujo
El comando tee
permite ver la salida en pantalla mientras también la guardas en un archivo:
# Ver y guardar al mismo tiempo
$ ls -la | tee lista.txt
total 16
drwxr-xr-x 2 user user 4096 oct 15 11:00 .
drwxr-xr-x 5 user user 4096 oct 15 10:25 ..
-rw-r--r-- 1 user user 0 oct 15 11:00 lista.txt
-rw-r--r-- 1 user user 27 oct 15 10:30 saludo.txt
# Agregar con tee (opción -a)
$ date | tee -a lista.txt
vie oct 15 11:00:00 UTC 2021
# Dividir salida hacia múltiples archivos
$ echo "Información importante" | tee archivo1.txt archivo2.txt archivo3.txt
Process Substitution
La sustitución de procesos <(...)
y >(...)
permite usar la salida de un comando como si fuera un archivo:
# Comparar salidas de dos comandos
$ diff <(ls /bin) <(ls /usr/bin) | head -5
1,3c1,3
< bash
< cat
< chgrp
---
> X11
> [
> aa-enabled
# Usar salida de comando como archivo de entrada
$ sort <(echo -e "c\na\nb")
a
b
c
# Process substitution para salida
$ echo "contenido" > >(cat > nuevo_archivo.txt)
$ cat nuevo_archivo.txt
contenido
Nota sobre Portabilidad
Process substitution es una característica específica de Bash y no está disponible en todos los shells. Si necesitas compatibilidad con sh, usa archivos temporales en su lugar.
Casos Prácticos y Ejemplos Reales
#!/bin/bash
# Script de respaldo con logs detallados
BACKUP_DIR="/backup"
LOG_FILE="/var/log/backup.log"
ERROR_FILE="/var/log/backup_errors.log"
# Función que hace respaldo y registra todo
hacer_respaldo() {
echo "=== Iniciando respaldo $(date) ===" | tee -a "$LOG_FILE"
# Respaldo con logs de progreso y errores separados
tar -czf "$BACKUP_DIR/backup_$(date +%Y%m%d).tar.gz" /home 2> >(tee -a "$ERROR_FILE") | tee -a "$LOG_FILE"
# Verificar si hubo errores
if [ -s "$ERROR_FILE" ]; then
echo "¡ADVERTENCIA: Se encontraron errores!" | tee -a "$LOG_FILE"
echo "Revisa $ERROR_FILE para más detalles" | tee -a "$LOG_FILE"
fi
echo "=== Respaldo completado $(date) ===" | tee -a "$LOG_FILE"
}
# Análisis de logs del sistema
analizar_logs() {
echo "Análisis de logs del sistema:" > informe.txt
echo "=============================" >> informe.txt
# Errores más frecuentes
echo -e "\nErrores más frecuentes:" >> informe.txt
grep -i error /var/log/syslog | cut -d' ' -f6- | sort | uniq -c | sort -nr | head -10 >> informe.txt
# Actividad por hora
echo -e "\nActividad por hora:" >> informe.txt
grep "$(date '+%b %d')" /var/log/syslog | cut -d' ' -f3 | cut -d':' -f1 | sort | uniq -c >> informe.txt
echo "Informe generado en informe.txt"
}
#!/bin/bash
# Script de monitoreo del sistema
# Función que genera reporte del sistema
generar_reporte() {
{
echo "REPORTE DEL SISTEMA - $(date)"
echo "================================="
echo
echo "MEMORIA:"
free -h | grep -E "(Mem|Swap)"
echo
echo "DISCO:"
df -h | grep -v tmpfs | sort -k5 -nr
echo
echo "TOP PROCESOS POR CPU:"
ps aux --sort=-%cpu | head -6
echo
echo "TOP PROCESOS POR MEMORIA:"
ps aux --sort=-%mem | head -6
echo
echo "CONEXIONES DE RED:"
netstat -an | grep ESTABLISHED | wc -l | xargs echo "Conexiones activas:"
} | tee "reporte_sistema_$(date +%Y%m%d_%H%M).txt"
}
# Monitoreo continuo con alertas
monitoreo_continuo() {
while true; do
# Verificar uso de CPU
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
# Si CPU > 80%, registrar procesos
if (( $(echo "$cpu_usage > 80" | bc -l) )); then
{
echo "ALERTA: CPU alto $(date)"
ps aux --sort=-%cpu | head -10
echo "========================"
} >> alertas_sistema.log
fi
sleep 60
done &
}
Ejercicios Prácticos
Ejercicio 1: Análisis de Archivos
Crea un script que analice los archivos en tu directorio home:
# 1. Crear lista de todos los archivos con tamaños
find $HOME -type f -exec ls -la {} \; > inventario_archivos.txt
# 2. Encontrar los 10 archivos más grandes
find $HOME -type f -exec ls -la {} \; | sort -k5 -nr | head -10 > archivos_grandes.txt
# 3. Contar archivos por extensión
find $HOME -type f | grep -E '\.[^.]+$' | sed 's/.*\.//' | sort | uniq -c | sort -nr > extensiones.txt
# 4. Buscar archivos duplicados por tamaño
find $HOME -type f -exec ls -la {} \; | awk '{print $5, $NF}' | sort | uniq -d -f1 > posibles_duplicados.txt
# 5. Generar reporte combinado
{
echo "REPORTE DE ANÁLISIS DE ARCHIVOS"
echo "==============================="
echo
echo "ARCHIVOS MÁS GRANDES:"
head -5 archivos_grandes.txt
echo
echo "EXTENSIONES MÁS COMUNES:"
head -10 extensiones.txt
echo
echo "POSIBLES DUPLICADOS:"
wc -l posibles_duplicados.txt
} | tee reporte_archivos.txt
Ejercicio 2: Log de Sistema
Analiza los logs del sistema y crea un dashboard en texto:
# 1. Análisis básico de syslog (donde esté disponible)
sudo tail -1000 /var/log/syslog 2>/dev/null | grep -i error | head -10 > errores_recientes.txt
# 2. Si no hay syslog, usar dmesg
dmesg | tail -100 | grep -i error > errores_kernel.txt 2>/dev/null || echo "Sin acceso a dmesg" > errores_kernel.txt
# 3. Análisis de conexiones
{
echo "CONEXIONES DE RED ACTUALES:"
netstat -an 2>/dev/null | grep ESTABLISHED | wc -l | xargs echo "Total establecidas:"
echo
echo "PUERTOS EN ESCUCHA:"
netstat -tln 2>/dev/null | grep LISTEN | head -10
} > conexiones.txt 2>/dev/null || echo "netstat no disponible" > conexiones.txt
# 4. Dashboard final
{
echo "DASHBOARD DEL SISTEMA - $(date)"
echo "================================"
echo
echo "ERRORES RECIENTES:"
cat errores_recientes.txt errores_kernel.txt 2>/dev/null | head -5
echo
echo "ESTADO DE RED:"
cat conexiones.txt
echo
echo "USO DE RECURSOS:"
free -h 2>/dev/null | head -2 || echo "free no disponible"
df -h . | tail -1
} | tee dashboard_sistema.txt