Qual è lo scopo di 'tee'?


90

Tutti gli usi che teeio abbia mai visto erano tali:

 do_something | tee -a logfile

O:

do_something_else | tee logfile

È stato teeinventato per coloro che non sanno che puoi fare lo stesso con i reindirizzamenti del tubo shell? Ad esempio:

do_something >> logfile

O:

do_something_else > logfile

È praticamente lo stesso e richiede meno colpi di tastiera per scrivere. In quali funzioni nascoste non vedo tee?


62
Come è stato risposto alla prima riga della pagina man "... e scrivere su output e file standard" ? Le risposte sono interessanti, ma parlando in generale di come le pipe siano utili non fa che rafforzare il modo in cui questa Q sembra troppo ampia e forse avrebbe dovuto essere chiusa.
Xen2050,

3
@ Xen2050 Non è possibile incolpare una domanda per una risposta troppo ampia. La domanda è molto specifica, così come l'attuale risposta con il punteggio più alto .
Jon Bentley,

1
@JonBentley la domanda non sembra "un problema specifico con dettagli sufficienti per identificare una risposta adeguata" (come si legge nella finestra di dialogo di chiusura). Sembra così: "se la tua domanda potrebbe essere risolta da un intero libro o abbia molte risposte valide (ma non c'è modo di determinare quali - se del caso - siano corrette), allora è probabilmente troppo ampia per il nostro formato". (Fonte: Centro assistenza )
Xen2050,

4
@ Xen2050 Stiamo leggendo la stessa domanda? Mi sembra molto specifico: qual è la differenza tra tee e pipe? Ha ricevuto una risposta adeguata usando due frasi. Lontano da un intero libro. Il fatto che alcune risposte scelgano di andare su una tangente non ha nulla a che fare con l'ambito della domanda.
Jon Bentley,

@JonBentley: stiamo leggendo la stessa domanda? R Il tipo di tipo di Moog implica una domanda abbastanza ben focalizzata: qual è la differenza tra tee e reindirizzamento I / O ?   Il fatto che dica " reindirizzamenti shell pipe come e " non è un punto a suo favore, ed è un argomento per chiudere come poco chiaro. Ma si chiede in realtà molteplici domande: “Qual è lo scopo di ?”, “È inventato per coloro che non sa che si può fare lo stesso con i reindirizzamenti tubo shell?” E “Quali caratteristiche nascoste sono io, non vedendo in ?”. Almeno due di queste domande sono troppo ampie. >>>teeteetee
G-Man,

Risposte:


242

Quello che non vedi è che do_something | tee -a logfilemette l'output in logfile e to stdout, mentre lo do_something >> logfileinserisce solo nel file di log.

Lo scopo teeè quello di produrre uno scenario di input singolo, output multiplo - proprio come in un incrocio a "T".

MODIFICARE

Ci sono stati commenti su come teeconsentire un uso più apparente di sudo. Questa è questo il punto: cat, ddo forse meglio bufferfornire questa possibilità con la migliore prestazione, se non hai bisogno di uscite multiple. Utilizzare teeper ciò che è progettato, non per ciò che "può anche fare"


37
L'output multiplo è la chiave. teepuò persino accettare più argomenti e scrivere su più file contemporaneamente.
Kamil Maciorowski,

20
Lo definirei un raccordo a T , non un incrocio (come in un incrocio stradale?) La roba arriva in un modo ed esce in entrambi i modi.
user253751

7
Come userei catin modo semplice invece che teead es. echo /var/work/core.%p | sudo tee /proc/sys/kernel/core_pattern? echo /var/work/core.%p | sudo cat > /proc/sys/kernel/core_patternnon funziona perché il reindirizzamento viene elaborato dalla shell non sudo. Per quanto riguarda dd, echo /var/work/core.%p | sudo dd of=/proc/sys/kernel/core_patternfunziona, ma ddè spesso uno strumento sopraffatto in grado di fare grandi danni, specialmente sotto sudo. Per quanto riguarda buffer, non è installato di default in nessuna delle distro basate su RedHat o Ubuntu che devo consegnare (o MacOS) ...
Digital Trauma,

3
@EugenRieck Ho capito il tuo punto sulla relazione 1: n tra in: out è la funzione principale. Tuttavia, né il builtin catné il /bin/catlavoro per me in questa situazione. Non importa da dove catviene, la >volontà verrà comunque gestita dalla shell di livello superiore (non sudo). Il vantaggio di teeover catin questa situazione è che consente al file di output di essere passato come parametro della riga di comando (e non come reindirizzamento). ddè certamente un'opzione praticabile, anche se preferirei comunque teequesto
Digital Trauma,

