Guide Bash-Scripting Advanced

Signals & Trap

Handling SIGTERM, SIGINT, and other signals in Bash scripts with trap, for graceful shutdown and guaranteed cleanup.

3 min read

What Signals Are (Recap)

Signals are how the OS or another process asks a running process to do something — most commonly, to stop. Scripts can catch most signals with trap and run custom cleanup logic instead of dying immediately.

kill -l                # list all available signals
SignalNumberCommon TriggerDefault Behavior
SIGINT2Ctrl+CTerminate
SIGTERM15kill pid (default)Terminate
SIGHUP1Terminal closedTerminate
SIGKILL9kill -9 pidTerminate — cannot be caught by trap

Basic trap Syntax

trap 'COMMAND' SIGNAL_NAME

trap 'echo "Caught SIGINT, exiting..."; exit 1' INT
trap 'cleanup' TERM
trap 'echo "Script exiting (any reason)"' EXIT

Graceful Shutdown Pattern

#!/usr/bin/env bash
set -euo pipefail

RUNNING=true

cleanup() {
    echo "Received shutdown signal — cleaning up..."
    RUNNING=false
}
trap cleanup SIGTERM SIGINT

echo "Starting worker loop (PID $$)..."
while [ "$RUNNING" = true ]; do
    echo "Processing batch..."
    sleep 2
done
echo "Worker stopped cleanly"
./worker.sh &
kill -TERM $!    # triggers cleanup() instead of an abrupt kill

trap EXIT: Guaranteed Cleanup

TMPDIR=$(mktemp -d)
LOCKFILE="/tmp/myapp.lock"
touch "$LOCKFILE"

cleanup() {
    rm -rf "$TMPDIR" "$LOCKFILE"
    echo "Cleaned up temp resources"
}
trap cleanup EXIT    # runs on normal exit, error exit (with set -e), OR a caught signal that calls exit

# ... rest of script, even if it fails partway through, cleanup() still runs ...

trap ... EXIT is the single most reliable way to guarantee cleanup — it fires whether the script finishes normally, errors out, or is interrupted (as long as the signal handler itself calls exit).

Ignoring a Signal

trap '' INT    # ignore Ctrl+C entirely (empty command = ignore)
echo "This can't be interrupted with Ctrl+C"
sleep 10
trap - INT       # restore default SIGINT behavior

Multiple Signals, One Handler

trap cleanup SIGINT SIGTERM SIGHUP    # one function handles several signals

Resetting a Trap

trap - EXIT    # remove a previously set EXIT trap (revert to default behavior)

A Realistic Example: A Long-Running Sync Script

#!/usr/bin/env bash
set -euo pipefail

PIDFILE="/var/run/sync.pid"
echo $$ > "$PIDFILE"

cleanup() {
    echo "Shutting down sync process..."
    rm -f "$PIDFILE"
    exit 0
}
trap cleanup SIGTERM SIGINT EXIT

while true; do
    rsync -a /data/ /backup/
    sleep 300
done

Production Considerations

  • SIGKILL (9) cannot be trapped — never rely on cleanup logic running after a kill -9; design for that possibility (e.g., idempotent operations, lock files with staleness checks).
  • Container orchestrators (Kubernetes, Docker) send SIGTERM on shutdown and wait a grace period before SIGKILL — a script/entrypoint that doesn’t handle SIGTERM gracefully gets forcibly killed, potentially mid-write.
  • trap cleanup EXIT should be set as early as possible in a script, right after acquiring any resource (temp file, lock, PID file) that needs guaranteed cleanup.

Quick Interview Answer

trap 'command' SIGNAL lets a Bash script intercept signals like SIGTERM/SIGINT and run cleanup logic instead of dying immediately — essential for graceful shutdown in long-running scripts or daemons. trap cleanup EXIT is the most reliable pattern, since it fires on normal completion, error exit, or a caught signal, guaranteeing temp files and locks get cleaned up. SIGKILL is the one exception — it can never be trapped, so cleanup logic must not be the ONLY safety net for critical resources.”

Common Mistakes

  • Assuming trap can catch SIGKILL — it fundamentally cannot, by kernel design.
  • Not handling SIGTERM in long-running scripts/containers, causing the orchestrator to hard-kill them after the grace period, potentially corrupting in-progress work.
  • Setting trap cleanup EXIT too late in the script, after resources needing cleanup were already created.

Add More Questions to This Guide

Know a question that should be here? Share it and help the community!

Open Google Form