www.wbglinks.net

Bash: Die Linux-Shell verstehen und erste Skripte schreiben

Die Bash bildet als Kommandozeilenschnittstelle das funktionale Rückgrat von Unix- und Linux-Umgebungen und ermöglicht die direkte Steuerung des Betriebssystems über strukturierte Textbefehle. Als Weiterentwicklung historischer Interpreter verbindet das Programm interaktive Befehlseingaben mit einer Skriptsprache zur Systemautomatisierung.

Ursprung und Geschichte der GNU-Standard-Shell

Hinter der Software steht das GNU-Projekt der Free Software Foundation. Brian Fox begann 1987 mit der Entwicklung, um eine freie Alternative zur Bourne-Shell (sh) bereitzustellen. Am 8. Juni 1989 erschien die erste Beta-Version 0.99. Der Name steht als Wortspiel für „Bourne Again Shell“ und verweist auf Stephen Bourne, den Entwickler der ursprünglichen Bourne-Shell aus den Bell Labs von 1977. Bereits 1990 übernahm Chet Ramey die Projektpflege, der die Software bis heute als offizieller Maintainer betreut.

Das in der Programmiersprache C geschriebene Werkzeug unterliegt der GNU General Public License v3 (ab Version 4.0). Brian Fox entwickelte parallel Komponenten wie Readline, Makeinfo, Info und Echo. Am 3. Juli 2025 wurde die Version 5.3 veröffentlicht. Von 2003 bis 2019 lieferte Apple auf macOS (Versionen 10.3 bis 10.14) die Version 3.x als Standardinterpreter aus, verzichtete jedoch aus lizenzrechtlichen Gründen auf ein Upgrade auf Version 4.

Architektur: Terminal, Kernel-Schnittstelle und Interpreter

Im IT-Alltag werden drei Ebenen häufig miteinander verwechselt, obwohl sie architektonisch klar getrennt sind:

  • Terminal-Emulator: Das Anwendungsfenster (etwa GNOME Terminal, Konsole unter KDE oder xterm), welches Tastaturanschläge empfängt und Text darstellt.
  • Kernel-Schnittstelle (tty): Die nach historischen Teletype-Geräten benannte Vermittlungsschicht des Betriebssystemkerns, die Daten zwischen Anzeige und Prozessen weiterleitet.
  • Befehlsinterpreter: Die eigentliche Schnittstelle zur Kernschale (Shell), welche Eingaben parst, Builtin-Routinen aufruft oder externe Systemprogramme startet.

Die Unabhängigkeit zeigt sich im praktischen Betrieb: Jeder Interpreter lässt sich in jedem beliebigen Emulator starten. Bei Remote-Verbindungen via SSH existiert auf dem lokalen Client gar keine laufende Shell-Sitzung, sondern lediglich die darstellende Terminal-Instanz.

Wichtige Werkzeuge und Builtin-Routinen

Viele elementare Aufrufe greifen nicht auf separate Programmdateien zu, sondern laufen als interne Funktionen (Builtins) direkt in der Shell ab.

Kategorie Kommando Typ Funktion
Navigation pwd, cd, ls Builtin / Utility Arbeitsverzeichnis ausgeben, Verzeichnis wechseln, Inhalte auflisten
Dateiverwaltung cp, mv, rm, mkdir Dienstprogramm Dateien kopieren, umbenennen, entfernen und Verzeichnisse anlegen
Suche grep, find Dienstprogramm Textmuster in Inhalten filtern bzw. Dateinamen im Dateisystem suchen
Dokumentation man, --help Hilfesystem Vollständige Handbuchseiten einsehen oder Kurzreferenzen aufrufen

Befehle wie cd oder echo sind direkt in die Bash integriert und laufen ohne externen Prozess ab.

Datenströme, Pipes und Umgebungsvariablen

Unix-Prozesse kommunizieren über Standardkanäle: Deskriptor 0 (stdin), Deskriptor 1 (stdout) und Deskriptor 2 (stderr). Mittels > wird die Ausgabe überschreibend umgeleitet, während >> an das Ziel anhängt. Fehlerkanäle lassen sich separat mit 2> steuern. Unnötige Ausgaben werden häufig über 2>/dev/null verworfen. Mit der Kombination 2>&1 wird der Fehlerkanal auf den regulären Ausgabestrom gelegt; hierbei entscheidet die exakte Reihenfolge von links nach rechts.

