While running a script, I want to create a temporary file in /tmp directory.

After execution of that script, that will be cleaned by that script.

How to do that in shell script?

7 Answers 7

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.

# create temporary file
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)

# create file descriptor 3 for writing to a temporary file so that
# echo ... >&3 writes to that file
exec 3>"$tmpfile"

# create file descriptor 4 for reading from the same file so that
# the file seek positions for reading and writing can be different
exec 4<"$tmpfile"

# delete temp file; the directory entry is deleted at once; the reference counter
# of the inode is decremented only after the file descriptor has been closed.
# The file content blocks are deallocated (this is the real deletion) when the
# reference counter drops to zero.
rm "$tmpfile"

# your script continues
: ...

# example of writing to file descriptor
echo foo >&3

# your script continues
: ...

# reading from that file descriptor
head -n 1 <&4

# close the file descriptor (done automatically when script exits)
# see section 2.7.6 of the POSIX definition of the Shell Command Language
exec 3>&-
  • 9
    Good answer, elegant solution with the file descriptor in case of a crash +1
    – chaos
    Commented Jan 30, 2015 at 7:29
  • 7
    what does the exec 3> "$tmpfile" do? Isn't that only useful if the tmpfile is a stand-alone script? Commented Nov 29, 2016 at 18:36
  • 8
    How do you read from the created FD?
    – eckes
    Commented Apr 7, 2017 at 9:37
  • 7
    " You can use cat <3 or something similar." actually that reads from a file named 3 @dragon788. Also, cat <&3 will give Bad file descriptor. I'd appreciate it if you either fix it or remove it; misinformation doesn't much help.
    – erik258
    Commented Feb 21, 2019 at 5:24
  • 4
    @HaukeLaging will you update this to show how to read from the file descriptor? Automatically deleting a file you write to and don't read from isn't much good.
    – erik258
    Commented Feb 21, 2019 at 6:13

Use mktemp to create a temporary file. The utility returns the full path of the created file.


Or, to create a temporary directory:

temp_dir=$(mktemp -d)

At the end of the script, you may want to delete the temporary file or directory:

rm "${temp_file}"
rm -r "${temp_dir}"

Note: mktemp creates a file in the /tmp directory or in the directory given with the --tmpdir argument. See the utility's manual for other options and how to modify its behaviour in other ways.

  • 51
    You can use trap "rm -f $temp_file" 0 2 3 15 right after creating the file so that when the script exits or is stopped with ctrl-C the file is still removed.
    – wurtel
    Commented Jan 30, 2015 at 7:27
  • 3
    @wurtel What happens if EXIT is the only hook for trap? Commented Jan 30, 2015 at 7:41
  • 4
    @HaukeLaging Then the trap doesn't fire if the script is stopped with Ctrl+C. A thing to note is that TRAP doesn't help if you kill -9 $somepid. That particular kill signal is insta-death with nothing else happening.
    – dragon788
    Commented Jul 21, 2017 at 22:08
  • 7
    @dragon788 Have you tried that? You should. bash -c 'echo $$; trap "echo foo" 0; sleep 5' Commented Aug 5, 2017 at 6:22
  • 29
    For those wondering, the trailing integers in trap "rm -f $temp_file" 0 2 3 15 are the signals upon which to run the first argument. 0: exit shell, 2: Interrupt, 3: Quit, 15: Terminate.
    – ijoseph
    Commented May 23, 2020 at 18:41

Some shells have the feature built-in.


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)}
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0

That file is automatically removed, once the command has finished.

bash/zsh on Linux.

Here-documents or here-strings in bash versions prior to 5.1 and zsh are implemented as deleted temporary files (as was the case in the Bourne shell which introduced here-documents in the late 70s).

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.0, you'd first to need to restore write permissions to it (which bash explicitly removes in that version):

$ exec 3<<< test
$ cat <&3
$ chmod u+w /dev/fd/3 # only needed in bash 5.0
$ echo foo > /dev/fd/3
$ cat /dev/fd/3

