Linux / Comando tail: ultime righe e log in tempo reale

tail mostra la parte finale di un file: senza opzioni stampa le ultime 10 righe. Con -n scegliete quante righe leggere; con -f o -F continuate a vedere i dati aggiunti al file.

È utile per leggere gli ultimi messaggi prima di un problema o osservare i log di un servizio in esecuzione. Gli esempi seguenti distinguono lettura statica, inseguimento di un file, rotazione dei log, filtri e più file contemporaneamente.

Che cosa fa tail?

Tail legge la parte finale di un input testuale. Se omettete il file o indicate - al suo posto, legge lo standard input, cioè i dati ricevuti dal terminale o da una pipe. L’unità predefinita è la riga e la quantità predefinita è 10 righe.

Non dovete aprire l’intero file in un editor per consultarne la fine. Tail legge e segue i dati: per analisi, conservazione e ricerca centralizzata dei log servono altri strumenti.

Sintassi e primi esempi

La sintassi generale è questa. Le parentesi quadre indicano elementi facoltativi: sostituite options con le opzioni e file... con uno o più percorsi, senza digitare le parentesi.

tail [options] [file...]

Per leggere le ultime 10 righe del file di esempio /var/log/app.log:

tail /var/log/app.log

Usate un percorso che esiste realmente e per cui avete accesso in lettura. Per le ultime 20 righe:

tail -n 20 /var/log/app.log

La forma abbreviata -20 è disponibile in GNU tail, ma -n 20 esprime meglio l’intenzione negli script e nella documentazione. I nomi come app.log senza percorso si riferiscono alla directory corrente.

Selezionare righe o byte

Le ultime N righe

-n N stampa le ultime N righe, oppure tutte quelle disponibili se il file ne contiene meno. Per esempio:

tail -n 50 access.log

Per leggere una porzione più ampia una schermata alla volta, inviate l’output a less, descritto nella guida in inglese:

tail -n 500 access.log | less

In less potete scorrere il testo e uscire con q. Questo esempio consulta le ultime 500 righe già lette da tail; non aggiunge da solo il monitoraggio continuo.

Dalla riga N fino alla fine

Con un segno più davanti al numero, -n +N cambia significato: parte dalla riga N, contando da 1, anziché selezionare le ultime N righe.

tail -n +2 data.csv

L’esempio salta la prima riga fisica di un CSV (valori separati da virgole). È adatto a un’intestazione su una riga; tail non interpreta il formato CSV e non riconosce i record che contengono ritorni a capo tra virgolette.

Usare i byte anziché le righe

-c N stampa gli ultimi N byte. GNU tail accetta anche suffissi come K e M:

tail -c 1K output.bin

1K equivale a 1.024 byte; 1kB equivale a 1.000 byte. Con -c +N la lettura inizia dal byte N. Un taglio per byte può spezzare un carattere UTF-8, comprese le lettere accentate e i caratteri di altre lingue: per un testo normale preferite le righe.

Seguire i nuovi messaggi di un log

Seguire il file aperto con -f

-f mostra prima la fine del file, poi continua a stampare i dati aggiunti. In GNU tail segue per impostazione predefinita il descrittore, cioè il riferimento al file già aperto.

tail -f /var/log/app.log

È adatto quando lo stesso file continua a crescere. Per interrompere la lettura e tornare alla shell, premete Ctrl+C: il log non viene cancellato né modificato.

Seguire il nome con -F dopo la rotazione

La rotazione dei log può rinominare il vecchio file e crearne uno nuovo con il nome originale. GNU -F equivale a --follow=name --retry: segue quel nome e riprova ad aprirlo se il file non è accessibile.

tail -F /var/log/app.log

Per i servizi che sostituiscono i file durante la rotazione, -F è spesso la scelta più pratica. Il codice e l’aiuto ufficiale di GNU tail specificano la differenza tra nome e descrittore. Se il file viene troncato, tail può rilevarlo e riprendere dall’inizio; non è però un sistema che garantisce l’acquisizione di ogni messaggio durante rotazioni o scritture molto rapide.

Mostrare solo ciò che viene aggiunto

Aggiungete -n 0 se non volete le ultime 10 righe già presenti quando tail apre il file:

tail -n 0 -f /var/log/app.log

Vedrete i dati aggiunti dopo il posizionamento iniziale alla fine del file. Se non appare nulla, il programma potrebbe non aver ancora scritto o svuotato il proprio buffer, oppure potreste osservare il percorso sbagliato.

Le opzioni più usate

Opzione Funzione Esempio o impiego
-n N Ultime N righe tail -n 100 app.log
-n +N Dalla riga N tail -n +2 data.csv
-c N Ultimi N byte tail -c 2K data.bin
-f Segue il file aperto Un file che cresce senza essere sostituito
-F Segue il nome e riprova Log soggetti a rotazione
-s N Intervallo di attesa approssimativo in secondi tail -f -s 2 app.log
--pid=PID Termina l’inseguimento dopo la fine del processo indicato Osservare il log di un processo batch
-q Nasconde le intestazioni con il nome del file Unire l’output di più file senza intestazioni
-v Mostra sempre il nome del file Rendere esplicita l’origine dell’output

Verificate le opzioni con tail --help sul sistema di destinazione: GNU, BSD e altre implementazioni possono differire. Con il meccanismo Linux inotify, le modifiche possono essere notificate direttamente; -s non va quindi interpretato come un ritardo obbligatorio per ogni aggiornamento.

Esempi pratici per i log

Filtrare gli errori recenti

Per cercare la stringa ERROR solo nelle ultime 200 righe:

tail -n 200 app.log | grep 'ERROR'

