Ai/automazione

Bash Scripting Sysadmin: 10 Script Pratici per Automazione Quotidiana (2026)

Bash Scripting Sysadmin: 10 Script Pratici per Automazione Quotidiana (2026)

L’automazione è la chiave per mantenere la sanità mentale in un ruolo da SysAdmin. Quando un sysadmin junior mi ha chiesto: “Come fai a gestire 80 server senza impazzire?”, la risposta è stata semplice: ho mostrato la mia cartella /usr/local/sbin con i miei 23 script bash. Tutto, dai backup al controllo dei servizi, dai report al deploy, è automatizzato. Il vero segreto non risiede nello strumento ‘magico’, ma nella disciplina di identificare e automatizzare ogni singolo task ripetitivo. Questo approccio non solo riduce drasticamente il carico di lavoro manuale, ma aumenta anche l’affidabilità dei sistemi, minimizzando gli errori umani che, secondo un report IBM del 2024, sono responsabili del 23% dei downtime non pianificati.

In questo articolo, condividerò 10 script bash pratici che utilizzo regolarmente in ambienti di produzione per gestire infrastrutture complesse, come un’organizzazione con 2.000 endpoint e centinaia di VM. Questi script ti aiuteranno a ottimizzare il tuo flusso di lavoro, migliorare la resilienza dei tuoi sistemi e liberare tempo prezioso per attività più strategiche. Vedremo come costruire script robusti, gestire backup, monitorare servizi, generare report e molto altro. Ogni script è progettato per essere un punto di partenza, facilmente adattabile alle tue esigenze specifiche.

Prerequisiti / Ambiente di test

Per replicare gli esempi e implementare questi script, avrai bisogno di un ambiente Linux (come Ubuntu Server, CentOS o Debian) con accesso root o privilegi sudo. Assicurati di avere installati strumenti comuni come rsync, mailutils (o un altro MTA per l’invio di email), systemctl (per sistemi basati su systemd) e ssh client. Tutti gli script sono stati testati su Ubuntu Server 22.04 LTS e CentOS 9 Stream.

Struttura base di uno script robusto

Prima di immergerci nei singoli script, è fondamentale comprendere come costruire script bash che siano robusti, sicuri e tolleranti agli errori. Un singolo errore non gestito può causare problemi seri in produzione. Ecco la struttura di base che adotto per ogni script:

#!/bin/bash
# Script Name: my_robust_script.sh
# Description: A template for robust bash scripts.
# Author: Rosario Giordano
# Date: 2026-06-23

# --- Error Handling and Safety ---
# -e: Exit immediately if a command exits with a non-zero status.
# -u: Treat unset variables as an error and exit immediately.
# -o pipefail: The return value of a pipeline is the status of the last command
#              to exit with a non-zero status, or zero if no command exited with
#              a non-zero status. This is crucial for error checking in pipes.
set -euo pipefail

# Trap errors: Execute this command if any command exits with a non-zero status.
# This allows for cleanup or logging before exiting.
trap 'echo "Errore critico alla riga $LINENO. Lo script è terminato inaspettatamente." >&2' ERR

# --- Variables (optional, but good practice) ---
LOG_FILE="/var/log/my_script.log"
DATE=$(date +%Y%m%d_%H%M%S)

# --- Functions (optional, for modularity) ---
log_message() {
    echo "[$DATE] $1" | tee -a "$LOG_FILE"
}

# --- Main Logic ---
log_message "Avvio dello script..."

# Example command that might fail
# non_existent_command || log_message "Comando non trovato, lo script si fermerà."

echo "Lo script è stato eseguito con successo."
log_message "Script completato."

Questa intestazione (set -euo pipefail e trap '...' ERR) ha salvato innumerevoli volte le mie nottate, evitando che script parzialmente falliti continuassero a operare, causando danni maggiori o dati inconsistenti. È una pratica essenziale per qualsiasi automazione in produzione.

Script 1: backup incrementale con rsync e rotazione

La gestione dei backup è una delle attività più critiche per un SysAdmin. Questo script utilizza rsync per creare backup incrementali e gestisce la rotazione, mantenendo una cronologia efficiente.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nel backup alla riga $LINENO" >&2' ERR

