Saltar a contenido

📚 Módulo 5: Organizando y escalando tareas

Duración estimada: 4-5 horas según tu ritmo y experiencia.

Objetivo: Organizar el código en funciones reutilizables, usar bucles avanzados (while, until), automatizar tareas con cron y personalizar el entorno con .bashrc. 🎯

Prerrequisitos: Haber completado los Módulos 1-4, saber crear scripts con variables, condicionales y bucles for.

Nota: Las funciones y los bucles avanzados marcan la transición de scripts simples a programas bien estructurados. Dedica tiempo a cada sección.


📖 Contenidos del Módulo

5.1. Funciones: Organiza y reutiliza tu código 🌱

Teoría:

Una función es un bloque de código con nombre que puedes llamar múltiples veces desde distintos puntos del script. Esto evita repetir código y hace los scripts más fáciles de leer y mantener. La sintaxis básica es:

nombre_funcion() {
    # comandos
}

Las funciones pueden recibir argumentos (accesibles como $1, $2, etc. dentro de la función) y devolver un valor de estado con return.

Práctica:

  1. Crea un script funciones.sh:
nano funciones.sh
  1. Define y llama a una función sencilla:
#!/bin/bash
saludar() {
    echo "¡Hola, $1!"
}
saludar "Mundo"
saludar "Bash"

Guarda, dale permisos (chmod +x funciones.sh) y ejecútalo.

  1. Añade una función que reciba dos argumentos:
nano funciones.sh
#!/bin/bash
saludar() {
    echo "¡Hola, $1! Tienes $2 años."
}
saludar "Ana" 28
saludar "Luis" 35
  1. Crea una función que realice un cálculo y guarde el resultado en una variable:
nano funciones.sh
#!/bin/bash
calcular_doble() {
    resultado=$(( $1 * 2 ))
    echo "$resultado"
}
doble=$(calcular_doble 7)
echo "El doble de 7 es: $doble"
  1. Añade una función que verifique si un archivo existe:
nano funciones.sh
#!/bin/bash
verificar_archivo() {
    if [ -f "$1" ]; then
        echo "El archivo '$1' existe."
    else
        echo "El archivo '$1' NO existe."
    fi
}
verificar_archivo "texto.txt"
verificar_archivo "inexistente.txt"

Consejo: Escribe una función para cada tarea concreta. Si una función hace más de una cosa, probablemente debería dividirse en dos. 💡


5.2. Bucles while y until: Repite hasta que sea necesario 🖌️

Teoría:

El bucle while ejecuta un bloque mientras la condición sea verdadera. El bucle until es su opuesto: ejecuta el bloque mientras la condición sea falsa (es decir, hasta que se cumpla). Ambos son ideales para situaciones en las que no sabes de antemano cuántas iteraciones necesitas.

# while: repite MIENTRAS la condición es verdadera
while [ condición ]; do
    comandos
done

# until: repite HASTA QUE la condición sea verdadera
until [ condición ]; do
    comandos
done

Advertencia: Asegúrate siempre de que la condición del bucle puede llegar a ser falsa. Un while true sin una salida explícita (break) crea un bucle infinito. 🛑

Práctica:

  1. Crea un script bucle_while.sh:
nano bucle_while.sh
#!/bin/bash
contador=1
while [ "$contador" -le 5 ]; do
    echo "Iteración: $contador"
    contador=$(( contador + 1 ))
done

Guarda, dale permisos y ejecútalo.

  1. Crea un bucle que lea líneas de un archivo:
nano leer.sh
#!/bin/bash
while IFS= read -r linea; do
    echo "Línea: $linea"
done < texto.txt

IFS= evita que se recorten los espacios iniciales y finales; -r evita que read interprete las barras invertidas.

  1. Añade entrada del usuario con límite:
nano limite.sh
#!/bin/bash
contador=1
read -p "¿Hasta qué número quieres contar? " limite
while [ "$contador" -le "$limite" ]; do
    echo "Número: $contador"
    contador=$(( contador + 1 ))
done
echo "¡Listo! Conté hasta $limite."
  1. Usa until para esperar a que exista un archivo:
nano esperar.sh
#!/bin/bash
echo "Esperando a que aparezca 'señal.txt'..."
until [ -f "señal.txt" ]; do
    sleep 1
done
echo "¡Archivo detectado!"

En otra terminal, crea el archivo con touch señal.txt para desbloquear el bucle.

  1. Usa break para salir de un bucle antes de que termine:
nano buscar.sh
#!/bin/bash
contador=1
while [ "$contador" -le 10 ]; do
    echo "Revisando: $contador"
    if [ "$contador" -eq 5 ]; then
        echo "¡Encontrado en $contador! Saliendo."
        break
    fi
    contador=$(( contador + 1 ))