grep -i ignora la distinzione tra maiuscole e minuscole. grep -n aggiunge numeri di riga, ma in questa pipe li conta dall’inizio dell’input ricevuto da tail: non sono i numeri originali nel file completo.

Filtrare mentre il log cresce

Per seguire il file per nome e mostrare le righe che contengono ERROR:

tail -F app.log | grep --line-buffered 'ERROR'

GNU grep --line-buffered svuota il buffer di output dopo ogni riga e può ridurre i ritardi nelle pipe. Il manuale di GNU grep descrive sia questa opzione sia i numeri di riga. Il filtro non cambia il log; il comando mostra anche eventuali ERROR tra le righe iniziali già presenti. Per soli dati nuovi potete aggiungere -n 0 a tail.

Terminate la pipe con Ctrl+C. Il filtro non può mostrare un messaggio che l’applicazione non ha ancora scritto: --line-buffered riguarda l’output di grep, non il buffer del servizio.

Seguire più file

Indicate più percorsi per osservarli insieme:

tail -F access.log error.log

Le intestazioni indicano da quale file provengono i dati. -v le rende esplicite anche con un solo file; -q le elimina. Non interpretate l’ordine di arrivo da file diversi come un ordinamento globale garantito per data.

Terminare quando finisce il processo che scrive

In GNU tail, --pid permette di uscire quando il processo osservato non esiste più. PID significa identificatore del processo; $! è quello dell’ultimo processo avviato in background dalla shell.

some_command > build.log 2>&1 &
tail --pid=$! -f build.log

some_command è un segnaposto: sostituitelo con il comando reale da eseguire, nella stessa shell. L’operatore > crea o sovrascrive build.log; scegliete un file di lavoro che potete scrivere e il cui contenuto precedente non serve. 2>&1 invia anche lo standard error nel log, e & avvia il comando in background.

Il controllo del PID funziona insieme all’inseguimento e può rilevare la fine con un ritardo. Il processo che scrive e tail devono essere nello stesso ambiente di processi; un PID di un’altra macchina o di un namespace diverso non è un riferimento valido. Tail non restituisce automaticamente il codice di uscita del comando osservato: negli script conservate il PID e controllate separatamente il risultato con wait.

Differenza tra -f e -F

Aspetto -f -F
Riferimento Descrittore del file aperto, per impostazione predefinita Nome indicato
Sostituzione del file Può continuare a leggere il vecchio file Riapre il nuovo file con lo stesso nome
Percorso temporaneamente assente Il descrittore già aperto può restare leggibile, ma non riapre il nuovo file Riprova finché il file torna accessibile
Uso tipico Osservare un file non sostituito, o il vecchio file ancora scritto Osservare il nome di un log soggetto a rotazione

La scelta dipende da come il servizio scrive e ruota i log. Se il processo continua a scrivere nel vecchio file dopo averlo rinominato, seguire il descrittore con -f può essere proprio ciò che vi serve. Nessuna delle due opzioni sostituisce una raccolta affidabile e persistente dei log.

Quando usare un altro strumento

  • Journal di systemd: per i log nel journal, usate journalctl -f; con journalctl -f -u nome-servizio limitate il risultato al servizio, sostituendo il segnaposto con l’unità reale.
  • Inizio del file: head è più diretto per leggere le prime righe.
  • Lettura e inseguimento: less +F nomefile consente di seguire le aggiunte. Interrompete l’inseguimento con Ctrl+C, scorrete il testo e riprendetelo con F; uscite da less con q.
  • Ripetere un comando: se volete aggiornare il risultato di un comando anziché seguire le aggiunte a un file, consultate la guida a watch, in inglese.
  • Log centralizzati: per ricerca, aggregazione e avvisi su più server, usate un sistema di raccolta e osservazione dei log.

Permessi e uso in produzione

Errore Permission denied

Controllate il percorso, il proprietario e i permessi con ls -l nomefile. Può essere necessario verificare anche l’accesso alle directory del percorso. Richiedete i permessi appropriati all’amministratore; evitate di ampliare indiscriminatamente i permessi o aggiungere sudo a ogni comando.

Dati sensibili nei log

I log possono contenere token, identificatori di sessione e dati personali. Prima di condividere lo schermo o inviare un messaggio di errore, estraete solo la parte necessaria e oscurate i valori sensibili, comprese eventuali copie salvate dal terminale.

Domande frequenti

Quante righe stampa tail senza opzioni?

Le ultime 10. Per una quantità diversa usate, per esempio, tail -n 30 nomefile.

Come si interrompe tail -f?

Premete Ctrl+C per fermare la lettura e tornare alla shell. Questo non cancella né modifica il file seguito.

Perché non vedo nuovi messaggi dopo la rotazione?

-f potrebbe seguire ancora il vecchio descrittore. Provate GNU tail -F nomefile per seguire il nome e riaprire il file sostitutivo. Se non cambia nulla, verificate percorso reale, permessi e destinazione dell’output del servizio.

Tail legge automaticamente i log compressi?

No. Potete decomprimere il flusso e inviarlo a tail, per esempio zcat archive.log.gz | tail -n 50 per gzip. Leggere e decomprimere tutto un grande archivio può essere costoso; tail da solo non consente di saltare direttamente alle sue ultime righe testuali.

Riepilogo

Usate tail per le ultime righe, -n per la quantità, -f per seguire il file aperto e GNU -F per seguire un nome durante la sostituzione del log. Aggiungete grep quando volete selezionare messaggi specifici.

Controllate sempre percorsi, permessi e dati sensibili. La raccolta dei comandi Linux più usati, in inglese descrive altri strumenti utili nelle stesse attività.