Mestring av Linux-kommandolinjen og Bash-skripting · leksjon

Statisk analyse og revisjon med ShellCheck

Integrer ShellCheck i en sikkerhetskontroll, og tolk funnene for å sikre hvert skript bedre.

Leksjon 4 av 413 trinn

Statisk analyse og revisjon med ShellCheck er en gratis leksjon i Mestring av Linux-kommandolinjen og Bash-skripting på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Mestring av Linux-kommandolinjen og Bash-skripting, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Mestring av Linux-kommandolinjen og Bash-skripting inneholder totalt 4 leksjoner.

Hva er ShellCheck, og hvorfor er det viktig

ShellCheck er et åpen kildekode-verktøy for statisk analyse av shell-skript. Det analyserer Bash-kildekode (samt POSIX sh, dash og ksh) uten å kjøre den, og rapporterer feil, usikre konstruksjoner, portabilitetsproblemer og stilproblemer – hvert funn er merket med en unik regelkode, for eksempel SC2086.

I en sikkerhetsherdet prosess fungerer ShellCheck som en obligatorisk kontroll: Ingen skript leveres før de består kontrollen. Dette er viktig fordi:

  • Mange sårbarheter i shell (orddeling, injeksjon og anførselstegn rundt utvidelser som mangler) er usynlige ved testing av normale tilfeller, men utløses av angriperkontrollerte inndata.
  • ShellCheck oppdager disse feiltypene før kjøring, uten kostnad.
  • Det dokumenterer hvorfor hvert mønster er farlig, slik at teamet gradvis blir mer bevisst.

Installer det på et hvilket som helst 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 --version

Kjøre ShellCheck for første gang

Den enkleste måten å starte på er shellcheck <script>. ShellCheck leser shebang-linjen for å finne shell-dialekten og skriver deretter funnene til stdout.

Hvert funn inneholder:

  • Fil- og linjenummer – nøyaktig plassering
  • Alvorlighetsgrad – error, warning, info eller style
  • SC-kode – en stabil regelidentifikator som De kan slå opp eller undertrykke
  • Forklaring i klartekst – forteller hva som er galt, og ofte hvordan det kan rettes

Kjør skriptet nedenfor og se hvilken utdata ShellCheck ville produsert:

#!/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 -l

Tolke ShellCheck-utdata og SC-koder

For skriptet i forrige scene ville ShellCheck rapportert funn som:

  • SC2086 (warning) – Double quote to prevent globbing and word splitting – for $FILE i [ $FILE == '' ] og i cat $FILE.
  • SC2039 / SC3010 (info) – == in [ ] is a bashism; use = for POSIX.
  • SC2002 (style) – Useless cat. Consider cmd < file instead of cat file | cmd.

Hver SC-kode viser til en wikiside på https://www.shellcheck.net/wiki/SCxxxx med begrunnelse og et korrigert eksempel.

Den korrigerte versjonen av skriptet:

#!/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"

Alvorlighetsgrader og hva De bør gjøre noe med

ShellCheck klassifiserer hvert funn etter alvorlighetsgrad. I en sikkerhetskontroll bør De behandle dem slik:

  • error – Nesten sikkert en feil eller et sikkerhetshull. Stans byggingen. Rett det umiddelbart. Eksempel: SC2148 manglende shebang, SC2070 $? uten anførselstegn.
  • warning – Et høyrisikomønster som ofte kan utnyttes. Stans byggingen. Rett det, eller begrunn uttrykkelig hvorfor funnet undertrykkes. Eksempel: SC2086 variabel uten anførselstegn.
  • info – Sannsynligvis korrekt i dag, men skjørt eller ikke-portabelt. Rett det i samme PR, med mindre det uttrykkelig er utenfor omfanget.
  • style – Kosmetikk eller POSIX-preferanse. Anbefalt, men valgfritt i en ren Bash-kodebase.

Bruk --severity=warning for å avslutte med en feilkode bare ved advarsler eller høyere alvorlighetsgrad – standardterskelen for sikkerhetskontrollen:

#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"

Integrere ShellCheck som en sikkerhetskontroll i CI

En sikkerhetskontroll er bare nyttig når den er obligatorisk og automatisert. Mønsteret nedenfor pakker ShellCheck inn i et CI-trinn som:

  • Finner alle .sh-filer i repositoriet.
  • Kjører ShellCheck med --severity=warning og maskinlesbar JSON-utdata.
  • Får pipelinen til å feile (exit 1) hvis det finnes et funn.
  • Skriver ut et sammendrag, slik at utviklere kan håndtere funnene uten å forlate CI-loggen.

Legg denne filen i repositoriet og kall den fra CI-pipelinen (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: Variabelutvidelser uten anførselstegn

SC2086 er det vanligste ShellCheck-funnet og en av de mest utnyttede sårbarhetene i shell: variabelutvidelser uten anførselstegn.

Når en variabel ikke står i doble anførselstegn, utfører skallet orddeling (deler ved IFS) og jokertegnutvidelse av verdien. En angriper som kontrollerer variabelen, kan injisere ekstra argumenter, utløse katalogkryssing eller få kommandoer til å motta uventede operander.

Klassisk farlig 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[@]}"

Oppdage risiko for kommandoinjeksjon med SC2046 og SC2035

