Michael Federczuk
Michael Federczuk

Reputation: 73

POSIX sh: Best solution to create a unique temporary directory

Currently, the only POSIX compliant way of creating a unique directory (that I know) is by creating a unique file using the mkstemp() function exposed by m4 and then replacing this file with a directory:

tmpdir="$(printf "mkstemp(tmp.)" | m4)"
unlink "$tmpdir"
mkdir "$tmpdir"

This seems rather hacky though, and I also don't know how safe/secure it is.
Is there better/more direct POSIX compliant way to create a unique temporary directory in shellscript, or is this as good as it gets?

The mktemp command is out of the question because it is not defined in POSIX.

Upvotes: 1

Views: 323

Answers (1)

jhnc
jhnc

Reputation: 16642

I'd expect using unlink/mkdir to be statistically safe as the window of opportunity for another process to create the directory is likely to be small. But a simple fix is just to retry on failure:

while
    tmpdir="$(printf "mkstemp(tmp.)" | m4)"
    unlink "$tmpdir"
    ! mkdir "$tmpdir"
do : ; done

Similarly, we could simply attempt to create a directory directly without creating a file first. Directory creation is atomic so there is no race condition. We do have to pick a name that doesn't exist but, as above, if we fail we can just try again.

For example, using a simple random number generator:

mkdtemp.sh

#!/bin/sh

# initial entropy, the more we can get the better 
random=$(( $(date +%s) + $$ ))

while
    # C standard rand(), without truncation
    # cf. https://en.wikipedia.org/wiki/Linear_congruential_generator
    random=$(( (1103515245*random + 12345) % 2147483648 ))

    # optionally, shorten name a bit
    tmpdir=$( printf "tmp.%x" $random )

    # loop until new directory is created
    ! mkdir $tmpdir 2>&-
do : ; done

printf %s "$tmpdir"

Notes:

Upvotes: 1

Related Questions