EMZETT.
Login

Kurz: Jedes Programm hat drei Standardkanäle:

Teil des Kurses Bash

Kapitel 7 von 13 im Kurs Bash (Abschnitt „Programme verbinden“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Die drei Datenströme

Jedes Programm hat drei Standardkanäle:

KanalNummerBedeutung
stdin0Eingabe
stdout1normale Ausgabe
stderr2Fehlermeldungen

Umleitungen

cd "$(mktemp -d)"
echo "Zeile 1" > datei.txt               # überschreiben
echo "Zeile 2" >> datei.txt              # anhängen
cat datei.txt
wc -l < datei.txt                        # Datei als Eingabe
 
ls /gibt/es/nicht 2> fehler.txt          # nur Fehler in Datei
echo "Fehler gespeichert: $(wc -l < fehler.txt) Zeile(n)"
ls /gibt/es/nicht 2>/dev/null            # Fehler wegwerfen
echo "stdout" > alles.txt 2>&1           # beide in dieselbe Datei
ls /gibt/es/nicht >> alles.txt 2>&1
wc -l < alles.txt
echo "nur Fehlerausgabe" >&2             # stdout nach stderr umleiten

Ausgabe:

Zeile 1
Zeile 2
2
Fehler gespeichert: 1 Zeile(n)
2

/dev/null verschluckt alles. Die Reihenfolge zählt: > datei 2>&1 (beide in die Datei) ist etwas anderes als 2>&1 > datei.

Pipes

Eine Pipe | verbindet die Ausgabe des einen Programms mit der Eingabe des nächsten:

printf "banane\napfel\nkirsche\napfel\n" | sort | uniq -c | sort -rn
echo "Hallo Welt" | tr 'a-z' 'A-Z' | rev
printf "3\n1\n2\n" | sort -n | head -n 2 | tail -n 1
seq 1 10 | paste -sd+ | bc

Ausgabe:

2 apfel
      1 kirsche
      1 banane
TLEW OLLAH
2
55

Unix-Philosophie: Jedes Programm macht eine Sache gut, und Pipes kombinieren sie. Der Exit-Status einer Pipe ist standardmäßig der des letzten Befehls; mit set -o pipefail zählt der erste Fehler.

false | true; echo "ohne pipefail: $?"
set -o pipefail
false | true; echo "mit pipefail: $?"
echo "Status einzeln: ${PIPESTATUS[*]}"

Ausgabe:

ohne pipefail: 0
mit pipefail: 1
Status einzeln: 0

Here-Documents und Here-Strings

cat <<EOF
Hallo $USER_DUMMY
Mehrzeiliger Text mit Variablen: $((1 + 1))
EOF
 
cat <<'EOF'
Hier wird nichts ersetzt: $HOME $(date)
EOF
 
wc -w <<< "ein Here-String mit fünf Wörtern"
cat <<-EOF
	Eingerückte Zeilen (Tabs) werden bei <<- entfernt
EOF

Ausgabe:

Hallo
Mehrzeiliger Text mit Variablen: 2
Hier wird nichts ersetzt: $HOME $(date)
5
Eingerückte Zeilen (Tabs) werden bei <<- entfernt

tee, xargs und Prozess-Ersetzung

cd "$(mktemp -d)"
echo "Daten" | tee ausgabe.txt | tr a-z A-Z     # an Datei und weiter
cat ausgabe.txt
 
printf "a\nb\nc\n" | xargs -I{} echo "Verarbeite {}"
printf "1 2 3\n" | xargs -n1 | paste -sd,
echo "ein  Argument  mit   Leerzeichen" | xargs printf "[%s]\n"
 
diff <(printf "a\nb\n") <(printf "a\nc\n")        # Ausgaben wie Dateien vergleichen
comm -12 <(printf "a\nb\nc\n") <(printf "b\nc\nd\n")

Ausgabe:

DATEN
Daten
Verarbeite a
Verarbeite b
Verarbeite c
1,2,3
[ein]
[Argument]
[mit]
[Leerzeichen]
2c2
< b
---
> c
b
c

Hintergrundprozesse und Jobs

sleep 0.2 &
pid=$!
echo "Hintergrundprozess läuft: $(kill -0 $pid 2>/dev/null && echo ja || echo nein)"
wait $pid
echo "fertig, Status $?"
 
( sleep 0.1; echo "Teil A" ) &
( sleep 0.2; echo "Teil B" ) &
wait
echo "alle fertig"

Ausgabe:

Hintergrundprozess läuft: ja
fertig, Status 0
Teil A
Teil B
alle fertig

Weitere nützliche Werkzeuge: jobs, fg, bg, Strg+Z (anhalten), Strg+C (abbrechen), nohup, disown, timeout 5 befehl.

Merke

  • > überschreibt, >> hängt an, < liest, 2> leitet Fehler um, 2>&1 führt zusammen
  • | verbindet Programme; set -o pipefail meldet Fehler in der Pipe
  • Here-Document <<EOF, Here-String <<<
  • tee, xargs, <(...) erweitern die Möglichkeiten
  • & startet im Hintergrund, wait wartet

Übungsaufgabe

Zähle mit einer Pipe die Dateien eines Ordners nach Endung (ls | sed ... | sort | uniq -c).

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Arrays, Maps und String-Operationen

Weiter: grep, sed, awk und Co.

Alle Kapitel: Bash im Überblick