(some other shells use pipes, or may use /dev/null if the here doc is empty).


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:

  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:

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

  • 2
    Bash also has process substitution using <() Commented Jan 30, 2015 at 20:45
  • 5
    @WinnieNicklaus, yes, but that doesn't use temporary files so is irrelevant here. Process substitution was introduced by ksh, copied by bash and zsh, and zsh extended it with a 3rd form: =(...). Commented Jan 30, 2015 at 21:01

If you're on system which has mktemp, you should use it as other answers.

With POSIX toolchest:

umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"
  • What happens if EXIT is the only hook for trap? Commented Jan 30, 2015 at 7:40
  • @HaukeLaging: tmpfile still be removed before script exit, but not when script received other signals.
    – cuonglm
    Commented Jan 30, 2015 at 8:00
  • That's not what happens here (GNU bash, Version 4.2.53). Commented Jan 30, 2015 at 8:03
  • 1
    @HaukeLaging: What do you mean That's not what happens?
    – cuonglm
    Commented Jan 30, 2015 at 8:05
  • 4
    mktemp originated in HP/UX with a different syntax. Todd C. Miller created a different one for OpenBSD in the mid-90s (copied by FreeBSD and NetBSD) and later made it also available as a standalone utility (www.mktemp.org). That's the one that was typically used on Linux until a (mostly compatible) mktemp utility was added to the GNU coreutils in 2007. Just to say one cannot really say mktemp is a GNU utility. Commented Jan 30, 2015 at 22:01

Here is a little bit improved answer in the line of Hauke Laging's:


tmpfile=$(mktemp)  # Create a temporal file in the default temporal folder of the system

# Lets do some magic for the tmpfile to be removed when this script ends, even if it crashes
exec {FD_W}>"$tmpfile"  # Create file descriptor for writing, using first number available
exec {FD_R}<"$tmpfile"  # Create file descriptor for reading, using first number available
rm "$tmpfile"  # Delete the file, but file descriptors keep available for this script

# Now it is possible to work with the temporal file
echo foo >&$FD_W
echo bar >&$FD_W  # Note that file descriptor always concatenates, not overwrites

cat <&$FD_R
  • 4
    It should be noted that the content is available only once. I.e. if I do cat <&$FD_R for the second time, no output is produced. See unix.stackexchange.com/questions/166482/…. Is there any way to have the file automatically deleted if the program crashes, but making it accessible multiple times?
    – smihael
    Commented Aug 24, 2017 at 22:09
  • 1
    @smihael You can simply create a second exec {FD_R2}<"$tmpfile" before the call to rm "$tmpfile" Then, to read it first time, use cat <&$FD_R. And, to read it the second time, use cat <&$FD_R2. To generalize, if you need to read it n times, you can create n read file descriptors.
    – Gino
    Commented Apr 21, 2021 at 4:13

My workflow typically with temp files is because of some bash script I'm testing. I want to tee it up so I can see that it's working and save the output for the next iteration of my process. I've created a file called tmp

echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))

so that I can use it like

$ some_command --with --lots --of --stuff | tee $(tmp)

The reason I like the datetime formatted before the random values is it allows me to find the tmp file that I just made easily, and I don't have to think about what to name it next time (and focus on just getting my dang script to work).


If you want your solution to work with a pure POSIX shell, it's a little tricky, because POSIX doesn't have a mktemp. See Why is there no mktemp command in POSIX? for more information.

However, here is a work-around solution for POSIX shell that doesn't require m4 and implements at least basic mktemp as well as the -d/--directory option to create temporary folders as well:

mktemp() (
    for option; do
        case $option in
            -d|--directory) create=d;;
            *) printf %s\\n "$0: unknown option '$option'" >&2; exit 1;;
    set -o noclobber
    exec 2>/dev/null
    while :; do
        tmpname="$TMPDIR/tmp.$(</dev/urandom tr -dc "[:alnum:]" | dd bs=1 count=10 2>/dev/null)"
        case $create in
            f) umask 0177; printf "" >"$tmpname";;
            d) umask 0077; mkdir "$tmpname";;
        esac && break
    printf %s\\n "$tmpname"

Of course, it would be possible to further extend this function with option parsing via getopts, for example, to add support for templates etc.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .