Skip to content
Traps and Cleanup
step 1/5

Reading — step 1 of 5

Learn

~1 min readRobust Scripting

trap registers a handler for signals or shell events. The classic use: cleanup on exit.

#!/bin/bash
set -euo pipefail

tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT     # cleanup, no matter how we exit

echo "data" > "$tmpfile"
process_data "$tmpfile"
# tmpfile is automatically removed when script ends

The EXIT pseudo-signal fires when the script exits, normally or due to error.

Common signals and uses:

  • EXIT — runs on any script exit
  • ERR — runs when a command fails (with set -e, before exit)
  • INT — Ctrl+C
  • TERMkill <pid> default
  • HUP — terminal closed
  • DEBUG — runs before EVERY command (slow but useful for tracing)

Multiple traps:

cleanup() {
    rm -rf "$workdir"
    kill $(jobs -p) 2>/dev/null    # kill background jobs
}

on_error() {
    echo "failed at line $1" >&2
}

trap cleanup EXIT
trap 'on_error $LINENO' ERR
trap 'echo "interrupted"; exit 130' INT TERM

Disabling a trap:

trap - EXIT      # remove the EXIT handler
trap '' INT      # ignore SIGINT (empty handler)

Real-world patterns:

# Lock file
lock_file="/tmp/myscript.lock"
if [[ -e "$lock_file" ]]; then
    echo "already running"; exit 1
fi
touch "$lock_file"
trap 'rm -f "$lock_file"' EXIT

# Background process management
./long-running &
bg_pid=$!
trap "kill $bg_pid 2>/dev/null" EXIT
wait $bg_pid

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…