3
@EugenRieck Che shell ha cate teecome builtin? E quale versione di sudopuò eseguire i shell incorporati?
wjandrea,

118

Tee non è inutile

Forse lo sapevi comunque? In caso contrario, continua a leggere! O se sai come funziona, ma non sei sicuro del motivo per cui esiste, salta alla fine per vedere come si adatta alla filosofia Unix.

Qual è lo scopo di tee?

Nella sua forma più semplice, prende i dati sull'input standard e li scrive sull'output standard e su uno (o più) file. È stato paragonato a un raccordo a T idraulico nel modo in cui divide un ingresso in due uscite (e due direzioni).

Esempi

Facciamo il tuo primo esempio:

do_something | tee -a logfile

Questo prende l'output di do_somethinge lo aggiunge al file di log, mostrandolo allo stesso tempo all'utente. In effetti, la pagina di Wikipedia sutee ha questo come secondo esempio:

Per visualizzare e aggiungere l'output di un comando a un file esistente:

  lint program.c | tee -a program.lint

Questo visualizza l'output standard del comando lint program.c sul computer e allo stesso tempo ne aggiunge una copia alla fine del file program.lint. Se il file program.lint non esiste, viene creato.

Il prossimo esempio ha un altro uso: escalation delle autorizzazioni :

Per consentire l'escalation delle autorizzazioni:

cat ~/.ssh/id_rsa.pub | ssh admin@server "sudo tee -a /root/.ssh/authorized_keys2 > /dev/null"

Questo esempio mostra il tee utilizzato per bypassare una limitazione intrinseca nel sudocomando. sudonon è in grado di reindirizzare l'output standard in un file. Scaricando il suo flusso standard in /dev/null, eliminiamo anche l'output speculare nella console. Il comando sopra fornisce all'utente root l'accesso corrente a un server tramite ssh, installando la chiave pubblica dell'utente nell'elenco di autorizzazioni della chiave del server.

O forse vuoi prendere l'output di un comando, scriverlo da qualche parte e anche usarlo come input per un altro comando?

È inoltre possibile utilizzare il comando tee per memorizzare l'output di un comando su un file e reindirizzare lo stesso output di un input su un altro comando.

Il comando seguente eseguirà un backup delle voci crontab e passerà le voci crontab come input per il comando sed che effettuerà la sostituzione. Dopo la sostituzione, verrà aggiunto come nuovo cron job.

$ crontab -l | tee crontab-backup.txt | sed 's/old/new/' | crontab –

(credito per esempi di utilizzo del comando Tee )

Tee funziona con la filosofia Unix:

Scrivi programmi che fanno una cosa e la fanno bene. Scrivi programmi per lavorare insieme. Scrivi programmi per gestire flussi di testo, perché questa è un'interfaccia universale.

(Ringraziamenti di base della filosofia Unix )

tee si adatta a tutti questi:

  • fa una cosa: crea una copia aggiuntiva di input
  • funziona con altri programmi perché è la colla (o un pezzo idraulico a "T" se preferisci) che consente ad altri programmi di lavorare insieme come negli esempi sopra
  • lo fa manipolando un flusso di testo fornito sull'input standard

3
@Joe: sudo tee -aè probabilmente un'innovazione più recente (l'ho visto per la prima volta nelle guide / wiki di Ubuntu soprattutto per l'impostazione delle cose /proc/sys, perché il passaggio a Ubuntu è stato quando sono passato a un sudosistema basato (come Ubuntu è configurato per impostazione predefinita) invece di utilizzare sucon un password di root). Penso che teeprecede sudo, quindi non è un motivo per teeesistere. Non è necessario teeper questo, è semplicemente più breve digitare interattivamente di sudo sh -c 'cat > output'.
Peter Cordes,

1
Con gusci moderni come bash, puoi teealimentare due condotte, come foo | tee >(pipe2) | pipe1. Oppure un altro divertente è ffmpeg ... |& tee /dev/tty | sed 's/.*\r// > encode.logvedere gli aggiornamenti della linea di stato in modo interattivo sul tty, mentre rimuovono le "linee" che terminano con il ritorno a capo invece di newline per la registrazione effettiva. (ovvero filtrare gli aggiornamenti della riga di stato). In generale, è possibile incollare un tee /dev/ttypunto qualsiasi in una pipeline come una stampa di debug.
Peter Cordes,