done

Consejo: Usa while cuando la condición de parada depende del estado del sistema (archivos, procesos, entradas del usuario). Usa for cuando iteras sobre una lista conocida. 💡


5.3. Manejo de errores y señales 🛡️

Teoría:

Un script robusto anticipa los fallos. Bash ofrece varias herramientas para manejar errores:

  • $? — contiene el código de salida del último comando (0 = éxito, cualquier otro valor = error).
  • set -e — detiene el script si cualquier comando falla.
  • trap — captura señales y errores para ejecutar código de limpieza antes de salir.

Las señales más comunes son EXIT (al terminar), INT (Ctrl+C) y ERR (cualquier error).

Práctica:

  1. Comprueba el código de salida de un comando:
nano error.sh
#!/bin/bash
ls /tmp
echo "Código de salida de ls /tmp: $?"
ls /ruta/inexistente
echo "Código de salida del error: $?"
  1. Usa set -e para detener el script en el primer fallo:
nano robusto.sh
#!/bin/bash
set -e
echo "Inicio"
ls /ruta/inexistente
echo "Esta línea no se ejecutará"
  1. Crea una función de manejo de errores:
nano manejador.sh
#!/bin/bash
manejar_error() {
    echo "Error en la línea $1. Abortando."
    exit 1
}
trap 'manejar_error $LINENO' ERR
echo "Inicio del script"
ls /ruta/inexistente
echo "Fin (no llegará aquí)"
  1. Usa trap para limpiar archivos temporales al salir:
nano limpieza.sh
#!/bin/bash
TMPFILE=$(mktemp)
trap "rm -f $TMPFILE; echo 'Limpieza completada.'" EXIT
echo "Usando archivo temporal: $TMPFILE"
echo "datos temporales" > "$TMPFILE"
cat "$TMPFILE"
  1. Captura Ctrl+C con la señal INT:
nano interrupcion.sh
#!/bin/bash
trap "echo 'Interrumpido por el usuario. Saliendo.'; exit 0" INT
echo "Ejecutando... Pulsa Ctrl+C para interrumpir."
while true; do
    sleep 1
    echo "Tick..."
done

Consejo: Usa trap ... EXIT en cualquier script que cree archivos temporales para garantizar que se limpian aunque el script falle. 💡


5.4. cron: Automatiza con el planificador de tareas ⏰

Teoría:

cron es el planificador de tareas de Unix/Linux. Permite ejecutar scripts automáticamente en momentos específicos sin intervención humana. La configuración se edita con crontab -e y cada línea sigue el formato:

minuto  hora  día_del_mes  mes  día_de_la_semana  comando

Cada campo acepta un número, * (cualquier valor), rangos (1-5) o listas (1,3,5).

Práctica:

  1. Crea un script de log sencillo:
nano log_script.sh

Escribe el siguiente contenido y guarda:

#!/bin/bash
echo "$(date): Registro automático" >> ~/registro_cron.log

Dale permisos de ejecución:

chmod +x log_script.sh
  1. Verifica que el script funciona manualmente:
./log_script.sh
cat ~/registro_cron.log
  1. Abre el editor de crontab:
crontab -e
  1. Añade una entrada para ejecutar el script cada minuto (para pruebas):
* * * * * /ruta/completa/a/log_script.sh

Sustituye /ruta/completa/a/ por la ruta real. Usa pwd para obtenerla. Guarda y cierra el editor.

  1. Espera un par de minutos y verifica que se han creado entradas en el log:
cat ~/registro_cron.log

Cuando termines la prueba, elimina o comenta la entrada en crontab -e para no llenar el log.

Advertencia: En cron, el script se ejecuta con un entorno mínimo (sin las variables de tu sesión). Usa siempre rutas absolutas para archivos y comandos. 🛑


5.5. Arrays: Trabaja con colecciones de datos 📊

Teoría:

Los arrays en Bash almacenan múltiples valores bajo un mismo nombre. Se accede a cada elemento por su índice (empezando en 0). Sintaxis básica:

mi_array=("valor1" "valor2" "valor3")
echo "${mi_array[0]}"      # primer elemento
echo "${mi_array[@]}"      # todos los elementos
echo "${#mi_array[@]}"     # número de elementos

Práctica:

  1. Crea y accede a un array:
nano arrays.sh
#!/bin/bash
frutas=("manzana" "naranja" "pera" "uva")
echo "Primera fruta: ${frutas[0]}"
echo "Todas las frutas: ${frutas[@]}"
echo "Total de frutas: ${#frutas[@]}"
  1. Recorre el array con un for:
