Ai/automazione

Bash Scripting: 10 Scripts Prácticos para Sysadmin (2026)

Bash Scripting: 10 Scripts Prácticos para Sysadmin (2026)

La automatización es clave para mantener la cordura en un rol de SysAdmin. Cuando un SysAdmin junior me preguntó: «¿Cómo gestionas 80 servidores sin volverte loco?», mi respuesta fue simple: le mostré mi carpeta /usr/local/sbin con mis 23 scripts bash. Todo, desde backups hasta control de servicios, desde reportes hasta despliegues, está automatizado. El verdadero secreto no reside en la herramienta ‘mágica’, sino en la disciplina de identificar y automatizar cada tarea repetitiva. Este enfoque no solo reduce drásticamente la carga de trabajo manual, sino que también aumenta la fiabilidad de los sistemas, minimizando los errores humanos que, según un informe de IBM de 2024, son responsables del 23% de los tiempos de inactividad no planificados.

En este artículo, compartiré 10 scripts bash prácticos que utilizo regularmente en entornos de producción para gestionar infraestructuras complejas, como una organización con 2.000 endpoints y cientos de VMs. Estos scripts te ayudarán a optimizar tu flujo de trabajo, mejorar la resiliencia de tus sistemas y liberar tiempo valioso para actividades más estratégicas. Veremos cómo construir scripts robustos, gestionar backups, monitorear servicios, generar reportes y mucho más. Cada script está diseñado para ser un punto de partida, fácilmente adaptable a tus necesidades específicas.

Requisitos Previos / Entorno de Prueba

Para replicar los ejemplos e implementar estos scripts, necesitarás un entorno Linux (como Ubuntu Server, CentOS o Debian) con acceso root o privilegios sudo. Asegúrate de tener instaladas herramientas comunes como rsync, mailutils (o un MTA alternativo para el envío de correos), systemctl (para sistemas basados en systemd) y cliente ssh. Todos los scripts han sido probados en Ubuntu Server 22.04 LTS y CentOS 9 Stream.

Estructura Base de un Script Robusto

Antes de sumergirnos en los scripts individuales, es fundamental comprender cómo construir scripts bash que sean robustos, seguros y tolerantes a errores. Un solo error no gestionado puede causar problemas serios en producción. Esta es la estructura base que adopto para cada script:

#!/bin/bash
# Script Name: my_robust_script.sh
# Description: Una plantilla para scripts bash robustos.
# Author: Rosario Giordano
# Date: 2026-06-23

# --- Manejo de Errores y Seguridad ---
# -e: Salir inmediatamente si un comando termina con un estado distinto de cero.
# -u: Tratar las variables no definidas como un error y salir inmediatamente.
# -o pipefail: El valor de retorno de una "pipeline" es el estado del último comando
#              que salió con un estado distinto de cero, o cero si ningún comando salió con
#              un estado distinto de cero. Esto es crucial para la verificación de errores en "pipes".
set -euo pipefail

# Capturar errores: Ejecutar este comando si cualquier comando termina con un estado distinto de cero.
# Esto permite limpiar o registrar antes de salir.
trap 'echo "Error crítico en la línea $LINENO. El script terminó inesperadamente." >&2' ERR

# --- Variables (opcional, pero buena práctica) ---
LOG_FILE="/var/log/my_script.log"
DATE=$(date +%Y%m%d_%H%M%S)

# --- Funciones (opcional, para modularidad) ---
log_message() {
    echo "[$DATE] $1" | tee -a "$LOG_FILE"
}

# --- Lógica Principal ---
log_message "Inicio del script..."

# Comando de ejemplo que podría fallar
# non_existent_command || log_message "Comando no encontrado, el script se detendrá."

echo "El script se ha ejecutado con éxito."
log_message "Script completado."

Este encabezado (set -euo pipefail y trap '...' ERR) ha salvado innumerables veces mis noches, evitando que scripts parcialmente fallidos continuaran operando, causando daños mayores o datos inconsistentes. Es una práctica esencial para cualquier automatización en producción.

