Zum Inhalt springen

Systemadministration & Netzwerk

Bash-Scripting lernen: Alltag automatisieren

Bash-Scripting lernen: du automatisierst Admin-Alltag mit Variablen, Schleifen, Pipes, Fehlerbehandlung und erkennst, wann Python besser passt.

22. Juni 2023 7 Min. Lesezeit

KI-generiert

Ein paar wiederkehrende Kommandos auf dem Server, und du merkst schnell: Das klickst du nicht mehr per Hand. Bash-Scripting ist dann das naheliegende Werkzeug, um aus Einzelbefehlen robuste, wiederverwendbare Helfer zu bauen. Die Kunst besteht darin, nicht nur irgendetwas hinzuhacken, sondern Skripte zu schreiben, die auch Monate später noch verständlich sind und im Fehlerfall sauber reagieren.

Bash-Skripte sauber starten

Ein Bash-Skript ist im Kern eine Textdatei mit Befehlen, die du sonst in die Shell tippst. Ein minimaler, aber sinnvoller Start:

#!/usr/bin/env bash
set -euo pipefail

echo "Backup läuft..."

Die erste Zeile sagt dem System, welche Shell das Skript interpretieren soll. set -euo pipefail ist so etwas wie der Sicherheitsgurt:

  • -e: Skript bricht ab, wenn ein Befehl fehlschlägt.
  • -u: Zugriff auf nicht gesetzte Variablen wird als Fehler behandelt.
  • -o pipefail: Pipelines gelten als fehlgeschlagen, wenn ein Teilbefehl fehlschlägt, nicht nur der letzte.

Gerade in Admin-Skripten vermeidest du damit halbfertige Zustände, etwa bei Deployments oder Backups.

Variablen: sauber setzen und zitieren

In Bash gibt es keine Typen im klassischen Sinn. Alles ist String, und du musst mit Anführungszeichen und Substitution sauber umgehen.

Variablen setzen und lesen

NAME="web01"
PORT=8080

echo "Server: $NAME, Port: $PORT"

Wichtig:

  • Kein Leerzeichen um das Gleichheitszeichen.
  • Beim Lesen immer mit $ davor.
  • Strings mit Leerzeichen immer in Anführungszeichen:
DIR="/var/www/my app" # korrekt
cd "$DIR" # immer quoten

Das konsequente Quoten schützt dich vor kaputten Pfaden, Leerzeichen und Wildcards, die zu unerwartetem Verhalten führen.

Umgebungsvariablen und Defaults

Für Admin-Skripte ist es praktisch, Konfiguration über Umgebungsvariablen zuzulassen:

BACKUP_DIR="${BACKUP_DIR:-/var/backups}"
RETENTION_DAYS="${RETENTION_DAYS:-7}"

echo "Sichere nach: $BACKUP_DIR"
echo "Aufbewahrung: $RETENTION_DAYS Tage"

${VAR:-default} bedeutet: Nutze VAR, falls gesetzt, sonst den Default. So kannst du Skripte flexibel konfigurieren, ohne sie zu ändern.

Bedingungen: if, test und [[ ]]

Mit Bedingungen reagierst du auf Zustände des Systems oder Parameter.

Klassische if-Struktur

if [[ "$EUID" -ne 0 ]]; then
 echo "Bitte als root ausführen." >&2
 exit 1
fi

Empfehlenswert ist [[ ... ]] statt des alten test beziehungsweise [ ... ], weil es robuster mit Strings und Mustern umgeht.

Häufige Tests:

  • Dateien:
  • -f datei: reguläre Datei existiert
  • -d verzeichnis: Verzeichnis existiert
  • -x datei: Datei ist ausführbar
  • Strings:
  • -z "$VAR": leer
  • -n "$VAR": nicht leer
  • Zahlen:
  • -eq, -ne, -lt, -le, -gt, -ge

Beispiel: Check eines Konfigurationsverzeichnisses:

CONFIG_DIR="/etc/myapp"

if [[ ! -d "$CONFIG_DIR" ]]; then
 echo "Konfigurationsverzeichnis $CONFIG_DIR fehlt." >&2
 exit 2
fi

Schleifen: über Listen und Dateien iterieren

Schleifen sind das Herzstück vieler Admin-Skripte, etwa um eine Liste von Hosts oder Dateien abzuarbeiten.

for-Schleife

