Traps and Cleanup
Prerequisites: Strict mode: set -euo pipefail
Scripts create temporary files, lock files, and background processes. A trap runs code when the script exits or receives a signal, so cleanup happens even if something fails or the user presses Ctrl + C.
trap on EXIT
set -euo pipefail
workdir=$(mktemp -d)
cleanup() {
rm -rf "$workdir"
echo "cleaned up temporary folder"
}
trap cleanup EXIT
echo "working..." > "$workdir/data.txt"
echo "wrote $(wc -l < "$workdir/data.txt") line"
false
echo "never reached"
wrote 1 line
cleaned up temporary folder
The script failed at false, but cleanup still ran. EXIT fires
however the script ends: normally, through exit, or from an error under
set -e.
Safe temporary files
Never use fixed names like /tmp/myscript.tmp — two runs collide,
and another user could create the file first. mktemp creates a unique
file (or mktemp -d a directory) that only you can access.
Handling Ctrl + C and termination
# illustrative
on_interrupt() {
echo "Interrupted — stopping workers" >&2
kill 0 # signal every process in this script's group
exit 130
}
trap on_interrupt INT TERM
Exit code 130 (128 + signal 2) is the convention for "stopped by
Ctrl + C".
Reporting errors with an ERR trap
An ERR trap runs whenever a command fails — useful for showing where
a script died:
set -Eeuo pipefail
trap 'echo "Error on line $LINENO: $BASH_COMMAND" >&2' ERR
step_one() { echo "step one ok"; }
step_two() { cp /no/such/file /tmp/ 2>/dev/null; }
step_one
step_two
step one ok
Error on line 5: cp /no/such/file /tmp/ 2> /dev/null
$LINENO is the line number and $BASH_COMMAND the command that failed.
Common mistakes
- Setting the trap after creating the temporary file, leaving a gap where a failure skips cleanup. Set traps first.
- Using
trap ... EXITin several places — each call replaces the previous trap. Keep one cleanup function that handles everything.