DevOps-bootcamp · Les

Strikte modus met set -euo pipefail

Schakel fail-fastgedrag in en begrijp precies welke fouten elke vlag van de strikte modus wel en niet opvangt.

Les 1 van 413 stappen

Strikte modus met set -euo pipefail is een gratis DevOps-bootcamp-les op CoddyKit. Dit is les 1 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject DevOps-bootcamp. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus DevOps-bootcamp bevat in totaal 4 lessen.

Waarom Bash standaard stilletjes faalt

Standaard blijft Bash doorgaan, zelfs wanneer opdrachten mislukken. Dat leidt in productiescripts tot subtiele rampen die moeilijk te debuggen zijn.

Neem dit script dat een back-up probeert te maken:

  • Een typefout in een pad zorgt ervoor dat cp mislukt
  • Bash negeert de fout en gaat door
  • Het script meldt succes, hoewel er nooit een back-up van de gegevens is gemaakt

Dit is het probleem van stil falen. De strikte modus lost dit op door Bash zich als een gecompileerde taal te laten gedragen: stop onmiddellijk wanneer er iets misgaat.

#!/usr/bin/env bash
# Without strict mode — dangerous default behavior

cp /important/data /backups/data   # fails (path doesn't exist)
echo "Backup complete"              # still prints — false confidence!
rm -rf /tmp/staging                # still runs — potentially destructive

De drie belangrijkste vlaggen: set -euo pipefail

Je schakelt de strikte modus in door deze regel bovenaan elk script te plaatsen:

set -euo pipefail

Hiermee activeer je drie afzonderlijke beveiligingen:

  • -e — Sluit onmiddellijk af als een opdracht een status ongelijk aan nul retourneert
  • -u — Behandel niet-ingestelde variabelen als een fout (in plaats van ze uit te breiden naar een lege tekenreeks)
  • -o pipefail — Een pijplijn mislukt als een willekeurige opdracht erin mislukt, niet alleen de laatste

Samen vormen ze de standaard defensieve kop voor serieuze Bash-scripts. Elke vlag vangt een ander type bug op.

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

echo "Strict mode is now active"
echo "Every command failure will abort the script"

set -e (errexit) begrijpen

set -e (ook geschreven als set -o errexit) zorgt ervoor dat het script onmiddellijk afsluit wanneer een opdracht eindigt met een status ongelijk aan nul.

Belangrijk gedrag:

  • Eenvoudige opdrachten: false, grep pattern file (geen overeenkomst) en ls /nonexistent zorgen allemaal voor afsluiten
  • De afsluitcode van de laatste opdracht in het script wordt de afsluitcode van het script
  • Opdrachten in if-voorwaarden zijn uitgesloten — -e wordt niet geactiveerd voor de testexpressie
  • Opdrachten gevolgd door || true zijn eveneens uitgesloten (zie de volgende scènes)

Zie -e als je eerste verdedigingslinie tegen stil doorgaan na een fout.

#!/usr/bin/env bash
set -e

echo "Before failure"
ls /this/path/does/not/exist   # exits here with code 2
echo "This line never runs"

set -u (nounset) begrijpen

set -u (ook geschreven als set -o nounset) zorgt ervoor dat Bash elke verwijzing naar een niet-ingestelde variabele als een fatale fout behandelt.

Zonder -u wordt een typefout zoals $FLENAME in plaats van $FILENAME stilletjes uitgebreid naar een lege tekenreeks. Daardoor gedragen opdrachten zich onverwacht — of gevaarlijk (denk aan rm -rf "$TMPDIR/" wanneer $TMPDIR niet is ingesteld).

Belangrijke uitzonderingen:

  • ${VAR:-default} — veilige vervanging door een standaardwaarde, activeert -u niet
  • ${VAR:+value} — voorwaardelijke uitbreiding, eveneens veilig
  • "$@" en "$*" zijn vrijgesteld wanneer er geen positionele argumenten zijn doorgegeven
#!/usr/bin/env bash
set -euo pipefail

# Safe: provide a default for optional vars
OUTPUT_DIR="${1:-/tmp/output}"
LOG_LEVEL="${LOG_LEVEL:-info}"

echo "Writing to: $OUTPUT_DIR"
echo "Log level: $LOG_LEVEL"

# This would abort the script:
# echo "$UNDEFINED_VAR"   # bash: UNDEFINED_VAR: unbound variable

-o pipefail begrijpen

Zonder pipefail wordt de afsl status van een pijplijn uitsluitend bepaald door de laatste opdracht. Eerdere fouten worden stilletjes genegeerd.

Voorbeeld zonder pipefail:

  • cat /missing/file | wc -l
  • cat mislukt met afsluitcode 1, maar wc -l slaagt met code 0
  • De pijplijn retourneert 0 — succes! Hoewel er gegevens verloren zijn gegaan.

Wanneer pipefail is ingeschakeld, retourneert Bash de afsluitcode van de meest rechtse opdracht die is mislukt. Daardoor worden fouten in pijplijnen zichtbaar en kunnen ze worden afgehandeld.

