Statische Analyse und Prüfung mit ShellCheck
Integrieren Sie ShellCheck als Sicherheits-Gate und interpretieren Sie seine Befunde, um jedes Skript abzusichern.
Statische Analyse und Prüfung mit ShellCheck ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Was ist ShellCheck und warum ist es wichtig?
ShellCheck ist ein Open-Source-Tool zur statischen Analyse von Shell-Skripten. Es analysiert Ihren Bash- (sowie POSIX-sh-, dash- und ksh-)Quellcode, ohne ihn auszuführen, und meldet Fehler, unsichere Konstrukte, Portabilitätsprobleme und Stilprobleme – jeweils mit einem eindeutigen Regelcode wie SC2086.
In einer sicherheitsgehärteten Pipeline fungiert ShellCheck als verbindliche Prüfstation: Kein Skript wird ausgeliefert, bevor es die Prüfung besteht. Das ist wichtig, weil:
- Viele Sicherheitslücken in Shell-Skripten (Wortaufteilung, Injection, nicht gesetzte Anführungszeichen) bei Tests im Erfolgsfall unsichtbar bleiben, aber durch von Angreifern kontrollierte Eingaben ausgelöst werden.
- ShellCheck diese Fehlerklassen vor der Laufzeit ohne zusätzliche Kosten erkennt.
- Es dokumentiert, warum jedes Muster gefährlich ist, und schärft dadurch mit der Zeit das Bewusstsein Ihres Teams.
Installieren Sie es auf jedem System:
# Debian / Ubuntu
sudo apt-get install shellcheck
# macOS (Homebrew)
brew install shellcheck
# From source via Cabal (any platform)
cabal update && cabal install ShellCheck
# Verify
shellcheck --versionShellCheck zum ersten Mal ausführen
Der einfachste Aufruf lautet shellcheck <script>. ShellCheck liest die Shebang-Zeile, um den Shell-Dialekt zu bestimmen, und gibt die Befunde anschließend auf stdout aus.
Jeder Befund enthält:
- Datei- und Zeilennummer – die genaue Position
- Schweregrad –
error,warning,infooderstyle - SC-Code – eine stabile Regelkennung, die Sie nachschlagen oder unterdrücken können
- Erklärung in verständlicher Sprache – erläutert, was falsch ist und oft auch, wie es behoben werden kann
Führen Sie das folgende Skript aus und beobachten Sie die Ausgabe, die ShellCheck erzeugen würde:
#!/usr/bin/env bash
# demo_bad.sh — intentionally flawed for ShellCheck demonstration
FILE=$1
if [ $FILE == '' ]; then
echo "No file given"
fi
cat $FILE | grep 'error' | wc -lShellCheck-Ausgabe und SC-Codes interpretieren
Für das Skript aus der vorherigen Szene würde ShellCheck Befunde wie die folgenden ausgeben:
SC2086(warning) – Setzen Sie Anführungszeichen, um Globbing und Wortaufteilung zu verhindern – bei$FILEin[ $FILE == '' ]und incat $FILE.SC2039/SC3010(info) – == in [ ] ist ein Bashismus; verwenden Sie für POSIX =.SC2002(style) – Überflüssiges cat. Verwenden Sie cmd < file statt cat file | cmd.
Jeder SC-Code verweist auf eine Wiki-Seite unter https://www.shellcheck.net/wiki/SCxxxx mit Begründung und einem korrigierten Beispiel.
Die korrigierte Version dieses Skripts:
#!/usr/bin/env bash
# demo_fixed.sh — ShellCheck-clean
FILE="$1"
if [ -z "$FILE" ]; then
echo "No file given" >&2
exit 1
fi
grep -c 'error' "$FILE"Schweregrade und erforderliche Maßnahmen
ShellCheck klassifiziert jeden Befund nach seinem Schweregrad. In einer Sicherheitsprüfung sollten Sie wie folgt damit umgehen:
- error – Mit ziemlicher Sicherheit ein Fehler oder eine Sicherheitslücke. Blockieren Sie den Build. Beheben Sie das Problem sofort. Beispiel:
SC2148, fehlende Shebang, oderSC2070, nicht in Anführungszeichen gesetztes$?. - warning – Ein Muster mit hohem Risiko, das häufig ausnutzbar ist. Blockieren Sie den Build. Beheben Sie das Problem oder begründen Sie die Unterdrückung ausdrücklich. Beispiel:
SC2086, Variable ohne Anführungszeichen. - info – Heute wahrscheinlich korrekt, aber fragil oder nicht portabel. Beheben Sie das Problem im selben PR, sofern es nicht ausdrücklich aus dem Umfang ausgeschlossen wurde.
- style – Kosmetische Empfehlung bzw. POSIX-Präferenz. In einer reinen Bash-Codebasis empfohlen, aber optional.
Verwenden Sie --severity=warning, damit nur bei Warnungen und schwerwiegenderen Befunden ein Exit-Code ungleich null zurückgegeben wird – die standardmäßige Schwelle für eine Sicherheitsprüfung:
#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"ShellCheck als Sicherheitsprüfung in CI integrieren
Eine Sicherheitsprüfung ist nur dann nützlich, wenn sie verbindlich und automatisiert ist. Das folgende Muster bindet ShellCheck in einen CI-Schritt ein, der:
- jede
.sh-Datei im Repository findet, - ShellCheck mit
--severity=warningund maschinenlesbarer JSON-Ausgabe ausführt, - die Pipeline (
exit 1) fehlschlagen lässt, wenn ein Befund vorliegt, - eine Zusammenfassung ausgibt, damit Entwickler die Befunde direkt im CI-Protokoll bearbeiten können.
Legen Sie diese Datei in Ihrem Repository ab und rufen Sie sie aus Ihrer CI-Pipeline auf (GitHub Actions, Jenkins, GitLab CI usw.):
#!/usr/bin/env bash
# ci/shellcheck_gate.sh
set -euo pipefail
SCRIPTS=$(find . -name '*.sh' -not -path './.git/*')
FAILED=0
for script in $SCRIPTS; do
echo "==> Checking: $script"
if ! shellcheck --severity=warning --format=tty "$script"; then
FAILED=1
fi
done
if [ "$FAILED" -eq 1 ]; then
echo "[GATE] ShellCheck found warnings or errors. Build blocked." >&2
exit 1
fi
echo "[GATE] All scripts passed ShellCheck."Die SC2086-Familie: Variablenexpansion ohne Anführungszeichen
SC2086 ist der häufigste ShellCheck-Befund und eine der am häufigsten ausgenutzten Sicherheitslücken in Shell-Skripten: Variablenexpansion ohne Anführungszeichen.
Wenn eine Variable nicht in doppelte Anführungszeichen gesetzt wird, führt die Shell auf ihrem Wert eine Wortaufteilung (anhand von IFS) und eine Glob-Erweiterung durch. Ein Angreifer, der die Variable kontrolliert, kann zusätzliche Argumente einschleusen, Dateisystem-Traversal auslösen oder dafür sorgen, dass Befehle unerwartete Operanden erhalten.
Klassisches gefährliches Muster:
#!/usr/bin/env bash
# Attacker sets: FILENAME="important.txt /etc/passwd"
FILENAME="$1"
# UNSAFE — word splitting turns this into two args
rm $FILENAME
# SAFE — double quotes prevent splitting
rm "$FILENAME"
# Arrays are the right tool for lists
FILES=("$@")
rm -- "${FILES[@]}"Risiken durch Command Injection mit SC2046 und SC2035 erkennen
Zwei weniger bekannte, aber wichtige Regeln behandeln die Command Injection über die Ausgabe von Subshells:
SC2046– Setzen Sie dies in Anführungszeichen, um Wortaufteilung und Globbing zu verhindern innerhalb von$(…). Wird die Ausgabe einer Subshell ohne Anführungszeichen verwendet, wird jedes Leerzeichen und jedes Glob-Zeichen in der Ausgabe zu einem Shell-Token.SC2035– Verwenden Sie./*.shstatt*.sh, damit Dateinamen, die mit-beginnen, nicht als Optionen interpretiert werden (ein klassischer Vektor für Argument-Injection).
Konkretes Ausnutzungsszenario und Behebung:
#!/usr/bin/env bash
# SC2046 example — output of find fed unquoted to chmod
# If a filename contains spaces, extra arguments appear
# UNSAFE
chmod 600 $(find /secrets -name '*.key')
# SAFE — use a while-read loop or xargs with -0
find /secrets -name '*.key' -print0 \
| xargs -0 chmod 600
# SC2035 example
# UNSAFE — a file named '-rf' would be passed as an option
rm *.sh
# SAFE
rm -- ./*.shDas JSON-Ausgabeformat für Automatisierung verwenden
ShellCheck unterstützt über --format mehrere Ausgabeformate:
tty(Standard) – für Menschen lesbare Terminalausgabejson– maschinenlesbar; ideal für Dashboards, benutzerdefinierte Blockierregeln oder den Upload auf SAST-Plattformengcc– kompatibel mit Tools, die das GCC-Fehlerformat verarbeiten (IDEs, Vim/Emacs)checkstyle– XML-Format für das Jenkins-Checkstyle-Plugin
Mit dem JSON-Format können Sie automatisierte Richtlinien erstellen, beispielsweise nur bei bestimmten SC-Codes zu blockieren oder Befunde aus einer großen Codebasis in einem Sicherheitsbericht zusammenzufassen.
#!/usr/bin/env bash
# Emit JSON and filter for only error-severity findings using jq
shellcheck --format=json scripts/deploy.sh \
| jq '[.[] | select(.level == "error")]'
# Count distinct SC codes across all scripts
find . -name '*.sh' -print0 \
| xargs -0 shellcheck --format=json 2>/dev/null \
| jq '[.[] | .code] | group_by(.) | map({code: .[0], count: length}) | sort_by(-.count)'Falsch positive Befunde korrekt unterdrücken
Eine pauschale Deaktivierung von ShellCheck verfehlt seinen Zweck. Der richtige Ansatz ist eine gezielte, dokumentierte Unterdrückung, die nur die genaue Zeile oder den Block betrifft, für den der Befund tatsächlich nicht zutrifft.
Drei Mechanismen zur Unterdrückung:
- Inline-Deaktivierung –
# shellcheck disable=SC2086in der Zeile über dem fehlerhaften Code. Betrifft nur diese Zeile. - Blockweise deaktivieren/aktivieren – umschließen Sie einen Abschnitt mit
# shellcheck disable=…und# shellcheck enable=…. - Direktive auf Dateiebene – platzieren Sie
# shellcheck disable=…am Anfang der Datei (nur selten gerechtfertigt; dokumentieren Sie den Grund).
Jede Unterdrückung muss einen Kommentar enthalten, der erklärt, warum der Befund falsch positiv ist:
#!/usr/bin/env bash
# deploy.sh
# Legitimate suppression: $DEPLOY_ARGS is intentionally word-split
# because it is a pre-validated list of flags from a trusted config file.
# shellcheck disable=SC2086
exec deploy-tool $DEPLOY_ARGS
# Block suppression for a section that generates dynamic code
# shellcheck disable=SC2016
VARS='$HOME $PATH $USER'
echo "Unexpanded vars: $VARS"
# shellcheck enable=SC2016ShellCheck über .shellcheckrc konfigurieren
Für projektweite Einstellungen liest ShellCheck die Datei .shellcheckrc ausgehend vom Verzeichnis des Skripts bis hinauf nach /. So müssen Sie die Optionen nicht bei jedem Aufruf wiederholen, und Ihre Prüfskripte bleiben übersichtlich.
Nützliche Direktiven in .shellcheckrc:
shell=bash– überschreibt die Erkennung des Dialekts (nützlich für Dateien ohne Shebang)enable=all– aktiviert optionale Prüfungen (z. B.avoid-nullary-conditions,require-variable-braces)disable=SC2059– projektweite Unterdrückung für eine begründete Ausnahmeexternal-sources=true– folgtsource- bzw..-Direktiven und prüft die eingebundenen Dateien
# .shellcheckrc — project root
shell=bash
enable=all
external-sources=true
# SC2312: consider invoking this command separately to avoid masking its
# return value — suppressed project-wide because we use set -e.
# Rationale: errexit already aborts on failure; masking risk is mitigated.
disable=SC2312Gehärtetes Skript von Anfang bis Ende: vorher und nachher
ShellCheck-Befunde lassen sich am besten verinnerlichen, indem Sie ein realistisches Skript von einem fehlerhaften Zustand zu einer sauberen, gehärteten Version umarbeiten. Das folgende Skript erstellt eine Sicherungskopie eines Verzeichnisses und wurde ohne Sicherheitsaspekte geschrieben. Es verletzt mindestens fünf verschiedene Regeln von ShellCheck.
Untersuchen Sie beide Versionen. Die nachher-Version besteht shellcheck --severity=warning ohne Unterdrückungsdirektiven und ist bei von Angreifern kontrollierten Eingaben deutlich sicherer:
#!/usr/bin/env bash
# BEFORE — multiple ShellCheck violations
DEST=$1
SRC=$2
DATE=`date +%Y%m%d`
if [ ! -d $DEST ]; then
mkdir $DEST
fi
cp -r $SRC $DEST/$DATE
echo Done
#!/usr/bin/env bash
# AFTER — ShellCheck-clean and hardened
set -euo pipefail
DEST="${1:?Usage: backup.sh <dest> <src>}"
SRC="${2:?Usage: backup.sh <dest> <src>}"
DATE=$(date +%Y%m%d)
if [ ! -d "$DEST" ]; then
mkdir -p -- "$DEST"
fi
cp -r -- "$SRC" "$DEST/$DATE"
echo 'Done' >&2Wissenscheck: ShellCheck als Sicherheitsprüfung
Testen Sie Ihr Verständnis der Rolle von ShellCheck als Sicherheitsprüfung.
Zusammenfassung: Statische Analyse als Sicherheitsprüfung
In dieser Lektion haben Sie gelernt, wie Sie ShellCheck zu einer verbindlichen Sicherheitsprüfung in Ihrem Bash-Workflow machen:
- ShellCheck führt eine statische Analyse durch, ohne Ihre Skripte auszuführen, und erkennt Anführungsfehler, Injection-Risiken und unsichere Muster vor der Laufzeit.
- Jeder Befund enthält einen SC-Code (z. B.
SC2086), der mit ausführlicher Dokumentation und Hinweisen zur Behebung verknüpft ist. - Die Schweregradabstufung –
error,warning,info,style– ermöglicht die Abstimmung der Prüfung:--severity=warningist die empfohlene Sicherheitsschwelle. - Verwenden Sie maschinenlesbare Ausgabe (
--format=json), um Berichte, Trendanalysen und die SAST-Integration zu automatisieren. - Unterdrückungen sparsam einsetzen: immer auf eine einzelne Zeile begrenzen, den Grund stets in einem Kommentar dokumentieren und niemals global unterdrücken, außer wenn dies durch
.shellcheckrcbegründet ist. - Kombinieren Sie ShellCheck mit
set -euo pipefail, expliziten Anführungszeichen,-- argument-Abschlüssen und Eingabevalidierung für eine mehrschichtige Verteidigung.
Ein Skript, das ShellCheck besteht, ist nicht automatisch sicher – ein Skript, das ShellCheck nicht besteht, sollte jedoch niemals in die Produktion gelangen.
Häufig gestellte Fragen
Ist die Lektion „Statische Analyse und Prüfung mit ShellCheck“ kostenlos?
Ja — der vollständige Text von „Statische Analyse und Prüfung mit ShellCheck“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Statische Analyse und Prüfung mit ShellCheck“?
Integrieren Sie ShellCheck als Sicherheits-Gate und interpretieren Sie seine Befunde, um jedes Skript abzusichern. Du übst Linux Command Line & Bash Scripting Mastery mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Linux Command Line & Bash Scripting Mastery zu starten?
Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Statische Analyse und Prüfung mit ShellCheck“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?
Ja. Jede Linux Command Line & Bash Scripting Mastery-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Command- und Argument-Injection verhindern
- Sichere Geheimnisverwaltung und saubere Umgebungen
- Ausführung mit geringsten Berechtigungen und sudo-Disziplin
- Statische Analyse und Prüfung mit ShellCheck