Useful Flags to Set on Every Shell Script
When writing shell scripts, it's a good idea to start with a standard set of flags that help make the scripts more robust and easier to debug. Here are some common flags that I include at the top of every shell script:
#!/bin/bash
The first line specifies which interpreter to use to run the script. #!/bin/bash
will ensure the Bash shell is used. This allows the script to use Bash features and syntax not available in other shells like dash or sh. You could also adapt this to ZSH or other shells if you prefer.
set -euo pipefail
This set of flags helps catch errors early and makes the script behave in a predictable way:
-
-e
exits immediately if any simple command fails with a non-zero status. This avoids executing further commands that may have unintended consequences. -
-u
treats unset variables as an error when substituting, rather than substituting with an empty string. This helps catch typos in variable names. -
-o pipefail
returns a non-zero exit code if any command in the pipeline fails, not just the last one. This helps catch errors in a pipeline.
set -x
Including set -x
will print each command before executing it. This is extremely useful for debugging scripts to see exactly what commands are run. It's common to wrap it in a check for a DEBUG environment variable so it's easy to enable debugging:
if [ -n "$DEBUG" ]; then set -x; fi
Error Handling
Adding some boilerplate error handling can make scripts more resilient. Trapping errors with ERR and EXIT traps lets you perform cleanup tasks:
trap 'echo An error occurred; exit 1' ERR
trap 'echo Exited!; exit 1' EXIT
For more robust handling, saving the exit code to a variable allows inspecting the specific failure:
err=$?
if [ $err -ne 0 ]; then
echo "Error with exit code $err" >&2
exit $err
fi
Starting scripts with a standard header like this makes adding flags easier. The keys are -e
for early exits, -u
to catch typos, -o pipefail
for pipeline errors, -x
debugging, and ERR
/EXIT
traps for cleanup. Following these best practices will produce more reliable and debuggable Bash scripts.
Complete Example
Here's a complete example that you can copy and paste as a starting template:
#!/bin/bash
# Exit on any failure
set -eo pipefail
# Debug mode
if [ -n "$DEBUG" ]; then
set -x
fi
# Handle errors
trap 'echo "Error: $? at line $LINENO" >&2' ERR
# Script logic
function cleanup() {
# Commands to clean up resources
echo "Cleaning up..."
}
# Cleanup before exit
trap 'cleanup' EXIT
echo "Starting script..."
# Rest of script...
echo "Script finished!"
Enjoy.