getopts – Skript-Parameter, die sich wie richtige Befehle anfühlen
$1, $2, $3 funktioniert genau so lange, bis man einen Parameter weglassen will. Mit getopts bekommt dein Skript benannte Optionen, eine Hilfe und eine klare Fehlermeldung – in fünfzehn Zeilen.
Jedes Skript fängt so an:
ZIEL="$1"
ANZAHL="$2"Und dann kommt der Tag, an dem man $2 weglassen möchte, aber $3 braucht. Oder man ruft das Skript nach drei Monaten wieder auf und weiß nicht mehr, in welcher Reihenfolge die Argumente kamen. Ab da lohnt getopts.
Das Grundgerüst
#!/usr/bin/env bash
set -euo pipefail
ziel=""
anzahl=10
ausfuehrlich=0
hilfe() {
cat <<EOF
Verwendung: ${0##*/} -z ZIEL [-n ANZAHL] [-v]
-z ZIEL Zielordner (Pflicht)
-n ANZAHL Anzahl der Einträge (Standard: $anzahl)
-v ausführliche Ausgabe
-h diese Hilfe
EOF
}
while getopts ":z:n:vh" opt; do
case "$opt" in
z) ziel="$OPTARG" ;;
n) anzahl="$OPTARG" ;;
v) ausfuehrlich=1 ;;
h) hilfe; exit 0 ;;
:) echo "Option -$OPTARG braucht einen Wert." >&2; exit 2 ;;
\?) echo "Unbekannte Option: -$OPTARG" >&2; hilfe >&2; exit 2 ;;
esac
done
shift $((OPTIND - 1)) # verbrauchte Optionen wegräumen
[[ -n "$ziel" ]] || { echo "Fehler: -z fehlt." >&2; hilfe >&2; exit 2; }Ab hier hat dein Skript alles, was man von einem ordentlichen Befehl erwartet: benannte Optionen in beliebiger Reihenfolge, Standardwerte, eine Hilfe und verständliche Fehlermeldungen.
Die drei Zeichen, die man kennen muss
- Der Doppelpunkt nach einem Buchstaben (
z:) heißt: Diese Option braucht einen Wert. Ohne Doppelpunkt ist es ein reiner Schalter. - Der Doppelpunkt ganz vorne (
":z:n:vh") schaltet in den stillen Modus. Ohne ihn gibt Bash selbst eine englische Fehlermeldung aus, und der:-Zweig wird nie erreicht. Deine eigenen, deutschen Meldungen greifen erst mit diesem führenden Doppelpunkt. shift $((OPTIND - 1))entfernt alles, wasgetoptsverarbeitet hat. Danach stehen in$@nur noch die übrigen Argumente — praktisch, wenn dein Skript zusätzlich Dateinamen entgegennimmt.
Standardwerte richtig setzen
Die Zuweisung vor der Schleife ist der Standardwert; die Option überschreibt ihn nur, wenn sie angegeben wurde. Das ist der Grund, warum anzahl=10 oben steht und nicht irgendwo im case.
Wenn ein Wert auch aus der Umgebung kommen darf:
ziel="${ZIEL:-}" # nimmt $ZIEL, sonst leer
anzahl="${ANZAHL:-10}" # nimmt $ANZAHL, sonst 10Danach kann die Option beides überschreiben. Diese Reihenfolge — Standard, dann Umgebung, dann Option — ist die, die Nutzer erwarten.
Was getopts nicht kann
Lange Optionen wie --ziel=/pfad beherrscht es nicht. Dafür bräuchte man getopt (ohne s, ein eigenes Programm) oder eine eigene while-Schleife über $@. Ich verzichte darauf: Kurze Optionen plus eine gute -h-Hilfe reichen für eigene Werkzeuge völlig, und getopts ist überall vorhanden, ohne Sonderfälle zwischen Linux und macOS.
Warum sich das lohnt
Ein Skript mit -h ist ein Skript, das man in sechs Monaten noch benutzen kann. Ohne muss man den Quelltext lesen, um herauszufinden, was $3 eigentlich war. Die fünfzehn Zeilen oben sind bei mir inzwischen eine Vorlage, die ich in jedes neue Wartungsskript kopiere — und sie haben sich schon oft ausgezahlt.
Du hast Skripte auf deinem Server, die nur noch eine Person bedienen kann? Das lässt sich meist mit wenig Aufwand ändern. Melde dich.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Warum deine Zählvariable nach der Schleife wieder 0 ist – Prozess-Substitution in Bash
Ein Klassiker, der jeden einmal erwischt: Du zählst in einer while-Schleife hoch, und hinterher steht die Variable trotzdem auf 0. Schuld ist eine Subshell hinter der Pipe. Mit Prozess-Substitution behältst du das Ergebnis – und kannst nebenbei zwei Befehle direkt vergleichen.
Pfade und Namen zerlegen — ganz ohne basename, dirname und sed
Die Shell kann Zeichenketten selbst zerschneiden. Kein Aufruf eines externen Programms, keine Pipe – nur geschweifte Klammern. Wenn du das einmal kennst, werden deine Skripte kürzer und deutlich schneller.
Zwei Listen vergleichen mit comm – wer fehlt, wer ist neu, wer ist in beiden
Welche Dateien fehlen im Backup? Welche Kunden aus der alten Liste stehen nicht in der neuen? Für genau diese Fragen gibt es seit Unix-Urzeiten ein Werkzeug, das kaum jemand kennt – comm vergleicht zwei sortierte Listen und sagt dir in einer Zeile, was nur links, nur rechts oder in beiden steht.