for host in web01 web02 db01; do
 echo "Pinge $host..."
 ping -c1 "$host" >/dev/null 2>&1 || echo "$host nicht erreichbar"
done

Statt feste Hostnamen kannst du auch Kommandosubstitution nutzen:

for user in $(cut -d: -f1 /etc/passwd); do
 echo "Benutzer: $user"
done

Vorsicht: Diese $(...)-Variante bricht bei Leerzeichen. Für Dateilisten ist eine while-Schleife mit read meist besser.

while read für Dateien und Pipes

while IFS= read -r line; do
 echo "Zeile: $line"
done < /var/log/syslog

Wichtig:

  • IFS= verhindert das Trimmen von führenden/trailing Spaces.
  • -r verhindert, dass Backslashes interpretiert werden.

So kannst du Logdateien auswerten oder Konfigurationsdateien Zeile für Zeile durchgehen, ohne an Sonderzeichen zu scheitern.

Pipes und Filter: die Unix-Philosophie ausnutzen

Bash-Skripte glänzen, wenn du viele kleine Werkzeuge kombinierst. Typischer Admin-Alltag:

journalctl -u nginx.service \
 | grep "error" \
 | tail -n 50

Oder: Veraltete Logdateien löschen, aber vorher einmal anzeigen:

find /var/log -name "*.log" -mtime +30 \
 | tee /tmp/alte-logs.txt \
 | xargs -r rm

Erläuterung:

  • find liefert eine Liste alter Logs.
  • tee schreibt diese Liste in eine Datei und reicht sie gleichzeitig weiter.
  • xargs -r rm löscht die Dateien, führt rm aber nur aus, wenn es überhaupt Einträge gibt (-r).

Pipes sind ideal, wenn du Datenströme verarbeitest: Logs filtern, Prozesse suchen, Backups durch gzip jagen.

Fehlerbehandlung: nicht nur auf Gutwetter optimieren

Viele Bash-Skripte funktionieren, solange nichts schiefgeht. Professionell wird es, wenn du Fehler erkennst und sauber reagierst.

Exit-Codes prüfen

Jeder Befehl liefert einen Exit-Code, abrufbar über $?. 0 bedeutet Erfolg, alles andere ist ein Fehler.

cp /etc/nginx/nginx.conf /backup/nginx.conf
if [[ $? -ne 0 ]]; then
 echo "Backup der nginx.conf fehlgeschlagen." >&2
 exit 1
fi

Mit set -e sparst du dir viele dieser Checks, aber bei kritischen Schritten kannst du trotzdem gezielt reagieren.

Eleganter ist es oft, direkt zu prüfen:

if ! cp /etc/nginx/nginx.conf /backup/nginx.conf; then
 echo "Backup der nginx.conf fehlgeschlagen." >&2
 exit 1
fi

trap für Aufräumarbeiten

Wenn ein Skript abbricht, sollen temporäre Dateien weggeräumt oder Dienste wieder gestartet werden. Das erledigst du mit trap:

TMPFILE="$(mktemp)"

cleanup() {
 rm -f "$TMPFILE"
}

trap cleanup EXIT

echo "Arbeite mit $TMPFILE..."
# hier dein Code

Die Funktion cleanup wird bei jedem Skriptende aufgerufen, egal ob erfolgreich oder wegen Fehlers. Du kannst auch gezielt auf Signale reagieren, etwa INT für Strg+C.

Praktische Admin-Skripte: drei typische Beispiele

Statt Theorie ein paar kompakte Muster, die du leicht an deine Umgebung anpassen kannst.

1. Einfaches Log-Rotationsskript

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/myapp"
RETENTION_DAYS="${RETENTION_DAYS:-7}"

find "$LOG_DIR" -name "*.log" -mtime +"$RETENTION_DAYS" \
 -print -delete

Dieses Skript löscht alle Logdateien, die älter als eine bestimmte Anzahl von Tagen sind, und gibt sie beim Löschen aus. Du kannst es per Cron einplanen.

2. Service-Check mit Benachrichtigung

#!/usr/bin/env bash
set -euo pipefail

SERVICE="${1:-nginx}"

if ! systemctl is-active --quiet "$SERVICE"; then
 echo "Dienst $SERVICE ist nicht aktiv." >&2
 # hier z. B. Mail verschicken oder Monitoring triggern
 exit 1
fi

