Kieran Hunt

How I start my Bash scripts

✦ 2023-06-15

2024-05-17: I’ve updated this post to expand all set commands to their long versions. Longer names are easier to grok at a glance and much easier to Google for. I’ve also reordered them to set xtrace first to allow it to log out the other set commands.

#!/usr/bin/env bash

set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail

# ...

#!/usr/bin/env bash

This is the interpreter directive (or shebang). Older Bash shebangs used to look something like #!/bin/bash. But the bash executable might not be in /bin on all systems. Portability isn’t guarenteed.

env (archive) will search through the current $PATH for the interpreter. It should be able to find bash even if it is somewhere other than /bin.

The drawbacks of using this approach seem to be:

  • It’s hard to pass additional parameters to the intepreter. Not all versions of env seem to support the -S argument needed for this. I can’t recall having to do this for Bash, but have run into issues with ts-node (archive) before.
  • Just like bash may not be in /bin, env may not be in /usr/bin. I’ve never run into this in the wild though.

set -o ...

The -o flag enables the particular shell option. Use +o to disable them.

  • xtrace - Print each command before executing it, including expanding the value of arguments.
  • errexit - Stop executing the script when a command fails. Vital.
  • errtrace - The errexit flag disables the ERR trap and errtrace re-enables it.
  • nounset - Stop executing the script when trying to access unset variables. Also vital.
  • pipefail - Bash won’t propogate non-zero exit codes to the end of a pipeline. This turns that on.

Most of the above options have shorter versions. The errtrace option is E, nounset is u, etc. For scripts that you expect others to read, and that includes future you, I recommend always using the long versions.

For more, see Safer bash scripts with ‘set -euxo pipefail’ · (archive) and The Set Builtin section of the Bash Reference Manual (archive).