Create a Private Temporary File with Debian's tempfile
Debian's tempfile creates a mode 0600 scratch file and hands you the path, no guesswork required. It is from Debianutils 5.17 on this machine, and it is deprecated: reach for mktemp in new scripts, and only use this one to keep an older script running. Allow about ten minutes to work through the examples.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
- Run as an ordinary user. Nothing here needs
sudo. - Use a writable test directory such as
/tmp. Do not put private data in a shared directory with a looser mode. - Have a capable shell. You need command substitution and
trap, whichshandbashboth provide.
Checkpoint
The command prints a pathname, not the file's contents. Keep that pathname in a variable; do not try to reconstruct it from the prefix or suffix.
1. Create the file and inspect it
Run tempfile with no options. It picks a sensible temporary directory, creates the file exclusively, opens it for reading and writing, and prints the resulting path to standard output.
$ path=$(tempfile)
$ status=$?
$ printf 'status=%s path=%s\n' "$status" "$path"
status=0 path=/tmp/fileXXXXXX
$ stat -c 'mode=%a owner=%U path=%n' -- "$path"
mode=600 owner=YOUR-USER path=/tmp/fileXXXXXX
The final name has random characters, so your output will differ. This Debianutils version also writes a deprecation warning to standard error; that does not leak into path, because command substitution only captures standard output.
The default mode is 0600: you can read and write it, and group and other users get nothing. Check the exit status before you trust the variable. If creation fails, path could be empty or stale in a longer-running script.
2. Use a trap so cleanup happens on exit
A temporary file only earns its name if its lifetime is obvious. This script creates one, writes a line, reads it back, and removes it the moment the shell exits. The -- before the path stops a hyphen-prefixed name being read as an option by rm.
#!/bin/sh
path=$(tempfile) || exit 1
trap 'rm -f -- "$path"' EXIT
printf '%s\n' 'temporary data' > "$path"
cat -- "$path"
# The EXIT trap removes the file here.
Expected output:
temporary data
Quoting the substitution, as in path="$(tempfile)", is fine but is not a substitute for checking the status: that check is what stops a script operating on an empty or leftover value. Keep untrusted text out of a trap string, and for anything more complex use a cleanup function instead.
3. Choose the directory, prefix and suffix
Use -d to force a particular writable directory, -p for up to five prefix letters, and -s for a suffix such as .part.
$ path=$(tempfile --directory=/tmp --prefix=job --suffix=.part) || exit 1
$ printf '%s\n' "$path"
/tmp/jobXXXXXX.part
$ stat -c 'mode=%a path=%n' -- "$path"
mode=600 path=/tmp/jobXXXXXX.part
The random portion shown is illustrative. Five letters is the documented ceiling for the prefix, so it is not a reliable place to encode metadata: put anything meaningful in your own variable or the file contents instead.
TMPDIR is a trap waiting to happen. If it names a usable directory, this manpage says it wins over -d. Check it whenever a file shows up somewhere you did not expect:
$ printf 'TMPDIR=%s\n' "${TMPDIR-}"
$ path=$(tempfile --directory=/tmp)
$ printf '%s\n' "$path"
/tmp/fileXXXXXX
For a repeatable script, set TMPDIR on purpose or unset it after checking the environment. A directory is not trustworthy just because it is called /tmp; confirm it is writable and gives you the isolation your data needs.
4. Change the mode only when you mean to
-m changes the mode the file is opened with. This example lets group and other users read it:
$ path=$(tempfile --mode=0644) || exit 1
$ stat -c '%a %n' -- "$path"
644 /tmp/fileXXXXXX
Warning
This is a security-sensitive choice. Anyone who can read the directory entry and file can read what you wrote there, subject to directory permissions and the system's umask. Keep the default 0600 for credentials, tokens, private input and intermediate results. No elevated privilege is needed to pick a mode, and adding sudo just makes ownership and cleanup less predictable.
5. Use an exact name only for a controlled compatibility case
--name=FILE skips generated naming entirely. Supply it and -d, -p and -s are ignored. The file is still opened with exclusive creation, so an existing path errors out rather than silently overwriting it.
$ path=/tmp/my-controlled-input
$ tempfile --name="$path"
WARNING: tempfile is deprecated; consider using mktemp instead.
/tmp/my-controlled-input
$ stat -c 'mode=%a path=%n' -- "$path"
mode=600 path=/tmp/my-controlled-input
Treat an exact name as collision-prone. Never derive it from untrusted input, and never assume a clean-looking result means an old file was replaced. If the path already exists, pick another name or stop and investigate. This is exactly why generated names are the better default.
6. Handle failures and the NFS boundary
Any non-zero exit status means the file was not created. The usual suspects: a missing directory, no write permission, an invalid mode, or a collision with --name. Capture and check the status immediately:
path=$(tempfile --directory=/path/to/your/writable-directory)
if [ "$?" -ne 0 ]; then
printf '%s\n' 'could not create temporary file' >&2
exit 1
fi
trap 'rm -f -- "$path"' EXIT
Swap in a real directory before running that. If you need to diagnose a failure, tempfile --help and tempfile --version both exit successfully and print to standard output, though this build still tacks on the deprecation warning.
Warning
The manpage admits exclusive creation is not guaranteed on NFS. Do not use tempfile as a coordination primitive on an NFS-mounted directory. Prefer a local filesystem, or redesign so correctness does not depend on two processes never picking the same name. It creates files only; it cannot make you a temporary directory.
Done means
- Checked the version. You confirmed the installed command is Debianutils 5.17 and noted its deprecation warning.
- Captured the path. You save the printed pathname and check the exit status before using it.
- Kept the default mode. 0600 stays unless a wider mode is an explicit requirement.
- Accounted for TMPDIR. You checked it before trusting the destination directory.
- Wired up cleanup. A
traprunsrm -f -- "$path"on exit. - Have a migration plan. New code targets
mktempinstead.