Executing Code after an Error Occurs with Bash When Using set e
I'm sure you're using set -e in your scripts, and often times it's useful to execute some code if an error occurs. Here's how.
In case you’ve never heard of or used set -e
before, it’s something you can
add to a Bash script which tells Bash to immediately exit if any part of your
script throws an error.
set -e is something you would put at the top of your script, such as:
#!/bin/bash
set -e
echo "Hello World"
(exit 1)
echo "This will never execute"
In the above case, the second echo
command will never execute because set -e
will halt the script on the (exit 1)
line. We’re using (exit 1)
here to
emulate an error that would likely happen in a real world script.
If we didn’t have set -e
at the top of the file, then both echo commands would
get output to your terminal because Bash wouldn’t halt the script on the error.
Using set -e
is really useful because if a part of your script fails, chances
are you want everything to halt, because later parts of your script might depend
on everything before it running successfully.
# A Real World Use Case
I had this situation come up recently while creating my next course. One of the things we’ll do in the course is test an Ansible run inside of a Docker container.
One of the things that the test.sh
script does is stop the container after the
Ansible run, but I was noticing that the script never ran the stop container
function if the Ansible test failed because Ansible returned a non-0 exit code
which triggered set -e
.
This was a huge problem because after a few test script runs, I ended up with a bunch of running containers that were using quite a few resources. Eventually Docker for Windows would crash.
What I really wanted to do was something like “run the test script, but no matter what, make sure the container is stopped whether or not Ansible ran successfully”.
# Trapping Errors with Bash
Lucky for us, the author of Bash thought of how to solve this. If you
want to follow along, create a test.sh
file and then chmod +x test.sh
it so
you can run it.
Trapping errors and executing a custom function:
#!/bin/bash
set -e
do_something() {
echo "This will always execute"
}
trap "do_something" ERR
echo "Hello World"
return
do_something
If you run the above script, you’ll get this output:
Hello World
./test.sh: line 13: return: can only `return' from a function or sourced script
This will always execute
That’s because you can’t use the return
keyword like that. You can only use
it when it’s inside of a function. I’m just using it here as an example of how
to raise an error with Bash.
But as you can see, the “This will always execute” line was returned. That’s
because the return
keyword threw an error and we trapped that error and told
Bash to call the do_something
function.
If you comment out the return
line and run the script again, it will output
both “Hello World” and “This will always execute” but this time there was no
error, so it just called do_something
as usual.
Have you used this strategy before? Let me know in the comments below.