SOURCE_DIR="/var/www/html" # Directory da backuppare
DEST_BASE_DIR="/backup/webserver" # Directory base per i backup
RETENTION_DAYS=7 # Quanti giorni mantenere i backup completi

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}"

# Esegue il backup incrementale usando --link-dest per i file invariati
# e --backup / --backup-dir per i file modificati/cancellati
rsync -avz \n    --delete \n    --link-dest="${CURRENT_LINK}/" \n    --exclude='cache/' \n    "${SOURCE_DIR}/" "${DAILY_BACKUP_DIR}/"

# Aggiorna il link 'current' all'ultimo backup riuscito
rm -f "${CURRENT_LINK}"
ln -s "${DAILY_BACKUP_DIR}" "${CURRENT_LINK}"

# Rimuove i backup più vecchi di RETENTION_DAYS
find "${DEST_BASE_DIR}" -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} + \n    -print -o -name 'current' -prune

echo "Backup di ${SOURCE_DIR} completato in ${DAILY_BACKUP_DIR}"

Questo script crea una nuova directory per ogni giorno e usa hard link per i file che non sono cambiati rispetto al backup precedente, risparmiando spazio. Il link current punta sempre all’ultimo backup completo. La rotazione elimina automaticamente i backup più vecchi, mantenendo pulito lo storage. È un metodo robusto che ho impiegato per gestire backup di database Oracle e directory di configurazione critiche, garantendo un RPO (Recovery Point Objective) affidabile.

Script 2: controllo servizi critici con auto-restart

Per garantire la continuità operativa, è essenziale che i servizi critici siano sempre attivi. Questo script controlla lo stato di un servizio systemd e, se inattivo, tenta di riavviarlo e invia una notifica via email.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nel controllo servizio alla riga $LINENO" >&2' ERR

SERVICE_NAME="nginx.service" # Nome del servizio da controllare (es. nginx.service, postgresql.service)
ADMIN_EMAIL="[email protected]"
HOSTNAME=$(hostname)

if ! systemctl is-active --quiet "${SERVICE_NAME}"; then
    echo "Il servizio ${SERVICE_NAME} è inattivo. Tentativo di riavvio..."
    systemctl restart "${SERVICE_NAME}"

    # Attendi qualche secondo e ricontrolla
    sleep 5

    if systemctl is-active --quiet "${SERVICE_NAME}"; then
        MESSAGE="Il servizio ${SERVICE_NAME} su ${HOSTNAME} è stato riavviato con successo."
        echo "${MESSAGE}" | mail -s "ALERT: ${SERVICE_NAME} riavviato su ${HOSTNAME}" "${ADMIN_EMAIL}"
        echo "${MESSAGE}"
    else
        MESSAGE="ERRORE: Impossibile riavviare il servizio ${SERVICE_NAME} su ${HOSTNAME}. Intervento manuale richiesto!"
        echo "${MESSAGE}" | mail -s "CRITICAL ALERT: ${SERVICE_NAME} DOWN su ${HOSTNAME}" "${ADMIN_EMAIL}"
        echo "${MESSAGE}" >&2
        exit 1
    fi
else
    echo "Il servizio ${SERVICE_NAME} è attivo e funzionante."
fi

Questo script è ideale da eseguire tramite cron ogni 5-10 minuti. L’ho usato per monitorare servizi critici come web server (Nginx, Apache), database (PostgreSQL, MySQL) e agent SIEM/EDR, assicurando che un problema temporaneo non si trasformi in un’interruzione prolungata. Un’organizzazione enterprise con 300+ VM non può permettersi servizi critici offline per ore.

Script 3: report utilizzo disco con alert email

Lo spazio su disco è una risorsa finita. Questo script genera un report sull’utilizzo del disco e invia un avviso via email se una partizione supera una soglia definita. Questo script ha evitato innumerevoli interruzioni di servizio dovute a dischi pieni, un problema comune in ambienti con log voluminosi o database in crescita.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nel report disco alla riga $LINENO" >&2' ERR

THRESHOLD=85 # Percentuale di utilizzo disco oltre la quale inviare l'alert
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+="Allerta: la partizione ${MOUNT_POINT} su ${HOSTNAME} è al ${USAGE_PERCENT}% di utilizzo.\n"
    fi
done <<< "$DISK_USAGE"

