# mktemp — Safe Temporary Files and Directories

> Create unique temporary files and directories safely. Avoids race conditions and predictable names by generating a random suffix. Essential for shell scripts that need scratch space. Syntax differs between GNU coreutils (Linux) and BSD (macOS).

Source: https://www.jpkc.com/db/en/cheatsheets/files-text/mktemp/

<!-- PROSE:intro -->
mktemp creates temporary files and directories with a guaranteed-unique name, solving a real security problem: predictable names like `/tmp/$$.tmp` invite symlink attacks and race conditions, because an attacker can guess the name and plant a trap in /tmp ahead of time. Instead, mktemp generates a random suffix, creates the file atomically with mode 600 (directories with 700), and hands you back the path. Use `-d` to get a directory instead of a file. This guide covers the basics, templates, the differences between GNU (Linux) and BSD (macOS), and the indispensable cleanup with `trap`.
<!-- PROSE:intro:end -->

## Basic Usage

`mktemp` — Create a unique temporary file in $TMPDIR (or /tmp). Returns the full path on stdout.

```bash
mktemp
# /tmp/tmp.A3kLp9
```

`mktemp -d` — Create a unique temporary directory instead of a file.

```bash
mktemp -d
# /tmp/tmp.xY7qZ2
```

`<var>=$(mktemp)` — Capture the path into a shell variable for later use.

```bash
tmp=$(mktemp)
echo "log data" > "$tmp"
```

`<var>=$(mktemp -d)` — Capture a fresh temp directory path into a variable.

```bash
workdir=$(mktemp -d)
cd "$workdir"
```

`mktemp --help` — Show all available options with short descriptions.

```bash
mktemp --help
```

## Templates (XXX Placeholders)

`mktemp <template>` — Use a custom name template. The trailing X characters (at least 3) are replaced with random characters.

```bash
mktemp mydata.XXXXXX
# mydata.k7Bq2p
```

`mktemp <prefix>.XXXXXXXXXX` — More X characters means more entropy and lower collision probability. 10+ recommended for long-lived files.

```bash
mktemp build.XXXXXXXXXX
# build.Hf3k9pXw2L
```

`mktemp -d <template>` — Create a directory using a custom template.

```bash
mktemp -d myapp-XXXXXX
# myapp-9bTq2K
```

`mktemp --suffix=<ext> <template>` — Append a suffix after the random part. Useful for files that need a specific extension. GNU coreutils only.

```bash
mktemp --suffix=.json data.XXXXXX
# data.k7Bq2p.json
```

`mktemp <prefix>XXXXXX<suffix>` — BSD/macOS alternative: place XXX in the middle of the name for a literal suffix.

```bash
mktemp build-XXXXXX.tar.gz
# build-k7Bq2p.tar.gz
```

## Directory Options

`mktemp -p <dir>` — Create the temp file/directory inside <dir> instead of $TMPDIR. GNU coreutils.

```bash
mktemp -p /var/tmp
# /var/tmp/tmp.A3kLp9
```

`mktemp --tmpdir=<dir> <template>` — Long form of -p. Combine with a template.

```bash
mktemp --tmpdir=/var/cache app.XXXXXX
```

`mktemp -t <template>` — Place the file in $TMPDIR (or a system default). Behaviour differs: on Linux -t is mostly a legacy alias; on BSD/macOS it is commonly used to set the prefix.

```bash
mktemp -t myapp
```

`TMPDIR=<dir> mktemp` — Override the default temp directory via environment variable for a single command.

```bash
TMPDIR=/fast/ssd mktemp -d
```

`mktemp -p "" <template>` — Force relative placement: create in the current working directory instead of $TMPDIR.

```bash
mktemp -p "" cache-XXXXXX
```

## Other Flags

`mktemp -u` — Dry run: print a unique name without creating the file. UNSAFE — the name may be taken by another process before you use it. Avoid for real work.