Die Pipeline | leitet die Standardausgabe einer Operation ohne Zwischendatei direkt an den Eingabekanal der folgenden Operation weiter:

ls | wc -l

Variablen deklariert man ohne Typhinweis und strikt ohne Leerzeichen um das Zuweisungszeichen:

server="web01"

Parameter werden über $server oder ${server} referenziert. Vordefinierte Werte stehen bereit: $0 repräsentiert den Skriptnamen, $1 bis $9 die ersten neun Argumente, $# deren Gesamtanzahl, $@ die vollständige Parameterliste und $? den numerischen Exit-Code des vorangegangenen Prozesses. Globale Umgebungswerte wie $HOME, $PATH und $USER vererben sich automatisch an Kindprozesse.

Schritt-für-Schritt: Das erste Skript erstellen und starten

Wiederkehrende Kommandoketten lassen sich in einer Klartextdatei bündeln und automatisiert abarbeiten:

  1. Textdatei anlegen: Datei namens backup.sh im Editor öffnen.
  2. Shebang eintragen: Die erste Zeile definiert den Lader. Portabel geschieht dies über:
    #!/usr/bin/env bash

    Alternativ verweist #!/bin/bash auf den absoluten Pfad. Fehlt dieser Hinweis, übergibt der Kernel den Inhalt an /bin/sh.

  3. Fehlertoleranz minimieren: Der sogenannte Strict Mode sorgt für Stabilität:
    set -euo pipefail

    Bricht bei Fehlern ab (-e), warnt vor undefinierten Variablen (-u) und fängt Pipeline-Fehler ab (pipefail).

  4. Logik implementieren: Kontrollstrukturen wie Bedingungen und Schleifen einfügen:
    if [[ -f "$1" ]]; then
        echo "Verarbeite Datei: $1"
    fi

    Bedingungen enden mit fi, Fallunterscheidungen via case mit esac. Getestet werden Existenz (-e), Verzeichnisse (-d) oder Zeitstempel (-nt, -ot).

  5. Rechte setzen und starten: Die Datei muss als ausführbar markiert werden:
    chmod +x backup.sh
    ./backup.sh "daten.txt"

    Wird stattdessen bash backup.sh aufgerufen, liest der Interpreter die Datei direkt ein und ignoriert den Shebang.

Konfigurationshierarchie: .bashrc versus .bash_profile

Beim Start unterscheidet das System zwischen zwei Modi:

  • Interaktive Nicht-Login-Sitzung: Ein neues Terminal-Fenster liest ~/.bashrc (zuvor global /etc/bash.bashrc). Hier stehen Aliase, Prompt-Anpassungen und Umgebungsvariablen.
  • Login-Sitzung: Nach Authentifizierung via SSH oder an der Textkonsole werden /etc/profile und anschließend ~/.bash_profile (ersatzweise ~/.bash_login oder ~/.profile) ausgewertet – nicht jedoch ~/.bashrc.

Um redundante Konfigurationen zu vermeiden, bindet man die Konfiguration in ~/.bash_profile manuell über source ~/.bashrc ein. Für Testzwecke lässt sich das Laden mittels --norc komplett umgehen oder via --rcfile DATEI umlenken.

Vergleich: sh, Bash und Zsh im Überblick

Die wichtigsten Unterschiede zwischen den Shells im Überblick:

Kriterium sh (Bourne / DASH) Bash Zsh
Standard-Spezifikation POSIX-Minimalstandard Obermenge von sh / GNU Erweiterte Shell-Architektur
Erweiterte Bedingungen Nur POSIX [ ] Mächtiges [[ ]] & Regex Mächtiges [[ ]] & Regex
Array-Unterstützung Nein Indiziert & assoziativ Vollständig integriert
Durchschnittliche Startzeit – 180–220 ms 300–350 ms
Primärer Einsatzzweck Systemstart (Ubuntu /bin/sh -> dash) Linux-Server & DevOps-CI/CD Interaktiver macOS-Desktop

