There is a simple, useful idiom to make your bash scripts more
robust – ensuring they always perform necessary cleanup
operations, even when something unexpected goes wrong. The secret
sauce is a pseudo-signal provided by bash, called EXIT, that you
can trap;
commands or functions trapped on it will execute when the script
exits for any reason. Let’s see how this works.
The basic code structure is like this:
#!/bin/bash
function finish {
# Your cleanup code here
}
trap finish EXIT
You place any code that you want to be certain to run in this
“finish” function. A good common example: creating a temporary
scratch directory, then deleting it after.
#!/bin/bash
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish {
rm -rf "$scratch"
}
trap finish EXIT
You can then download, generate, slice and dice intermediate or
temporary files to the $scratch
directory to your heart’s
content. [1]
# Download every linux kernel ever.... FOR SCIENCE!
for major in {1..4}; do
for minor in {0..99}; do
for patchlevel in {0..99}; do
tarball="linux-${major}-${minor}-${patchlevel}.tar.bz2"
curl -q "http://kernel.org/path/to/$tarball" -o "$scratch/$tarball" || true
if [ -f "$scratch/$tarball" ]; then
tar jxf "$scratch/$tarball"
fi
done
done
done
# magically merge them into some frankenstein kernel ...
# That done, copy it to a destination
cp "$scratch/frankenstein-linux.tar.bz2" "$1"
# Here at script end, the scratch directory is erased automatically
Compare this to how you’d remove the scratch directory without
the trap:
#!/bin/bash
# DON'T DO THIS!
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
# Insert dozens or hundreds of lines of code here...
# All done, now remove the directory before we exit
rm -rf "$scratch"
What’s wrong with this? Plenty:
- If some error causes the script to exit prematurely, the
scratch directory and its contents don’t get deleted. This is
a resource leak, and may have security
implications too. - If the script is designed to exit before the end, you must
manually copy ‘n paste the rm command at each exit point. - There are maintainability problems as well. If you later
add a new in-script exit, it’s easy to forget to include the
removal – potentially creating mysterious heisenleaks.