Entwicklung / Systemprogrammierung / Linux / Shell & Bash Praxis-Handbuch

Aus Dokument
Zur Navigation springen Zur Suche springen

Shell & Bash Scripting – Das Praxis-Handbuch

Die Bash (Bourne Again Shell) ist die Standard-Kommandozeile und Skriptsprache auf den meisten Linux- und Unix-Systemen. Sie dient als primäre Schnittstelle zur Automatisierung von Systemaufgaben, CI/CD-Pipelines, Server-Administration, Log-Analysen und Prozess-Orchestrierungen.

Dieses Handbuch bietet eine strukturierte Übersicht über Shell-Grundlagen, Ein- und Ausgabenumleitungen, Textverarbeitung mit grep/awk/sed, Datentypen, Arrays, Kontrollstrukturen, defensive Fehlerbehandlung (set -euo pipefail), trap-Signale, Cron-Jobs und shellcheck.



🚀 1. Shell-Grundlagen & Befehlsstruktur

Was ist die Shell?

Die Shell ist ein Befehlszeilen-Interpreter, der Benutzereingaben entgegennimmt und als Betriebssystem-Befehle ausführt.

Beliebte Shells im Vergleich

  • Bash (/bin/bash): Der weltweite De-facto Standard auf Linux-Servern.
  • Zsh (/bin/zsh): Standard-Shell auf macOS; bietet erweiterte Autovervollständigung und Themes (Oh My Zsh).
  • Dash (/bin/dash): Extrem schnelle, POSIX-konforme Shell (wird in Ubuntu für System-Skripte /bin/sh genutzt).
  • Fish (/usr/bin/fish): Benutzerfreundliche interaktive Shell mit nativer Auto-Suggestion.



🔀 2. I/O-Redirection, Streams & Pipelines

Die 3 Standard-Streams

Jeder Linux-Prozess besitzt drei vorgegebene I/O-Kanäle:

Stream Dateideskriptor (FD) Beschreibung Standard-Ziel
stdin 0 Standard-Eingabe (Keyboard / Input) Tastatur
stdout 1 Standard-Ausgabe (Normale Ergebnisse) Terminal-Bildschirm
stderr 2 Standard-Fehlerausgabe (Fehlermeldungen) Terminal-Bildschirm

Umleitungen & Piping (|)

# Output Umleitung (Überschreiben > vs. Anfügen >>)
echo "Zeile 1" > datei.txt
echo "Zeile 2" >> datei.txt

# Fehlerbehandlung: stderr separat umleiten oder mit stdout zusammenführen
command_with_error 2> error.log
command_with_error > output.log 2>&1  # stderr & stdout in selbe Datei
command_with_error &> output.log     # Moderne Bash-Kurzform

# Process Substitution: Erzeugt eine temporäre FIFO-Datei für Befehlsausgaben
diff -u <(ls /folder1) <(ls /folder2)

✍️ 3. Variablen, Datentypen & String-Manipulation

Variablen & Gültigkeitsbereiche

#!/bin/bash

# Definition (KEINE Leerzeichen um das '=' erlaubt!)
NACHRICHT="Hello World"
declare -i ZAHLER=42         # Typsicheres Integer
declare -r KONSTANTE="FIXED" # Read-Only Variable

# Umgebungsvariable für Kindprozesse exportieren
export DB_HOST="localhost"

# Spezialvariablen
echo "Skriptname: $0"
echo "Anzahl Argumente: $#"
echo "Alle Argumente: $@"
echo "Exit-Code des letzten Befehls: $?"
echo "Prozess-ID (PID) des Skripts: $$"

Arrays & Assoziative Arrays (Key-Value)

Indizierte Arrays

# Indiziertes Array definieren
FRUCHTE=("Apfel" "Banane" "Kirsche")

# Elemente hinzufügen & auslesen
FRUCHTE+=("Orange")
echo "Erstes Element: ${FRUCHTE[0]}"
echo "Alle Elemente: ${FRUCHTE[@]}"
echo "Anzahl Elemente: ${#FRUCHTE[@]}"

Assoziative Arrays (Hashes)

# Deklaration zwingend erforderlich!
declare -A SERVERE_IPS

SERVERE_IPS=(
    ["web01"]="192.168.1.10"
    ["db01"]="192.168.1.20"
)

