Bash · Code-Review · ShellCheck · CI/CD
Shell-Skripte reviewen —
was Teams standardisieren sollten

Ohne einheitliche Regeln entstehen Shell-Coderbasen, in denen jedes Skript einem anderen Stil folgt, Fehlerbehandlung fehlt oder inkonsistent ist und niemand weiß, welche Prüfungen beim Review Pflicht sind. Eine Review-Checkliste, klare Stilregeln, EditorConfig und ShellCheck als CI-Gate schaffen die Grundlage, Shell-Skripte reviewen zu können, ohne jeden PR von Grund auf neu zu diskutieren.

15 Min. Lesezeit ShellCheck · EditorConfig · BATS · GitHub Actions Bash 4.x · 5.x · Linux · macOS

1. Warum Shell-Skripte reviewen oft scheitert

Das Shell-Skripte reviewen im Teamkontext leidet unter einem strukturellen Problem: Die meisten Entwickler haben keine gemeinsame Vorstellung davon, was ein gutes Shell-Skript ausmacht. In Sprachen wie Python oder TypeScript gibt es Linter, Formatter und etablierte Style Guides — bei Shell-Skripten fehlt diese Kultur oft vollständig. Das Ergebnis sind Reviews, in denen grundlegende Probleme wie fehlende Fehlerbehandlung, unquotierte Variablen oder stille Pipe-Fehler nicht auffallen, weil der Reviewer schlicht nicht weiß, wonach er suchen soll.

Ein zweites Problem ist die Heterogenität bestehender Shell-Codebasen. Skripte entstehen über Jahre von verschiedenen Personen, und jedes Skript spiegelt den Wissensstand und den Stil des jeweiligen Autors wider. Neue Teammitglieder orientieren sich an bestehenden Skripten — und reproduzieren dabei sowohl die guten als auch die schlechten Muster. Ohne explizite Standards und automatisierte Prüfungen wird jede neue Datei Teil eines wachsenden Wirrwarrs, das kaum noch wartbar ist. Das Ziel dieses Artikels ist, einen klaren Rahmen für das Shell-Skripte reviewen zu etablieren.

Ein dritter Faktor ist die Unterschätzung von Shell-Skripten als kritische Infrastruktur. Deployment-Skripte, Backup-Routinen, Datenmigrations-Skripte und Monitoring-Alerter sind oft in Bash geschrieben und laufen mit root-Rechten auf Produktionssystemen. Ein Fehler in diesen Skripten kann Datenverlust, Ausfallzeiten oder Sicherheitslücken verursachen. Das rechtfertigt denselben Qualitätsanspruch wie für Anwendungscode — inklusive Review, Tests und automatisierter Prüfung.

2. Die Review-Checkliste für Shell-Skripte