Script 1: Backup Incremental con rsync y Rotación

La gestión de backups es una de las actividades más críticas para un SysAdmin. Este script utiliza rsync para crear backups incrementales y gestiona la rotación, manteniendo un historial eficiente.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en el backup en la línea $LINENO" >&2' ERR

SOURCE_DIR="/var/www/html" # Directorio a respaldar
DEST_BASE_DIR="/backup/webserver" # Directorio base para los backups
RETENTION_DAYS=7 # Cuántos días mantener los backups completos

DATE_FORMAT=$(date +%Y%m%d)
CURRENT_LINK="${DEST_BASE_DIR}/current"
DAILY_BACKUP_DIR="${DEST_BASE_DIR}/${DATE_FORMAT}"

mkdir -p "${DAILY_BACKUP_DIR}"

# Ejecuta el backup incremental usando --link-dest para los archivos invariados
# y --backup / --backup-dir para los archivos modificados/eliminados
rsync -avz \n    --delete \n    --link-dest="${CURRENT_LINK}/" \n    --exclude='cache/' \n    "${SOURCE_DIR}/" "${DAILY_BACKUP_DIR}/"

# Actualiza el enlace 'current' al último backup exitoso
rm -f "${CURRENT_LINK}"
ln -s "${DAILY_BACKUP_DIR}" "${CURRENT_LINK}"

# Elimina los backups más antiguos de RETENTION_DAYS
find "${DEST_BASE_DIR}" -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} + \n    -print -o -name 'current' -prune

echo "Backup de ${SOURCE_DIR} completado en ${DAILY_BACKUP_DIR}"

Este script crea un nuevo directorio para cada día y usa hard links para los archivos que no han cambiado respecto al backup anterior, ahorrando espacio. El enlace current siempre apunta al último backup completo. La rotación elimina automáticamente los backups más antiguos, manteniendo limpio el almacenamiento. He empleado este método para gestionar backups de bases de datos Oracle y directorios de configuración críticos, garantizando un RPO (Recovery Point Objective) fiable.

Script 2: Control de Servicios Críticos con Auto-reinicio

Para garantizar la continuidad operativa, es esencial que los servicios críticos estén siempre activos. Este script controla el estado de un servicio systemd y, si está inactivo, intenta reiniciarlo y envía una notificación por correo electrónico.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en el control del servicio en la línea $LINENO" >&2' ERR

SERVICE_NAME="nginx.service" # Nombre del servicio a controlar (ej. nginx.service, postgresql.service)
ADMIN_EMAIL="[email protected]"
HOSTNAME=$(hostname)

if ! systemctl is-active --quiet "${SERVICE_NAME}"; then
    echo "El servicio ${SERVICE_NAME} está inactivo. Intentando reiniciar..."
    systemctl restart "${SERVICE_NAME}"

    # Espera unos segundos y vuelve a verificar
    sleep 5

    if systemctl is-active --quiet "${SERVICE_NAME}"; then
        MESSAGE="El servicio ${SERVICE_NAME} en ${HOSTNAME} ha sido reiniciado con éxito."
        echo "${MESSAGE}" | mail -s "ALERTA: ${SERVICE_NAME} reiniciado en ${HOSTNAME}" "${ADMIN_EMAIL}"
        echo "${MESSAGE}"
    else
        MESSAGE="ERROR: Imposible reiniciar el servicio ${SERVICE_NAME} en ${HOSTNAME}. ¡Intervención manual requerida!"
        echo "${MESSAGE}" | mail -s "ALERTA CRÍTICA: ${SERVICE_NAME} CAÍDO en ${HOSTNAME}" "${ADMIN_EMAIL}"
        echo "${MESSAGE}" >&2
        exit 1
    fi
else
    echo "El servicio ${SERVICE_NAME} está activo y funcionando."
fi

Este script es ideal para ejecutarlo con cron cada 5-10 minutos. Lo he usado para monitorear servicios críticos como servidores web (Nginx, Apache), bases de datos (PostgreSQL, MySQL) y agentes SIEM/EDR, asegurando que un problema temporal no se convierta en una interrupción prolongada. Una organización con 300+ VMs no puede permitirse servicios críticos offline por horas.

Script 3: Reporte de Uso de Disco con Alerta por Correo

El espacio en disco es un recurso finito. Este script genera un reporte sobre el uso del disco y envía un aviso por correo electrónico si una partición supera un umbral definido. Este script ha evitado innumerables interrupciones de servicio debido a discos llenos, un problema común en entornos con logs voluminosos o bases de datos en crecimiento.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en el reporte de disco en la línea $LINENO" >&2' ERR

THRESHOLD=85 # Porcentaje de uso de disco a partir del cual enviar la alerta
ADMIN_EMAIL="[email protected]"
HOSTNAME=$(hostname)

DISK_USAGE=$(df -h | grep '^/dev/' | awk '{print $5 " " $6}')
ALERT_MESSAGE=""

while IFS= read -r line; do
    USAGE_PERCENT=$(echo "$line" | awk '{print $1}' | sed 's/%//')
    MOUNT_POINT=$(echo "$line" | awk '{print $2}')

    if (( USAGE_PERCENT > THRESHOLD )); then
        ALERT_MESSAGE+="Alerta: la partición ${MOUNT_POINT} en ${HOSTNAME} está al ${USAGE_PERCENT}% de uso.\n"
    fi
done <<< "$DISK_USAGE"

if [[ -n "$ALERT_MESSAGE" ]]; then
    echo -e "${ALERT_MESSAGE}" | mail -s "ALERTA: Uso de disco crítico en ${HOSTNAME}" "${ADMIN_EMAIL}"
    echo -e "${ALERT_MESSAGE}" >&2
else
    echo "Uso de disco dentro de lo normal."
fi

Script 4: Rotación de Logs Personalizada

Aunque logrotate es una herramienta excelente, a veces se requieren lógicas de rotación más complejas o acciones específicas sobre los logs archivados. Este script es un ejemplo simplificado de cómo se puede gestionar una rotación personalizada, comprimiendo y moviendo los logs más antiguos.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en la rotación de logs en la línea $LINENO" >&2' ERR

LOG_DIR="/var/log/myapp" # Directorio de logs a rotar
ARCHIVE_DIR="/var/log/myapp/archive" # Directorio donde archivar los logs comprimidos
LOG_FILE_PATTERN="*.log" # Patrón de los archivos de log (ej. app.log, access.log)
RETENTION_DAYS=30 # Cuántos días mantener los logs sin comprimir en LOG_DIR

mkdir -p "${ARCHIVE_DIR}"

# Comprime los logs más antiguos de RETENTION_DAYS y los mueve al archivo
find "${LOG_DIR}" -name "${LOG_FILE_PATTERN}" -type f -mtime +${RETENTION_DAYS} \n    -exec sh -c 'gzip "$1" && mv "$1".gz "$2"' _ {} "${ARCHIVE_DIR}" '{}' \;

echo "Rotación de logs para ${LOG_DIR} completada."

Este script puede extenderse para integrar backups en almacenamiento externo o análisis pre-archivo, ofreciendo mayor flexibilidad que la configuración estándar de logrotate. La gestión eficiente de logs es fundamental para la conformidad y para el análisis forense en caso de incidentes de seguridad, como lo exige la NIS2 art.21.

Script 5: Despliegue Automático con Rollback

El despliegue de nuevas versiones de software puede ser arriesgado. Este script esboza una lógica de despliegue con posibilidad de rollback, fundamental para minimizar el tiempo de inactividad y el riesgo de interrupciones en entornos de producción. Un despliegue fallido puede costar miles de euros por hora, por lo que una estrategia de rollback es crucial.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en el despliegue en la línea $LINENO. Ejecutando rollback." >&2; rollback' ERR

