Statisk analyse og audit med ShellCheck
Integrér ShellCheck i en sikkerhedsgate, og fortolk resultaterne for at sikre hvert script bedre.
Statisk analyse og audit med ShellCheck er en gratis Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Linux-kommandolinjen og Bash-scripting på ekspertniveau, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset indeholder 4 lektioner i alt.
Hvad er ShellCheck, og hvorfor er det vigtigt
ShellCheck er et open source-værktøj til statisk analyse af shell-scripts. Det fortolker din Bash-kildekode (samt POSIX sh, dash og ksh) uden at køre den og rapporterer fejl, usikre konstruktioner, problemer med portabilitet og stilproblemer – hver med en unik regelkode som SC2086.
I en sikkerhedshærdet pipeline fungerer ShellCheck som en obligatorisk kontrol: Intet script leveres, før det er godkendt. Det er vigtigt, fordi:
- Mange shell-sårbarheder (ordopdeling, injektion og anførselstegnsløs ekspansion) er usynlige under test af den normale situation, men udløses ved input, som en angriber kontrollerer.
- ShellCheck fanger disse fejltyper før kørsel uden ekstra omkostninger.
- Det dokumenterer hvorfor hvert mønster er farligt, så dit team gradvist bliver mere opmærksomt.
Installér det på ethvert 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 --versionKørsel af ShellCheck for første gang
Det enkleste kald er shellcheck <script>. ShellCheck læser shebang-linjen for at bestemme shell-dialekten og skriver derefter resultaterne til stdout.
Hvert resultat indeholder:
- Fil og linjenummer – præcis placering
- Alvorlighedsgrad –
error,warning,infoellerstyle - SC-kode – stabil regelidentifikator, som du kan slå op eller undertrykke
- Forklaring i almindeligt sprog – fortæller dig hvad der er galt, og ofte hvordan du løser det
Kør scriptet nedenfor, og se det output, ShellCheck ville producere:
#!/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 -lFortolkning af ShellCheck-output og SC-koder
For scriptet fra den foregående scene ville ShellCheck skrive resultater som:
SC2086(warning) – Sæt dette i dobbelte anførselstegn for at forhindre globbing og ordopdeling – på$FILEi[ $FILE == '' ]og icat $FILE.SC2039/SC3010(info) – == i [ ] er en Bash-specifik konstruktion; brug = til POSIX.SC2002(style) – Overflødigt cat. Overvej cmd < file i stedet for cat file | cmd.
Hver SC-kode henviser til en wikiside på https://www.shellcheck.net/wiki/SCxxxx med begrundelse og et korrigeret eksempel.
Den korrigerede version af scriptet:
#!/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"Alvorlighedsgrader, og hvad du skal reagere på
ShellCheck klassificerer hvert resultat efter alvorlighedsgrad. I en sikkerhedskontrol bør du behandle dem sådan:
- error – Næsten med sikkerhed en fejl eller sikkerhedsbrist. Blokér bygningen. Ret det straks. Eksempel:
SC2148manglende shebang,SC2070anførselstegnsløs$?. - warning – Mønster med høj risiko, som ofte kan udnyttes. Blokér bygningen. Ret det, eller begrund udtrykkeligt, hvorfor det undertrykkes. Eksempel:
SC2086variabel uden anførselstegn. - info – Sandsynligvis korrekt i dag, men skrøbeligt eller ikke-portabelt. Ret det i den samme PR, medmindre det udtrykkeligt er uden for omfanget.
- style – Kosmetisk anbefaling eller POSIX-præference. Anbefales, men er valgfrit i en ren Bash-kodebase.
Brug --severity=warning for kun at afslutte med en fejlkode ved advarsler og højere alvorlighedsgrader – den almindelige tærskel for en sikkerhedskontrol:
#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"Integration af ShellCheck som sikkerhedskontrol i CI
En sikkerhedskontrol er kun nyttig, når den er obligatorisk og automatiseret. Mønsteret nedenfor indlejrer ShellCheck i et CI-trin, der:
- Finder alle
.sh-filer i lageret. - Kører ShellCheck med
--severity=warningog maskinlæsbar JSON-output. - Fejler pipelinen (
exit 1), hvis der findes et resultat. - Udskriver en opsummering, så udviklere kan reagere på resultaterne uden at forlade CI-loggen.
Læg denne fil i dit repository, og kald den fra din CI-pipeline (GitHub Actions, Jenkins, GitLab CI osv.):
#!/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."SC2086-familien: Anførselstegnsløse variabelekspansioner
SC2086 er det mest almindelige ShellCheck-resultat og en af de mest udnyttede shell-sårbarheder: variabelekspansioner uden anførselstegn.
Når en variabel ikke står i dobbelte anførselstegn, udfører shellen ordopdeling (opdeling ved IFS) og glob-ekspansion på dens værdi. En angriber, der kontrollerer variablen, kan indsætte ekstra argumenter, udløse gennemgang af filsystemet eller få kommandoer til at modtage uventede operander.
Klassisk farligt mønster:
#!/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[@]}"Registrering af risiko for kommandoinjektion med SC2046 og SC2035
To mindre kendte, men kritiske regler håndterer kommandoinjektion via output fra subshells:
SC2046– Sæt dette i anførselstegn for at forhindre ordopdeling eller glob inde i$(…). Hvis outputtet fra en subshell bruges uden anførselstegn, bliver mellemrum eller glob-tegn i outputtet til et shell-token.SC2035– Brug./*.shi stedet for*.shfor at undgå, at filnavne, der begynder med-, fortolkes som indstillinger (en klassisk vektor for argumentinjektion).
Konkret udnyttelsesscenarie og løsning:
#!/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 -- ./*.shBrug af JSON-outputformatet til automatisering
ShellCheck understøtter flere outputformater via --format:
tty(standard) – terminaloutput, der kan læses af menneskerjson– maskinlæsbar; ideel til dashboards, brugerdefinerede blokeringer eller upload til SAST-platformegcc– kompatibelt med værktøjer, der fortolker GCC-fejlformatet (IDE'er, Vim/Emacs)checkstyle– XML-format, der bruges af Jenkins Checkstyle-pluginet
JSON-formatet giver dig mulighed for at skrive automatiserede politikker, for eksempel kun at blokere ved bestemte SC-koder eller samle resultater fra en stor kodebase i en sikkerhedsrapport.
#!/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)'Korrekt undertrykkelse af falske positiver
En omfattende deaktivering af ShellCheck modarbejder formålet med værktøjet. Den korrekte tilgang er en målrettet, dokumenteret undertrykkelse, der kun påvirker den nøjagtige linje eller blok, hvor resultatet reelt ikke er relevant.
Tre mekanismer til undertrykkelse:
- Deaktivering på linjen –
# shellcheck disable=SC2086på linjen over den problematiske kode. Påvirker kun den linje. - Deaktivering/aktivering af blok – omslut en sektion med
# shellcheck disable=…og# shellcheck enable=…. - Direktiv på filniveau – placér
# shellcheck disable=…øverst i filen (sjældent berettiget; dokumentér hvorfor).
Enhver undertrykkelse skal indeholde en kommentar, der forklarer, hvorfor resultatet er en falsk positiv:
#!/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=SC2016Konfiguration af ShellCheck via .shellcheckrc
For indstillinger, der gælder for hele projektet, læser ShellCheck .shellcheckrc fra scriptets mappe og op gennem mappestrukturen til /. Det betyder, at du ikke behøver gentage indstillinger ved hvert kald, og at kontrolscripts holdes enkle.
Nyttige direktiver i .shellcheckrc:
shell=bash– tilsidesæt registreringen af dialekten (nyttigt for filer uden shebangs)enable=all– aktivér valgfrie kontroller (f.eks.avoid-nullary-conditions,require-variable-braces)disable=SC2059– projektdækkende undertrykkelse af en begrundet undtagelseexternal-sources=true– følg og kontrollérsource- og.-direktiver
# .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=SC2312Hærdet script fra start til slut: før og efter
Den mest effektive måde at få ShellCheck-resultater ind under huden på er at omstrukturere et realistisk script fra en tilstand med fejl til et rent og hærdet script. Scriptet nedenfor sikkerhedskopierer en mappe og blev skrevet uden sikkerhed for øje. Det fejler i ShellCheck på mindst fem forskellige regler.
Studér begge versioner. Versionen efter består shellcheck --severity=warning uden direktiver til undertrykkelse og er betydeligt sikrere ved input, som en angriber kontrollerer:
#!/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' >&2Videnstjek: ShellCheck som sikkerhedskontrol
Test din forståelse af ShellChecks rolle som sikkerhedskontrol.
Opsummering: Statisk analyse som sikkerhedskontrol
I denne lektion har du lært at gøre ShellCheck til en obligatorisk sikkerhedskontrol i din Bash-arbejdsgang:
- ShellCheck udfører statisk analyse uden at køre dine scripts og fanger citeringsfejl, injektionsrisici og usikre mønstre før kørsel.
- Hvert resultat har en SC-kode (f.eks.
SC2086), der linker til detaljeret dokumentation og vejledning i, hvordan problemet løses. - Alvorlighedstrinnene –
error,warning,info,style– giver dig mulighed for at tilpasse kontrollen:--severity=warninger den anbefalede sikkerhedstærskel. - Brug maskinlæsbar output (
--format=json) til at automatisere rapportering, følge udviklingen og integrere SAST. - Undertryk sparsomt: målret altid en enkelt linje, dokumentér altid hvorfor i en kommentar, og undertryk aldrig globalt, medmindre det er begrundet i
.shellcheckrc. - Kombinér ShellCheck med
set -euo pipefail, eksplicitte anførselstegn,-- argument-afslutninger og inputvalidering for et forsvar i dybden.
Et script, der består ShellCheck, er ikke automatisk sikkert – men et script, der fejler i ShellCheck, bør aldrig nå produktionen.
Lær Bash med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 22
- Lektioner
- 88
Ofte stillede spørgsmål
Er lektionen “Statisk analyse og audit med ShellCheck” gratis?
Ja — hele teksten til “Statisk analyse og audit med ShellCheck” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset, skal du opgradere til CoddyKit PRO. Linux-kommandolinjen og Bash-scripting på ekspertniveau-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Statisk analyse og audit med ShellCheck”?
Integrér ShellCheck i en sikkerhedsgate, og fortolk resultaterne for at sikre hvert script bedre. Du øver dig i Linux-kommandolinjen og Bash-scripting på ekspertniveau med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Linux-kommandolinjen og Bash-scripting på ekspertniveau?
Der kræves ingen tidligere erfaring. Linux-kommandolinjen og Bash-scripting på ekspertniveau på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.
Hvor lang tid tager lektionen “Statisk analyse og audit med ShellCheck”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektion?
Ja. Alle Linux-kommandolinjen og Bash-scripting på ekspertniveau-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Forebyggelse af kommando- og argumentinjektion
- Sikker håndtering af hemmeligheder og rent miljø
- Kørsel med færrest mulige rettigheder og disciplineret brug af sudo
- Statisk analyse og audit med ShellCheck