- 1 Section
- 10 Lessons
- unbegrenzt
- Bash / Shell-Scripting10
- 1.1Was ist eine Shell? bash, sh, zsh im Vergleich
- 1.2Grundlegende Befehle: cd, ls, cp, mv, rm, grep
- 1.3Variablen, Eingabe und Ausgabe
- 1.4Kontrollstrukturen: if, case, for, while
- 1.5Funktionen und Argumente
- 1.6Fehlerbehandlung: exit codes, trap
- 1.7Textverarbeitung: sed, awk, cut, sort
- 1.8Dateisystem-Automation: find, xargs, cron
- 1.9Netzwerk-Scripting: curl, ssh, rsync
- 1.10Praxisprojekt: Systemstatus- und Backup-Script
Kontrollstrukturen: if, case, for, while
Mit Variablen und I/O aus L3 kannst du jetzt Daten speichern und anzeigen. Aber jedes nicht-triviale Skript muss Entscheidungen treffen („wenn die Datei existiert, dann mache X") und Wiederholungen machen („für jede Datei im Ordner..."). Das sind Kontrollstrukturen – sie sind in jeder Programmiersprache zu finden und machen aus stumpfen Befehlsketten echte Programme.
Bash hat dafür: if/elif/else, case, for und while. Konzeptionell sind sie ähnlich wie in Python oder Java, aber die Syntax hat einige Eigenheiten – besonders die [ ... ]-Klammern und die Pflicht-Leerzeichen darin. Wenn du diese Tücken kennst, geht das Schreiben flüssig.
1) Die if-Anweisung: Verzweigungen
Die Grundform: if BEDINGUNG; then ... fi. Der Strichpunkt ; oder ein Zeilenumbruch zwischen Bedingung und then ist Pflicht. Probier es: ändere die Zahl und sieh welcher Zweig genommen wird:
2) Die berüchtigten eckigen Klammern: [ und [[
Bash hat eine seltsame Syntax für Bedingungen. [ BEDINGUNG ] sieht wie Syntax aus, ist aber eigentlich ein Befehl! Die [ ist ein Programm (Alias für test), das mit Argumenten gefüttert wird. Daher die Pflicht-Leerzeichen:
if [ "$name" = "Anna" ]; then ... fi
# FALSCH – ohne Leerzeichen wirft Fehler
if ["$name"="Anna"]
# bash: [Anna=Anna]: command not found
# Modern: [[ ... ]] – Bash-Erweiterung
if [[ "$name" == "Anna" ]]; then ... fi
Die doppelten [[ ... ]] sind ein Bash-Built-in mit mehreren Vorteilen: kein Wort-Splitting bei Variablen, Regex-Match mit =~, sichere Logik mit &&/|| darin. Empfehlung: nutze [[ ... ]] bei Bash-Skripten. Nur bei POSIX-portablen sh-Skripten brauchst du das einfache [. Wichtig: trotzdem immer Variablen in Quotes packen!
3) Test-Operatoren: Strings vs. Zahlen vs. Dateien
Eine Eigenheit von Bash: für Strings und Zahlen gibt es unterschiedliche Vergleichs-Operatoren. Dazu noch eine Vielzahl von Datei-Tests. Hier die wichtigsten:
if [ $a == 5 ] denkt man wäre Zahlen-Vergleich. Falsch – das ist String-Vergleich. Für Zahlen: [ $a -eq 5 ]. Die Bedeutung: "5" = "5" ist gleich, aber "5" = "05" ist es nicht (verschieden lange Strings!), während 5 -eq 05 wahr ist. Bei Dateien: -e prüft auf Existenz allgemein, -f nur für reguläre Dateien (nicht Verzeichnisse).4) Sinnvolle if-Beispiele aus dem Alltag
Klassische Use-Cases mit denen du auf jedem Linux-System gleich produktiv wirst:
if [[ -f "$1" ]]; then
echo "Datei gefunden, bearbeite..."
else
echo "FEHLER: '$1' nicht gefunden" >&2
exit 1
fi
# Anzahl Argumente prüfen
if [[ $# -lt 2 ]]; then
echo "Aufruf: $0 <quelle> <ziel>"
exit 1
fi
# Root-User?
if [[ $EUID -ne 0 ]]; then
echo "Bitte als root ausführen"
exit 1
fi
# Negation mit !
if [[ ! -d "/backup" ]]; then
mkdir -p /backup
fi
Zwei wichtige Patterns hier: Frühe Validierung (Argumente checken, sofort raus mit exit 1), und Fehler nach stderr (>&2 – siehe L3 Streams). Exit-Codes sind das Thema von L6 Fehlerbehandlung.
5) Kompakte Tests: && und ||
Bash hat eine elegante Kurzform für „mach X wenn Y erfolgreich" – ohne ganzes if. Die Short-Circuit-Operatoren nutzen Exit-Codes (0 = Erfolg, alles andere = Fehler):
mkdir backup && cp *.txt backup/
# Macht B nur wenn A FEHLSCHLÄGT (Fallback)
cd /etc || echo "Konnte nicht in /etc wechseln"
# Kombiniert
test -f config.txt && echo "da" || echo "fehlt"
Vorsicht bei der Drei-Operand-Variante: das ist NICHT genau wie ein if/else! Wenn der THEN-Teil fehlschlägt, läuft auch noch der ELSE-Teil. Für echte Verzweigungen lieber if nehmen.
6) case – die switch-Anweisung
Wenn du viele Möglichkeiten hast, wird if-elif-elif schnell unleserlich. case ist Bashs Antwort auf das switch aus Java oder match-case aus Python:
start|begin|los) – mit Pipe getrennt. Das Default-Pattern * matcht alles (wie else). Wichtig: jede Aktion endet mit ;; – das ist der „Break" wie in anderen Sprachen. Vergisst man die, fällt es einfach durch. case unterstützt auch Wildcards: *.txt) matcht alle Dateinamen die auf .txt enden. Sehr nützlich für Datei-Verarbeitung.7) for-Schleifen – mehrere Geschmacksrichtungen
Bash hat zwei Stile von for: die Bash-Form (iteriert über eine Liste, ähnlich Python) und die C-Form (mit Zähler, wie Java/C):
8) while-Schleifen
Wenn die Anzahl Durchläufe nicht im Voraus bekannt ist – läuft solange eine Bedingung wahr ist:
while IFS= read -r line; do ... done < datei.txt. Dieses Muster behandelt jede Zeile sicher – auch mit Leerzeichen und Sonderzeichen. Viel besser als die for line in $(cat ...)-Variante! Auch wichtig: Endlosschleife mit while true; do ... done – Abbruch mit Strg+C oder break drinnen.9) break und continue
Wie in Python oder Java kannst du Schleifen verlassen oder überspringen:
for datei in *.log; do
if [[ "$datei" == "stop.log" ]]; then
echo "Stop-Signal gefunden, breche ab"
break
fi
grep "ERROR" "$datei"
done
# continue – diesen Durchlauf überspringen
for datei in *; do
if [[ -d "$datei" ]]; then
continue # Verzeichnisse überspringen
fi
echo "Datei: $datei"
done
10) until – das umgekehrte while
Selten genutzt aber gut zu kennen: until läuft solange die Bedingung nicht wahr ist. Nützlich beim Warten auf einen Zustand:
until ping -c 1 server.local &> /dev/null; do
echo "Server noch offline, warte..."
sleep 5
done
echo "Server ist erreichbar!"
Zusammenfassung
if: if BEDINGUNG; then ... elif ... else ... fi. Bedingungen mit [[ ... ]] (modern, Bash) oder [ ... ] (portabel). Leerzeichen Pflicht um Operatoren! Zahlen: -eq -ne -lt -le -gt -ge. Strings: = != -z -n. Dateien: -e -f -d -r -w -x. Logik: && || !. Short-Circuit: A && B = B wenn A erfolgreich. case: case $x in pattern1) ... ;; pattern2) ... ;; *) ... ;; esac. for: über Liste (for x in a b c), range ({1..10}), C-Style (((i=0;i<5;i++))), Dateien (Glob), Command-Output. while bis Bedingung falsch wird. until bis Bedingung wahr wird. break verlässt Schleife, continue überspringt Durchlauf.