echo "Dienst $SERVICE läuft."

So ein Skript kannst du in Monitoring-Checks einbinden oder auf mehreren Servern ausrollen.

3. Einfache Backup-Routine mit Datum

#!/usr/bin/env bash
set -euo pipefail

SRC_DIR="/var/www"
DEST_DIR="/backup"
DATE="$(date +%Y-%m-%d)"
TARGET="$DEST_DIR/www-$DATE.tar.gz"

mkdir -p "$DEST_DIR"

tar -czf "$TARGET" "$SRC_DIR"

echo "Backup erstellt: $TARGET"

Danach ergänzst du Rotationslogik, Checks auf freien Speicherplatz und vielleicht eine Übertragung auf einen anderen Host.

Wann Bash und wann Python?

Bash ist nicht für jede Aufgabe das richtige Werkzeug. Ein paar Leitlinien helfen bei der Entscheidung:

SituationBash geeignet?Python geeigneter?
Einfache KommandoabfolgenJa, optimalOverkill
Dateisystem-Operationen, rsync, cpJa, sehr gutNur bei komplexer Logik nötig
Komplexe Stringverarbeitung, JSONEingeschränktKlarer Vorteil
API-Calls (HTTP, JSON)Nur mit Tools wie curlJa, sehr gut
Längere Geschäftslogik, viele BedingungenUnübersichtlichBesser lesbar und testbar
Cross-Plattform (Linux, macOS, Windows)ProblematischMit Einschränkungen gut machbar

Faustregeln:

  • Wenn dein Skript hauptsächlich andere Programme aufruft und Dateien verschiebt, ist Bash fast immer passend.
  • Wenn du beginnst, mehr als ein paar Zeilen Stringmanipulation, JSON-P parsing oder komplexe Datenstrukturen zu bauen, wechsle lieber zu Python.
  • Ab etwa 150 bis 200 Zeilen Bash lohnt es sich, kritisch zu prüfen, ob die Logik nicht in einer „richtigen“ Programmiersprache besser aufgehoben ist.

Für Admins in München und anderswo ist eine realistische Mischung sinnvoll: kleine Helfer in Bash, komplexere Tools in Python. Beides ergänzt sich gut.

Struktur, Lesbarkeit und Sicherheit

Ein Bash-Skript ist schnell geschrieben, aber schwer zu warten, wenn Struktur und Stil fehlen. Einige einfache Konventionen helfen:

  • Kopfbereich:
  • Shebang
  • set -euo pipefail
  • kurze Beschreibung als Kommentar
  • Klare Funktionsnamen:
backup_nginx_config() { ... }
restart_service() { ... }
  • Eingaben prüfen:
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <service-name>" >&2
exit 1
fi
  • Keine gefährlichen rm-Aufrufe ohne Pfad-Checks:
if [[ -d "$TARGET_DIR" && "$TARGET_DIR" == /var/www/* ]]; then
rm -rf "$TARGET_DIR"
else
echo "Unsicheres Zielverzeichnis: $TARGET_DIR" >&2
exit 1
fi

So vermeidest du die klassischen „rm -rf /“-Unfälle und andere böse Überraschungen.

Wie du weiter übst

Am besten lernst du Bash-Scripting, indem du reale Aufgaben aus deinem Admin-Alltag automatisierst:

  • Ein kleines Inventar-Skript, das Hostname, IPs und installierte Pakete auflistet.
  • Ein Deployment-Skript für eine Webanwendung.
  • Ein Helfer, der Logdateien auf typische Fehler durchsucht und eine Übersicht erzeugt.

Nimm dir bestehende Einmal-Kommandos aus deiner Shell-History und forme sie zu wiederverwendbaren Skripten. Wenn du das strukturiert und mit Feedback lernen willst, findest du passende Linux- und Scripting-Schulungen bei cmt.de.

Bash ist kein Selbstzweck. Aber als Admin, der seine tägliche Arbeit ernst nimmt, kommst du an soliden Shell-Skripten nicht vorbei. Je früher du dir saubere Muster und Gewohnheiten antrainierst, desto entspannter läuft dein Alltag auf der Kommandozeile.

Nächster Schritt

Passenden Kurs zu Admin & Netzwerk finden.

Feste Termine, erfahrene Trainer, Präsenz in München und Durchführungsgarantie. Buchen kannst du direkt auf cmt.de.