Auf Distributionen wie Debian oder Ubuntu verweist /bin/sh via Symlink auf dash. Werden Features wie Arrays in Skripten mit #!/bin/sh verwendet, bricht die Ausführung ab. Ein Schalter wie bash --posix erzwingt weitgehende POSIX-Konformität.

Historische Sicherheitsanalyse: Shellshock (CVE-2014-6271)

Die als „Shellshock“ (CVE-2014-6271) bekannt gewordene Sicherheitslücke betraf Bash bis Version 4.3 und wurde am 24. September 2014 veröffentlicht. Der Forscher Stéphane Chazelas entdeckte, dass Angreifer beliebigen Code ausführen konnten, indem sie Code nach Funktionsdefinitionen in Umgebungsvariablen platzierten. Die Lücke wurde mit dem maximalen CVSS-Wert von 10.0 (höchste Kritikalität) bewertet.

Angriffsvektoren betrafen unter anderem CGI-Skripte im Apache-Webserver, DHCP-Clients und OpenSSH-ForceCommand. Da die erste Fehlerbehebung unvollständig war, folgten insgesamt sechs CVE-Meldungen (darunter CVE-2014-7169 und CVE-2014-6278). Der Fix erfolgte ab Bash 4.3 Patch 29. Behörden wie CISA führen die Schwachstelle bis heute in ihrem Katalog bekannter, aktiv ausgenutzter Sicherheitslücken (KEV).

Typische Fehlerquellen und Praxis-Mythen

In der praktischen Umsetzung treten regelmäßig wiederkehrende Fallstricke auf:

  • Fehlendes Quoting bei Leerzeichen: Der unbedachte Aufruf von echo $name führt zu Fehlern, sobald Variablenwerte Leerzeichen enthalten. Korrekt ist die Einklammerung in Anführungszeichen: "$name".
  • Verlust von Variablen durch Pipelines: Da Pipes Subshells erzeugen, gehen Variablenwerte, die innerhalb einer nachgeschalteten while read-Schleife gesetzt wurden, nach Schleifenende im übergeordneten Skript verloren.
  • Ausführungsberechtigungen: Ein Skript ohne gesetztes Ausführungsbit lässt sich nicht direkt über einen relativen Pfad starten, kann jedoch jederzeit über bash skript.sh ausgeführt werden.

Häufige Fragen

Was ist Bash in Linux?

Es handelt sich um den Standard-Befehlsinterpreter des GNU-Betriebssystems. Das Programm nimmt Tastaturbefehle im Terminal entgegen, startet Anwendungen, verwaltet Datei- und Prozessströme und verarbeitet strukturierte Automatisierungsskripte.

Was ist der Unterschied zwischen Bash und sh?

Die historische Bourne-Shell (sh) von 1977 definiert den POSIX-Standard. Bash stellt eine abwärtskompatible Obermenge dar, die zusätzliche Programmierfeatures wie Arrays, mathematische Ausdrücke und erweiterte Prüfbedingungen mitbringt. Auf Debian-basierten Systemen verweist /bin/sh meist auf dash, nicht auf Bash.

Wie kann man die Skripterstellung fundiert lernen?

Ein strukturierter Einstieg gelingt über das offizielle GNU Bash Reference Manual sowie über Lernprojekte wie Bashcrawl. Für die Codequalität empfiehlt sich die Integration statischer Prüfwerkzeuge wie ShellCheck und automatischer Formatierer wie shfmt.

Muss man den Interpreter in DevOps und Systemadministration beherrschen?

Ja. Nahezu alle Linux-Server werden über diese Schnittstelle gewartet. In CI/CD-Pipelines, Docker-Container-Entrypoints und Deployment-Routinen fungiert die Syntax als Verbindungskleber zwischen Werkzeugen wie Kubernetes, Ansible und Terraform.

Was bedeutet der Begriff bashen?

Umgangssprachlich bedeutet „bashen“ (vom englischen „to bash“ für schlagen oder dreschen) das Beschimpfen, Kritisieren oder Fertigmachen von Personen. In der Jugendsprache wird es synonym für lästern oder schlechtmachen verwendet. Mit der Shell hat dieser Begriff trotz des Gleichklangs nichts zu tun.

Ebenfalls lesenswert