Skip to content
Linux Basics: Clean Up Bash Temporary Files with Traps

Linux Basics: Clean Up Bash Temporary Files with Traps

October 19, 2026

Register cleanup just after creating temporary state. These examples remove only files they created, and use rmdir rather than recursive deletion.

These examples were tested on Linux with GNU Bash 5.2.37. Use Bash rather than sh. No packages or administrator access are needed.

Prepare a scratch directory

You need Bash, a text editor, and the mktemp, rm, and rmdir utilities. Keep using the same terminal. Save each named source file in this scratch directory before running its command. Calling bash explicitly avoids changing executable permissions.

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

1. Remove one temporary file on exit

Save this as trap-file.sh:

#!/usr/bin/env bash
temp_file=$(mktemp) || exit 1
cleanup() {
  if rm -- "$temp_file"; then
    printf 'Temporary file removed\n'
  else
    printf 'Could not remove temporary file\n' >&2
  fi
}
trap cleanup EXIT
printf '%s\n' 'temporary notes' > "$temp_file"
IFS= read -r line < "$temp_file"
printf 'Read: %s\n' "$line"

Run it:

bash trap-file.sh

Output:

Read: temporary notes
Temporary file removed

The EXIT trap runs when the script ends. A named function keeps cleanup readable. Variables are expanded when the function runs, so keep the temporary path unchanged.

2. Preserve a failure status during cleanup

Save this as trap-status.sh:

#!/usr/bin/env bash
temp_dir=$(mktemp -d) || exit 1
cleanup() {
  status=$?
  trap - EXIT
  rmdir -- "$temp_dir"
  printf 'Cleanup after status %d\n' "$status"
  exit "$status"
}
trap cleanup EXIT
printf 'Stopping a simulated failed check\n'
exit 7

Run it:

bash trap-status.sh
printf "Script status: %s\n" "$?"

Output:

Stopping a simulated failed check
Cleanup after status 7
Script status: 7

Capture the status before another command replaces it. Removing the EXIT trap before explicitly exiting avoids re-entry concerns. The failure here is deliberate; cleanup does not turn it into success.

3. Route a handled signal through EXIT cleanup

Save this as trap-signal.sh:

#!/usr/bin/env bash
temp_dir=$(mktemp -d) || exit 1
cleanup() {
  if rm -f -- "$temp_dir/marker" && rmdir -- "$temp_dir"; then
    printf 'Workspace removed\n'
  else
    printf 'Could not remove workspace completely\n' >&2
  fi
}
trap cleanup EXIT
trap 'exit 143' TERM
printf '%s\n' ready > "$temp_dir/marker"
printf 'Sending TERM to this script only\n'
kill -TERM "$$"

Run it:

bash trap-signal.sh
printf "Script status: %s\n" "$?"

Output:

Sending TERM to this script only
Workspace removed
Script status: 143

This script sends TERM only to itself. The handler explicitly exits with 143, then EXIT performs cleanup. Traps cannot handle SIGKILL or power loss, so temporary cleanup is best effort rather than a durability guarantee.

Clean up

In the same terminal, remove only the example files, return to your original directory, and remove the empty scratch directory:

rm -- trap-file.sh trap-status.sh trap-signal.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

Reference

See the GNU Bash manual: Bourne Shell Builtins for the relevant shell behavior. The installed Bash help command also documents these builtins.

Acknowledgements

This post was created with assistance from AI.

Last updated on