patternbashMajor
trap for cleanup: always run teardown code on exit or signal
Viewed 0 times
trapEXIT trapcleanuptemp filesignal handlingteardownSIGINTSIGTERM
Problem
Scripts that create temp files, acquire locks, or start background processes leave behind mess when they exit abnormally (Ctrl-C, error, kill). Cleanup code at the bottom of a script is skipped if the script exits early.
Solution
Use 'trap cleanup EXIT' to register a function that runs whenever the script exits, regardless of how it exits.
cleanup() {
rm -f "$tmpfile"
kill "$bgpid" 2>/dev/null || true
}
trap cleanup EXIT
tmpfile=$(mktemp)
bg_process &
bgpid=$!
cleanup() {
rm -f "$tmpfile"
kill "$bgpid" 2>/dev/null || true
}
trap cleanup EXIT
tmpfile=$(mktemp)
bg_process &
bgpid=$!
Why
The EXIT pseudo-signal fires for any exit: normal completion, set -e triggered exit, explicit exit N, and most signals after they are handled. It is the single reliable hook for teardown.
Gotchas
- trap does NOT fire on SIGKILL (kill -9) — nothing does, by design
- Each trap call replaces the previous one for that signal — chain multiple cleanups inside a single function
- Trap functions inherit the exit code at the time they run; use 'exit $?' at the end to preserve it
- In subshells, traps are inherited but EXIT fires at subshell exit, not parent exit
- Use 'trap - EXIT' inside the cleanup to prevent recursion if the cleanup itself fails with set -e
Code Snippets
Robust EXIT trap with cleanup
#!/usr/bin/env bash
set -euo pipefail
TMPDIR_WORK=$(mktemp -d)
cleanup() {
local exit_code=$?
rm -rf "$TMPDIR_WORK"
echo "Cleaned up. Exit: $exit_code" >&2
exit "$exit_code"
}
trap cleanup EXIT
# Also catch specific signals explicitly if needed
trap 'echo "Interrupted" >&2' INT TERM
# ... do work in $TMPDIR_WORK ...Context
Scripts that create temporary resources, background processes, or exclusive locks
Revisions (0)
No revisions yet.