2
È meno una limitazione di sudo a cui stai lavorando e più una limitazione dell'interpretazione della shell di>. Quando si esegue un comando con sudo, il suo stdout viene rinviato al programma della shell e ulteriori reindirizzamenti con> vengono eseguiti con le autorizzazioni della shell. Se si desidera scrivere con autorizzazioni elevate, è necessario che la parte elevata della pipeline sia la scrittura. Esistono molti modi per farlo a seconda dell'effetto che stai cercando. Se vuoi davvero usare> qualcosa come 'sudo bash -c "command> outfile"' farà il lavoro.
Perkins,

Esatto, @Perkins. La shell analizza >e imposta il reindirizzamento prima che sudo lo ottenga exec, quindi non è assolutamente una limitazione di sudo che non gestisce cose che non vede mai. :) Di solito cerco di fare riferimento a questo come "flusso di lavoro sudo" o ad un termine simile quando lo sto spiegando, piuttosto che descrivere lo stesso sudo.
dannysauer,

sudo tee -aIMHO è un abuso di tee. Usare sudo cat, sudo ddo (con le migliori prestazioni in molti casi) sudo buffer, se non è necessario le uscite multiple.
Eugen Rieck,

70

È praticamente lo stesso e richiede meno colpi di tastiera per scrivere.

Non è affatto lo stesso ...

Quanto segue sembra essere in qualche modo equivalente, ma non lo sono:

$ echo "hi" > test.txt
$ echo "hi" | tee test.txt
hi

La differenza fondamentale è che il primo ha scritto i dati solo nel file indicato, mentre il secondo ha scritto hinel terminale ( stdout) e nel file indicato, come mostrato di seguito:

reindirizzamento vs tee


teeti consente di scrivere i dati in un file e di usarli in una pipeline successiva, permettendoti di fare cose utili - come mantenere i dati a metà strada attraverso una pipeline:

grep '^look ' interesting_file.txt \
  | tee interesting_lines.txt \
  | sort

In alternativa, è possibile scrivere su un file con privilegi elevati, senza assegnare privilegi elevati all'intera pipeline (qui echoviene eseguito come utente, mentre teescrive nel file come root):

echo 0 \
  | sudo tee /proc/sys/net/ipv4/ip_forward

Con tee, puoi scrivere su molti file ( e stdout ):

echo "hi" \
  | tee a.txt b.txt

È anche possibile utilizzare execcon teeper registrare tutto l'output di uno script in un file, consentendo comunque a un osservatore ( stdout) di vedere i dati:

exec > >( tee output.log )

2
Da non dimenticare exec > >(tee "$LOGFILE") 2>&1in uno script bash che consente allo script di generare stdout e stderr su entrambi, stdout e il file a cui punta $LOGFILE.
rexkogitans,

@rexkogitans 2> & 1 non è questa sintassi batch cmd?
dmb,

@dmb: è la sintassi della shell per "invia stderr (= 2) nello stesso posto di stdout (= 1)"
psmears,

@rexkogitans Era davvero una bella domanda, non posso davvero sapere che non usi "Windoze" da un decennio. Uso 2>&1per eliminare l'output ed errare su file txt in Windows.
dmb,

1
@dmb Mi dispiace per il suono scortese. Riguarda il commento di psmears. Ovviamente, Windows ha adottato lo stile Unix qui.
rexkogitans,

27

Questa è una maglietta:
inserisci qui la descrizione dell'immagine

Un raccordo a forma di T. Ha un'entrata e due prese separate.
In altre parole, divide una pipa in due; come un bivio.

Allo stesso modo, teeè un pipe ( |) che consente di reindirizzare l'input standard a due output separati.


Esempio
Dire ad esempio che si digita ls /.
Otterrai un output simile a:

Applications    Network     Users       bin        dev      net      private    tmp         var
Library         System      Volumes     cores      etc      home     opt        sbin        usr

Reindirizza l'output su un file di testo ls / > ls.txte nessun output viene visualizzato nella shell, solo nel file di testo risultante.

Vuoi vedere l'output E passarlo contemporaneamente a un file di testo?
Aggiungi a teealla tua pipe ( |) cioè:ls / | tee ls.txt


Confronta i due:

ls /          >          ls.txt
ls /        | tee        ls.txt

4
+1 per un'immagine che, come sappiamo, vale più di mille parole
Sergiy Kolodyazhnyy,

Se avessi scelto un raccordo a T per tubo da giardino, saresti stato in linea con la metafora originale di Doug McIlroy.
JdeBP,

