Die drei Datenströme
Jedes Programm hat drei Standardkanäle:
| Kanal | Nummer | Bedeutung |
|---|---|---|
stdin | 0 | Eingabe |
stdout | 1 | normale Ausgabe |
stderr | 2 | Fehlermeldungen |
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 umleitenAusgabe
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+ | bcAusgabe
2 apfel
1 kirsche
1 banane
TLEW OLLAH
2
55Unix-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
EOFAusgabe
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>&1führt zusammen|verbindet Programme;set -o pipefailmeldet Fehler in der Pipe- Here-Document
<<EOF, Here-String<<< tee,xargs,<(...)erweitern die Möglichkeiten&startet im Hintergrund,waitwartet
Aufgabe
Zähle mit einer Pipe die Dateien eines Ordners nach Endung (ls | sed ... | sort | uniq -c).