Files and data
Create and clean temporary files
Use mktemp and a trap so unique temporary data is removed on success, failure, or interruption.
10 minute lesson
Scripts need scratch space: an archive to assemble, a download to inspect, a sorted copy of a log. Hardcoding a path like /tmp/work.txt looks harmless, but predictable temporary filenames can collide or be replaced by another user on a shared machine. mktemp asks the operating system for a unique private path instead.
Create a temporary directory with cleanup
work=$(mktemp -d)
cleanup() { rm -rf -- "$work"; }
trap cleanup EXIT INT TERM
printf 'working in %s\n' "$work"
# working in /tmp/tmp.X8s2Lk4bQz
mktemp -d creates a directory only your user can access and prints its path, which we capture with command substitution.
The trap line makes this reliable. A trap registers a command to run when the shell receives a signal or, with the special EXIT condition, whenever the script ends. This one runs cleanup on normal exit, on Ctrl-C (INT), and on termination (TERM) — so the directory disappears whether the script succeeds, fails, or gets interrupted halfway.
The -- in rm -rf -- "$work" ends option parsing, so even a path starting with a dash can’t be misread as a flag.
Verify the cleanup runs
Exit normally and interrupt the script. Confirm the exact generated directory is removed both times:
./make-report
# working in /tmp/tmp.QpB7wq2c1M
ls /tmp/tmp.QpB7wq2c1M
# ls: cannot access '/tmp/tmp.QpB7wq2c1M': No such file or directory
Run it again and press Ctrl-C mid-run, then check again. If the directory survives an interrupt, the trap was registered too late — register it immediately after creating the resource, before any work that can fail.
The failure mode to fear
rm -rf next to a variable that might be empty is the classic shell disaster:
rm -rf "$workdir/cache" # if $workdir is empty: rm -rf /cache
Validate the variable before any recursive deletion. set -u catches unset names, and a one-line guard costs nothing:
[[ -n $work ]] || exit 1
Never build a destructive target from an empty or broad environment variable. The pattern above — mktemp output, straight into a trap — is safe precisely because the value comes from a program you just ran, not from inherited environment.
Lesson completed