Eine strukturierte Checkliste ist der wichtigste erste Schritt, um Shell-Skripte reviewen systematisch zu gestalten. Die Checkliste ersetzt nicht das Nachdenken, aber sie stellt sicher, dass grundlegende Prüfpunkte bei keinem Review vergessen werden. Der erste Block betrifft das Fundament: Beginnt das Skript mit dem korrekten Shebang (#!/usr/bin/env bash)? Sind set -euo pipefail und IFS=$'\n\t' gesetzt? Gibt es eine trap cleanup EXIT-Registrierung? Ohne diese drei Punkte fehlt das Sicherheitsnetz für alle nachfolgenden Operationen.

Der zweite Block der Checkliste betrifft Variablen und Quoting: Sind alle Variablenreferenzen in Anführungszeichen gesetzt? Werden Arrays für Dateilisten und Befehlslisten verwendet statt Strings? Sind Pfad-Variablen mit readonly oder declare -r geschützt? Der dritte Block betrifft Fehlerbehandlung: Werden Exit-Codes kritischer Befehle explizit geprüft? Gibt es klare Fehlermeldungen, die auf stderr ausgegeben werden? Wird pipefail korrekt genutzt? Diese Punkte beim Shell-Skripte reviewen konsequent abzuhaken, deckt die häufigsten Bugs ab, bevor das Skript in Produktion geht.

Der vierte Block der Review-Checkliste ist Sicherheit: Werden externe Eingaben validiert? Werden temporäre Dateien mit mktemp erstellt und mit trap aufgeräumt? Gibt es race conditions bei Dateizugriffen? Werden Befehle mit Benutzereingaben in eval-Kontexten ausgeführt? Ein fünfter Block betrifft Testbarkeit: Hat das Skript eine main()-Funktion? Kann es per source eingebunden werden, ohne Seiteneffekte auszulösen? Sind Funktionen klein genug, um einzeln testbar zu sein? Diese Struktur macht das Shell-Skripte reviewen zum wiederholbaren Prozess.


#!/usr/bin/env bash
# review-check.sh — Automated pre-review checks for shell scripts
# Run: bash review-check.sh path/to/script.sh

set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT="${1:?Usage: $0 <script.sh>}"
declare -i errors=0

check() {
  local desc="$1" pattern="$2"
  if ! grep -qE "$pattern" "$SCRIPT"; then
    echo "[FAIL] $desc" >&2
    (( errors++ )) || true
  else
    echo "[OK]   $desc"
  fi
}

echo "=== Reviewing: $SCRIPT ==="
check "Shebang: #!/usr/bin/env bash"    '^#!/usr/bin/env bash'
check "set -e present"                  'set -[a-z]*e|set -euo'
check "set -u present"                  'set -[a-z]*u|set -euo'
check "pipefail set"                    'pipefail'
check "IFS hardened"                    "IFS=\$'\\\\n\\\\t'"
check "trap EXIT registered"            'trap .* EXIT'
check "SCRIPT_DIR defined"              'SCRIPT_DIR'

echo ""
if (( errors > 0 )); then
  echo "[RESULT] $errors check(s) failed — review required" >&2
  exit 1
fi
echo "[RESULT] All basic checks passed"

3. Stilregeln: was im Team gelten soll

Stilregeln für Shell-Skripte sind kein Selbstzweck — sie reduzieren den kognitiven Aufwand beim Shell-Skripte reviewen, weil der Reviewer nicht gleichzeitig Inhalt und Form beurteilen muss. Die erste Stilregel betrifft Benennung: Funktionen werden in snake_case geschrieben, globale Konstanten in UPPER_SNAKE_CASE, lokale Variablen in lower_snake_case. Wer diese Konvention konsequent anwendet, erkennt auf einen Blick, ob eine Variable lokal oder global ist — und ob sie verändert werden darf.

Die zweite Stilregel: Jede Funktion erhält einen einzigen klar definierten Zweck. Funktionen, die mehr als 30 Zeilen haben, sind meistens zu groß und sollten in kleinere Einheiten aufgeteilt werden. Die dritte Regel: Kommentare erklären das Warum, nicht das Was. Ein Kommentar wie # delete temp file vor rm -f "$tmpfile" ist nutzlos. Ein Kommentar wie # trap ensures cleanup even on SIGPIPE from downstream consumer erklärt eine nicht-offensichtliche Design-Entscheidung. Beim Shell-Skripte reviewen auf fehlende "Warum"-Kommentare hinzuweisen ist eine der wertvollsten Reviewer-Aktivitäten.

Die vierte Stilregel betrifft die Shebang-Zeile: Immer #!/usr/bin/env bash statt #!/bin/bash, weil der Pfad zu Bash auf macOS und verschiedenen Linux-Distributionen unterschiedlich ist. Die fünfte Stilregel: Kein Parsing von ls-Ausgaben, keine for f in $(cat filelist)-Konstrukte, keine Zeilenauswertung mit sed oder awk für Aufgaben, die Bash-Builtins übernehmen können. Diese Regeln schriftlich festzuhalten und im Repository als SHELL_STYLE.md zu hinterlegen, gibt dem Review-Prozess eine stabile Referenz.

4. EditorConfig für konsistente Skript-Dateien

Eine .editorconfig-Datei im Repository-Root stellt sicher, dass alle Entwickler dieselben Basis-Einstellungen für Shell-Skript-Dateien verwenden — unabhängig vom Editor. Die wichtigsten Einstellungen für Shell-Skripte: indent_style = space mit indent_size = 2 (Shell-Konvention, nicht 4 wie in Python), end_of_line = lf (CRLF in Shell-Skripten unter Windows verursacht schwer zu diagnostizierende Fehler), trim_trailing_whitespace = true und insert_final_newline = true. Diese Einstellungen sind trivial zu konfigurieren, verhindern aber eine ganze Klasse von Diff-Lärm beim Shell-Skripte reviewen.

Ein häufig übersehenes Problem: Shell-Skripte, die auf Windows-Systemen bearbeitet und dann auf Linux ausgeführt werden, können durch CRLF-Zeilenenden brechen. Das \r-Zeichen wird nicht als Whitespace interpretiert und landet in Variablen-Werten, was zu kryptischen Fehlermeldungen führt. end_of_line = lf in der EditorConfig verhindert das, und file -i skript.sh zeigt, ob eine Datei bereits CRLF-Zeilenenden enthält. Beim Shell-Skripte reviewen empfiehlt es sich, file -i als ersten Schritt in das Review-Script aufzunehmen.


# .editorconfig — consistent settings for all shell scripts in the repo
root = true

[*.sh]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

[*.bash]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

# Prevent CRLF contamination in CI helper scripts
[bin/*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

5. ShellCheck: statische Analyse im Detail

ShellCheck ist das wichtigste Werkzeug, um Shell-Skripte reviewen zu automatisieren. Es analysiert Bash-Skripte statisch und erkennt über 500 verschiedene Fehlerklassen — von unquotierten Variablen (SC2086) über verlorene Exit-Codes (SC2155) bis hin zu Portierbarkeits-Problemen zwischen Bash-Versionen. ShellCheck gibt zu jeder Warnung einen Link auf shellcheck.net aus, der das Problem erklärt und die korrekte Lösung zeigt. Das macht es zum idealen Lehrmittel für Teams, die gerade anfangen, Shell-Skripte reviewen ernst zu nehmen.

Die wichtigsten ShellCheck-Warnungskategorien sind: SC2086 (fehlende Anführungszeichen bei Variablenexpansion), SC2034 (unbenutzte Variable — oft ein Tippfehler im Variablennamen), SC2155 (Deklaration und Zuweisung kombiniert, Exit-Code geht verloren), SC2046 (unquotierte Command Substitution in Befehlsargumenten) und SC1090/SC1091 (Quelldatei nicht statisch analysierbar — ShellCheck kann dynamische source-Pfade nicht prüfen). Die Option shellcheck -S warning filtert nur Warnungen und Fehler, keine style-Hinweise — ein guter Ausgangspunkt für Legacy-Codebasen, bei denen style-Hinweise zu viel Lärm erzeugen würden.

ShellCheck unterstützt Directives zum gezielten Ausblenden von Warnungen: # shellcheck disable=SC2086 vor einer Zeile deaktiviert die Warnung für genau diese Zeile. Das ist nützlich, wenn eine Warnung falsch positiv ist — aber diese Directives sollten immer mit einem Kommentar begründet werden, der erklärt, warum die Warnung hier nicht anwendbar ist. Ein häufiger Anwendungsfall: bewusst unquotierte Variablen, wenn Word Splitting erwünscht ist. Beim Shell-Skripte reviewen sind unbegründete ShellCheck-Directives ein klares Review-Feedback-Item.

6. ShellCheck in der CI-Pipeline integrieren

ShellCheck als CI-Gate zu integrieren ist der effektivste Weg, um Standards beim Shell-Skripte reviewen durchzusetzen, ohne dass Reviewer manuell nach bekannten Fehlern suchen müssen. In GitHub Actions steht ShellCheck als fertige Action zur Verfügung und lässt sich in wenigen Zeilen integrieren. Alternativ kann ShellCheck direkt im Runner installiert und als Shell-Befehl aufgerufen werden — das gibt mehr Kontrolle über Parameter und macht die Pipeline weniger abhängig von externen Actions. Die wichtigste Entscheidung: Soll ShellCheck als Hard Gate (Pipeline schlägt fehl) oder als Soft Gate (Warnung ohne Blockierung) laufen? Für neue Codebasen empfiehlt sich von Anfang an das Hard Gate.

Für bestehende Codebasen mit vielen Altskripten empfiehlt sich ein schrittweiser Ansatz: Zunächst nur neue und geänderte Dateien prüfen (git diff --name-only HEAD~1 | grep '\.sh$'), dann schrittweise den Schwellenwert der erlaubten Warnungen senken. Eine .shellcheckrc im Repository-Root erlaubt projektweite Konfiguration ohne Kommandozeilenparameter und macht die CI-Konfiguration übersichtlicher. Beim Shell-Skripte reviewen durch Menschen deckt ShellCheck dann nur noch die Fälle ab, die statische Analyse nicht erkennt — Logikfehler, fehlerhafte Annahmen über Systemzustand und fehlende Business-Logik-Validierung.


# .github/workflows/shellcheck.yml — ShellCheck CI gate for all shell scripts

name: ShellCheck
on:
  push:
    paths: ['**.sh', 'bin/**']
  pull_request:
    paths: ['**.sh', 'bin/**']

jobs:
  shellcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install ShellCheck
        run: sudo apt-get install -y shellcheck

      - name: Run ShellCheck on all scripts
        run: |
          # Find all shell scripts (including those without .sh extension)
          mapfile -t scripts < <(
            find . -name "*.sh" -not -path "./.git/*" -print
            find bin/ -type f -not -name "*.*" -exec grep -l '#!/.*bash' {} \;
          )
          echo "Checking ${#scripts[@]} scripts..."
          shellcheck --severity=warning --shell=bash "${scripts[@]}"

      - name: Check EditorConfig compliance
        run: |
          # Detect CRLF line endings — fatal for shell scripts on Linux
          if grep -rlU $'\r' --include="*.sh" .; then
            echo "ERROR: CRLF line endings found in shell scripts" >&2
            exit 1
          fi

7. Automatisierte Tests mit BATS

BATS (Bash Automated Testing System) ermöglicht Unit-Tests für Shell-Skripte mit einer Syntax, die pytest oder RSpec ähnelt. Für das Shell-Skripte reviewen ist BATS besonders wertvoll, weil es testbare Skripte von nicht-testbaren unterscheidet: Ein Skript mit einer main()-Funktion und klarer Trennung von Funktionen und Hauptlogik lässt sich mit BATS testen. Ein Skript, das beim source-Einbinden sofort Befehle ausführt, nicht. Diese Unterscheidung wird im Review sichtbar: Fehlende Testbarkeit ist ein handfester Kritikpunkt, nicht nur ein Stilproblem.

Ein vollständiger BATS-Test prüft das Verhalten einer Funktion in Isolation, mockt externe Befehle über Funktions-Shadowing und verifiziert sowohl stdout als auch stderr-Ausgaben sowie Exit-Codes. Das Testfile liegt im Verzeichnis tests/ neben den Skript-Dateien und wird in der CI-Pipeline nach ShellCheck ausgeführt. Beim Shell-Skripte reviewen empfiehlt es sich, für jede neue Funktion mindestens drei Tests zu fordern: den Happy-Path, den Fehlerfall und den Edge-Case (leere Eingabe, Leerzeichen im Argument). Das Einfordern von Tests beim Review ist die nachhaltigste Maßnahme für langfristige Shell-Codebase-Qualität.

8. Den Review-Prozess im Team verankern

Technische Werkzeuge allein reichen nicht aus — das Shell-Skripte reviewen muss auch kulturell verankert werden. Das bedeutet: Pull Requests für alle Skript-Änderungen, auch kleine Hotfixes. Ein Minimum von einem Reviewer, der Bash-Kenntnisse hat. Eine klare Definition, welche Punkte in der automatisierten Prüfung abgedeckt sind und welche Punkte im manuellen Review geprüft werden sollen. Und ein Review-Template als PR-Beschreibungsvorlage, das die Checkliste aus Abschnitt 2 abbildet.

Ein häufig unterschätzter Aspekt des Shell-Skripte reviewen ist die Dokumentation im Skript selbst. Jedes Skript sollte einen Usage-Kommentar am Anfang haben, der zeigt, wie es aufgerufen wird, welche Umgebungsvariablen es erwartet und was es zurückgibt. Eine usage()-Funktion, die bei -h oder --help aufgerufen wird, ist kein Luxus — sie ist die erste Dokumentation, die ein neuer Teammitglied sieht. Im Review zu fordern, dass diese Dokumentation aktuell ist, kostet wenig, spart aber bei jedem späteren Debugging-Einsatz erheblich Zeit.

9. Werkzeugvergleich für Shell-Reviews

Für das Shell-Skripte reviewen stehen verschiedene Werkzeuge zur Verfügung, die sich in Scope, Integration und Tiefe der Analyse unterscheiden. Die richtige Kombination hängt von Teamgröße, Repository-Komplexität und dem vorhandenen CI-Stack ab.

Werkzeug Typ Stärken Grenzen
ShellCheck Statische Analyse 500+ Regeln, CI-fertig, erklärt Fehler Keine Laufzeit-Checks, kein Logik-Test
BATS Unit-Tests Funktions-Tests, Mock-Support, CI-integrierbar Erfordert testbare Skript-Struktur
shfmt Formatter Automatische Formatierung, diff-freundlich Kein Inhalt-Check, nur Stil
EditorConfig Editor-Konfiguration Verhindert CRLF, falsche Einrückung Nur Basis-Formatting, kein Bash-Wissen
Manuelle Review-Checkliste Prozess Logikfehler, Designentscheidungen, Kontext Zeitaufwändig, abhängig von Reviewer-Wissen

Die optimale Kombination für das Shell-Skripte reviewen in Teams: ShellCheck als obligatorisches CI-Gate, shfmt für automatische Formatierung im Pre-Commit-Hook, BATS für kritische Skripte mit Produktionsrelevanz und die manuelle Checkliste für den menschlichen Review. Diese Schichtung trennt automatisierbar Prüfbares von dem, was menschliches Urteilsvermögen erfordert.

Mironsoft

Shell-Automatisierung, DevOps-Tooling und Deployment-Infrastruktur

Shell-Skripte reviewen und standardisieren lassen?

Wir analysieren bestehende Shell-Codebasen, etablieren Review-Checklisten, richten ShellCheck-CI-Gates ein und schulen Teams im systematischen Shell-Review-Prozess — für nachhaltig wartbare Automatisierung.

Codebase-Audit

ShellCheck-Analyse der gesamten Shell-Codebasis mit priorisierten Empfehlungen

CI-Setup

ShellCheck, shfmt und BATS in bestehende CI-Pipelines integrieren

Team-Training

Review-Prozess verankern und Bash-Kenntnisse im Team aufbauen

10. Zusammenfassung

Das Shell-Skripte reviewen im Team wird effektiv, wenn es auf drei Säulen steht: automatisierte Prüfung durch ShellCheck als CI-Gate, konsistente Formatierung durch EditorConfig und shfmt sowie ein strukturierter manueller Review-Prozess mit Checkliste. ShellCheck übernimmt die bekannten Fehlerklassen automatisch und gibt Reviewern mehr Zeit für Logik und Design. EditorConfig verhindert die häufigsten Format-Diskussionen und schützt vor CRLF-Problemen. Die manuelle Checkliste stellt sicher, dass Fundament, Fehlerbehandlung und Sicherheit systematisch geprüft werden.

Der kulturelle Aspekt ist genauso wichtig wie die Werkzeuge: Pull Requests für alle Skript-Änderungen, ein Reviewer mit Bash-Kenntnissen und die Erwartung, dass Skripte genauso wie Anwendungscode dokumentiert, getestet und nach Standards entwickelt werden. Das lohnt sich besonders für Deployment-Skripte, Backup-Routinen und andere Automatisierungen, die mit erweiterten Rechten auf Produktionssystemen laufen — hier sind Fehler keine akademische Frage, sondern haben direkte operative Konsequenzen.

Shell-Skripte reviewen — Das Wichtigste auf einen Blick

Review-Checkliste

Shebang, set -euo pipefail, trap EXIT, Variablen-Quoting, Fehlerbehandlung, Sicherheit und Testbarkeit als Pflichtpunkte im Review.

ShellCheck als CI-Gate

ShellCheck mit --severity=warning als Hard Gate in der CI-Pipeline — befreit manuelle Reviewer von bekannten Fehlerklassen.

EditorConfig

end_of_line = lf, indent_style = space, indent_size = 2 für alle .sh-Dateien — verhindert CRLF-Bugs und Diff-Lärm.

BATS-Tests

Testbare Skripte mit main()-Funktion. BATS für Happy-Path, Fehlerfall und Edge-Cases kritischer Funktionen.

11. FAQ: Shell-Skripte reviewen — was Teams standardisieren sollten

1Was gehört zwingend in jeden Shell-Skript-Review?
Shebang, set -euo pipefail, IFS-Härtung, trap cleanup EXIT, Quoting aller Variablenreferenzen und explizite Fehlerbehandlung kritischer Befehle. ShellCheck deckt viele davon automatisch ab.
2Warum ShellCheck statt manueller Prüfung?
ShellCheck erkennt 500+ Fehlerklassen zuverlässig und konsistent, ohne Reviewer-Ermüdung, mit Erklärung und Lösung zu jeder Warnung.
3Was ist shfmt?
Automatischer Formatter für Shell-Skripte. Als Pre-Commit-Hook eliminiert er Format-Diskussionen im Review vollständig.
4Legacy-Skripte mit vielen ShellCheck-Warnungen?
Schrittweise: erst nur geänderte Dateien prüfen, kritische Warnungsklassen zuerst beheben, Gate schrittweise verschärfen.
5Warum ist CRLF in Shell-Skripten gefährlich?
Das \r landet in Variablen-Werten und Pfaden — mysteriöse 'command not found'-Fehler. cat -A macht es als ^M sichtbar.
6Was macht ein Shell-Skript testbar mit BATS?
main()-Funktion plus [[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@". Erlaubt source-Einbindung ohne Seiteneffekte für BATS-Tests.
7Kritischste ShellCheck-Warnungen?
SC2086 (unquotierte Variable), SC2155 (Exit-Code verloren), SC2046, SC2164 (cd ohne Fehlerbehandlung) und SC2068.
8Hard Gate oder Soft Gate für ShellCheck?
Neue Codebasen: immer Hard Gate. Legacy: zunächst Soft Gate, dann schrittweise verschärfen. Der Schmerz des Hard Gates ist der stärkste Anreiz zur Behebung.
9Wie dokumentiere ich Shell-Skripte korrekt?
Usage-Kommentar am Anfang, usage()-Funktion für -h/--help, Kommentare erklären das Warum, Funktionen haben einzeilige Beschreibung.
10Wie viele Reviewer für Shell-Skripte?
Mindestens einer mit Bash-Kenntnissen. Für sicherheitskritische Skripte (root-Rechte, Deployment) ein zweiter Reviewer empfohlen.