Skip to content

$ cat ./posts/bash/bash-strict-mode-is-not-enough.sh

-rw-r--r-- 1.7K #bash

Bash strict mode is not enough

by chris · 2 min read · /bash


Every serious shell script starts with the same three lines, and most of the people who write them could not say what the third one does. Strict mode is worth having. It is not worth trusting.

set -euo pipefail
IFS=$'nt'

1. What -e does not catch

errexit is suspended inside any command that is part of a condition. This script exits zero, prints nothing useful, and looks fine in CI:

set -e
check() { grep -q pattern missing-file; echo "checked"; }
if check; then echo "ok"; fi   # grep fails, function keeps going

The moment a function is called in a conditional context, every command inside it loses -e. This is documented behaviour and it surprises people every time.

2. Unset variables are a weaker guarantee than they look

-u catches $TYPO, but not an empty value from a command that failed quietly. If DIR=$(find_root) returns an empty string, then rm -rf "$DIR/build" is aimed at /build. Check the value, not just its existence:

: "${DIR:?find_root returned nothing}"

3. What actually helps

  • Run shellcheck in CI and fix its findings rather than silencing them.
  • Quote every expansion. There is no exception worth the argument.
  • Check exit codes explicitly at the points that matter, instead of hoping -e covers them.
  • Write the destructive operation as a function with a dry-run mode, and default to the dry run.

Strict mode is a seatbelt. It is not a reason to drive into a wall and find out.

← cd .. fris@linux:~/blog$ man bash