nano arrays.sh
#!/bin/bash
frutas=("manzana" "naranja" "pera" "uva")
for fruta in "${frutas[@]}"; do
    echo "Fruta: $fruta"
done
  1. Añade elementos al array:
frutas+=("mango")
echo "Ahora hay ${#frutas[@]} frutas"
  1. Recorre el array con sus índices:
for i in "${!frutas[@]}"; do
    echo "Índice $i: ${frutas[$i]}"
done
  1. Crea un script que use un array para almacenar nombres de archivos y procesarlos:
nano procesar.sh
#!/bin/bash
archivos=("texto.txt" "personas.txt" "datos.csv")
for archivo in "${archivos[@]}"; do
    if [ -f "$archivo" ]; then
        echo "$archivo: $(wc -l < "$archivo") líneas"
    else
        echo "$archivo: no existe"
    fi
done

Consejo: Usa siempre "${array[@]}" con comillas dobles al iterar para que los elementos con espacios se traten correctamente. 💡


5.6. Gestión del entorno con .bashrc 🏠

Teoría:

El archivo ~/.bashrc es un script que Bash ejecuta automáticamente al iniciar cada sesión interactiva. Es el lugar ideal para definir:

  • Alias: atajos para comandos que usas frecuentemente.
  • Variables de entorno: como PATH o EDITOR.
  • Funciones: utilidades personalizadas disponibles en cualquier terminal.

Los cambios en .bashrc no tienen efecto inmediato; hay que recargar el archivo con source ~/.bashrc.

Práctica:

  1. Visualiza el contenido actual de .bashrc:
less ~/.bashrc

Usa las flechas para navegar y q para salir.

  1. Abre .bashrc para editarlo:
nano ~/.bashrc
  1. Añade un alias al final del archivo:
alias ll='ls -lh --color=auto'
alias ..='cd ..'
  1. Añade una variable de entorno y una función:
export EDITOR=nano

saludo_rapido() {
    echo "¡Hola, $(whoami)! Son las $(date +%H:%M)."
}
  1. Guarda el archivo con Ctrl+O, Enter, Ctrl+X, y recarga la configuración:
source ~/.bashrc

Ahora prueba los alias y la función en tu terminal:

ll
saludo_rapido

Advertencia: Edita .bashrc con cuidado. Un error de sintaxis puede impedir que la terminal funcione correctamente. Si eso ocurre, abre .bashrc con nano ~/.bashrc desde otra sesión y corrige el error. 🛑


🛠️ Ejercicios prácticos

  1. Función: Crea una función crear_directorio que reciba un nombre, cree la carpeta y muestre un mensaje de confirmación.
  2. While: Crea un script que pida al usuario un número y repita la solicitud mientras no sea mayor que 10.
  3. Cron: Configura una tarea en cron que ejecute date >> ~/fecha_log.txt cada 5 minutos.
  4. Arrays: Crea un array con 5 ciudades y usa un bucle para mostrar cada una con su índice.
  5. Desafío: Crea un script que use una función para procesar cada línea de un archivo CSV, muestre los datos formateados y guarde el resultado en un informe.

📝 Evaluación

Cuestionario (5 preguntas):

  1. ¿Cuál es la diferencia entre while y until?
  2. ¿Cómo defines una función que acepte argumentos en Bash?
  3. ¿Qué hace trap 'comando' EXIT?
  4. ¿Cómo accedes a todos los elementos de un array en Bash?
  5. ¿Por qué hay que usar rutas absolutas en las entradas de cron?

Tarea práctica:

Crea un script gestor.sh que: - Defina una función registrar que añada una línea con fecha y mensaje a un archivo gestor.log. - Use un bucle while para mostrar un menú de opciones al usuario (registrar, ver log, salir). - Maneje la opción de salida limpiamente con trap.

Entrega: El script y el archivo gestor.log generado tras probar el menú.

🎬 Vídeo con la solución de la evaluación: Próximamente.


🎉 Recursos adicionales

  • Documentación: man bash (sección "Functions"), man crontab.
  • Editor de cron online: Crontab.guru — traduce expresiones cron a lenguaje natural.
  • Referencia de arrays: Bash Arrays (tldp.org).

Tip: Crontab.guru es indispensable para construir expresiones cron correctas sin memorizar la sintaxis. 💡


🚀 Siguientes pasos

¡Felicidades por completar el Módulo 5! En el Módulo 6 aprenderás a conectar tu terminal al mundo real: ssh, curl, jq y monitoreo del sistema. ¡La red te espera! ✍️