if [[ -n "$ALERT_MESSAGE" ]]; then
    echo -e "${ALERT_MESSAGE}" | mail -s "ALERT: Utilizzo disco critico su ${HOSTNAME}" "${ADMIN_EMAIL}"
    echo -e "${ALERT_MESSAGE}" >&2
else
    echo "Utilizzo disco nella norma."
fi

Script 4: log rotation personalizzata

Mentre logrotate è uno strumento eccellente, a volte sono necessarie logiche di rotazione più complesse o azioni specifiche sui log archiviati. Questo script è un esempio semplificato di come si possa gestire una rotazione personalizzata, comprimendo e spostando i log più vecchi.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nella log rotation alla riga $LINENO" >&2' ERR

LOG_DIR="/var/log/myapp" # Directory dei log da ruotare
ARCHIVE_DIR="/var/log/myapp/archive" # Directory dove archiviare i log compressi
LOG_FILE_PATTERN="*.log" # Pattern dei file di log (es. app.log, access.log)
RETENTION_DAYS=30 # Quanti giorni mantenere i log non compressi nella LOG_DIR

mkdir -p "${ARCHIVE_DIR}"

# Comprime i log più vecchi di RETENTION_DAYS e li sposta nell'archivio
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 "Log rotation per ${LOG_DIR} completata."

Questo script può essere esteso per integrare backup su storage esterno o analisi pre-archiviazione, offrendo maggiore flessibilità rispetto alla configurazione standard di logrotate. La gestione efficiente dei log è fondamentale per la compliance e per l’analisi forense in caso di incidenti di sicurezza, come richiesto dalla NIS2 art.21.

Script 5: deploy automatico con rollback

Il deploy di nuove versioni di software può essere rischioso. Questo script abbozza una logica di deploy con possibilità di rollback, fondamentale per minimizzare il downtime e il rischio di interruzioni in ambienti di produzione. Un deploy fallito può costare migliaia di euro all’ora, quindi una strategia di rollback è cruciale.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nel deploy alla riga $LINENO. Eseguo rollback." >&2; rollback' ERR

APP_DIR="/var/www/myapp" # Directory dell'applicazione
NEW_RELEASE_DIR="/tmp/new_app_release" # Directory della nuova release (es. scaricata da Git)
BACKUP_DIR="/tmp/app_backup_$(date +%Y%m%d%H%M%S)" # Backup della versione corrente

# Funzione di rollback
rollback() {
    echo "Esecuzione rollback..."
    if [[ -d "${BACKUP_DIR}" ]]; then
        rm -rf "${APP_DIR}"
        mv "${BACKUP_DIR}" "${APP_DIR}"
        echo "Rollback completato alla versione precedente."
        # Restart servizio
        systemctl restart myapp.service || true # '|| true' per non far fallire il trap se il restart fallisce
    else
        echo "Nessun backup trovato per il rollback. Intervento manuale richiesto." >&2
    fi
    exit 1
}

echo "Avvio deploy..."

# 1. Stop del servizio (se necessario)
systemctl stop myapp.service || true

# 2. Backup della versione corrente
mv "${APP_DIR}" "${BACKUP_DIR}"

# 3. Deploy della nuova release
mv "${NEW_RELEASE_DIR}" "${APP_DIR}"

# 4. Installazione dipendenze (esempio)
# cd "${APP_DIR}" && npm install --production

# 5. Start del servizio
systemctl start myapp.service

echo "Deploy completato. Testare l'applicazione."
# Qui si potrebbe aggiungere un controllo post-deploy (es. curl localhost:8080/health)

# Rimuovi il backup solo dopo aver verificato che il deploy è stabile
# rm -rf "${BACKUP_DIR}"

Questo script è un framework di base. In un ambiente reale, integreresti passaggi per la validazione della nuova release, test di integrazione, e magari l’uso di git per il deploy. La chiave è la capacità di tornare indietro rapidamente in caso di problemi, un requisito fondamentale per le applicazioni di produzione con SLA stringenti.

Script 6: inventory rapido dei server (SSH loop)

Conoscere lo stato dei tuoi server è cruciale. Questo script esegue un comando su un elenco di server remoti via SSH, utile per un inventory rapido o per controlli di conformità. Ho usato varianti di questo script per raccogliere informazioni su versioni del kernel, stato dei servizi o configurazioni di rete su decine di macchine in pochi minuti.

