Chiunque amministri sistemi Linux passa gran parte della giornata dentro una shell, e la cronologia dei comandi (history) è probabilmente lo strumento più usato e meno conosciuto a fondo. Sappiamo tutti premere la freccia su o lanciare Ctrl+R, ma pochi sfruttano davvero le variabili che controllano cosa viene salvato, come viene formattato e come sincronizzarlo tra più terminali aperti in contemporanea. Vediamo come portare la gestione della cronologia Bash a un livello professionale, con configurazioni pronte per essere messe in produzione su server multi-utente.
Le variabili che governano la cronologia
Bash tiene traccia dei comandi in due posti distinti: la memoria della sessione corrente e il file su disco (di default ~/.bash_history). Questa distinzione è la fonte di gran parte della confusione quando si lavora con più terminali aperti, quindi vale la pena chiarirla subito con le variabili che la controllano.
HISTSIZE e HISTFILESIZE
HISTSIZE stabilisce quanti comandi restano in memoria durante la sessione attiva, mentre HISTFILESIZE determina quante righe vengono conservate nel file su disco. Sono due limiti indipendenti: si può avere una sessione “leggera” con poche centinaia di comandi in memoria ma un archivio storico molto più ampio su disco.
export HISTSIZE=10000
export HISTFILESIZE=20000
Impostare un valore negativo (o vuoto) rende la cronologia illimitata: sconsigliato su sistemi condivisi, dove un file di history che cresce senza controllo può diventare un problema sia di spazio che di sicurezza.
HISTFILE
HISTFILE indica dove viene scritta la cronologia. Il default è ~/.bash_history, ma è possibile ridirigerla altrove, ad esempio per tenere una history separata per progetto o per sessioni di audit:
export HISTFILE="$HOME/.bash_history_$(date +%Y%m)"
HISTTIMEFORMAT: i timestamp che quasi nessuno abilita
Per impostazione predefinita, history non mostra quando un comando è stato eseguito. Abilitare i timestamp con HISTTIMEFORMAT è probabilmente l’impostazione a più alto rapporto beneficio/sforzo di questo articolo, specialmente in fase di troubleshooting: sapere che un comando è stato lanciato tre minuti prima di un incidente è un’informazione preziosa.
export HISTTIMEFORMAT="%F %T "
Con questa impostazione, history | grep nginx restituirà righe del tipo:
1042 2026-09-03 10:14:02 systemctl reload nginx
Un dettaglio tecnico da tenere a mente: il timestamp viene registrato internamente come epoch Unix ad ogni comando, ma diventa visibile solo se HISTTIMEFORMAT è impostato prima che i comandi vengano eseguiti. Se lo si abilita a metà sessione, i comandi precedenti non avranno un timestamp recuperabile.
HISTCONTROL: cosa non salvare
HISTCONTROL filtra cosa entra in cronologia:
ignorespace– esclude i comandi che iniziano con uno spazio (utile per non salvare comandi con password o token inline)ignoredups– salta i duplicati consecutiviignoreboth– combina entrambi i comportamenti precedentierasedups– rimuove tutte le occorrenze precedenti di un comando ripetuto, non solo quelle consecutive
export HISTCONTROL=ignoreboth
Il trucco di ignorespace è particolarmente utile: basta digitare un comando con uno spazio iniziale (es. curl -H "Authorization: Bearer xyz..." ...) per evitare che token o credenziali finiscano nel file di history in chiaro.
HISTIGNORE: filtrare per pattern
HISTIGNORE permette di escludere dalla cronologia comandi ricorrenti e poco utili come ls, cd o pwd. Attenzione: i pattern ancorano l’inizio della riga e devono corrispondere all’intero comando, quindi vanno elencati esplicitamente anche gli argomenti comuni.
export HISTIGNORE="ls:ll:la:cd:cd -:pwd:exit:date:clear:history"
Le opzioni della shell: histappend e histverify
Due shopt completano la configurazione di base. La prima è quasi obbligatoria su qualunque sistema con più terminali:
shopt -s histappend
Senza histappend, Bash sovrascrive il file HISTFILE alla chiusura della shell con il contenuto della sessione corrente, perdendo i comandi salvati da altri terminali chiusi nel frattempo. Con histappend attivo, ogni sessione aggiunge in coda invece di sovrascrivere.
La seconda opzione utile è histverify, che intercetta le espansioni di history (come !! o !497) e le mostra sul prompt per una conferma, invece di eseguirle immediatamente:
shopt -s histverify
Questo piccolo accorgimento evita un classico incidente: digitare !42 pensando che sia un comando innocuo e scoprire, dopo l’esecuzione, che il comando numero 42 era un rm -rf lanciato ore prima in un altro contesto.
Sincronizzare la cronologia tra terminali multipli
Per chi lavora con molte finestre o sessioni tmux/screen aperte in parallelo, il comportamento di default di Bash è frustrante: ogni shell scrive la propria history solo alla chiusura, quindi i comandi digitati in un terminale non sono visibili negli altri finché non li si chiude esplicitamente.
La soluzione è agganciare la scrittura e la ricarica della history a PROMPT_COMMAND, che Bash esegue prima di ogni visualizzazione del prompt:
PROMPT_COMMAND="history -a; history -c; history -r${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
Scomponendo la sequenza:
history -a– accoda immediatamente su disco i nuovi comandi della sessionehistory -c– svuota la lista in memoria della sessione correntehistory -r– ricarica in memoria l’intero file, inclusi i comandi scritti da altre sessioni
Il risultato: la freccia su e Ctrl+R attingono a una cronologia condivisa e aggiornata quasi in tempo reale tra tutti i terminali aperti. Il costo è un piccolo overhead ad ogni prompt, generalmente trascurabile salvo file di history molto grandi; in quel caso è preferibile una variante più leggera con history -n, che legge solo le righe nuove invece di ricaricare l’intero file:
PROMPT_COMMAND="history -a; history -n${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
Comandi di gestione della history
Oltre alle variabili di ambiente, il builtin history offre diverse operazioni utili in amministrazione quotidiana:
# Mostra tutta la cronologia con numerazione
history
# Ultimi 20 comandi
history 20
# Cerca nella cronologia
history | grep nginx
# Scrive subito su disco la sessione corrente
history -a
# Elimina una riga specifica dalla memoria (es. riga 497)
history -d 497
# Elimina e persiste la rimozione sul file
history -d 497 && history -w
# Svuota completamente memoria e file
history -c && history -w
Per disabilitare temporaneamente la registrazione, ad esempio prima di digitare una password su un comando che non supporta variabili d’ambiente:
set +o history
# comandi non registrati qui
set -o history
Le scorciatoie da tastiera che valgono la pena imparare
Oltre al classico Ctrl+R per la ricerca incrementale, Bash espone un intero linguaggio di espansione della history, largamente sotto-utilizzato:
| Scorciatoia | Funzione |
|---|---|
!! |
Ripete l’ultimo comando |
!$ |
Ultimo argomento del comando precedente |
!^ |
Primo argomento del comando precedente |
!* |
Tutti gli argomenti del comando precedente |
!N |
Esegue il comando numero N |
!stringa |
Ultimo comando che inizia con “stringa” |
!stringa:p |
Mostra il comando senza eseguirlo (preview) |
^vecchio^nuovo |
Sostituisce e rilancia l’ultimo comando |
Alt+. |
Richiama ciclicamente l’ultimo argomento dei comandi precedenti |
!$ in particolare è utile più spesso di quanto sembri: dopo mkdir /var/log/miaapp, digitare cd !$ evita di riscrivere il percorso.
Ricerca interattiva avanzata con fzf
Per chi trova Ctrl+R limitante, fzf lo sostituisce con un fuzzy finder interattivo molto più potente:
sudo apt install fzf # Debian/Ubuntu
eval "$(fzf --bash)" # da aggiungere a ~/.bashrc
Una volta configurato, Ctrl+R apre un filtro interattivo con evidenziazione live: premendo Invio la prima volta il comando viene incollato sul prompt (non eseguito), permettendo di modificarlo prima del lancio effettivo.
Sicurezza: la history non è un controllo, è un log
Alcuni punti da tenere presenti quando si gestiscono cronologie su sistemi condivisi o in produzione:
- Il file di history dovrebbe avere permessi restrittivi:
chmod 600 ~/.bash_history ignorespacenasconde un comando dalla history solo se lo spazio iniziale viene digitato manualmente: non è un meccanismo automatico- File di history su NFS o directory sincronizzate (Dropbox, syncthing, ecc.) possono esporre comandi sensibili a più host
- La cronologia è auditabile dall’utente stesso ma non è un controllo di sicurezza: chiunque abbia accesso alla shell può disabilitarla con
set +o historyo cancellarla - Per un audit trail affidabile in produzione, la history di Bash va affiancata (non sostituita) da strumenti dedicati come
auditdo da logging centralizzato della sessione shell
Configurazione completa consigliata
Riassumendo tutto quanto visto in un blocco pronto per ~/.bashrc:
# Configurazione History Bash
HISTSIZE=10000
HISTFILESIZE=20000
HISTTIMEFORMAT="%F %T "
HISTCONTROL=ignoreboth
HISTIGNORE="ls:ll:la:cd:cd -:pwd:exit:date:clear:history"
shopt -s histappend
shopt -s histverify
# Sincronizza la cronologia tra terminali dopo ogni comando
PROMPT_COMMAND="history -a; history -c; history -r${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
Dopo averla incollata, applicarla con:
source ~/.bashrc
Conclusione
La cronologia di Bash è uno di quegli strumenti che si usano per anni senza mai configurarli davvero. Pochi minuti spesi su HISTTIMEFORMAT, HISTCONTROL e la sincronizzazione via PROMPT_COMMAND trasformano un log grezzo e volatile in uno strumento di troubleshooting affidabile, specialmente su server dove si lavora regolarmente da più sessioni contemporanee. Per chi gestisce ambienti multi-utente, vale la pena ricordare che la history resta comunque uno strumento lato client: per l’audit reale servono log centralizzati indipendenti dalla volontà dell’utente.
Fonte originale: Master Linux Bash History with historyctl, HISTFILE, and Shortcuts – LinuxBlog.io