Introducción: ¿Por qué aprender Bash?
Si trabajas con servidores Linux, Bash es posiblemente la herramienta más poderosa que puedes dominar. A diferencia de lenguajes de propósito general como Python, Bash está diseñado específicamente para interactuar con el sistema operativo: gestionar archivos, ejecutar procesos, manejar permisos y automatizar tareas de administración.
Un script de Bash bien escrito puede ahorrar horas de trabajo manual repetitivo. En esta guía, pasaremos de los conceptos básicos a técnicas de automatización avanzadas que uso diariamente en producción.
Puntos clave de esta guía
- Estructura básica de un script Bash
- Variables, arrays y sustitución de comandos
- Condicionales y bucles
- Funciones reutilizables
- Manejo de errores
- Cron jobs para automatización programada
- Casos de uso reales en servidores
1. Estructura Básica de un Script Bash
Todo script Bash comienza con el shebang, una línea especial que indica al sistema qué intérprete usar.
echo "Hola, mundo desde Bash"
echo "Fecha actual: $(date)"
echo "Usuario: $USER"
Para ejecutar el script, primero debes darle permisos de ejecución:
chmod +x mi_primer_script.sh
./mi_primer_script.sh
2. Variables y Tipos de Datos
En Bash, las variables no tienen tipos estrictos — todo es una cadena de texto por defecto. Sin embargo, puedes trabajar con números y arrays.
nombre="ClickHalo"
version="2.5"
contador=0
echo "Sitio: $nombre v${version}"
echo "Usuario: $USER"
echo "Directorio home: $HOME"
echo "PID del script: $$"
servidores=("web01" "web02" "db01")
echo "Primer servidor: ${servidores[0]}"
echo "Todos: ${servidores[@]}"
echo "Total: ${#servidores[@]}"
fecha_actual=$(date +%Y-%m-%d)
espacio_libre=$(df -h / | awk 'NR==2{print $4}')
echo "Hoy: $fecha_actual | Espacio libre: $espacio_libre"
3. Condicionales: if, else, case
Las estructuras condicionales en Bash tienen una sintaxis peculiar que puede confundir al principio, pero una vez que la dominas es muy expresiva.
archivo="/etc/nginx/nginx.conf"
if [ -f "$archivo" ]; then
echo "✓ Nginx está configurado"
elif [ -d "/etc/nginx" ]; then
echo "⚠ Directorio existe pero falta config"
else
echo "✗ Nginx no está instalado"
fi
carga=$(uptime | awk '{print $10}' | tr -d ',')
if (( $(echo "$carga > 5" | bc -l) )); then
echo "ALERTA: Carga del sistema alta: $carga"
fi
entorno="produccion"
case $entorno in
desarrollo) echo "Modo debug activado" ;;
staging) echo "Pruebas de integración" ;;
produccion) echo "¡Cuidado! Entorno productivo" ;;
*) echo "Entorno desconocido" ;;
esac
4. Bucles: for, while, until
Los bucles son donde Bash realmente brilla para automatización. Iterar sobre archivos, servidores o líneas de texto es extremadamente eficiente.
servidores=("192.168.1.10" "192.168.1.11" "192.168.1.12")
for servidor in "${servidores[@]}"; do
if ping -c 1 -W 2 "$servidor" &>/dev/null; then
echo "✓ $servidor — Online"
else
echo "✗ $servidor — Sin respuesta"
fi
done
for log in /var/log/*.log; do
tamaño=$(du -sh "$log" | cut -f1)
echo "$tamaño — $log"
done
intentos=0
while ! curl -s http://localhost:8080/health &>/dev/null; do
intentos=$((intentos + 1))
if [ $intentos -ge 30 ]; then
echo "Error: servicio no responde después de 30s"
exit 1
fi
echo "Esperando servicio... ($intentos)"
sleep 1
done
echo "Servicio listo."
5. Funciones Reutilizables
Las funciones hacen tus scripts más organizados y reutilizables. Son fundamentales para cualquier script de producción.
log() {
local nivel="$1"
local mensaje="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$nivel] $mensaje" | tee -a /var/log/mi_script.log
}
verificar_deps() {
local deps=("curl" "jq" "git")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &>/dev/null; then
log "ERROR" "Dependencia no encontrada: $dep"
exit 1
fi
done
log "INFO" "Todas las dependencias verificadas"
}
backup_directorio() {
local origen="$1"
local destino="$2"
local dias_retencion="${3:-7}"
local fecha=$(date +%Y%m%d_%H%M%S)
local archivo="backup_${fecha}.tar.gz"
tar -czf "${destino}/${archivo}" "$origen" 2>/dev/null
log "INFO" "Backup creado: $archivo"
find "$destino" -name "backup_*.tar.gz" -mtime +"$dias_retencion" -delete
log "INFO" "Backups de más de $dias_retencion días eliminados"
}
verificar_deps
backup_directorio "/var/www/html" "/backups" 14
6. Cron Jobs: Automatización Programada
Los cron jobs permiten ejecutar scripts automáticamente en momentos específicos. Son fundamentales para tareas de mantenimiento, backups y monitoreo.
Sintaxis de cron
30 2 * * * /home/admin/scripts/backup_db.sh >> /var/log/backup.log 2>&1
0 * * * * /home/admin/scripts/check_services.sh
0 0 * * 0 find /var/log -name "*.log" -mtime +30 -delete
*/5 * * * * /home/admin/scripts/monitor_cpu.sh
0 8 1 * * /home/admin/scripts/reporte_mensual.sh
Para editar tus cron jobs, usa crontab -e. Para ver los existentes: crontab -l.
7. Script Real: Monitor de Servidor
Aquí tienes un script completo que puedes usar inmediatamente en producción para monitorear el estado de tu servidor:
EMAIL_ALERTA="tu@email.com"
UMBRAL_CPU=80
UMBRAL_DISCO=90
UMBRAL_RAM=85
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }
verificar_cpu() {
local cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
if (( $(echo "$cpu > $UMBRAL_CPU" | bc -l) )); then
log "ALERTA: CPU al ${cpu}%"
return 1
fi
log "CPU OK: ${cpu}%"
}
verificar_disco() {
while IFS= read -r linea; do
local uso=$(echo "$linea" | awk '{print $5}' | tr -d '%')
local mount=$(echo "$linea" | awk '{print $6}')
if [ "$uso" -gt "$UMBRAL_DISCO" ]; then
log "ALERTA: Disco $mount al ${uso}%"
fi
done < <(df -h | grep '^/')
}
verificar_servicios() {
local servicios=("nginx" "mysql" "ssh")
for srv in "${servicios[@]}"; do
if ! systemctl is-active --quiet "$srv"; then
log "ALERTA: Servicio $srv CAÍDO"
systemctl restart "$srv" && log "INFO: $srv reiniciado"
else
log "OK: $srv activo"
fi
done
}
log "=== Inicio de monitoreo ==="
verificar_cpu
verificar_disco
verificar_servicios
log "=== Monitoreo completado ==="
Conclusión
Bash es una herramienta que se aprende haciendo. Empieza con scripts simples — automatizan el backup de un directorio, verifican el estado de un servicio — y poco a poco combina técnicas hasta construir sistemas de automatización completos.
Los conceptos más importantes a recordar son: siempre incluir manejo de errores, usar variables con comillas para evitar problemas con espacios en nombres de archivos, y hacer logging de todas las operaciones importantes.
En próximos artículos exploraremos la integración de Bash con APIs REST, el uso de jq para procesar JSON en la terminal y la creación de dashboards de monitoreo desde la línea de comandos.
Recursos adicionales
- ShellCheck — Herramienta online para analizar y mejorar tus scripts Bash
- explainshell.com — Desglosa cualquier comando complejo en partes explicadas
- man bash — La documentación oficial completa, directamente en tu terminal
- Bash Hackers Wiki — Referencia técnica avanzada para Bash