#!/bin/bash
set -euo pipefail
trap 'echo "Errore nell\'inventory alla riga $LINENO" >&2' ERR

SERVER_LIST="servers.txt" # File con un IP/hostname per riga
SSH_USER="sysadmin" # Utente SSH
COMMAND_TO_RUN="hostname -I; uptime; df -h /;"

if [[ ! -f "${SERVER_LIST}" ]]; then
    echo "File ${SERVER_LIST} non trovato." >&2
    exit 1
fi

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

Ricorda di configurare l’autenticazione SSH basata su chiave pubblica per l’utente sysadmin per evitare richieste di password. Questo script è incredibilmente versatile: puoi sostituire COMMAND_TO_RUN con qualsiasi comando o sequenza di comandi che desideri eseguire sui server remoti, dalla verifica delle patch installate all’analisi dei log recenti.

Script 7-10: utility di troubleshooting quotidiano

Questi script sono più semplici ma estremamente utili per il troubleshooting rapido.

Script 7: find_large_files.sh – Trova i file più grandi in una directory:

#!/bin/bash
set -euo pipefail
trap 'echo "Errore in find_large_files alla riga $LINENO" >&2' ERR

TARGET_DIR="${1:-.}" # Directory da analizzare (default: corrente)
NUM_FILES=10 # Numero di file più grandi da mostrare

if [[ ! -d "${TARGET_DIR}" ]]; then
    echo "Directory non trovata: ${TARGET_DIR}" >&2
    exit 1
fi

echo "Trovando i ${NUM_FILES} file più grandi in ${TARGET_DIR}..."
find "${TARGET_DIR}" -type f -print0 | xargs -0 du -h | sort -rh | head -n "${NUM_FILES}"

Script 8: check_port.sh – Verifica l’accessibilità di una porta remota:

#!/bin/bash
set -euo pipefail
trap 'echo "Errore in check_port alla riga $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} è raggiungibile."
else
    echo "${HOST}:${PORT} NON è raggiungibile." >&2
    exit 1
fi

Script 9: tail_all_logs.sh – Visualizza i log più recenti di una directory:

#!/bin/bash
set -euo pipefail
trap 'echo "Errore in tail_all_logs alla riga $LINENO" >&2' ERR

LOG_DIR="${1:-/var/log}" # Directory dei log (default: /var/log)

if [[ ! -d "${LOG_DIR}" ]]; then
    echo "Directory log non trovata: ${LOG_DIR}" >&2
    exit 1
fi

# Trova i 5 log più recenti e fa un tail -f su di essi
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 – Pulisce i file temporanei:

#!/bin/bash
set -euo pipefail
trap 'echo "Errore in cleanup_tmp alla riga $LINENO" >&2' ERR

TEMP_DIRS=('/tmp' '/var/tmp') # Directory temporanee da pulire
RETENTION_DAYS=7 # Elimina file più vecchi di 7 giorni

for dir in "${TEMP_DIRS[@]}"; do
    echo "Pulizia di ${dir}..."
    find "${dir}" -type f -mtime +${RETENTION_DAYS} -delete
    find "${dir}" -type d -empty -delete # Elimina directory vuote
done

echo "Pulizia file temporanei completata."

Questi script, pur nella loro semplicità, sono i cavalli di battaglia del SysAdmin. Permettono di risolvere problemi comuni rapidamente, diagnosticare l’utilizzo delle risorse e mantenere l’ordine nel filesystem, contribuendo a un ambiente di produzione più stabile.

Errori comuni e troubleshooting

