Fix or alternative for mktemp in OS X
The following is what I ended up using to reliably create a temporary directory that works on both Linux and Darwin (all versions before Mac OS X 10.11), without hardcoding $TMPDIR
or /tmp
:
mytmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
Background:
The GNU mktemp command requires no arguments. Plain mktemp
will work and creates a temporary file in the system's temporary directory.
Plain mktemp -d
will create a directory instead of a file, which is what you'd want to use on Linux.
(gnu-coreutils)$ man mktemp
> ..
> If DIR is not specified, uses $TMPDIR if set, else /tmp.
> ..
By default, GNU mktemp uses the template tmp.XXXXXXXXXX
for the name of the sub directory (or file). To customise this template, the -t
option can be used.
OSX's mktemp has no default template and requires a template to be specified. Unfortunately, where GNU mktemp takes the template as -t
option, on OSX this is passed as positional argument. Instead, OSX's mktemp has a -t
option that means something else. The -t
option on OSX is documented as a "prefix" for the template. It is expanded to {prefix}.XXXXXXXX
, so it adds the Xs to it automatically (e.g. mktemp -d -t example
could create example.zEJZWCTQ
in the temp directory).
I was surprised to find that in many Linux environments, $TMPDIR
is not set by default. Many CLI programs do support it when set, but still need a default for /tmp
. This means passing $TMPDIR/example.XXXXXXXX
to mktemp or mkdir is dangerous because it may produce /example.XXXXXXXX
in the root directory of the local disk (due to $TMPDIR being unset and becoming an empty string).
On OSX, $TMPDIR
is always set and (at least in the default shell) it is not set to /tmp
(which is a symlink to /private/tmp
) but to /var/folders/dx/*****_*************/T
. So whatever we do for OSX, should honour that default behaviour.
In conclusion, the following is what I ended up using to reliably create a temporary directory that works on both Linux and Darwin (Mac OS X), without hardcoding either $TMPDIR
or /tmp
:
mytmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
The first part is for Linux. This command will fail on Darwin (Mac OS X) with error status code 1
responding with "usage: ...". That's why we ignore stderr and instead then execute the Mac variant. The mytmpdir
prefix is only used on Mac (where that option is required to be set).
You have to supply a template. mktemp -d /tmp/foo.XXXX
should work. I've never seen --directory
. The --
suggests that it is a GNU extension.
Change --directory
to -d
. The former is a GNU-ism, but GNU mktemp
from coreutils also supports -d
. The mktemp
in OS X is the same as from BSD, so -d
should be pretty portable among systems that actually ship a mktemp
program.