Stop making insecure or messy temporary files in your shell scripts

Shell Scripting & Automation

Stop making insecure or messy temporary files in your shell scripts

Technical Briefing | 10/5/2026

You’ve written that quick utility script, right? The one that needs to stash some data, process a list, or build a complex command before execution. And usually, the first thought is to just toss a temporary file into `/tmp`. Maybe `/tmp/myscript.$$.tmp` if you’re feeling fancy, adding the PID to make it ‘unique’. It seems harmless enough, until it isn’t. I’ve seen this pattern silently fail in production, cause security headaches, or just leave behind a graveyard of orphaned files that eventually fill up disks or confuse the next admin trying to debug.

The Lazy Temp File: A Source of Pain

Let’s be blunt: just creating files directly in `/tmp` using `$$.tmp` isn’t good enough. First, it’s a race condition waiting to happen. What if two instances of your script run at nearly the same time? Their PIDs might overlap if one finishes and another starts quickly, or if your system reuses PIDs aggressively. Even worse, if an attacker can predict your temp filename, they could create it first (a TOCTOU attack) and then feed your script malicious data or trick it into overwriting critical system files via symlink attacks. And even if you avoid those pitfalls, if your script dies unexpectedly — maybe a `SIGKILL`, a power outage, or a subtle bug — that temp file often just sits there, taking up space and cluttering `/tmp` until the next reboot or manual cleanup.

Your New Best Friend: `mktemp`

The right approach here is to use the `mktemp` utility. It’s part of `coreutils` so it’s available on pretty much every Linux system you’ll ever touch. `mktemp` does one job, and it does it really well: it creates a temporary file or directory with a unique, unguessable name. Crucially, it does this atomically, which prevents race conditions right from the start. You give it a template, usually with some `X`’s, and it replaces those with a random string to guarantee uniqueness. This isn’t just about preventing collisions; it’s about security. An attacker simply can’t predict what filename `mktemp` will generate.

#!/bin/bash
# A safer way to handle temporary files in your scripts


# Exit immediately if a command exits with a non-zero status.
# Exit if an unset variable is used.
# The pipefail option prevents errors in a pipeline from being masked.
set -euo pipefail


# Create a temporary file. If mktemp fails, we should too.
# The --tmpdir option ensures it's in a standard temp location.
TMP_FILE=$(mktemp --tmpdir="/var/tmp" my_script_XXXXXX.txt) || {
echo "ERROR: Failed to create temp file" >&2
exit 1
}


echo "Created secure temp file: $TMP_FILE"


# Set up a trap to clean up the temporary file when the script exits (normally or via signal).
# EXIT: triggered when the shell exits.
# INT: triggered by Ctrl+C (interrupt).
# TERM: triggered by a 'kill' command (terminate).
# Always double-quote the variable in trap to handle potential spaces, even if mktemp won't create them.
trap 'rm -f "$TMP_FILE"' EXIT INT TERM


# --- Now, do your actual work with the temporary file ---


echo "Some important data line 1" > "$TMP_FILE"
echo "Some important data line 2" >> "$TMP_FILE"


echo "Sleeping for 3 seconds to simulate complex operations..."
sleep 3


echo "Content of temporary file:"
cat "$TMP_FILE"


# If you needed a temporary directory, you'd use mktemp -d
# TMP_DIR=$(mktemp -d)
# trap 'rm -rf "$TMP_DIR"' EXIT INT TERM


echo "Script finished. The temp file will now be removed by the trap."

Notice that `trap` command in the example. That’s the other half of the battle. Creating a unique temp file is great, but ensuring it gets cleaned up is equally important. By setting a `trap` for `EXIT`, `INT`, and `TERM` signals, you ensure that no matter how your script ends — successfully, manually interrupted by Ctrl+C, or killed by an external signal — your temporary file (or directory, if you used `mktemp -d`) is removed. I usually put my `trap` right after `mktemp` so cleanup is configured as early as possible. For directories, remember `rm -rf` to recursively delete everything inside. And always, *always* double-quote your variables in `rm` commands, especially when dealing with paths, to avoid word splitting issues.

  • Always use `mktemp` for creating temporary files and directories. Seriously, it’s not optional.
  • Ensure your `mktemp` call has error handling, as it can fail, especially if `TMPDIR` isn’t writable.
  • Use `trap ‘rm -f “$VAR”‘ EXIT INT TERM` (or `rm -rf` for directories) immediately after creating the temporary resource.
  • Consider using `–tmpdir` with `mktemp` if you need your temporary files in a specific location other than the default (`/tmp` or `TMPDIR`).
  • The default permissions `mktemp` uses (`0600` for files, `0700` for directories) are usually appropriate for security, limiting access to the owner.

This isn’t just about good practice; it’s about reliability and security in your automation. Small scripts grow into critical infrastructure, and these simple patterns prevent nasty surprises when they’re running under load or in a compromised environment. Knowing `mktemp` and properly using `trap` will save you from some infuriating debugging sessions and potential security audits down the road. It’s a fundamental shell-scripting skill that too many people skip.

Linux Admin Automation  |  © www.ngelinux.com  |  10/5/2026

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Newest
Oldest Most Voted