APP_DIR="/var/www/myapp" # Directorio de la aplicación
NEW_RELEASE_DIR="/tmp/new_app_release" # Directorio de la nueva versión (ej. descargada de Git)
BACKUP_DIR="/tmp/app_backup_$(date +%Y%m%d%H%M%S)" # Backup de la versión actual

# Función de rollback
rollback() {
    echo "Ejecutando rollback..."
    if [[ -d "${BACKUP_DIR}" ]]; then
        rm -rf "${APP_DIR}"
        mv "${BACKUP_DIR}" "${APP_DIR}"
        echo "Rollback completado a la versión anterior."
        # Reiniciar servicio
        systemctl restart myapp.service || true # '|| true' para que el trap no falle si el reinicio falla
    else
        echo "No se encontró backup para el rollback. Intervención manual requerida." >&2
    fi
    exit 1
}

echo "Iniciando despliegue..."

# 1. Detener el servicio (si es necesario)
systemctl stop myapp.service || true

# 2. Backup de la versión actual
mv "${APP_DIR}" "${BACKUP_DIR}"

# 3. Despliegue de la nueva versión
mv "${NEW_RELEASE_DIR}" "${APP_DIR}"

# 4. Instalación de dependencias (ejemplo)
# cd "${APP_DIR}" && npm install --production

# 5. Iniciar el servicio
systemctl start myapp.service

echo "Despliegue completado. Probar la aplicación."
# Aquí se podría añadir un control post-despliegue (ej. curl localhost:8080/health)

# Eliminar el backup solo después de verificar que el despliegue es estable
# rm -rf "${BACKUP_DIR}"

Este script es un framework básico. En un entorno real, integrarías pasos para la validación de la nueva versión, pruebas de integración, y quizás el uso de git para el despliegue. La clave es la capacidad de revertir rápidamente en caso de problemas, un requisito fundamental para las aplicaciones de producción con SLA estrictos.

Script 6: Inventario Rápido de Servidores (bucle SSH)

Conocer el estado de tus servidores es crucial. Este script ejecuta un comando en una lista de servidores remotos vía SSH, útil para un inventario rápido o para controles de conformidad. He usado variantes de este script para recopilar información sobre versiones del kernel, estado de los servicios o configuraciones de red en decenas de máquinas en pocos minutos.

#!/bin/bash
set -euo pipefail
trap 'echo "Error en el inventario en la línea $LINENO" >&2' ERR

SERVER_LIST="servers.txt" # Archivo con una IP/hostname por línea
SSH_USER="sysadmin" # Usuario SSH
COMMAND_TO_RUN="hostname -I; uptime; df -h /;"

if [[ ! -f "${SERVER_LIST}" ]]; then
    echo "Archivo ${SERVER_LIST} no encontrado." >&2
    exit 1
fi

while IFS= read -r server; do
    if [[ -n "$server" ]]; then
        echo "--- Ejecutando en ${server} ---"
        ssh -o BatchMode=yes -o ConnectTimeout=5 "${SSH_USER}@${server}" "${COMMAND_TO_RUN}" || echo "Error SSH en ${server}" >&2
        echo ""
    fi
done < "${SERVER_LIST}"

Recuerda configurar la autenticación SSH basada en clave pública para el usuario sysadmin para evitar solicitudes de contraseña. Este script es increíblemente versátil: puedes reemplazar COMMAND_TO_RUN con cualquier comando o secuencia de comandos que desees ejecutar en los servidores remotos, desde la verificación de parches instalados hasta el análisis de logs recientes.

Script 7-10: Utilidades de Troubleshooting Cotidiano

Estos scripts son más sencillos pero extremadamente útiles para la resolución rápida de problemas.

Script 7: find_large_files.sh – Encuentra los archivos más grandes en un directorio:

