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).