```bash
mktemp -u
# /tmp/tmp.A3kLp9 (not created)
```

`mktemp --dry-run` — Long form of -u. Same warning applies: only safe for preview purposes.

```bash
mktemp --dry-run --suffix=.log test.XXXXXX
```

`mktemp -q` — Quiet mode. Suppress error messages if creation fails. Useful in scripts with custom error handling.

```bash
tmp=$(mktemp -q) || exit 1
```

`mktemp --version` — Show the installed mktemp version. On Linux this tells you the coreutils release; on macOS it reports the BSD build.

```bash
mktemp --version
```

## GNU (Linux) vs BSD (macOS)

`mktemp (portable)` — Plain form with no template works on both GNU and BSD. Safest default if you do not need a custom prefix.

```bash
tmp=$(mktemp) || exit 1
```

`mktemp -t <prefix>` — GNU: prefix is optional; path goes to $TMPDIR. BSD/macOS: -t REQUIRES a prefix and inserts it before the random suffix.

```bash
# macOS:
mktemp -t myapp
# /var/folders/.../myapp.XXXXXX
```

`mktemp <prefix>.XXXXXX` — Template form works on both. Must contain at least 3 X's at the END of the filename component on BSD (suffix via explicit characters after XXXXXX).

```bash
mktemp app.XXXXXX       # both
mktemp app-XXXXXX.log  # BSD ok, GNU needs --suffix
```

`mktemp --suffix=.ext` — GNU only. BSD/macOS does NOT support --suffix. For cross-platform scripts use an inline suffix: prefix-XXXXXX.ext.

```bash
# Linux only:
mktemp --suffix=.sql dump.XXXXXX
```

`mktemp -p <dir>` — GNU only. BSD does not support -p. For cross-platform scripts pass the directory inside the template or set TMPDIR.

```bash
# Portable:
TMPDIR=/var/tmp mktemp
```

## Cleanup Patterns (trap)

`trap 'rm -f "$tmp"' EXIT` — Remove a temp file when the script exits — normally, on error, or on Ctrl+C. Set the trap right after creating the file.

```bash
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXIT
```

`trap 'rm -rf "$dir"' EXIT` — Recursive cleanup for a temp directory. Use -rf because the dir will usually contain files by the time the trap fires.

```bash
dir=$(mktemp -d) || exit 1
trap 'rm -rf "$dir"' EXIT
```

`cleanup() { rm -rf "$dir"; }; trap cleanup EXIT` — Use a function for more complex cleanup (close fds, kill background jobs, unmount loop devices, then remove the dir).

```bash
cleanup() {
  [[ -n $pid ]] && kill $pid 2>/dev/null
  rm -rf "$dir"
}
trap cleanup EXIT
```

`trap '...' EXIT INT TERM HUP` — Also clean up on common signals. EXIT alone is enough in bash (EXIT fires after signals too), but explicit signals help in POSIX sh.

```bash
trap 'rm -rf "$dir"' EXIT INT TERM HUP
```

`tmp=$(mktemp) || { echo "mktemp failed" >&2; exit 1; }` — Always check that mktemp succeeded before trusting the variable. Failure is rare but possible (full disk, bad permissions).

```bash
tmp=$(mktemp) || { echo "mktemp failed" >&2; exit 1; }
trap 'rm -f "$tmp"' EXIT
```

## Common Use Cases

`Scratch file for command output` — Capture output for later processing without risking a name collision in /tmp.

```bash
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
curl -s https://example.com > "$tmp"
grep -c "<h1>" "$tmp"
```

`Atomic file replacement` — Write to a temp file in the same directory, then rename on top of the target. Rename is atomic on the same filesystem.

```bash
tmp=$(mktemp -p "$(dirname "$target")")
./generate > "$tmp" && mv "$tmp" "$target"
```

`Sorted/deduplicated edit in place` — sort -o / sed -i exist, but mktemp gives you the pattern for tools that lack in-place support.

