Der "Strict Mode"
Standardmäßig läuft Bash bei Fehlern einfach weiter, auch wenn ein Befehl scheitert oder eine Variable leer ist. Das ist gefährlich. Üblicher Skript-Kopf:
#!/usr/bin/env bash
set -euo pipefail| Option | Wirkung |
|---|---|
-e | Skript bricht beim ersten fehlgeschlagenen Befehl ab |
-u | Verwendung nicht gesetzter Variablen ist ein Fehler |
-o pipefail | Eine Pipe schlägt fehl, wenn irgendein Teil fehlschlägt |
bash -c '
set -e
echo "Anfang"
false
echo "wird nie erreicht"
'; echo "Status: $?"
bash -c '
set -u
echo "vor der Variable"
echo "$nicht_gesetzt"
' 2>&1 | head -3
bash -c 'set -u; echo "mit Standardwert: ${var:-standard}"'
bash -c 'set -e; false || echo "|| fängt den Fehler ab"; echo "weiter"'Ausgabe
Anfang Status: 1 vor der Variable bash: line 4: nicht_gesetzt: unbound variable mit Standardwert: standard || fängt den Fehler ab weiter
Fehler prüfen und melden
fehler() { echo "FEHLER: $*" >&2; }
abbruch() { fehler "$@"; return 1; }
kopiere() {
local quelle=$1 ziel=$2
[[ -f $quelle ]] || { abbruch "Quelle '${quelle##*/}' fehlt"; return 1; }
cp "$quelle" "$ziel"
}
d=$(mktemp -d)
echo x > "$d/a"
kopiere "$d/a" "$d/b" && echo "kopiert"
kopiere "$d/nix" "$d/c" 2>&1 || echo "kopiere scheiterte (Status $?)"
if ! ls "$d/nix" >/dev/null 2>&1; then
echo "Datei nicht vorhanden"
fiAusgabe
kopiert FEHLER: Quelle 'nix' fehlt kopiere scheiterte (Status 1) Datei nicht vorhanden
trap: aufräumen und Fehler fangen
trap führt Code bei Signalen oder am Ende aus. Typisch: temporäre Dateien löschen, egal wie das Skript endet.
tmp=$(mktemp -d)
aufraeumen() {
rm -rf "$tmp"
echo "aufgeräumt"
}
trap aufraeumen EXIT
echo "arbeite in einem temporären Ordner"
[[ -d $tmp ]] && echo "Ordner existiert"Ausgabe
arbeite in einem temporären Ordner Ordner existiert aufgeräumt
bash -c '
set -e
trap '"'"'echo "Fehler in Zeile $LINENO"'"'"' ERR
echo "läuft"
ls /gibt/es/nicht 2>/dev/null
echo "nie erreicht"
'; echo "Status: $?"Ausgabe
läuft Fehler in Zeile 5 Status: 2
Gängige Signale: EXIT (immer am Ende), ERR (Befehl scheitert), INT (Strg+C), TERM (Beenden-Anfrage).
Eingaben validieren
nur_zahl() {
[[ $1 =~ ^-?[0-9]+$ ]]
}
for wert in 42 -7 4x "" 3.5; do
if nur_zahl "$wert"; then echo "[$wert] ist eine Ganzzahl"; else echo "[$wert] keine Zahl"; fi
done
pruefe_argumente() {
(( $# == 2 )) || { echo "Aufruf: skript QUELLE ZIEL" >&2; return 2; }
echo "OK: $1 -> $2"
}
pruefe_argumente a b
pruefe_argumente a || echo "Status $?"Ausgabe
[42] ist eine Ganzzahl [-7] ist eine Ganzzahl [4x] keine Zahl [] keine Zahl [3.5] keine Zahl OK: a -> b Status 2
Sicherer Umgang mit Dateien und Variablen
- Immer
"$variable"quoten - Mit
--das Ende der Optionen markieren:rm -- "$datei"(Dateinamen mit-am Anfang) - Temporäre Dateien nur mit
mktempanlegen - Vor
rm -rfdie Variable prüfen:rm -rf "${ordner:?}/"bricht ab, wennordnerleer ist - Befehle auf Existenz prüfen:
command -v jq >/dev/null || { echo "jq fehlt"; exit 1; } - Skripte mit ShellCheck (shellcheck.net) analysieren
ordner=""
bash -c 'ordner=""; echo rm -rf "${ordner:?Variable leer}/"' 2>&1 | head -1
command -v bash >/dev/null && echo "bash gefunden"
command -v programm_gibts_nicht >/dev/null || echo "programm fehlt"
echo "--" ; touch -- "-komischer-name" && ls -- -komischer-name && rm -- -komischer-nameAusgabe
bash: line 1: ordner: Variable leer bash gefunden programm fehlt -- -komischer-name
Debugging
bash -x -c 'x=5; y=$((x * 2)); echo "$y"' 2>&1 | head -5Ausgabe
+ x=5 + y=10 + echo 10 10
set -x zeigt jeden ausgeführten Befehl, set +x schaltet es wieder ab. bash -n skript.sh prüft nur die Syntax. Zusätzlich helfen echo-Ausgaben nach stderr und PS4='+ ${LINENO}: '.
Merke
- Skript-Kopf:
#!/usr/bin/env bashundset -euo pipefail - Fehlermeldungen nach
stderr(>&2), sinnvolle Exit-Codes trap ... EXITräumt zuverlässig auf- Eingaben validieren, Variablen quoten,
--vor Dateinamen shellcheck,bash -nundset -xhelfen beim Debuggen
Aufgabe
Schreibe ein Skript, das einen Ordner sichert (tar), temporäre Dateien per trap löscht und bei fehlendem Argument sauber abbricht.