Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Allowing for Errors in Bash When You Have set -e Defined

allowing-for-errors-in-bash-when-you-have-set-e-defined.jpg

Using set -e is great for dealing with errors in Bash, but sometimes you want to gracefully handle an error instead of exit immediately.

Quick Jump:

It’s generally a good idea to use set -e in your Bash scripts because when you do, Bash will immediately halt your script when a command you run results in an error, or more specifically exits with an exit code that’s not 0.

I’ve written about trapping errors with Bash when using set -e which explains how set -e works, so I recommend skimming that for a quick run if you’re not sure what set -e is.

# A Real World Use Case

Lately I’ve been working hard putting together my next course and one focus point of that course is deploying web applications.

While creating an app deployment tool (with Bash) I wanted you to be able to choose whether or not a database migration gets ran during the deploy.

This tool is something I’ve been working on for a while because I have been using it for my own projects and client work for quite some time now.

But when it comes to releasing it in a course, a certain level of polish needs to happen so I’ve been doing everything I can to make it as robust as possible.

I’m doing everything in my power to prevent you from being able to initiate a deploy with invalid parameters, such as a wrong service or container name, or in this case, a database migration command that’s invalid.

Naturally I’m using set -e at the top of my script, and if you enter in an invalid database migration command the entire script comes to a halt, which is expected.

However, that’s not a very friendly user experience. What I really want to happen is to allow the command to fail, and then take a custom action depending on whether or not the command worked.

# Toggling set -e On Demand

Lucky for us, Bash is awesome, and there’s a way to easily allow for what we want.

An example of disabling set -e to gracefully handle errors:
# Override the `set -e` defined at the top of the file.
set +e

# Run your command that may or may not work.
db_migrate_command

# Store the exit code of the previously ran command.
migrate_rc="${?}"

# Turn `set -e` back on so future errors halt the script.
set -e

# If the return code is not equal to zero then the command had an error.
if [ "${migrate_rc}" -ne 0 ]; then
  # Write an informative error message and halt the script with an `exit 1`, or
  # perhaps let it continue onwards, depending on what you're doing.
fi

# Everything is all good, do whatever you planned to do.

It’s worth mentioning that it’s important to store the rc (return code) of the command inside of the set +e and set -e block because otherwise you’ll capture the rc of running set -e itself which is always going to return 0. That was a fun one to debug. :D

Using this pattern lets you keep set -e on almost all the time and situationally turn it off when you anticipate a command may fail. Victory!

Have you used this pattern before? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per year (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments