tee — Ausgaben gleichzeitig anzeigen und in Dateien schreiben

Praxis-Guide zu tee — von der Standardeingabe lesen und gleichzeitig auf den Bildschirm und in mehrere Dateien schreiben. Ideal zum Mitloggen in Pipelines.

tee liest von der Standardeingabe und schreibt das Ergebnis gleichzeitig auf die Standardausgabe und in eine oder mehrere Dateien – wie ein T-Stück in einer Rohrleitung, das den Datenstrom abzweigt. Damit siehst du die Ausgabe eines Befehls live auf dem Bildschirm und protokollierst sie zugleich in eine Datei, ohne die Pipeline zu unterbrechen. Standardmäßig überschreibt tee die Zieldatei; mit -a hängst du stattdessen an. Sein bekanntester Trick ist das sudo tee-Muster: Weil eine Umleitung mit > von der Shell und nicht von sudo ausgeführt wird, ist … | sudo tee datei der saubere Weg, um in root-eigene Dateien zu schreiben.

Grundlagen

<command> | tee <file> — Schreibt die Befehlsausgabe sowohl auf den Bildschirm als auch in eine Datei (überschreibt die Datei).

ls -la | tee listing.txt

<command> | tee -a <file> — Hängt die Ausgabe an eine Datei an, statt sie zu überschreiben.

echo 'new entry' | tee -a log.txt

<command> | tee <file1> <file2> — Schreibt die Ausgabe gleichzeitig in mehrere Dateien.

date | tee log1.txt log2.txt backup.txt

<command> | tee /dev/stderr — Dupliziert die Ausgabe nach stderr (praktisch zum Loggen in Pipelines).

curl -s api.example.com | tee /dev/stderr | jq '.data'

Pipeline-Muster

<cmd1> | tee <file> | <cmd2> — Sichert die Zwischenausgabe und setzt die Pipeline fort.

cat data.csv | tee raw-backup.csv | sort -t',' -k2 > sorted.csv

<cmd1> | tee >(cmd2) | <cmd3> — Sendet die Ausgabe per Prozesssubstitution an einen Befehl UND setzt die Pipeline fort.

ls -la | tee >(grep '.log' > logs.txt) | wc -l

<cmd1> | tee >(cmd2) >(cmd3) > /dev/null — Verteilt die Ausgabe an mehrere Befehle, ohne sie im Terminal anzuzeigen.

cat data.txt | tee >(wc -l > count.txt) >(grep ERROR > errors.txt) > /dev/null

<command> 2>&1 | tee <file> — Erfasst stdout und stderr in einer Datei und zeigt beides an.

make build 2>&1 | tee build.log

Schreiben mit erhöhten Rechten

echo '<text>' | sudo tee <file> — Schreibt in eine root-eigene Datei (eine Umleitung mit > allein funktioniert mit sudo nicht).

echo 'nameserver 8.8.8.8' | sudo tee /etc/resolv.conf

echo '<text>' | sudo tee -a <file> — Hängt an eine root-eigene Datei an.

echo '192.168.1.100 myserver' | sudo tee -a /etc/hosts

echo '<text>' | sudo tee <file> > /dev/null — Schreibt in eine root-eigene Datei, ohne die Ausgabe auf dem Bildschirm anzuzeigen.

echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.conf > /dev/null

cat <source> | sudo tee <dest> > /dev/null — Kopiert eine Datei an einen root-eigenen Ort.

cat nginx.conf | sudo tee /etc/nginx/sites-available/mysite > /dev/null

Logging & Debugging

<script> 2>&1 | tee -a <logfile> — Führt ein Skript aus und protokolliert die gesamte Ausgabe (stdout + stderr) im Anhängemodus.

./deploy.sh 2>&1 | tee -a /var/log/deploy.log

script -q /dev/null <command> | tee <file> — Erfasst Ausgaben von Befehlen, die eine Nicht-Terminal-Ausgabe erkennen.

script -q /dev/null ls --color | tee colored-output.txt

<command> | tee >(logger -t <tag>) — Sendet die Pipeline-Ausgabe per Prozesssubstitution an syslog.

backup.sh 2>&1 | tee >(logger -t backup)

<command> | tee >(ts '[%Y-%m-%d %H:%M:%S]' >> <logfile>) — Versieht die protokollierte Ausgabe mit Zeitstempeln per ts (aus moreutils).

tail -f /var/log/app.log | tee >(ts '[%Y-%m-%d %H:%M:%S]' >> timestamped.log)

Typische Anwendungsfälle

tar czf - <dir> | tee <archive> | md5sum — Erzeugt ein Archiv und berechnet in einem Durchgang seine Prüfsumme.

tar czf - /var/www | tee backup.tar.gz | md5sum > backup.md5

<command> | tee /dev/tty | <next_command> — Zeigt die Ausgabe im Terminal an und leitet sie zugleich an den nächsten Befehl weiter.

find . -name '*.log' | tee /dev/tty | xargs rm

echo '<config>' | tee <file1> <file2> <file3> > /dev/null — Schreibt denselben Inhalt auf einmal in mehrere Konfigurationsdateien.

echo 'export NODE_ENV=production' | tee .env .env.local > /dev/null

diff <(command1) <(command2) | tee diff-output.txt — Vergleicht zwei Befehlsausgaben und speichert den Diff.

diff <(curl -s api.example.com/v1) <(curl -s api.example.com/v2) | tee api-diff.txt

cat <<'EOF' | sudo tee <file> > /dev/null\n<content>\nEOF — Schreibt ein mehrzeiliges Here-Dokument in eine root-eigene Datei.

cat <<'EOF' | sudo tee /etc/nginx/conf.d/app.conf > /dev/null
server {
    listen 80;
    server_name example.com;
}
EOF

Fazit

tee schließt die Lücke zwischen „auf dem Bildschirm sehen" und „in eine Datei schreiben" – unverzichtbar beim Mitloggen von Build- und Deploy-Läufen, beim Schreiben in root-eigene Dateien (sudo tee) und beim Aufzweigen eines Stroms an mehrere Ziele per Prozesssubstitution. Achte auf zwei Dinge: tee überschreibt ohne Vorwarnung, wenn du -a vergisst – beim Loggen ist -a fast immer die richtige Wahl. Und um Fehlermeldungen mit aufzuzeichnen, leitest du stderr vorher mit 2>&1 auf stdout um, denn tee sieht nur den stdout-Strom der Pipe. Den Exit-Status liefert in einer Pipe standardmäßig der letzte Befehl, also tee selbst; brauchst du den des eigentlichen Befehls, setze set -o pipefail.

Verwandte Kommandos

  • xargs – Eingaben zu Argumenten für weitere Befehle aufbereiten
  • tail – Logdateien live mitlesen, oft als Gegenstück zu tee-Logs
  • less – große Ausgaben und Logdateien seitenweise durchblättern