Let op: pipefail is geen lettervlag — deze moet worden ingesteld met -o pipefail.

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

# With pipefail: this aborts if grep finds nothing (exit 1)
# grep returns 1 when no match found
ps aux | grep "[n]ginx" | awk '{print $2}'

echo "If we reach here, nginx is running"

Opzettelijk mislukte opdrachten — || true gebruiken

Soms mag een opdracht mislukken. Met set -e moet je expliciet aangeven welke fouten zijn toegestaan; anders wordt het script afgebroken.

De gebruikelijke oplossing is || true, waarmee je een terugval toevoegt die altijd slaagt:

  • command || true — de fout volledig negeren
  • command || echo "Warning: step failed, continuing" — de fout vastleggen en doorgaan
  • command || { echo "fatal"; exit 1; } — aangepaste foutafhandeling

Dit patroon maakt je bedoeling expliciet in de code: een gewone opdracht betekent "dit moet slagen"; || true betekent "dit mag mislukken en dat is geen probleem".

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

# Remove temp dir if it exists — OK if it doesn't
rm -rf /tmp/my_workspace || true
mkdir -p /tmp/my_workspace

# Check if a service is running — OK if not
if systemctl is-active --quiet nginx 2>/dev/null || true; then
  echo "nginx is active"
fi

# Grep that may find nothing — OK
grep 'ERROR' /var/log/app.log || true

echo "Done"

Wat set -e NIET opvangt

set -e heeft bekende uitzonderingen en valkuilen. Als je die begrijpt, voorkom je een vals gevoel van zekerheid:

  • Opdrachten in voorwaarden van if / while / until — de testexpressie is bewust vrijgesteld
  • Opdrachten die met ! worden ontkend — ! false zorgt niet voor afsluiten
  • De laatste opdracht vóór || — bijvoorbeeld false || handle_error
  • De afsluitstatus van subshells in bepaalde contexten — bijvoorbeeld VAR=$(failing_command) in sommige Bash-versies
  • Retourwaarden van functies — alleen de laatste opdracht in een functie telt

De strikte modus vervangt geen expliciete foutcontroles — het is een vangnet dat de meeste onbedoelde fouten opvangt.

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

# These do NOT trigger -e:
if false; then echo "never"; fi         # -e exempt in conditions
! false                                  # negation exempts
false || echo "handled"                 # || exempts the left side

# This DOES trigger -e (no condition, no ||):
# false

echo "Script continues after exempted failures"

Subshells en functies met de strikte modus

Instellingen van de strikte modus worden overgenomen door subshells, maar gedragen zich subtiel in functies en opdrachtvervangingen.

Belangrijkste regels:

  • Functies nemen -e, -u en pipefail over van de aanroepende shell
  • Een retourwaarde ongelijk aan nul van een functie zorgt ervoor dat de aanroeper afsluit (wanneer -e is ingesteld) — tenzij de aanroep in een voorwaarde staat of na || komt
  • Opdrachtvervanging $(): in oudere Bash-versies activeert een mislukte opdracht binnen $() mogelijk niet -e in de bovenliggende shell; wijs de waarde toe en gebruik deze daarna afzonderlijk om veilig te zijn
  • Expliciete subshells () nemen alle vlaggen over
#!/usr/bin/env bash
set -euo pipefail

setup_workspace() {
  local dir="$1"
  mkdir -p "$dir"          # fails here if permissions denied
  cd "$dir"
  echo "Ready in $(pwd)"
}

# Safe pattern: assign result then use it
TODAY=$(date +%Y-%m-%d)   # capture separately
WORKDIR="/tmp/run_${TODAY}"

setup_workspace "$WORKDIR"
echo "Workspace: $WORKDIR"

De strikte modus combineren met fouttraps

De strikte modus vertelt Bash wanneer het moet stoppen. Met een trap op ERR kun je voordat het script afsluit opruimacties of diagnostiek uitvoeren.

Het gebruikelijke patroon is:

  • Stel de strikte modus bovenaan in
  • Definieer een functie cleanup of on_error
  • Registreer deze met trap 'on_error' ERR
  • Stel eventueel ook een trap in op EXIT voor gegarandeerde opruimacties, ongeacht succes of mislukking

Belangrijk: gebruik set -E (hoofdletter E, ook errtrace genoemd) zodat de ERR-trap ook wordt overgenomen door functies en subshells — zonder deze instelling werken traps alleen in de hoofdtekst van de shell.

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

on_error() {
  local exit_code=$?
  local line_number=${BASH_LINENO[0]}
  echo "ERROR: command failed with code ${exit_code} at line ${line_number}" >&2
}

cleanup() {
  echo "Cleaning up temporary files..." >&2
  rm -rf /tmp/my_run_dir 2>/dev/null || true
}

trap on_error ERR
trap cleanup EXIT

mkdir -p /tmp/my_run_dir
echo "hello" > /tmp/my_run_dir/output.txt
cat /tmp/my_run_dir/output.txt
echo "Done"

De strikte modus lokaal uitschakelen

