Signals and Graceful Termination
Production automation is interrupted by users, CI runners, containers, and supervisors. A reliable Bash process responds deliberately, forwards termination to owned children, and cleans up without hiding the original status.
Learning objectives
By the end of this lesson
- Explain common termination signals.
- Install traps for cleanup and shutdown.
- Forward signals to children.
- Preserve status through cleanup.
- Design for untrappable termination.
1. Signals notify processes asynchronously
2. trap installs handlers
cleanup() {
printf 'cleanup before exit\n' >&2
}
trap cleanup EXITEXIT is a Bash pseudo-signal that runs for many normal shell exit paths.
3. TERM and INT should have explicit behavior
on_term() {
printf 'termination requested\n' >&2
exit 143
}
trap on_term TERM
trap on_term INTIf callers depend on a status convention, document it.
4. Wrappers may need to forward signals to children
child_pid=""
forward_term() {
if [[ -n $child_pid ]]; then
kill -TERM "$child_pid" 2>/dev/null || true
fi
}
trap forward_term TERM INT
long_running_command &
child_pid=$!
wait "$child_pid"
status=$?
child_pid=""
exit "$status"A Bash wrapper that swallows supervisor signals can leave the actual workload running.
5. kill sends signals; it is not limited to SIGKILL
kill -TERM "$pid"
kill -HUP "$pid"Symbolic signal names make intent much clearer than unexplained signal numbers.
6. Signal 0 can probe reachability
if kill -0 "$pid" 2>/dev/null; then
printf 'PID appears reachable\n'
fiThis does not prove application health, and PID reuse means stale PID files require careful handling.
7. Cleanup should tolerate partially initialized state
tmpdir=""
child_pid=""
cleanup() {
local status=$?
[[ -n $child_pid ]] && kill -TERM "$child_pid" 2>/dev/null || true
[[ -n $tmpdir && -d $tmpdir ]] && rm -rf -- "$tmpdir"
return "$status"
}
trap cleanup EXIT8. EXIT traps should preserve the incoming status
cleanup() {
local status=$?
rm -f -- "${tmp:-}"
exit "$status"
}
trap cleanup EXIT9. SIGKILL and machine failure bypass cleanup
SIGKILL cannot be trapped. Power failure, kernel failure, or abrupt runtime termination can also bypass shell cleanup.
Temporary files, locks, and recovery procedures must tolerate stale artifacts.
10. Cooperate with systemd, containers, CI, and Kubernetes
Supervisors usually send a graceful signal, wait for a grace period, then escalate. Shell wrappers should forward termination and finish promptly rather than trapping signals indefinitely.
11. Hands-on lab: graceful child shutdown
mkdir -p "$HOME/devops-academy/bash/chapter10/lesson03"
cd "$HOME/devops-academy/bash/chapter10/lesson03"
cat > graceful.sh <<'EOF'
#!/usr/bin/env bash
child_pid=""
cleanup() {
local status=$?
if [[ -n $child_pid ]]; then
kill -TERM "$child_pid" 2>/dev/null || true
wait "$child_pid" 2>/dev/null || true
fi
exit "$status"
}
on_term() {
printf 'parent received termination\n' >&2
exit 143
}
trap cleanup EXIT
trap on_term TERM INT
bash -c '
trap "echo child received TERM >&2; exit 0" TERM
while :; do sleep 1; done
' &
child_pid=$!
printf 'parent=%s child=%s\n' "$$" "$child_pid"
printf 'test from another shell: kill -TERM %s\n' "$$"
wait "$child_pid"
status=$?
child_pid=""
exit "$status"
EOF
chmod u+x graceful.shVerification checklist
12. Knowledge check
Question 1. Which common graceful shutdown signal can be trapped?
Question 2. Can SIGKILL be trapped?
Question 3. Why forward TERM to a child?
Question 4. Why design for stale artifacts?
13. Summary
Signals are part of process lifecycle design. Trap graceful termination, forward it to owned children, preserve status during cleanup, and remember that forced termination can bypass every shell handler.
14. Further reading
- GNU Bash Reference Manual — Signals and Traps.
- POSIX kill and signal concepts.
- Linux
signal(7)andkill(2). - systemd and Kubernetes process-termination documentation.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.