Anche gli script bash possono avere problemi. Ecco alcuni errori comuni e come risolverli:

  • Permessi di esecuzione: Dimenticare chmod +x my_script.sh è un errore classico. Assicurati che lo script sia eseguibile.
  • Variabili non definite: L’opzione -u in set -euo pipefail ti aiuterà a individuare le variabili non definite, prevenendo comportamenti inaspettati. Se uno script fallisce con un messaggio unbound variable, cerca una variabile che non è stata inizializzata.
  • Percorsi assoluti vs relativi: Usa sempre percorsi assoluti (/usr/local/bin/my_script.sh) negli script che verranno eseguiti da cron o da altri contesti in cui la variabile PATH potrebbe non essere quella attesa. Questo evita errori di ‘comando non trovato’.
  • Spazi nei nomi dei file: Se i tuoi script devono gestire nomi di file con spazi, racchiudi sempre le variabili tra virgolette doppie (es. "${MY_VAR}"). Altrimenti, bash le interpreterà come argomenti separati.
  • Test in ambiente di staging: Mai eseguire un nuovo script in produzione senza averlo testato a fondo in un ambiente di staging. Un errore banale può avere conseguenze disastrose, come l’eliminazione accidentale di dati.
  • Output in cron: Gli script eseguiti da cron non hanno una console. Reindirizza l’output (stdout e stderr) a un file di log (>> /var/log/my_script.log 2>&1) e configura l’invio di email per gli errori ([email protected] nel crontab) per sapere cosa succede.

FAQ — Domande Frequenti

Come posso programmare l’esecuzione di questi script?

Puoi programmare l’esecuzione degli script utilizzando cron. Apri il tuo crontab con crontab -e e aggiungi una riga come 0 3 * /usr/local/sbin/my_backup_script.sh. Questa riga eseguirà lo script ogni giorno alle 03:00. Ricorda di usare percorsi assoluti e di reindirizzare l’output per il logging.

È sicuro eseguire script bash con privilegi di root?

Eseguire script con privilegi di root è necessario per molte operazioni di SysAdmin (backup, controllo servizi). Tuttavia, è cruciale che gli script siano scritti in modo sicuro, testati e che contengano set -euo pipefail per prevenire esecuzioni parziali o errori inaspettati. Limita l’uso di sudo solo ai comandi che lo richiedono espressamente e non eseguire mai script sconosciuti come root.

Qual è la differenza tra #!/bin/bash e #!/bin/sh?

#!/bin/bash specifica di usare la Bash shell, che offre funzionalità avanzate come array, espressioni regolari avanzate e set -euo pipefail. #!/bin/sh specifica di usare la shell predefinita del sistema (spesso un link simbolico a Bash, Dash o Zsh), che aderisce allo standard POSIX. Per script complessi o che usano funzionalità specifiche di Bash, è sempre meglio usare #!/bin/bash esplicitamente.

Posso usare questi script in un ambiente Windows?

Questi script sono scritti per ambienti Linux/Unix. Per automatizzare task su Windows, dovresti utilizzare PowerShell o cmd scripting. Tuttavia, alcuni strumenti come rsync possono essere disponibili tramite WSL (Windows Subsystem for Linux) o Cygwin, permettendo l’esecuzione di script bash in un ambiente simulato.

Conclusioni con takeaway operativi

L’automazione tramite bash scripting non è solo una comodità: è una necessità per qualsiasi SysAdmin che gestisce infrastrutture complesse. Adottando una metodologia di scripting robusto, basata sull’errore handling e sull’efficienza, puoi trasformare ore di lavoro manuale in pochi minuti di esecuzione automatizzata. Ho visto personalmente come l’implementazione di questi principi abbia ridotto il tempo dedicato al troubleshooting del 40% in ambienti enterprise, liberando risorse per progetti di miglioramento continuo.

Inizia oggi stesso a identificare i tuoi task ripetitivi e a trasformarli in script. Non devi essere un programmatore esperto; la chiave è la pratica e l’applicazione di principi di robustezza come set -euo pipefail. Ogni script che scrivi è un investimento nel tuo tempo e nell’affidabilità della tua infrastruttura.

Leggi anche: Hardening SSH Linux: Guida Completa 2026 (10 Impostazioni Critiche)

Leggi anche: Ansible Windows: Gestire Server Windows con WinRM e Moduli Core (2026)

Leggi anche: Netdata Monitoring Linux: Installazione e Configurazione Real-Time (2026)

Aggiornato: giugno 2026

Link esterno: Bash Guide for Beginners

Condividi questo articolo:

Scritto da

Rosario Giordano

Rosario Giordano è System Administrator e consulente IT specializzato in cybersecurity e cloud, con oltre 20 anni di esperienza nella gestione di infrastrutture Linux enterprise. Le sue aree di competenza includono hardening di SSH, piattaforme Kubernetes, database PostgreSQL, ambient i virtualizzati VMware e Proxmox, nonché la conformità ai framework di sicurezza NIS2 e ISO 27001.