¿Qué son los Bucles?
Los bucles son estructuras de control que nos permiten repetir una secuencia de comandos múltiples veces. Son fundamentales para la automatización, ya que nos evitan escribir el mismo código repetidamente y nos permiten procesar grandes cantidades de datos de manera eficiente.
Bash proporciona tres tipos principales de bucles: for, while y until. Cada uno tiene sus casos de uso específicos y características únicas.
Comparación de Tipos de Bucles
Bucle FOR
Uso: Cuando conoces de antemano cuántas veces quieres repetir algo o tienes una lista específica de elementos.
Ejemplo: Procesar cada archivo en un directorio, iterar números del 1 al 10.
Bucle WHILE
Uso: Cuando quieres repetir mientras una condición sea verdadera.
Ejemplo: Leer líneas de un archivo, esperar hasta que un proceso termine.
Bucle UNTIL
Uso: Cuando quieres repetir hasta que una condición se vuelva verdadera.
Ejemplo: Intentar conectar hasta que la conexión sea exitosa.
Bucle FOR
El bucle for es probablemente el más utilizado. Tiene varias sintaxis dependiendo del caso de uso.
Sintaxis Básica con Lista
for variable in lista
do
# comandos a ejecutar
done
Ejemplos Prácticos
#!/bin/bash
# Procesar todos los archivos .txt en el directorio actual
for archivo in *.txt
do
echo "Procesando: $archivo"
# Contar líneas del archivo
lineas=$(wc -l < "$archivo")
echo " El archivo $archivo tiene $lineas líneas"
done
$ ./procesar_archivos.sh
Procesando: documento1.txt
El archivo documento1.txt tiene 25 líneas
Procesando: notas.txt
El archivo notas.txt tiene 15 líneas
Procesando: readme.txt
El archivo readme.txt tiene 8 líneas
#!/bin/bash
# Crear respaldos numerados
for ((i=1; i<=5; i++))
do
echo "Creando respaldo número $i"
cp important_file.txt "backup_${i}.txt"
done
#!/bin/bash
# Crear directorios del 2023 al 2025
for año in $(seq 2023 2025)
do
mkdir -p "reportes_$año"
echo "Directorio reportes_$año creado"
done
# También puedes usar expansión de llaves
for mes in {01..12}
do
mkdir -p "mes_$mes"
echo "Directorio mes_$mes creado"
done
Consejo Pro
Siempre usa comillas dobles alrededor de las variables que representen nombres de archivo: "$archivo". Esto previene problemas con espacios en los nombres.
Bucle WHILE
El bucle while ejecuta comandos mientras una condición sea verdadera. Es ideal cuando no sabes exactamente cuántas iteraciones necesitarás.
while [ condición ]
do
# comandos a ejecutar
done
Ejemplos Prácticos
#!/bin/bash
# Contador del 1 al 10
contador=1
while [ $contador -le 10 ]
do
echo "Iteración número: $contador"
((contador++)) # Incrementar contador
done
echo "¡Bucle terminado!"
#!/bin/bash
# Leer un archivo línea por línea
archivo="datos.txt"
numero_linea=1
while IFS= read -r linea
do
echo "Línea $numero_linea: $linea"
((numero_linea++))
done < "$archivo"
#!/bin/bash
# Esperar hasta que un proceso termine
proceso="mi_aplicacion"
while pgrep "$proceso" > /dev/null
do
echo "El proceso $proceso sigue corriendo..."
echo "Esperando 5 segundos..."
sleep 5
done
echo "El proceso $proceso ha terminado"
$ ./monitor_proceso.sh
El proceso mi_aplicacion sigue corriendo...
Esperando 5 segundos...
El proceso mi_aplicacion sigue corriendo...
Esperando 5 segundos...
El proceso mi_aplicacion ha terminado
Bucle UNTIL
El bucle until es lo opuesto a while: ejecuta comandos hasta que una condición se vuelva verdadera. Es útil cuando queremos repetir algo hasta alcanzar un objetivo.
until [ condición ]
do
# comandos a ejecutar
done
Ejemplos Prácticos
#!/bin/bash
# Esperar hasta que aparezca un archivo
archivo_esperado="/tmp/resultado.txt"
echo "Esperando que aparezca el archivo: $archivo_esperado"
until [ -f "$archivo_esperado" ]
do
echo "Archivo no encontrado, esperando 2 segundos..."
sleep 2
done
echo "¡El archivo ha aparecido!"
echo "Contenido del archivo:"
cat "$archivo_esperado"
#!/bin/bash
# Intentar conectar hasta que funcione
servidor="google.com"
intentos=0
echo "Intentando conectar con $servidor..."
until ping -c 1 "$servidor" &> /dev/null
do
((intentos++))
echo "Intento $intentos fallido, reintentando en 3 segundos..."
sleep 3
# Limitar intentos para evitar bucle infinito
if [ $intentos -ge 10 ]; then
echo "Error: No se pudo conectar después de $intentos intentos"
exit 1
fi
done
echo "¡Conexión exitosa con $servidor después de $intentos intentos!"
Cuidado con los Bucles Infinitos
Siempre asegúrate de que la condición del bucle pueda cambiar eventualmente, o incluye un mecanismo de escape como un contador de intentos máximos.
Bucles Anidados
Puedes anidar bucles para crear estructuras más complejas. Esto es útil para operaciones matriciales o procesamiento de estructuras de datos multidimensionales.
#!/bin/bash
# Generar tabla de multiplicar del 1 al 5
echo "Tabla de multiplicar:"
echo "====================="
for i in {1..5}
do
for j in {1..5}
do
resultado=$((i * j))
printf "%2d x %2d = %2d " $i $j $resultado
done
echo # Nueva línea al final de cada fila
done
$ ./tabla_multiplicar.sh
Tabla de multiplicar:
=====================
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5
2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10
3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15
4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16 4 x 5 = 20
5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25
Casos de Uso Avanzados
Procesamiento de Archivos
#!/bin/bash
# Comprimir archivos modificados hace más de 30 días
for archivo in $(find /var/log -name "*.log" -mtime +30)
do
if [ -f "$archivo" ]; then
echo "Comprimiendo: $archivo"
gzip "$archivo"
echo "Comprimido: ${archivo}.gz"
fi
done
Respaldo Automático
#!/bin/bash
# Lista de bases de datos a respaldar
bases_datos=("usuarios" "productos" "ventas")
for bd in "${bases_datos[@]}"
do
fecha=$(date +%Y%m%d_%H%M%S)
archivo_respaldo="${bd}_backup_${fecha}.sql"
echo "Respaldando base de datos: $bd"
mysqldump -u usuario -p "$bd" > "$archivo_respaldo"
if [ $? -eq 0 ]; then
echo "✓ Respaldo exitoso: $archivo_respaldo"
else
echo "✗ Error en respaldo de: $bd"
fi
done
Ejercicios Prácticos
Ejercicio 1: Organizador de Archivos
Crea un script que organice archivos por extensión:
#!/bin/bash
# Organizar archivos por extensión
directorio_origen="${1:-.}" # Usa directorio actual si no se especifica
echo "Organizando archivos en: $directorio_origen"
# Crear directorios para diferentes tipos de archivos
for tipo in "imagenes" "documentos" "videos" "audios" "otros"
do
mkdir -p "$tipo"
done
# Procesar archivos
for archivo in "$directorio_origen"/*
do
if [ -f "$archivo" ]; then
nombre=$(basename "$archivo")
extension="${nombre##*.}"
case "$extension" in
jpg|jpeg|png|gif|bmp)
echo "Moviendo imagen: $nombre"
mv "$archivo" "imagenes/"
;;
pdf|doc|docx|txt|rtf)
echo "Moviendo documento: $nombre"
mv "$archivo" "documentos/"
;;
mp4|avi|mkv|mov)
echo "Moviendo video: $nombre"
mv "$archivo" "videos/"
;;
mp3|wav|flac|aac)
echo "Moviendo audio: $nombre"
mv "$archivo" "audios/"
;;
*)
echo "Moviendo a otros: $nombre"
mv "$archivo" "otros/"
;;
esac
fi
done
echo "¡Organización completa!"
Ejercicio 2: Monitor de Sistema
Crea un script que monitoree el uso de CPU y memoria cada 5 segundos:
#!/bin/bash
# Monitor de sistema simple
echo "Monitor de Sistema - Presiona Ctrl+C para salir"
echo "================================================"
contador=0
while true
do
clear
echo "Monitor de Sistema - Actualización #$((++contador))"
echo "Hora: $(date)"
echo "================================================"
# CPU
cpu_uso=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//')
echo "Uso de CPU: ${cpu_uso}%"
# Memoria
memoria_info=$(free -h | grep "Mem:")
echo "Memoria: $memoria_info"
# Procesos con más CPU
echo ""
echo "Top 5 procesos por CPU:"
ps aux --sort=-%cpu | head -6
echo ""
echo "Esperando 5 segundos... (Ctrl+C para salir)"
sleep 5
done