Argumente sind die Brücke zwischen einem Skript und seinen Anwendern. Bash bietet dafür eine Reihe spezieller Variablen — von $1 bis ${10}, $@, $* und $# — sowie zwei Werkzeuge für strukturierte Optionen: das eingebaute getopts und das externe GNU getopt. Wer den Unterschied zwischen "$@" und "$*" kennt und getopts sauber einsetzt, vermeidet die häufigsten Skript-Bugs.
Was sind Parameter?
Parameter sind die Argumente, die du einem Skript oder einer Funktion beim Aufruf übergibst. Sie sind innerhalb des Codes über positions-basierte Variablen erreichbar und bilden die Schnittstelle zwischen Aufrufer und Skript-Logik.
./backup.sh /home/user /mnt/backup --verboseInnerhalb des Skripts hat jedes dieser drei Argumente eine eigene Position. Genau dieselben Mechanismen gelten für Bash-Funktionen: Auch hier liegen die übergebenen Werte in $1, $2, $3 und so weiter. Argumente sind in Bash immer Strings — eine Typisierung wie in anderen Sprachen gibt es nicht.
Positions-Parameter $1, $2, …
Die wichtigsten Variablen sind die positionalen Parameter. Sie geben dir Zugriff auf die einzelnen Argumente in der Reihenfolge ihrer Übergabe.
| Variable | Bedeutung |
|---|---|
$0 | Name des Skripts (bzw. der Shell bei interaktivem Aufruf) |
$1 | Erstes Argument |
$2 | Zweites Argument |
$9 | Neuntes Argument |
${10} | Zehntes Argument — Klammern sind ab hier Pflicht |
#!/bin/bash
echo "Skript: $0"
echo "Erstes: $1"
echo "Zweites: $2"
echo "Zehntes: ${10}"Skript: ./demo.sh
Erstes: eins
Zweites: zwei
Zehntes: zehnEine klassische Falle: $10 wird nicht als zehntes Argument interpretiert, sondern als $1 gefolgt von der Ziffer 0. Wer ohne geschweifte Klammern auf zweistellige Positionen zugreift, bekommt also den Wert von $1 mit angehängter Null — ein Bug, der erst bei vielen Argumenten auffällt. Ab ${10} sind Klammern Pflicht.
$@ vs $*
Beide Variablen liefern alle Argumente — aber unterschiedlich. Der Unterschied wird erst sichtbar, wenn man sie quotet.
| Form | Verhalten | Wann verwenden |
|---|---|---|
$* | Alle Args, ohne Quotes durch Wortzerlegung in Tokens aufgeteilt | Praktisch nie |
$@ | Alle Args, ohne Quotes wie $* (Wortzerlegung) | Praktisch nie |
"$*" | Alle Args zu einem einzigen String, getrennt durch das erste Zeichen von IFS | Wenn man einen einzelnen String braucht |
"$@" | Alle Args als separate, korrekt gequotete Tokens | Standard — fast immer das, was du willst |
#!/bin/bash
# Aufruf: ./demo.sh "hallo welt" foo bar
for arg in "$@"; do
echo "[at] $arg"
done
for arg in "$*"; do
echo "[star] $arg"
done[at] hallo welt
[at] foo
[at] bar
[star] hallo welt foo bar"$@" erhält die ursprüngliche Argument-Struktur — "hallo welt" bleibt ein Token. "$*" faltet alles zu einer einzigen Zeichenkette zusammen. Faustregel: Beim Weiterreichen von Argumenten an andere Befehle immer "$@" verwenden, sonst gehen Leerzeichen in Pfaden und Werten verloren.
$# — Anzahl der Argumente
$# enthält die Anzahl der übergebenen Argumente. Das ist die Grundlage für jede Validierung — ohne Argumente macht ein Skript meist keinen Sinn.
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: $0 <quelle> [ziel]"
exit 1
fi
echo "Anzahl Args: $#"
echo "Quelle: $1"Anzahl Args: 2
Quelle: /home/userDas Muster if [ $# -lt N ]; then ... ; exit 1; fi ist eines der am häufigsten verwendeten Bash-Idiome überhaupt. Es prüft schon ganz oben im Skript, ob die nötigen Argumente da sind, und bricht mit einer Hilfemeldung ab, wenn nicht.
shift — Argumente weiterschieben
shift entfernt das erste Argument aus der Parameter-Liste. Alle folgenden Argumente rücken eine Position nach vorne: Aus $2 wird $1, aus $3 wird $2, und so weiter. $# verringert sich um eins.
#!/bin/bash
# Aufruf: ./demo.sh a b c
echo "$1 $2 $3"
shift
echo "$1 $2"
shift 2
echo "verbleibend: $#"a b c
b c
verbleibend: 0shift N schiebt gleich N Positionen weiter. Klassisch wird shift in einer Schleife verwendet, um Argumente nacheinander zu verarbeiten — siehe Praxis-Patterns weiter unten.
Default-Werte und Pflichtprüfung
Die Parameter-Expansion erlaubt es, Default-Werte oder Fehler direkt bei der Verwendung zu setzen — ohne separates if.
#!/bin/bash
name="${1:-Welt}"
ziel="${2:?Zielpfad fehlt}"
echo "Hallo, $name!"
echo "Schreibe nach: $ziel"Hallo, Welt!
Schreibe nach: /tmp/out${1:-Welt} liefert $1, falls gesetzt und nicht leer — sonst den Default Welt. ${2:?Zielpfad fehlt} bricht das Skript mit der Fehlermeldung ab, wenn $2 leer oder nicht gesetzt ist. Eine ausführliche Übersicht aller Operatoren findest du im Artikel zur String-Manipulation.
getopts — Flag-Parsing (POSIX)
Sobald ein Skript mehr als ein paar Argumente erwartet, wird manuelles Parsen unübersichtlich. getopts ist ein Bash-Builtin, das Single-Character-Flags wie -v, -h oder -f datei sauber verarbeitet — POSIX-konform und in jeder Shell verfügbar.
Der OPTSTRING beschreibt die erlaubten Flags. Ein nachgestellter Doppelpunkt bedeutet: dieses Flag erwartet ein Argument. Das geparste Flag landet in der angegebenen Variable, ein eventuelles Argument in $OPTARG.
#!/bin/bash
verbose=0
file=""
while getopts "vhf:" opt; do
case $opt in
v) verbose=1 ;;
h) echo "Usage: $0 [-v] [-h] [-f datei]"; exit 0 ;;
f) file="$OPTARG" ;;
\?) echo "Unbekanntes Flag: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
echo "verbose=$verbose file=$file rest=$*"verbose=1 file=daten.txt rest=eingabe1 eingabe2Nach der Schleife sorgt shift $((OPTIND - 1)) dafür, dass die geparsten Flags entfernt werden — übrig bleiben in $@ nur noch die nicht-flag Argumente. Das ist essenziell, wenn anschließend Positions-Argumente verarbeitet werden.
Die zentrale Limitation: getopts kennt keine Long-Options. --verbose oder --file=daten.txt werden nicht unterstützt. Wer das braucht, greift zu GNU getopt.
GNU getopt — Long-Options
getopt (ohne s) ist ein externes Programm, kein Builtin. Die GNU-Variante unterstützt sowohl Short- als auch Long-Options. Beachte den Namensunterschied: getopts (Builtin, nur Short) vs. getopt (externes Tool, Long-Options möglich — aber nur in der GNU-Variante).
| Variante | Plattform | Long-Options | Empfehlung |
|---|---|---|---|
GNU getopt | Linux, util-linux | Ja | Standard für ernsthafte Skripte |
BSD getopt | macOS, FreeBSD | Nein | Praktisch unbrauchbar |
getopts (Builtin) | Bash, dash, ksh | Nein | Für POSIX-Skripte ohne Long-Options |
Auf macOS ist standardmäßig die BSD-Variante installiert, die keine Long-Options kennt. Abhilfe schafft brew install gnu-getopt — danach liegt die GNU-Variante als /opt/homebrew/opt/gnu-getopt/bin/getopt.
#!/bin/bash
PARSED=$(getopt -o vhf: --long verbose,help,file: -n "$0" -- "$@") || exit 1
eval set -- "$PARSED"
verbose=0
file=""
while true; do
case "$1" in
-v|--verbose) verbose=1; shift ;;
-h|--help) echo "Hilfe..."; exit 0 ;;
-f|--file) file="$2"; shift 2 ;;
--) shift; break ;;
esac
done
echo "verbose=$verbose file=$file rest=$*"verbose=1 file=daten.txt rest=eingabe1Der Trick mit eval set -- "$PARSED" setzt die Positions-Parameter neu — diesmal sauber normalisiert von getopt. Das -- markiert das Ende der Optionen; alles danach sind reguläre Argumente.
Praxis-Patterns
Die folgenden Muster begegnen dir in praktisch jedem produktiven Bash-Skript. Sie sind klein, robust und seit Jahrzehnten bewährt.
Pflicht-Argument-Check
[ $# -lt 1 ] && { echo "Usage: $0 <pfad>"; exit 1; }Einzeiler ganz oben im Skript: Fehlt das erste Argument, gibt das Skript eine Usage-Zeile aus und beendet sich mit Exit-Code 1. Die Klammern um echo/exit gruppieren beide Befehle, sodass && nur dann ausgelöst wird, wenn die Bedingung wahr ist.
Vollständiger getopts-Loop
verbose=0
file=""
while getopts "vhf:" opt; do
case $opt in
v) verbose=1 ;;
h) echo "Usage: $0 [-v] [-f file] args..."; exit 0 ;;
f) file="$OPTARG" ;;
*) exit 1 ;;
esac
done
shift $((OPTIND - 1))Der Standard-Baustein für Bash-Skripte mit Short-Flags. OPTIND ist die Position des nächsten zu prüfenden Arguments — das shift danach entfernt alle bereits verarbeiteten Flags.
shift-Loop für freies Argument-Parsing
while [ $# -gt 0 ]; do
case $1 in
--verbose) verbose=1 ;;
--file) file="$2"; shift ;;
*) echo "Unbekannt: $1" >&2; exit 1 ;;
esac
shift
doneWenn weder getopts noch getopt zur Verfügung stehen, oder wenn man ungewöhnliche Argument-Formen unterstützen will: Schleife über $#, im case jedes erwartete Flag behandeln, am Ende einmal shift. Bei Flags mit Wert ein zusätzliches shift im Case-Zweig.
Default-Werte für Funktions-Parameter
greet() {
local name="${1:-Welt}"
echo "Hallo, $name!"
}
greet # Hallo, Welt!
greet "Anna" # Hallo, Anna!Funktionen haben in Bash keine Parameter-Defaults wie in anderen Sprachen — aber ${1:-Welt} löst das Problem in einer Zeile. local sorgt dafür, dass die Variable nur in der Funktion existiert.
Catch-all: Argumente weiterreichen
#!/bin/bash
export LANG=C
exec mein-tool "$@"Ein Wrapper-Skript, das nur die Umgebung anpasst und alle Argumente unverändert an das eigentliche Tool durchreicht. Pflicht: "$@" mit Quotes — sonst werden Argumente mit Leerzeichen zerlegt. exec ersetzt den Skript-Prozess durch das Ziel-Programm und spart einen Shell-Prozess.
Häufige Stolperfallen
Die $10-Falle
Ohne geschweifte Klammern interpretiert Bash $10 als $1 gefolgt von einer literalen 0. Bei einem Aufruf mit zehn Argumenten gibt echo $10 also nicht das zehnte Argument aus, sondern den Wert von $1 mit angehängter Null — zum Beispiel eins0. Korrekt ist immer ${10}. Ab der zweistelligen Position sind Klammern Pflicht. Der Bug ist tückisch, weil er bei kurzen Aufrufen nie auftritt und erst in der Produktion zuschlägt.
Unquoted $@ zerstört Argumente mit Leerzeichen
Schreibst du cp $@ /ziel/, zerlegt die Shell jedes Argument an Leerzeichen. Aus dem Pfad /home/user/Mein Projekt werden zwei Argumente: /home/user/Mein und Projekt/. Korrekt ist immer cp "$@" /ziel/ — die Quotes sorgen dafür, dass jedes Argument als einzelnes Token erhalten bleibt. Diese Regel gilt auch für Variablen, die Pfade enthalten: "$datei", nicht $datei. Es ist wahrscheinlich der häufigste Bug in fehlerhaften Bash-Skripten überhaupt.
BSD getopt kann keine Long-Options
Auf macOS und FreeBSD ist standardmäßig die BSD-Variante von getopt installiert. Sie unterstützt keine Long-Options wie --verbose und keine optionalen Argumente. Skripte, die mit GNU getopt entwickelt wurden, scheitern auf macOS still oder mit kryptischen Fehlern. Abhilfe: brew install gnu-getopt und das resultierende Binary explizit per Pfad aufrufen, oder direkt auf das Bash-Builtin getopts (mit s) ausweichen, das überall identisch funktioniert — allerdings ohne Long-Options.
OPTIND nicht zurücksetzen bei wiederholtem getopts-Aufruf
getopts verwendet die globale Variable OPTIND, um sich die aktuelle Position zu merken. Wenn du getopts in einer Funktion verwendest, die mehrfach aufgerufen wird, startet der zweite Aufruf nicht bei Position 1, sondern dort, wo der erste aufgehört hat — die Argumente werden ignoriert. Lösung: Innerhalb der Funktion mit local OPTIND=1 (oder am Anfang OPTIND=1) den Zähler explizit zurücksetzen. Sonst bekommst du Bugs, die nur beim zweiten Aufruf auftreten.
Fehlendes Doppelpunkt-Zeichen im OPTSTRING
Im OPTSTRING von getopts markiert ein nachgestellter : ein Flag, das ein Argument erwartet. Schreibst du getopts "vhf" opt statt getopts "vhf:" opt, wird -f als reines Schalter-Flag behandelt — der nachfolgende Dateiname landet als nächstes positionales Argument im falschen Topf. Schlimmer noch: Es gibt keine Fehlermeldung, das Skript läuft scheinbar normal weiter, aber $OPTARG bleibt leer. Beim Schreiben des OPTSTRING immer prüfen, welche Flags ein Argument brauchen.
Trailing -- als Optionen-Separator
Das doppelte Minus -- ist das klassische POSIX-Idiom, um das Ende der Optionen zu markieren. Alles danach behandelt das Skript als reguläres Argument, selbst wenn es mit einem Minus beginnt. Beispiel: rm -- -datei.txt löscht eine Datei, die -datei.txt heißt — ohne -- würde rm versuchen, -datei.txt als Flag zu interpretieren. In eigenen Skripten solltest du das Idiom mit getopt oder einem expliziten case ebenfalls unterstützen, vor allem wenn Dateinamen oder beliebige Werte verarbeitet werden.
Weiterführende Ressourcen
Externe Quellen
- Bash-Manpage: Positional Parameters — Offizielle Referenz zu
$1,$@,$*,$#undshift - GNU Bash-Handbuch: Special Parameters — Vollständige Liste aller speziellen Variablen
- getopt(1) Manpage — GNU getopt mit allen Long-Option-Features
- BashFAQ: How can I handle command-line options? — Praxisorientierter Vergleich von getopts, getopt und manueller Verarbeitung
- POSIX: getopts — POSIX-Spezifikation des Builtins
Verwandte Artikel
- Skript-Grundlagen — Aufbau eines Bash-Skripts, Shebang und Ausführung
- Funktionen — Eigene Funktionen definieren und parametrisieren
- Bedingungen —
if,caseund Test-Ausdrücke für Argument-Validierung - String-Manipulation — Parameter-Expansion mit
${var:-default},${var:?fehler}und mehr - Exit-Codes — Saubere Rückgabewerte für Fehler bei fehlenden Argumenten