Three shell options that make scripts fail early and loudly instead of continuing with broken state. Together, they turn bash from "silently-ignore-errors" into "loudly-exit-on-error".
#!/bin/bash
set -e
mkdir -p /var/backups
cp source.db /var/backups/ # if this fails, script exits
process /var/backups/source.db
With set -e, any command returning nonzero (that isn't part
of an if, &&, or ||) exits the whole script. Without it,
the next command runs anyway, using state that might be broken.
set -u
echo "$name" # if $name is unset, script exits with error
Catches typos in variable names. $namae (typo) triggers an
error instead of expanding to empty and continuing silently.
Use ${var:-} when you actually want an empty default:
optional=${OPTIONAL:-}
set -o pipefail
grep nonexistent /etc/hosts | sort | uniq
Without pipefail, only the LAST command's exit code counts.
If grep fails but uniq succeeds, the pipeline is
"successful" from bash's point of view. pipefail says: if ANY
command in the pipeline fails, the pipeline as a whole fails.
#!/bin/bash
set -euo pipefail
That single line at the top of every serious script:
-e exit on error-u treat unset variables as errors-o pipefail fail if any part of a pipeline failsIf you learn one line from this whole topic, that is the one.
set -e has quirks. Commands in an if or after &&/||
don't trigger the exit, which is intentional. But some real
gotchas exist:
count=$(grep -c ERROR log.txt) # if no matches, grep exits 1
# set -e kills the script here
Workaround:
count=$(grep -c ERROR log.txt || true)
|| true swallows the failure. Ugly but effective.