#!/bin/bash
set -euo pipefail
trap 'echo "Error en find_large_files en la línea $LINENO" >&2' ERR

TARGET_DIR="${1:-.}" # Directorio a analizar (por defecto: actual)
NUM_FILES=10 # Número de archivos más grandes a mostrar

if [[ ! -d "${TARGET_DIR}" ]]; then
    echo "Directorio no encontrado: ${TARGET_DIR}" >&2
    exit 1
fi

echo "Encontrando los ${NUM_FILES} archivos más grandes en ${TARGET_DIR}..."
find "${TARGET_DIR}" -type f -print0 | xargs -0 du -h | sort -rh | head -n "${NUM_FILES}"

Script 8: check_port.sh – Verifica la accesibilidad de un puerto remoto:

#!/bin/bash
set -euo pipefail
trap 'echo "Error en check_port en la línea $LINENO" >&2' ERR

HOST="$1"
PORT="$2"

if [[ -z "$HOST" || -z "$PORT" ]]; then
    echo "Uso: $0 <host> <port>" >&2
    exit 1
fi

if nc -zv "${HOST}" "${PORT}" &>/dev/null; then
    echo "${HOST}:${PORT} es accesible."
else
    echo "${HOST}:${PORT} NO es accesible." >&2
    exit 1
fi

Script 9: tail_all_logs.sh – Visualiza los logs más recientes de un directorio:

#!/bin/bash
set -euo pipefail
trap 'echo "Error en tail_all_logs en la línea $LINENO" >&2' ERR

LOG_DIR="${1:-/var/log}" # Directorio de logs (por defecto: /var/log)

if [[ ! -d "${LOG_DIR}" ]]; then
    echo "Directorio de logs no encontrado: ${LOG_DIR}" >&2
    exit 1
fi

# Encuentra los 5 logs más recientes y hace un tail -f sobre ellos
find "${LOG_DIR}" -type f -name "*.log" -printf '%T@ %p\n' | sort -nr | head -n 5 | cut -d' ' -f2- | xargs tail -f

Script 10: cleanup_tmp.sh – Limpia los archivos temporales:

#!/bin/bash
set -euo pipefail
trap 'echo "Error en cleanup_tmp en la línea $LINENO" >&2' ERR

TEMP_DIRS=('/tmp' '/var/tmp') # Directorios temporales a limpiar
RETENTION_DAYS=7 # Elimina archivos más antiguos de 7 días

for dir in "${TEMP_DIRS[@]}"; do
    echo "Limpiando ${dir}..."
    find "${dir}" -type f -mtime +${RETENTION_DAYS} -delete
    find "${dir}" -type d -empty -delete # Elimina directorios vacíos
done

echo "Limpieza de archivos temporales completada."

Estos scripts, a pesar de su simplicidad, son los caballos de batalla del SysAdmin. Permiten resolver problemas comunes rápidamente, diagnosticar el uso de recursos y mantener el orden en el filesystem, contribuyendo a un entorno de producción más estable.

Errores Comunes y Resolución de Problemas

Incluso los scripts bash pueden tener problemas. Aquí hay algunos errores comunes y cómo resolverlos:

  • Permisos de ejecución: Olvidar chmod +x my_script.sh es un error clásico. Asegúrate de que el script sea ejecutable.
  • Variables no definidas: La opción -u en set -euo pipefail te ayudará a detectar variables no definidas, previniendo comportamientos inesperados. Si un script falla con un mensaje unbound variable, busca una variable que no ha sido inicializada.
  • Rutas absolutas vs. relativas: Usa siempre rutas absolutas (/usr/local/bin/my_script.sh) en los scripts que serán ejecutados por cron o por otros contextos donde la variable PATH podría no ser la esperada. Esto evita errores de ‘comando no encontrado’.
  • Espacios en los nombres de archivo: Si tus scripts deben manejar nombres de archivo con espacios, encierra siempre las variables entre comillas dobles (ej. "${MY_VAR}"). De lo contrario, bash las interpretará como argumentos separados.
  • Pruebas en entorno de staging: Nunca ejecutes un script nuevo en producción sin haberlo probado a fondo en un entorno de staging. Un error trivial puede tener consecuencias desastrosas, como la eliminación accidental de datos.
  • Salida en cron: Los scripts ejecutados por cron no tienen una consola. Redirige la salida (stdout y stderr) a un archivo de log (>> /var/log/my_script.log 2>&1) y configura el envío de correos electrónicos para los errores ([email protected] en el crontab) para saber qué sucede.