@JdeBP Siamo spiacenti, non ho idea di chi sia. È l'autore originale dell'utilità o qualcosa del genere? Il flusso di dati e la corrente elettrica fisica sono spesso confrontati con i sistemi idraulici, ma probabilmente lo sapete. Comunque, ho appena scelto questo stile per renderlo super semplice. In realtà lo avrei fatto per tenerlo familiare, ma la varietà da giardino tende ad avere più di una forma a Y e / o accessori visivamente complicati per il fissaggio degli accessori, ecc. È essenzialmente lo stesso però.
Voci del


18

No. Ti capita di menzionare uno dei pochi esempi in cui potresti effettivamente reindirizzare al file usando >e >>operatori.

Ma Tee può fare molto di più. Poiché esegui il pipe ad esso, puoi quindi eseguire il pipe a qualcos'altro.

Un buon esempio è elencato nella pagina di Wikipedia :

find "4DOS" wikipedia.txt | tee 4DOS.txt | sort > 4DOSsorted.txt

Fondamentalmente, puoi eseguire il pipe su Tee, quindi puoi eseguire il pipe da Tee a qualcos'altro. Se tutto ciò che vuoi fare è scrivere un file di registro, sì, allora non hai davvero bisogno di Tee.


17

teeè tutt'altro che inutile. Lo uso sempre e sono contento che esista. È uno strumento molto utile se si dispone di una pipeline che si desidera suddividere. Un esempio molto semplice è che hai qualche directory $dche vuoi tarare e vuoi anche cancellarla perché sei paranoico (come me) e non ti fidi del supporto di memorizzazione per conservare i dati in modo affidabile. Si potrebbe scrivere sul disco e poi hash, ma che sarebbe fallire se l'archivio viene danneggiato prima di essere hash. Inoltre, dovresti leggerlo e se lavori su file di diverse centinaia di GB, saprai che non vorrai davvero rileggerli se non è necessario.

Quindi quello che faccio è semplicemente questo:

tar -c "$d" | tee >(sha256sum) >(cat > "$d"".tar") > /dev/null

Crea la pallina di catrame e la convoglia per collegarla a T che poi la convoglia a due sotto-shell, in una delle quali è con hash e nell'altra in cui è scritta sul disco.

È fantastico anche se vuoi eseguire diverse operazioni su un file di grandi dimensioni:

< file.tar.gz tee >(sha256sum) >(tar -xz) /other/storage/location/file.tar.gz > /dev/null

Legge il file una volta, lo esegue l'hashing (in modo da poter verificare se è ancora come dovrebbe essere), lo estrae e lo copia in una posizione diversa. Non è necessario leggerlo tre volte per quello.


3
Nitpick: teenon crea i subshells; la shell chiamante viene eseguita sha5sume catcollega il proprio output ai descrittori di file a cui vengono passati tee. Inoltre, un uso inutile di cat; puoi utilizzare il reindirizzamento di input per aver teeletto direttamente file.tar.gz.
Chepner,

@chepner Hai ragione sulla prima interiezione ma hai completamente torto sulla seconda. Mi piace scrivere le mie pipeline in ordine, quindi indicare che l'ingresso a destra è terribile per la leggibilità e farlo è chiaramente oggettivamente inferiore al mio metodo e totalmente non una mia preferenza soggettiva. catè amore. catè la vita.
UTF-8

6
Puoi anche scrivere < file.tar.gz tee >(sha256sum) ...se sei preoccupato per l'ordinamento lessicale dei reindirizzamenti. Ciò non cambia il fatto che non è necessario un processo completamente separato solo per alimentare un singolo file tee.
Chepner,

1
@chepner Cool, grazie! Ho imparato qualcosa oggi. :)
UTF-8

1
Il costo di partenza cat è relativamente basso. Il costo di un extra di 100 GiB di chiamate di sistema write + read fa sicuramente perdere tempo in più alla CPU e larghezza di banda della memoria per il tuo esempio di file enorme. Ricorda che la larghezza di banda della memoria è una risorsa condivisa tra tutti i core, per non parlare dell'inquinamento aggiuntivo della cache L3 da quella copia. Su un x86 con l'attenuazione Spettro + Meltdown abilitata, le chiamate di sistema sono più costose di quanto non fossero in passato. Stai usando una quantità misurabile di tempo extra della CPU nel corso di quella copia. Inoltre, >(cat > foo)non è più facile da capire di foo, IMO.
Peter Cordes,

12

Nitpick sulla risposta di @ bertieb che dice Questo esempio mostra che tee viene usato per bypassare una limitazione intrinseca nel comando sudo. sudo non è in grado di reindirizzare l'output standard in un file.