Soms is een codeblok bewust "rommelig" — bijvoorbeeld wanneer je zoekt naar optionele hulpmiddelen of verouderde opdrachten uitvoert die om niet-foutredenen een waarde ongelijk aan nul retourneren. Je kunt de strikte modus tijdelijk uitschakelen en daarna herstellen.

Het veilige patroon:

  • Sla de toestand op met set +e (schakelt -e uit), voer het blok uit en schakel de modus daarna opnieuw in met set -e
  • Of gebruik een subshell ( set +e; ... ), zodat de vlaggen van de bovenliggende shell nooit worden beïnvloed
  • Schakel de vlaggen altijd weer in zodra het risicovolle blok eindigt — het uitgeschakeld laten van vlaggen is een veelvoorkomende bron van bugs

Geef bij blokken met meerdere opdrachten de voorkeur aan de subshell-vorm, omdat deze de vlaggen bij het afsluiten automatisch herstelt.

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

# Probe for optional tools without aborting
HAS_JQ=false
(
  set +e
  command -v jq > /dev/null 2>&1
  [[ $? -eq 0 ]] && echo "jq_found"
) && HAS_JQ=true || true

if [[ "$HAS_JQ" == "true" ]]; then
  echo "jq is available — using JSON output"
else
  echo "jq not found — using plain text"
fi

Een compleet sjabloon voor een script met strikte modus

Hier is een productieklaar sjabloon waarin alle best practices voor de strikte modus uit deze les samenkomen:

  • set -Eeuo pipefail — alle vier de vlaggen, inclusief errtrace
  • IFS=$'\n\t' — veiliger splitsen van woorden (voorkomt splitsen op spaties)
  • ERR- en EXIT-traps voor diagnostiek en opruimacties
  • Expliciete standaardwaarden voor optionele parameters
  • readonly en local om het bereik van variabelen te beperken

Kopieer dit sjabloon aan het begin van elk niet-triviaal Bash-script om direct te profiteren van gedrag waarbij het script snel stopt en fouten traceerbaar zijn.

#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'

# ── Constants ────────────────────────────────────────────
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"

# ── Trap handlers ────────────────────────────────────────
err_handler() {
  echo "[${SCRIPT_NAME}] ERROR on line ${BASH_LINENO[0]}: exit ${?}" >&2
}
cleanup() {
  echo "[${SCRIPT_NAME}] Exiting" >&2
}
trap err_handler ERR
trap cleanup EXIT

# ── Defaults ─────────────────────────────────────────────
ENV="${1:-production}"
MAX_RETRIES="${MAX_RETRIES:-3}"

# ── Main ─────────────────────────────────────────────────
main() {
  echo "Running in env=${ENV}, max_retries=${MAX_RETRIES}"
  echo "Script dir: ${SCRIPT_DIR}"
}

main "$@"

Kennischeck: gedrag van pipefail

Test je begrip van de invloed van pipefail op de afsluitcodes van pipelines.

Samenvatting: strikte modus met set -euo pipefail

In deze les heb je geleerd hoe je Bash-scripts snel en duidelijk kunt laten falen met de strikte modus.

De drie vlaggen en waartegen ze beschermen:

  • -e (errexit) — stopt bij elke opdrachtstatus die niet nul is; wordt niet toegepast in voorwaarden en na ||
  • -u (nounset) — breekt af bij verwijzingen naar niet-ingestelde variabelen; gebruik ${VAR:-default} voor optionele variabelen
  • -o pipefail — laat een volledige pipeline falen als een willekeurige stap faalt, niet alleen de laatste

Aanvullende werkwijzen:

  • Voeg -E (errtrace) toe zodat ERR-traps worden doorgegeven aan functies
  • Gebruik trap op ERR en EXIT voor diagnostiek en opruimen
  • Gebruik || true om fouten bewust toe te staan
  • Schakel de optie tijdelijk uit met set +e in subshells voor verouderde code of code die iets controleert

De strikte modus is geen wondermiddel — ken de uitzonderingen — maar het is wel de effectiefste gewoonte voor het schrijven van betrouwbare, defensieve Bash-scripts.

Gratis beginnen

Leer DevOps-bootcamp met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
142
Lessen
568

Veelgestelde vragen

Is de les “Strikte modus met set -euo pipefail” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad DevOps-bootcamp, waaronder “Strikte modus met set -euo pipefail”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus DevOps-bootcamp bevat in totaal 4 lessen.

Wat leer ik in “Strikte modus met set -euo pipefail”?

Schakel fail-fastgedrag in en begrijp precies welke fouten elke vlag van de strikte modus wel en niet opvangt. Je oefent met DevOps-bootcamp door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met DevOps-bootcamp te beginnen?

Ervaring vooraf is niet nodig. DevOps-bootcamp op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.

Hoe lang duurt de les “Strikte modus met set -euo pipefail”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over DevOps-bootcamp?

Ja. Elke les over DevOps-bootcamp bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Strikte modus met set -euo pipefail
  2. Trap-handlers voor opruimen en signalen
  3. Veilige tijdelijke bestanden en vergrendelingsmappen
  4. Idempotente scripts en retrylogica met back-off
← Terug naar DevOps-bootcamp