To mindre kjente, men kritiske regler gjelder kommandoinjeksjon via utdata fra underskall:

  • SC2046 – Quote this to prevent word splitting / glob i $(…). Hvis utdata fra et underskall brukes uten anførselstegn, blir alle mellomrom eller jokertegn i utdataene til shell-tokener.
  • SC2035 – Use ./*.sh instead of *.sh for å unngå at filnavn som begynner med -, tolkes som alternativer (en klassisk vektor for argumentinjeksjon).

Konkret scenario for utnyttelse 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 -- ./*.sh

Bruke JSON-utdataformatet til automatisering

ShellCheck støtter flere utdataformater via --format:

  • tty (standard) – terminalutdata som er lesbare for mennesker
  • json – maskinlesbart; ideelt for dashbord, tilpassede blokkeringer eller opplasting til SAST-plattformer
  • gcc – kompatibelt med verktøy som analyserer GCC-feilformatet (IDE-er, Vim/Emacs)
  • checkstyle – XML-format som brukes av Jenkins Checkstyle-plugin

JSON-formatet lar Dem skrive automatiserte regler, for eksempel blokkere bare ved bestemte SC-koder eller samle funn fra en stor kodebase i en sikkerhetsrapport.

#!/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)'

Undertrykke falske positiver på riktig måte

En generell deaktivering av ShellCheck undergraver hensikten med verktøyet. Den riktige tilnærmingen er en målrettet og dokumentert undertrykking som bare påvirker den nøyaktige linjen eller blokken der funnet faktisk ikke gjelder.

Tre mekanismer for undertrykking:

  • Deaktivering på én linje – # shellcheck disable=SC2086 på linjen over den aktuelle koden. Gjelder bare den linjen.
  • Deaktivering/aktivering av blokk – omslutt en del med # shellcheck disable=… og # shellcheck enable=….
  • Direktiv på filnivå – plasser # shellcheck disable=… øverst i filen (sjelden berettiget; dokumenter hvorfor).

Hver undertrykking må ha en kommentar som forklarer hvorfor funnet 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=SC2016

Konfigurere ShellCheck via .shellcheckrc

For innstillinger som gjelder hele prosjektet leser ShellCheck .shellcheckrc fra skriptets katalog og oppover til /. Dette gjør at De slipper å gjenta flagg ved hvert kall, og holder kontrollskriptene enkle.

Nyttige direktiver i .shellcheckrc:

  • shell=bash – overstyr dialektgjenkjenningen (nyttig for filer uten shebang)
  • enable=all – aktiver valgfrie kontroller (for eksempel avoid-nullary-conditions, require-variable-braces)
  • disable=SC2059 – prosjektomfattende undertrykking for et begrunnet unntak
  • external-sources=true – følg og kontroller source- 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=SC2312

Herdet skript fra start til slutt: før og etter

Den mest effektive måten å få grep om ShellCheck-funn på er å refaktorere et realistisk skript fra en tilstand som feiler, til et rent og herdet skript. Skriptet nedenfor sikkerhetskopierer en katalog og ble skrevet uten sikkerhet i tankene. Det feiler i ShellCheck på minst fem ulike regler.

Studer begge versjonene. Etter-versjonen består shellcheck --severity=warning uten undertrykkingsdirektiver og er betydelig sikrere ved angriperkontrollerte inndata:

#!/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' >&2

Kunnskapssjekk: ShellCheck som sikkerhetskontroll

Test forståelsen Deres av ShellChecks rolle som sikkerhetskontroll.

Oppsummering: Statisk analyse som sikkerhetskontroll

I denne leksjonen har De lært hvordan De gjør ShellCheck til en obligatorisk sikkerhetskontroll i Bash-arbeidsflyten:

  • ShellCheck utfører statisk analyse uten å kjøre skriptene, og oppdager siteringsfeil, injeksjonsrisiko og usikre mønstre før kjøring.
  • Hvert funn har en SC-kode (for eksempel SC2086) med lenke til detaljert dokumentasjon og veiledning for retting.
  • Alvorlighetsstigen – error, warning, info, style – lar Dem kalibrere kontrollen: --severity=warning er den anbefalte sikkerhetsterskelen.
  • Bruk maskinlesbare utdata (--format=json) til å automatisere rapportering, følge utviklingen over tid og integrere med SAST.
  • Undertrykk sparsomt: målrett alltid én enkelt linje, dokumenter alltid hvorfor i en kommentar, og undertrykk aldri globalt med mindre det er begrunnet i .shellcheckrc.
  • Kombiner ShellCheck med set -euo pipefail, eksplisitt bruk av anførselstegn, -- argument-avslutning og validering av inndata for et forsvar i dybden.

Et skript som består ShellCheck, er ikke automatisk sikkert – men et skript som ikke består ShellCheck, bør aldri nå produksjon.

Gratis å komme i gang

Lær deg Bash med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
22
Leksjoner
88

Ofte stilte spørsmål

Er leksjonen «Statisk analyse og revisjon med ShellCheck» gratis?

Ja – hele teksten i «Statisk analyse og revisjon med ShellCheck» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Mestring av Linux-kommandolinjen og Bash-skripting-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Mestring av Linux-kommandolinjen og Bash-skripting inneholder totalt 4 leksjoner.

Hva lærer jeg i «Statisk analyse og revisjon med ShellCheck»?

Integrer ShellCheck i en sikkerhetskontroll, og tolk funnene for å sikre hvert skript bedre. Du øver på Mestring av Linux-kommandolinjen og Bash-skripting med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Mestring av Linux-kommandolinjen og Bash-skripting?

Ingen tidligere erfaring er nødvendig. Mestring av Linux-kommandolinjen og Bash-skripting på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Statisk analyse og revisjon med ShellCheck»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Mestring av Linux-kommandolinjen og Bash-skripting-leksjonen?

Ja. Alle Mestring av Linux-kommandolinjen og Bash-skripting-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Forebygging av kommando- og argumentinjisering
  2. Sikker håndtering av hemmeligheter og ryddige miljøer
  3. Kjøring med minste privilegium og sudo-disiplin
  4. Statisk analyse og revisjon med ShellCheck
← Tilbake til Mestring av Linux-kommandolinjen og Bash-skripting