Problem

Quite a few of the bash scripts I write create temporary resources (temporary directories and files) which need to be cleaned up when the scripts terminate. Here is a little trick I use to make this task a little simpler.

Idea

The idea is to define a function named cleanup in which all cleanup tasks are defined. This function also contains all necessary actions to figure out what actually needs to be cleaned up (e.g if a file actually exists). This function is then registered with trap[1] so that it is executed when the script terminates.

Example

#!/bin/bash
set -e -o pipefail

function cleanup {
  EXIT_CODE=$?
  set +e # disable termination on error
  if [[ -n $TMP_DIR ]]; then
    rm -Rf $TMP_DIR
    echo "deleted dir $TMP_DIR"
  fi
  exit $EXIT_CODE
}
trap cleanup EXIT

TMP_DIR=$(mktemp -d) # create temporary directory
echo "created dir $TMP_DIR"

pushd $TMP_DIR # change dir to $TMP_DIR
# do something which gets cleaned up when done
touch a.txt
touch b.txt

Exit Code Propagation

Because the cleanup function will also be called if something goes wrong (the set -e call in the second line of the script changes the execution behaviour to “Exit immediately”[2]) we also do want to propagate the EXIT CODE[3] of the actual script to the caller.

So the first thing we do in the cleanup function is to capture that exit code in the variable EXIT_CODE and then disable the “Exit immediately” behaviour with set +e. The final thing in the cleanup function is then to exit with the original exit code.

Resources

  1. Traps
  2. The Set Builtin
  3. Exit and Exit Status