The Problem: Scripts That Leave a Mess

Every Bash script that creates temporary files, acquires locks, or spawns background jobs runs the risk of leaving garbage behind when it exits unexpectedly. A crashed script can leave stale lock files that block subsequent runs, or fill /tmp with orphaned data that eventually triggers disk‑space alerts. Manually cleaning up in every error path is tedious and error‑prone.

The Solution: trap for Guaranteed Cleanup

Bash’s trap builtin lets you register a command that runs whenever the shell receives a signal or exits. By trapping EXIT you get a single place where cleanup happens no matter how the script terminates — normal return, set -e abort, or an explicit exit.

Real‑World Scenario: Temporary Files and Locks

Imagine a nightly ETL job that downloads a CSV, transforms it, and loads the result into a database. The script creates a temporary directory, writes intermediate files there, and uses a lock file to prevent concurrent runs. If the transformation crashes, the lock must be released and the temporary directory removed, otherwise the next scheduled run will fail silently.

Production‑Ready Example

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

# Create a temporary directory that will be removed on exit
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

# Example work: write a couple of files
echo "data" > "$tmpdir/input.txt"
process_data "$tmpdir/input.txt" > "$tmpdir/output.txt"

# If process_data fails, the script exits because of -e,
# but the trap still runs and cleans up.

Why This Works

The trap command is evaluated when the script receives the EXIT pseudo‑signal, which Bash fires for every termination path. Because the trap is set early, even a failure in mktemp (unlikely but possible) won’t leave a stray directory. Quoting $tmpdir inside the trap prevents word‑splitting if the path ever contains spaces.

Common Pitfalls

  • Forgetting to quote the variable in the trap command.
  • Using trap '...' ERR instead of EXIT when you want cleanup on any exit.
  • Placing the trap after the resource is created but before a possible early exit; the trap won’t run for exits that occur before it’s registered.

Bonus: Combine with set -euo pipefail

The set -euo pipefail line at the top makes the script abort on any unset variable, non‑zero command, or failed pipeline. Together with trap you get a script that stops fast on errors *and* guarantees cleanup — exactly what production environments demand.

Remember: a script that cleans up after itself is a script you can trust in production.