tee ist das T-Stück der Pipeline: Es liest Daten von stdin und schreibt sie gleichzeitig an stdout und in eine (oder mehrere) Dateien. Damit kannst du Output mitloggen, ohne ihn aus dem Terminal zu verlieren — und du kannst eine Pipeline an einer Stelle abzweigen lassen, ohne sie zu unterbrechen. Sein bekanntestes Killer-Pattern ist sudo tee für root-Writes, das die klassische Falle mit sudo > /etc/datei umgeht.

Was tee macht

Bildlich gesprochen ist tee ein T-Verzweigungsstück in einer Wasserleitung: Was hineinfliesst, kommt am normalen Ausgang weiter — und ein Teil zweigt seitlich ab in eine Datei. tee liest stdin, gibt alles unverändert auf stdout aus und schreibt parallel in jede übergebene Datei.

Bash Output sehen UND speichern
echo "Hallo Welt" | tee gruss.txt
Output
Hallo Welt

Nach dem Aufruf existiert gruss.txt mit dem Inhalt Hallo Welt, und der Text steht im Terminal. Genau dieses doppelte Ziel — Anzeige plus Persistierung — ist der Kern von tee.

Optionen

OptionWirkung
-a, --appendHängt an die Datei an, statt sie zu überschreiben
-i, --ignore-interruptsIgnoriert SIGINT (Ctrl+C) — Pipeline läuft weiter, tee schreibt zu Ende
-pDiagnostiziert Schreibfehler bei Pipes (selten genutzt)
FILE...Mehrere Zieldateien möglich — tee a.log b.log c.log

Der häufigste Schalter ist -a zum Anhängen — denn der Default überschreibt jede Zieldatei. Vergisst du -a, ist deine alte Logdatei nach dem ersten Aufruf weg.

Klassische Use-Cases

tee glänzt immer dann, wenn du Output gleichzeitig sehen und persistieren willst.

Bash Build-Output mitloggen
make 2>&1 | tee build.log

Du siehst alle Compiler-Ausgaben live und hast nach dem Build eine vollständige Datei zum Nachlesen. 2>&1 leitet stderr nach stdout, sodass auch Fehlermeldungen in der Logdatei landen.

tee kann auch mehrere Ziele gleichzeitig beschreiben — selten gebraucht, aber gelegentlich nützlich, etwa um eine Datei und ein FIFO zu füttern.

Bash In zwei Dateien schreiben
ls -lh | tee verzeichnis.txt backup.txt

Killer-Pattern: sudo tee für root-Writes

Das wahrscheinlich wichtigste Idiom mit tee. Folgender Befehl schlägt unter normalen Bedingungen fehl:

Bash
sudo echo "config" > /etc/myservice.conf

Der Grund ist subtil: Die Umleitung > wird von der eigenen Shell ausgeführt — bevor sudo überhaupt startet. Die Shell versucht also als normaler User, /etc/myservice.conf zum Schreiben zu öffnen, scheitert mit Permission denied, und sudo echo ... kommt nie zum Zuge.

tee umgeht das, weil tee selbst das Schreiben übernimmt — und das tut es als root, wenn du es mit sudo startest.

Bash Konfig als root schreiben
echo "config" | sudo tee /etc/myservice.conf > /dev/null

Das > /dev/null am Ende unterdrückt die Doppel-Anzeige im Terminal — wir wollen die Datei schreiben, nicht den Inhalt nochmal sehen. Mit -a hängst du an Configfiles an, statt sie zu ersetzen.

Mit -a Anhängen

Logfiles wachsen — sie werden nicht überschrieben. Das Default-Verhalten von tee ist allerdings „truncate” (Datei auf 0 Byte zurücksetzen). Für Logging ist -a Pflicht.

Bash Logfile fortschreiben
date | tee -a aktivität.log

Jeder Aufruf hängt eine neue Zeile mit dem aktuellen Timestamp an aktivität.log an — alte Einträge bleiben erhalten.

