MWCodebymw.de ↗
Terminal

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, was getopts verarbeitet 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 10

Danach 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

#Terminal#Bash#getopts#Skripte#CLI

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 →