Creating temporary files in bash

LinuxBashUnix

Linux Problem Overview


Are there objectively better ways to create temporary files in bash scripts?

I normally just name them whatever comes to my mind, such as tempfile-123, since it will be deleted when the script is over. Is there any disadvantage in doing this other than overwriting a possible tempfile-123 in current folder? Or is there any advantage in creating a temporary file in a more careful way?

Linux Solutions


Solution 1 - Linux

The mktemp(1) man page explains it fairly well:

> Traditionally, many shell scripts take the name of the program with > the pid as a suffix and use that as a temporary file name. This kind > of naming scheme is predictable and the race condition it creates is > easy for an attacker to win. A safer, though still inferior, approach > is to make a temporary directory using the same naming scheme. While > this does allow one to guarantee that a temporary file will not be > subverted, it still allows a simple denial of service attack. For > these reasons it is suggested that mktemp be used instead.

In a script, I invoke mktemp something like

mydir=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")

which creates a temporary directory I can work in, and in which I can safely name the actual files something readable and useful.

mktemp is not standard, but it does exist on many platforms. The "X"s will generally get converted into some randomness, and more will probably be more random; however, some systems (busybox ash, for one) limit this randomness more significantly than others


By the way, safe creation of temporary files is important for more than just shell scripting. That's why python has tempfile, perl has File::Temp, ruby has Tempfile, etc…

Solution 2 - Linux

Yes, use mktemp.

It will create a temporary file inside a folder that is designed for storing temporary files, and it will guarantee you a unique name. It outputs the name of that file:

> mktemp
/tmp/tmp.xx4mM3ePQY
>

Solution 3 - Linux

You might want to look at mktemp

> The mktemp utility takes the given filename template and overwrites a portion of it to create a unique filename. The template may be any filename with some number of 'Xs' appended to it, for example /tmp/tfile.XXXXXXXXXX. The trailing 'Xs' are replaced with a combination of the current process number and random letters.

For more details: man mktemp

Solution 4 - Linux

> Is there any advantage in creating a temporary file in a more careful way

The temporary files are usually created in the temporary directory (such as /tmp) where all other users and processes has read and write access (any other script can create the new files there). Therefore the script should be careful about creating the files such as using with the right permissions (e.g. read only for the owner, see: help umask) and filename should be be not easily guessed (ideally random). Otherwise if the filenames aren't unique, it can create conflict with the same script ran multiple times (e.g. race condition) or some attacker could either hijack some sensitive information (e.g. when permissions are too open and filename is easy to guess) or create/replacing the file with their own version of the code (like replacing the commands or SQL queries depending on what is being stored).


You could use the following approach to create the temporary directory:

TMPDIR=".${0##*/}-$$" && mkdir -v "$TMPDIR"

or temporary file:

TMPFILE=".${0##*/}-$$" && touch "$TMPFILE"

However it is still predictable and not considered safe.

As per man mktemp, we can read:

> Traditionally, many shell scripts take the name of the program with the pid as a suffix and use that as a temporary file name. This kind of naming scheme is predictable and the race condition it creates is easy for an attacker to win.

So to be safe, it is recommended to use mktemp command to create unique temporary file or directory (-d).

Solution 5 - Linux

mktemp is probably the most versatile, especially if you plan to work with the file for a while.

You can also use a process substitution operator <() if you only need the file temporarily as input to another command, e.g.:

$ diff <(echo hello world) <(echo foo bar)

Solution 6 - Linux

The mktemp docs have some nice examples.

If you require a certain suffix (file extension) for your temporary file. You can do the following

$ myfile=$(mktemp --suffix ".txt")
$ echo "$myfile"
/tmp/tmp.9T9soL2QNp.txt

If you don't want the file to be created, but just want a name, you can additionally use the -u/--dry-run flag.

$ myfile=$(mktemp -u --suffix ".txt")
$ echo "$myfile"
/tmp/tmp.Y8cMDJ1DDr.txt

BUT NOTE, when using -u/--dry-run

> Using the output of this command to create a new file is inherently unsafe, as there is a window of time between generating the name and using it where another process can create an object by the same name.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStrapakowskyView Question on Stackoverflow
Solution 1 - LinuxkojiroView Answer on Stackoverflow
Solution 2 - LinuxPaulView Answer on Stackoverflow
Solution 3 - LinuxJohn LawrenceView Answer on Stackoverflow
Solution 4 - LinuxkenorbView Answer on Stackoverflow
Solution 5 - LinuxBarry JonesView Answer on Stackoverflow
Solution 6 - LinuxMichael HallView Answer on Stackoverflow