Comando tee in Linux: salvare e mostrare l’output di una pipeline

tee copia lo standard input sullo standard output e, contemporaneamente, in uno o più file. Ti permette di osservare un risultato nel terminale oppure di passarlo al comando successivo della pipe, conservandone anche una copia.

Per impostazione predefinita sovrascrive i file indicati; usa -a per aggiungere il nuovo contenuto in fondo. A differenza di una semplice redirezione con >, tee mantiene un’uscita utilizzabile dal resto della pipeline. Salva soltanto ciò che riceve sul proprio standard input: gli errori di un comando precedente non vi arrivano automaticamente.

Sintassi e preparazione

comando | tee [opzioni] file [altri-file...]

Questa è una notazione: sostituisci i segnaposto con il comando da eseguire, le opzioni e i percorsi reali, senza le parentesi quadre. tee crea i file mancanti quando i permessi lo consentono. Se specifichi più destinazioni, la stessa entrata viene copiata in tutte. Controlla man tee per le opzioni della tua installazione: -p, usata più avanti, è un’estensione GNU.

Esempi: visualizzare, aggiungere e proseguire la pipe

Mostrare e salvare un risultato

Esegui questa prova in una shell compatibile con Bash. Crea una directory nuova per non sovrascrivere dati precedenti: se tee-demo esiste, scegli un altro nome, perché il resto del blocco non verrà eseguito.

mkdir tee-demo && cd tee-demo && (
  set -e
  date | tee run-time.txt
)

La data e l’ora appaiono nel terminale e vengono registrate in run-time.txt. Il testo preciso dipende dall’orologio, dal fuso e dalle impostazioni locali: non aspettarti una data fissa. Rimani nella directory tee-demo per gli esempi successivi e verifica il file con cat run-time.txt.

Aggiungere al contenuto esistente

Per conservare la prima riga e aggiungere una seconda registrazione:

date | tee -a run-time.txt

Il terminale mostra solo la nuova uscita di date; il file contiene entrambe le registrazioni. Due esecuzioni molto ravvicinate possono mostrare lo stesso orario. Senza -a, la seconda esecuzione sostituirebbe il contenuto precedente. L’opzione di protezione della shell noclobber non protegge i file aperti direttamente da tee.

Salvare un risultato intermedio e leggerne l’inizio

Prepara un file di nomi e ordinalo, salvando l’intero risultato con GNU tee. La preparazione del file è protetta contro la sovrascrittura; scegli anche per names.sorted una destinazione nuova:

(
  set -e
  set -o noclobber
  printf 'Carla\nAna\nBob\n' > names.txt
) &&
LC_ALL=C sort names.txt | tee -p names.sorted | head

Ottieni Ana, Bob e Carla, su tre righe, e names.sorted contiene lo stesso risultato. head legge normalmente le prime dieci righe; con questi tre nomi legge tutto. La guida a sort spiega l’ordinamento e l’uso dell’ambiente locale C.

Il comando semplice sort names.txt | tee names.sorted | head può sembrare equivalente su input piccoli. Su una grande uscita, però, head può terminare dopo dieci righe e chiudere la pipe mentre tee sta ancora scrivendo: il comportamento GNU predefinito può allora interrompere tee e lasciare il file incompleto. Con -p, GNU tee continua verso le destinazioni ancora valide, compreso il file. Per una procedura portabile che richiede una copia completa, salva prima l’intero risultato e poi esegui head sul file, controllando il successo di ciascun passaggio.

Una riga identica nel terminale e nel file

Nella directory di prova, scegliendo result.txt come nome nuovo:

printf 'status=ok\n' | tee result.txt

Output atteso nel terminale:

status=ok

cat result.txt mostra la stessa riga. Per aggiungerne un’altra usa printf 'status=ok\n' | tee -a result.txt. Per due copie simultanee puoi usare printf 'status=ok\n' | tee copy-one.txt copy-two.txt, sempre scegliendo percorsi nuovi. Se vuoi salvare senza mostrare la copia sullo standard output, aggiungi > /dev/null dopo tee; questo non nasconde automaticamente i messaggi d’errore.

Opzioni principali

Opzione Effetto
-a Aggiunge ai file indicati invece di sovrascriverli.
-i Ignora il segnale di interruzione SIGINT nel processo tee; non equivale a rendere immune l’intera pipeline.
-p In GNU modifica la gestione degli errori di scrittura sulle pipe, continuando verso le altre uscite ancora valide quando un lettore termina prima.

Il modo predefinito di -p in GNU è warn-nopipe: gli errori sulle destinazioni che non sono pipe vengono segnalati e influiscono sul codice di uscita. Non è una garanzia contro spazio esaurito, percorsi errati o errori del produttore dei dati. Le varianti di --output-error richiedono la documentazione della versione installata.

Precauzioni: permessi, errori e dati sensibili

La shell esegue le redirezioni con i propri permessi. Per questo la forma sudo comando > file-protetto può fallire anche se il comando viene elevato: l’apertura del file viene tentata dalla shell corrente. Quando sei autorizzato a modificare quel preciso file, la forma comando | sudo tee file-protetto può assegnare l’apertura e la scrittura al processo tee elevato. Sono forme illustrative, non percorsi da copiare: verifica sempre destinazione, contenuto e necessità di -a prima di agire.

tee invia anche una copia sullo standard output, quindi evita di esporre password, token o altri dati riservati nel terminale o nei log. Non usare come destinazione un file che la pipeline sta leggendo: l’apertura per la scrittura può troncarlo mentre il produttore lo usa. Per trasformazioni di file esistenti usa una destinazione distinta, verifica il risultato e conserva l’originale fino al controllo.

Per comprendere la cattura degli errori, prova su nomi di file nuovi: (printf 'ok\n'; printf 'errore\n' >&2) 2>&1 | tee combined.log. La redirezione 2>&1 prima della pipe fa arrivare a tee sia lo standard output sia lo standard error del gruppo. Il file conterrà le due righe; su processi reali buffering e concorrenza possono influire sul loro ordine. Gli errori generati da tee stesso restano un flusso separato da verificare.

Controlla anche gli esiti della pipeline. In Bash, senza pipefail, lo stato complessivo è normalmente quello dell’ultimo comando: false | tee failed.log può quindi terminare con stato complessivo 0 pur avendo fallito il produttore. In una subshell di prova puoi usare (set -o pipefail; false | tee failed-check.log), che restituisce un errore. Per il codice appena terminato, echo "$?" va eseguito subito; comandi intermedi lo cambiano. Negli script valuta separatamente i processi rilevanti e non considerare il solo file presente come prova del successo.

Domande frequenti

tee salva anche lo standard error?

Salva soltanto ciò che arriva sul suo standard input. Per includere gli errori del comando precedente devi unirli esplicitamente al flusso, per esempio con 2>&1 prima della pipe. Decidi prima se vuoi davvero mescolare risultati e diagnostica nello stesso file.

Documentazione di riferimento

La pagina di manuale GNU di tee su man7 descrive opzioni e modi di gestione degli errori della versione documentata. Il riferimento POSIX per tee specifica duplicazione dell’ingresso, aggiunta ai file e codici di uscita.