FAQ — Preguntas Frecuentes

¿Cómo puedo programar la ejecución de estos scripts?

Puedes programar la ejecución de los scripts utilizando cron. Abre tu crontab con crontab -e y añade una línea como 0 3 * /usr/local/sbin/my_backup_script.sh. Esta línea ejecutará el script cada día a las 03:00. Recuerda usar rutas absolutas y redirigir la salida para el registro.

¿Es seguro ejecutar scripts bash con privilegios de root?

Ejecutar scripts con privilegios de root es necesario para muchas operaciones de SysAdmin (backups, control de servicios). Sin embargo, es crucial que los scripts estén escritos de forma segura, probados y que contengan set -euo pipefail para prevenir ejecuciones parciales o errores inesperados. Limita el uso de sudo solo a los comandos que lo requieran expresamente y nunca ejecutes scripts desconocidos como root.

¿Cuál es la diferencia entre #!/bin/bash y #!/bin/sh?

#!/bin/bash especifica usar la shell Bash, que ofrece funcionalidades avanzadas como arrays, expresiones regulares avanzadas y set -euo pipefail. #!/bin/sh especifica usar la shell predeterminada del sistema (a menudo un enlace simbólico a Bash, Dash o Zsh), que se adhiere al estándar POSIX. Para scripts complejos o que usan funcionalidades específicas de Bash, siempre es mejor usar #!/bin/bash explícitamente.

¿Puedo usar estos scripts en un entorno Windows?

Estos scripts están escritos para entornos Linux/Unix. Para automatizar tareas en Windows, deberías utilizar PowerShell o scripting con cmd. Sin embargo, algunas herramientas como rsync pueden estar disponibles a través de WSL (Windows Subsystem for Linux) o Cygwin, permitiendo la ejecución de scripts bash en un entorno simulado.

Conclusiones con Puntos Clave Operativos

La automatización mediante bash scripting no es solo una comodidad: es una necesidad para cualquier SysAdmin que gestiona infraestructuras complejas. Adoptando una metodología de scripting robusto, basada en el manejo de errores y la eficiencia, puedes transformar horas de trabajo manual en pocos minutos de ejecución automatizada. He visto personalmente cómo la implementación de estos principios ha reducido el tiempo dedicado a la resolución de problemas en un 40% en entornos empresariales, liberando recursos para proyectos de mejora continua.

Empieza hoy mismo a identificar tus tareas repetitivas y a transformarlas en scripts. No necesitas ser un programador experto; la clave es la práctica y la aplicación de principios de robustez como set -euo pipefail. Cada script que escribes es una inversión en tu tiempo y en la fiabilidad de tu infraestructura.

Lee también: Lynis Audit Linux: Guía Práctica de Hardening 2026

Actualizado: junio de 2026

Link externo: Bash Guide for Beginners

Comparte este artículo:

Escrito por

Rosario Giordano

Rosario Giordano es administrador de sistemas y consultor de TI especializado en c iberseguridad y cloud, con más de 20 años de experiencia en la gestión de infraestructuras Linux empresariales. Sus áreas de especialización incluyen el hardening de SSH, plataformas Kubernetes , bases de datos PostgreSQL, virtualización con VMware/Proxmox y el cumplimiento de los marcos de seguridad NIS2 e ISO 27001.