patternbashMajor
Signal handling: trap SIGTERM/SIGINT for graceful shutdown
Viewed 0 times
signaltrapSIGTERMSIGINTSIGKILLgraceful shutdowninterruptkill
Problem
Long-running scripts killed with SIGTERM or interrupted with Ctrl-C leave resources in an inconsistent state. By default, SIGTERM immediately kills the shell without running any cleanup.
Solution
Use trap to intercept signals and run controlled shutdown logic.
shutdown=0
trap 'shutdown=1' TERM INT
while (( !shutdown )); do
do_work
done
cleanup
# Or more direct:
trap 'echo Caught SIGTERM; cleanup; exit 0' TERM
trap 'echo Caught SIGINT; cleanup; exit 130' INT
shutdown=0
trap 'shutdown=1' TERM INT
while (( !shutdown )); do
do_work
done
cleanup
# Or more direct:
trap 'echo Caught SIGTERM; cleanup; exit 0' TERM
trap 'echo Caught SIGINT; cleanup; exit 130' INT
Why
When a shell receives a signal, if a trap is set for that signal, it queues the trap handler to run after the current command finishes. This allows controlled teardown rather than abrupt termination.
Gotchas
- SIGKILL (kill -9) cannot be trapped — design for it by using atomic operations
- Child processes do not automatically inherit signal traps from the parent shell
- In a script, 'trap handler SIGNAME' replaces any existing trap for that signal
- Exit code convention: SIGINT = 130 (128+2), SIGTERM = 143 (128+15)
- Use 'kill -0 $pid' to test if a process is still running without sending a signal
Code Snippets
Graceful signal handling with cleanup
#!/usr/bin/env bash
set -euo pipefail
cleanup() {
echo "Shutting down..." >&2
# kill child processes
jobs -p | xargs -r kill 2>/dev/null || true
rm -f /tmp/myscript.lock
}
trap cleanup EXIT
trap 'echo "SIGINT received"; exit 130' INT
trap 'echo "SIGTERM received"; exit 143' TERM
echo $$ > /tmp/myscript.lock
while true; do
do_work
sleep 5
doneContext
Daemon-like scripts, long-running jobs, or scripts managing external processes
Revisions (0)
No revisions yet.