Praxis

Build mitloggen — Compiler-Output am Bildschirm und im File.

Bash
make 2>&1 | tee build.log

Das 2>&1 zieht stderr in dieselbe Pipeline, sonst liefe nur stdout durch tee und Compiler-Fehler würden zwar im Terminal sichtbar, aber nicht in build.log landen. Reihenfolge ist hier wichtig: 2>&1 muss vor der Pipe stehen.

Paketinstallation dokumentierenapt-Output für später aufheben.

Bash
sudo apt install nginx 2>&1 | tee -a install.log

Mit -a wird angehängt, statt überschrieben — so sammelt sich über die Zeit eine Historie aller Installationen in einer Datei. Praktisch beim Debugging, wenn ein Paket plötzlich kaputt geht und du sehen willst, was zuletzt eingespielt wurde.

Konfig als root schreiben — das sudo tee-Idiom in der Praxis.

Bash
echo "127.0.0.1 mibeon.local" | sudo tee -a /etc/hosts > /dev/null

Der Trick: sudo echo ... > /etc/hosts funktioniert nicht, weil die Shell die Redirect-Umleitung mit den eigenen Rechten öffnet, nicht mit root. sudo tee umgeht das, weil tee selbst als root läuft und die Datei direkt öffnet. Das > /dev/null unterdrückt nur die zusätzliche Terminal-Ausgabe.

Pipeline debuggen — sehen, was zwischen zwei Stages durchfliesst.

Bash
cat data.txt | grep ERROR | tee stage2.dump | wc -l

stage2.dump enthält die Zwischenausgabe nach grep, und das wc -l am Ende zählt sie wie gewohnt — die Pipeline läuft unverändert weiter.

Besonderheiten

tee schreibt zu Datei UND stdout

Was selbstverständlich klingt, ist in Pipelines manchmal störend: cmd | tee log.txt | next heißt, dass next denselben Datenstrom bekommt, der auch in log.txt landet. Wenn du nur das File willst, hängst du > /dev/null an. Beim sudo tee-Pattern ist das fast immer nötig, sonst druckt das Terminal den Configinhalt nochmal nutzlos aus.

tee blockt nicht bei vollem Disk

Ein klassischer Bug-Vector: Wenn die Zieldatei nicht beschrieben werden kann (volle Disk, fehlende Rechte, Read-only-Filesystem), schreibt tee trotzdem weiter auf stdout. Die Pipeline läuft scheinbar normal — nur die Datei bleibt leer oder unvollständig. Bei kritischen Logs lohnt es sich, hinterher mit wc -l oder stat zu prüfen, ob das File wirklich Inhalt hat.

Reihenfolge der Files: schnellste Disk zuerst

Bei mehreren Zielen schreibt tee sequenziell pro Block. Wenn eine Datei auf einer langsamen Disk liegt (Netzwerklaufwerk, USB-Stick) und eine andere auf SSD, bremst der langsame Pfad die ganze Pipeline aus. Nicht oft praxisrelevant, aber bei IO-intensiven Logs einen Gedanken wert.

pipefail und tee maskieren Exit-Codes

In cmd | tee log.txt bekommt $? den Exit-Code von tee — nicht von cmd. Wenn cmd mit Fehlerstatus endet, merkst du das ohne set -o pipefail nicht. In Skripten mit tee solltest du pipefail aktivieren, sonst gehen Fehler in der Pipeline verloren und das Skript läuft falsch weiter.

Process Substitution als tee-Alternative

Bash und Zsh kennen >(...) — Process Substitution. Damit kannst du Output an mehrere Empfänger gleichzeitig schicken, ohne tee: cmd > >(gzip > out.gz) 2> >(grep ERROR > err.log). Eleganter als tee, wenn die einzelnen Ziele eigene Verarbeitungsschritte brauchen — tee ist dann nur das Bündelungswerkzeug, die Logik passiert in den Substitutionen.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Textverarbeitung

Zur Übersicht