setShell options: set -euo pipefail, set -x and friends
set changes how the shell itself behaves: -e stops a script on the first failing command, -u treats unset variables as errors, -o pipefail makes a pipeline fail if any part fails, and -x prints every command as it runs. It also sets positional parameters and, with no arguments, lists every variable and function.
set [-euxva] [-o OPTION] [+euxva] [+o OPTION] [-- ARG...]A deploy script kept going after a failed step and shipped a broken build. See what each option catches.
setBash builtin that changes options of the current shell. A minus turns an option on, a plus turns it off.
Shell options are flags inside the bash process; $- shows the single-letter ones that are on (hB for a typical script, himBHs for an interactive shell). With errexit (-e), after each simple command bash checks the exit status and, if it's non-zero and the command isn't part of a condition (if, while, until, an operand of && or ||, or negated with !), it exits with that status. Commands inside a function called from a condition are also exempt, which surprises people. nounset (-u) makes expanding an unset variable print 'unbound variable' and exit. ${VAR:-default} and ${VAR-} are allowed. pipefail changes a pipeline's exit status from the last command's to the rightmost non-zero one. xtrace (-x) prints each command after expansion to stderr, prefixed with PS4 ('+ '). set -- args replaces $1, $2... and $#. With no arguments, set prints every shell variable and function, exported or not. These options are per process: a child script starts with defaults unless SHELLOPTS is exported or it sets them itself.
-e (errexit)Exit on the first failing command (outside conditions)-u (nounset)Error on use of an unset variable-o pipefailPipeline fails if any command in it fails-x (xtrace)Print each command, expanded, to stderr before running it-v (verbose)Print each line as it's read, before expansion-a (allexport)Export every variable assigned-n (noexec)Parse only, don't run: a syntax check-C (noclobber)> refuses to overwrite existing files (use >| to force)+x, +e ...Turn an option off againset -oList all options with on/offset -- a b cSet positional parameters $1 $2 $3set (no args)Print all variables and functionsRelying on set -e to catch every failureIt's suspended inside if/while conditions, && / || chains and functions called from them, and pipelines report only the last command without pipefail.
set -euo pipefail, plus explicit checks: cmd || { echo 'cmd failed' >&2; exit 1; }grep pattern file | wc -l under set -eo pipefailgrep exits 1 when nothing matches, so 'zero matches' kills the script.
{ grep pattern file || true; } | wc -l # or grep -c pattern file || trueset -x in a CI job that handles tokensEvery expanded command is printed, secrets included, into build logs.
set +x before secret handling, or only trace locally with bash -xTyping set -e in your interactive shell to 'be safe'The next command that fails (a typo, a grep with no match) exits your shell or SSH session.
Use it in scripts onlyTry these on a Linux machine of your own. Each task has a hint and a solution.
Write a two-line script ~/strict.sh that uses set -euo pipefail and then reads an unset variable. Run it and check the exit code.
Trace ~/app/scripts/deploy.sh with version 9.9.9 and find the tar command it runs.
Show that without pipefail a failing grep is hidden by wc, and with it the pipeline fails.
In bash, list which of errexit, nounset, pipefail and xtrace are on in your interactive shell.
setShell options: set -euo pipefail, set -x and friends
set changes how the shell itself behaves: -e stops a script on the first failing command, -u treats unset variables as errors, -o pipefail makes a pipeline fail if any part fails, and -x prints every command as it runs. It also sets positional parameters and, with no arguments, lists every variable and function.
set [-euxva] [-o OPTION] [+euxva] [+o OPTION] [-- ARG...]A deploy script kept going after a failed step and shipped a broken build. See what each option catches.
setBash builtin that changes options of the current shell. A minus turns an option on, a plus turns it off.
Shell options are flags inside the bash process; $- shows the single-letter ones that are on (hB for a typical script, himBHs for an interactive shell). With errexit (-e), after each simple command bash checks the exit status and, if it's non-zero and the command isn't part of a condition (if, while, until, an operand of && or ||, or negated with !), it exits with that status. Commands inside a function called from a condition are also exempt, which surprises people. nounset (-u) makes expanding an unset variable print 'unbound variable' and exit. ${VAR:-default} and ${VAR-} are allowed. pipefail changes a pipeline's exit status from the last command's to the rightmost non-zero one. xtrace (-x) prints each command after expansion to stderr, prefixed with PS4 ('+ '). set -- args replaces $1, $2... and $#. With no arguments, set prints every shell variable and function, exported or not. These options are per process: a child script starts with defaults unless SHELLOPTS is exported or it sets them itself.
-e (errexit)Exit on the first failing command (outside conditions)-u (nounset)Error on use of an unset variable-o pipefailPipeline fails if any command in it fails-x (xtrace)Print each command, expanded, to stderr before running it-v (verbose)Print each line as it's read, before expansion-a (allexport)Export every variable assigned-n (noexec)Parse only, don't run: a syntax check-C (noclobber)> refuses to overwrite existing files (use >| to force)+x, +e ...Turn an option off againset -oList all options with on/offset -- a b cSet positional parameters $1 $2 $3set (no args)Print all variables and functionsRelying on set -e to catch every failureIt's suspended inside if/while conditions, && / || chains and functions called from them, and pipelines report only the last command without pipefail.
set -euo pipefail, plus explicit checks: cmd || { echo 'cmd failed' >&2; exit 1; }grep pattern file | wc -l under set -eo pipefailgrep exits 1 when nothing matches, so 'zero matches' kills the script.
{ grep pattern file || true; } | wc -l # or grep -c pattern file || trueset -x in a CI job that handles tokensEvery expanded command is printed, secrets included, into build logs.
set +x before secret handling, or only trace locally with bash -xTyping set -e in your interactive shell to 'be safe'The next command that fails (a typo, a grep with no match) exits your shell or SSH session.
Use it in scripts onlyTry these on a Linux machine of your own. Each task has a hint and a solution.
Write a two-line script ~/strict.sh that uses set -euo pipefail and then reads an unset variable. Run it and check the exit code.
Trace ~/app/scripts/deploy.sh with version 9.9.9 and find the tar command it runs.
Show that without pipefail a failing grep is hidden by wc, and with it the pipeline fails.
In bash, list which of errexit, nounset, pipefail and xtrace are on in your interactive shell.