```bash
tmp=$(mktemp)
sort -u input.txt > "$tmp" && mv "$tmp" input.txt
```

`Temp workspace for extraction` — Unpack an archive in an isolated directory, inspect it, then clean up automatically.

```bash
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
tar -xzf archive.tar.gz -C "$dir"
find "$dir" -name '*.conf'
```

`Named pipe alternative via temp file` — Pass two command outputs to a tool that expects two files (diff, cmp, comm).

```bash
a=$(mktemp); b=$(mktemp)
trap 'rm -f "$a" "$b"' EXIT
curl -s url1 > "$a"
curl -s url2 > "$b"
diff "$a" "$b"
```

`Temporary named pipe (FIFO)` — mktemp creates a regular file; for a FIFO, create a temp DIR with mktemp -d, then mkfifo inside it.

```bash
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
mkfifo "$dir/pipe"
producer > "$dir/pipe" &
consumer < "$dir/pipe"
```

## Security & Gotchas

`Default mode is 0600 (600)` — mktemp creates files with mode 600 (rw for owner only) and directories with 700. This is the main reason to use mktemp over ad-hoc /tmp/$$ patterns.

```bash
stat -c %a "$(mktemp)"
# 600
```

`Never use /tmp/$$.<name>` — PID-based names are predictable. An attacker can create symlinks in /tmp that your script will follow and overwrite. Use mktemp to get an unguessable name.

```bash
# BAD:  /tmp/mydata.$$
# GOOD: $(mktemp mydata.XXXXXX)
```

`Avoid -u / --dry-run for real files` — -u only prints a name; a TOCTOU race window exists between 'print' and 'create'. If you must use -u, understand the risk.

```bash
# Race condition:
name=$(mktemp -u)
# ... attacker creates $name as a symlink ...
echo data > "$name"   # follows symlink
```

`Always quote the variable` — Paths may contain spaces (especially on macOS where /var/folders/.../ is used). Unquoted expansion will break.

```bash
# GOOD:
rm -f "$tmp"
# BAD:
rm -f $tmp   # breaks on space
```

`Clean up on early exit` — Without a trap, aborted scripts leak files that may never be deleted (/tmp is cleared on reboot, /var/tmp is NOT).

```bash
# Without trap, Ctrl+C leaves $tmp behind:
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXIT
```

`Mind filesystem boundaries for atomic mv` — mv is only atomic when source and target are on the SAME filesystem. Place the temp file in the same directory as the target when doing atomic replacement.

```bash
# Same filesystem as target:
tmp=$(mktemp -p "$(dirname "$target")")
```

<!-- PROSE:outro -->
## Conclusion

mktemp is a security tool, not just a convenience: it replaces the error-prone, predictable /tmp/$$ patterns with unguessable names, creates files atomically with mode 600, and thereby closes off symlink and TOCTOU attacks in shared directories. Remember three rules: always check the return value (`|| exit 1`), set a `trap` for cleanup immediately afterwards, and quote the variable on every use. Use `-d` for a directory; for cross-platform scripts, mind the differences between GNU and BSD (no `-p`/`--suffix` on macOS) and avoid `-u`/`--dry-run` for real files.

## Further Reading

- [GNU coreutils: mktemp invocation](https://www.gnu.org/software/coreutils/manual/html_node/mktemp-invocation.html) – official reference for every option
- [Linux man page: mktemp(1)](https://man7.org/linux/man-pages/man1/mktemp.1.html) – the canonical manual page
<!-- PROSE:outro:end -->

## Related Commands

- [touch](https://www.jpkc.com/db/en/cheatsheets/files-text/touch/) – create empty files and set timestamps
- [mkdir](https://www.jpkc.com/db/en/cheatsheets/files-text/mkdir/) – create directories (also via mktemp -d)
- [mv](https://www.jpkc.com/db/en/cheatsheets/files-text/mv/) – move files for atomic replacement

