How create a temporary file in shell script?
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"
You can make sure that a file is deleted when the scripts exits (including kills and crashes) by opening a file descriptor to the file and deleting it. The file keeps available (for the script; not really for other processes but /proc/$PID/fd/$FD
is a work-around) as long as the file descriptor is open. When it gets closed (which the kernel does automatically when the process exits) the filesystem deletes the file.
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3
Use mktemp
to create a temporary file
temp_file=$(mktemp)
or, to create a temporary directory:
temp_dir=$(mktemp -d)
At the end of the script you have to delete the temporary file or directory
rm ${temp_file}
rm -R ${temp_dir}
mktemp
creates file in the /tmp
directory or in the directory given with the --tmpdir
argument.
Some shells have the feature built-in.
zsh
zsh
's =(...)
form of process substitution uses a temporary file. For instance =(echo test)
expands to the path of a temporary file that contains test\n
.
$ {cat $file; ls -l /dev/fd/3; echo test2 >&3; cat $file} 3<> ${file::==(echo test)}
test
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0
test2
That file is automatically removed, once the command has finished.
bash/zsh on Linux.
Here-files or here-strings in bash
and zsh
are implemented as deleted temporary files.
So if you do:
exec 3<<< test
The file descriptor 3 is connected to a deleted temporary file that contains test\n
.
You can get its content with:
cat <&3
If on Linux, you can also read or write to that file via /dev/fd/3
, though with bash version 5 and above, you'd first to need to restore write permissions to it (which bash now explicitly removes):
$ exec 3<<< test
$ cat <&3
test
$ chmod u+w /dev/fd/3 # only needed in bash 5+
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo
(some other shells use pipes, or may use /dev/null
if the here doc is empty).
POSIX
There is no mktemp
POSIX utility. POSIX however specifies a mkstemp(template)
C API, and the m4
standard utility exposes that API with the mkstemp()
m4 function by the same name.
mkstemp()
gives you a file name with a random part that was guaranteed not to exist at the time the function was called. It does create the file with permissions 0600 in a race-free way.
So, you could do:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
Note however that you need to handle the clean-up upon exit, though if you only need to write and read the file a fixed number of times, you could open it and delete it just after creating like for the here-doc/here-string approach above:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
# open once for writing, twice for reading:
exec 3> "$tempfile" 4< "$tempfile" 5< "$tempfile"
rm -f -- "$tmpfile"
cmd >&3 # store something in the temp file
exec 3>&- # fd no longer needed
# read the content twice:
cat <&4
cat <&5
You could open the file for reading once, and rewind in between two reads, however there's no POSIX utility that can do that rewinding (lseek()
), so you can't do it portably in a POSIX script (zsh
(sysseek
builtin) and ksh93
(<#((...))
operator) can do it though).