echo "IP von db01: ${SERVERE_IPS["db01"]}"

String-Manipulationen ohne externe Tools

Operation Syntax Ergebnis (bei STR="file.tar.gz")
String-Länge ${#STR} 11
Suffix entfernen ${STR%.gz} file.tar
Gierig Suffix entfernen ${STR%%.*} file
Prefix entfernen ${STR#*.} tar.gz
Ersetzung (Erste) ${STR/tar/zip} file.zip.gz
Großbuchstaben ${STR^^} FILE.TAR.GZ



🔀 4. Kontrollstrukturen & Operatoren

Dateitests & Vergleiche

Dateitests ([ -f file ])

  • -f file: Wahr, wenn die Datei existiert und eine reguläre Datei ist.
  • -d dir: Wahr, wenn das Verzeichnis existiert.
  • -e path: Wahr, wenn der Pfad existiert.
  • -r / -w / -x: Lesbar / Schreibbar / Ausführbar.

Zahlen- & String-Vergleiche

NAME="Alice"
AGE=25

# String-Vergleich (doppelte eckige Klammern [[ ]] nutzen!)
if [[ "$NAME" == "Alice" && -n "$NAME" ]]; then
    echo "Name passt und ist nicht leer."
fi

# Numerischer Vergleich (-eq, -ne, -lt, -gt, -le, -ge)
if [[ "$AGE" -gt 18 ]]; then
    echo "Volljährig."
fi

Loops (Schleifen)

# For-Schleife über Elemente
for DATEI in *.log; do
    [[ -f "$DATEI" ]] || continue
    echo "Verarbeite $DATEI..."
done

# C-Style For-Schleife
for ((i=1; i<=5; i++)); do
    echo "Durchlauf $i"
done

# While-Schleife mit 'read' (Zeilenweises Einlesen einer Datei)
while IFS= read -r ZEILE; do
    echo "Zeile: $ZEILE"
done < config.txt

🛡️ 5. Defensives Scripting, Debugging & Signal Handling

Unbeabsichtigte Fehler verhindern

Standardmäßig läuft ein Bash-Skript weiter, selbst wenn ein Befehl fehlschlägt. Aktivieren Sie immer den Strict Mode!

1. Der Bash Strict Mode (set -euo pipefail)

Fügen Sie diesen Block am Anfang jedes Skripts ein:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
  • set -e: Bricht das Skript bei Fehler (Exit-Code != 0) sofort ab.
  • set -u: Bricht ab, wenn eine undefinierte Variable aufgerufen wird.
  • set -o pipefail: Der Exit-Code einer Pipeline entspricht dem letzten fehlerhaften Befehl.

2. Traps & Aufräumarbeiten bei Signalen (trap)

Mit trap können temporäre Dateien oder Sperren beim Abbrechen oder Beenden aufgeräumt werden:

TMP_DIR=$(mktemp -d)

# Aufräum-Funktion definieren
cleanup() {
    echo "Räume temporäre Dateien auf: $TMP_DIR"
    rm -rf "$TMP_DIR"
}

# Registrieren für EXIT, SIGINT (Ctrl+C) und SIGTERM
trap cleanup EXIT INT TERM

3. Debugging & Static Analysis

  • bash -n script.sh: Prüft das Skript auf Syntax-Fehler ohne es auszuführen.
  • bash -x script.sh / set -x: Gibt jede auszuführende Zeile mit aufgelösten Variablen im Terminal aus.
  • shellcheck script.sh: Der Branchenstandard zur statischen Code-Analyse für Bash-Skripte.



⏰ 6. Automatisierung: Cron-Jobs & Systemd Timers

Task-Scheduling mit cron

# Benutzer-Crontab bearbeiten
crontab -e

# Syntax: Minute Stunde Tag Monat Wochentag Befehl
# ┌───────────── Minute (0 - 59)
# │ ┌─────────── Stunde (0 - 23)
# │ │ ┌───────── Tag des Monats (1 - 31)
# │ │ │ ┌─────── Monat (1 - 12)
# │ │ │ │ ┌───── Wochentag (0 - 6) (Sonntag=0)
# * * * * * /path/to/script.sh

# Beispiel: Jeden Tag um 02:30 Uhr nachts ein Backup ausführen
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1