27

I'm writing a shell script, and I need to create a temporary file with a certain extension.

I've tried

tempname=`basename $0`
TMPPS=`mktemp /tmp/${tempname}.XXXXXX.ps` || exit 1

and

tempname=`basename $0`
TMPPS=`mktemp -t ${tempname}` || exit 1

neither work, as the first creates a file name with a literal "XXXXXX" and the second doesn't give an option for an extension.

I need the extension so that preview won't refuse to open the file.

Edit: I ended up going with a combination of pid and mktemp in what I hope is secure:

tempname=`basename $0`
TMPTMP=`mktemp -t ${tempname}` || exit 1
TMPPS="$TMPTMP.$$.ps" 
mv $TMPTMP $TMPPS || exit 1

It is vulnerable to a denial of service attack, but I don't think anything more severe.

cobbal
  • 69,903
  • 20
  • 143
  • 156

8 Answers8

18

Recent versions of mktemp offer --suffix:

   --suffix=SUFF
          append SUFF to TEMPLATE.  SUFF must not contain slash.  This option is implied if TEMPLATE does not end in X.

$ mktemp /tmp/banana.XXXXXXXXXXXXXXXXXXXXXXX.mp3
/tmp/banana.gZHvMJfDHc2CTilINNuq2P0.mp3

I believe this requires coreutils >= 8 or so.

If you create a temp file (older mktemp version) without suffix and you're renaming that to append one, the least thing you could probably do is check if the file already exists. It doesn't protect you from race conditions, but it does protect you if there's already such a file which has been there for a while.

basic6
  • 3,643
  • 3
  • 42
  • 47
  • 2
    FYI: *BSD* mktemp in Mac OSX does have this option, at least not in 10.11 . – Jokester Jun 08 '16 at 02:18
  • 8
    @Jokester's name is no lie. And by that I mean OSX/macOS does *not* have `--suffix`, still as of 10.12. – Charlie Gorichanaz Apr 27 '17 at 23:06
  • @CharlieGorichanaz My bad. Guess I was trying to write "does not have this option", because I can still recall debugging my script in OSX for this difference :( . – Jokester Apr 28 '17 at 02:39
  • 2
    To future visitors: my first comment is incorrect, please read it as "BSD mktemp does *not* have this option". – Jokester Apr 28 '17 at 02:41
12

All of these solutions except --suffix (which isn't always available) have a race condition. You can eliminate the race condition by using mktemp -d to create a directory, then putting your file in there.

mydir=`mktemp -d`
touch "$mydir"/myfile.ps
Lucas Gonze
  • 575
  • 1
  • 5
  • 13
9

How about this one:

echo $(mktemp $TMPDIR/$(uuidgen).txt)
Stephan
  • 131
  • 2
  • 5
1

MacOS Sierra 10.12 doesn't have --suffix option, so I suggest workaround:

    tempname=`basename $0`
    TMPPS_PREFIX=$(mktemp "${TMPDIR:-/tmp/}${tempname}.XXXXXX")
    TMPPS=$(mktemp "${TMPPS_PREFIX}.ps")
    rm ${TMPPS_PREFIX}
    echo "Your temp file: ${TMPPS}"
  • 1
    Not sure if this would guarantee uniqueness of the generated file name. Suppose the generated prefix is `/tmp/temp.abcdef` but the file `/tmp/temp.abcdef.ps` already exists? – Ajay Brahmakshatriya Dec 05 '19 at 04:20
1

Here's a more portable solution (POSIX-compatible):

temp=$(mktemp -u).ps
: >"$temp"

The first line runs mktemp without creating the file, then sets temp to the generated filename with .ps appended. The second line then creates it; touch "$temp" can be used instead if you prefer it.

EDIT: Note that this doesn't have the same permissions as it creates it using shell redirection. If you need it to be unreadable by other users, you can use chmod to set it manually.

Crestwave
  • 61
  • 2
  • 1
  • Not sure if this would guarantee uniqueness of the generated file name. Suppose the generated prefix is /tmp/temp.abcdef but the file /tmp/temp.abcdef.ps already exists? – Ajay Brahmakshatriya Dec 05 '19 at 04:21
  • Well, yes, `-u` stands for unsafe mode; I should have noted that, sorry. This is more for normal shell scripts that would use something like `${TMPDIR:-/tmp}/$$.ps` otherwise. – Crestwave Dec 06 '19 at 06:59
  • It's not because of the `-u`. Even if you remove that, you are changing the name returned by `mktemp`. All the bets are off – Ajay Brahmakshatriya Dec 06 '19 at 07:48
  • I know, I was saying that it's inherently unsafe and should not be used in situations where such security matters. But for normal purposes, it's unlikely that there would be a collision and you could further strengthen it by adding stuff like the program name or the PID or something. Or test if it exists and regenerate it if it does, maybe. – Crestwave Dec 07 '19 at 07:30
1

For macOS -

brew install coreutils

Then -

gmktemp --suffix=.ps
Josh Unger
  • 6,717
  • 6
  • 33
  • 55
0

On the macOS 13, mktemp still doesn't support --suffix, I rename it after make the file, it seems working fine.

$ tmp=`mktemp -t prefix`

$ mv $tmp $tmp.txt

$ ls $tmp.txt
/var/folders/..../T/prefix.xxxx.txt
Míng
  • 2,500
  • 6
  • 32
  • 48
0

MacOS Ventura 13.1 still doesn't support --suffix. But based on Roman Chernyatchik's answer I'm using an inline solution that I think is the simplest possible:

mktemp "$(mktemp -t $tempname).ps"
Marcelo Barros
  • 930
  • 9
  • 16