Non ci sono limiti intrinseci, solo un malinteso su come viene elaborato il comando.

Esempio:

sudo echo 0 > /proc/sys/net/ipv4/ip_forward

La shell corrente analizza la riga di comando. Trova il reindirizzamento dell'output e lo esegue. Quindi esegue il comando, che è il sudoe fornisce la riga di comando rimanente come argomenti al comando eseguito. Se la shell corrente non ha i permessi di root, il reindirizzamento dell'output fallirà.

echo 0 | sudo tee /proc/sys/net/ipv4/ip_forward

Questo funziona perché il reindirizzamento dell'output è rinviato al teecomando, che a quel punto ha i permessi di root perché è stato eseguito tramite sudo.

sudo bash -c "echo 0 > /proc/sys/net/ipv4/ip_forward"

Questo funziona perché la shell che esegue il reindirizzamento ha i permessi di root.


2
Inoltre, potresti aver bisogno sudodel comando, ma non del file in uscita e il reindirizzamento funziona bene:sudo foo-needs-privilege > /tmp/this-output-file-doesnt
Dennis Williamson,

10

Come altri hanno già detto, il piping dell'output al teecomando scrive tale output su un file e su stdout.

Uso spesso teequando desidero catturare l'output di un comando che richiede molto tempo per essere eseguito, mentre voglio anche controllare visivamente l'output quando il comando lo rende disponibile. In questo modo, non devo aspettare che il comando finisca l'esecuzione prima di ispezionare l'output.

Ciò che sembra non essere stato ancora menzionato (a meno che non me lo sia perso), è che il teecomando può anche scrivere su più file contemporaneamente. Per esempio:

ls *.png | tee a.txt b.txt

scriverà tutti i *.pngfile nella directory corrente in due file diversi ( a.txte b.txt) contemporaneamente.

In effetti, puoi digitare il testo in diversi file contemporaneamente con teequesto:

$ tee --append a.txt b.txt c.txt d.txt
These lines are appended to four different files,
and are also written to stdout.
CTRL-D

9

L'uso più comune di tee è vedere il testo sul terminale mentre lo si invia al file (o ai file). La formulazione della tua domanda presuppone che tu scriva sempre e solo testo nei file di registro. Ho degli script che scrivono elenchi di nomi di file o di directory per attivare i file (che devono essere elaborati in modo asincrono da altri script) e utilizzo Tee per inviare lo stesso contenuto a stdout. Tutto lo stdout è diretto ai registri. Quindi ho il mio testo dove lo voglio e ho una voce di registro che registra ciò che ho fatto, tutto da una singola istruzione "echo"

tee è anche il metodo migliore in Unix per creare più file identici. Lo uso occasionalmente per creare più file vuoti, come questo ...

:|tee file01 file02 file03

5
perchè no touch? (più immediatamente ovvio che cosa sta succedendo)
Attie

@Attie touchnon troncerà i file se esistono già, ma aggiornerà solo i loro timestamp e lascerà il loro contenuto così com'è; ma teeli troncerà. Inoltre, fare rm+ touchè diverso da tee(pensa a hardlink e symlink)
Matija Nalis

Allora perché no truncate -s 0? :-)
Attie

1

Immagina di voler scrivere l'output di un comando in un file di registro E stampare su stdout. Quando è necessario farlo contemporaneamente, è necessario tee.

Un caso d'uso è avere script di build che scrivano l'intera build su stdout (ad esempio per Jenkins) ma allo stesso tempo cose importanti in un file di registro separato (per e-mail di riepilogo).

Inizierai davvero a perdere teequando devi script in Windows. Non c'è teee questo è davvero fastidioso.


Non è banale da creare?
Razze di leggerezza in orbita,

Non è possibile con batch / cmd in quanto non è possibile dividere facilmente un flusso di output da un comando.
domih,

Giusto ma come un programma C ++ a tre righe ...
Lightness Races in Orbit,

1
La distribuzione unxutils di Windows ha molti strumenti da riga di comando Unix che, a differenza di alcune distribuzioni, non inquinano l'ambiente di esecuzione di Windows. Il limite maggiore riguarda il bing "glob", che funziona in modo diverso su Unix / Linux che su Windows. "tee" è tra gli strumenti disponibili.
cmm

2
Non essere sciocco, è il 2018. Usa Powershell tee. Cmd non è mai stato concepito per uno scripting serio, ecco a cosa serviva VBS. Powershell è il nuovo strumento di scripting go-to. Certo, Cmd è ancora piuttosto potente, ma gli strumenti da riga di comando sono piuttosto pochi.
Luaan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.