# mktemp — Sichere temporäre Dateien und Verzeichnisse

> Praxis-Guide zu mktemp: temporäre Dateien und Verzeichnisse mit eindeutigem Namen anlegen, Race-Conditions vermeiden und sauber per trap aufräumen.

Source: https://www.jpkc.com/db/cheatsheets/files-text/mktemp/

<!-- PROSE:intro -->
mktemp legt temporäre Dateien und Verzeichnisse mit garantiert eindeutigem Namen an und löst damit ein echtes Sicherheitsproblem: Vorhersagbare Namen wie `/tmp/$$.tmp` laden zu Symlink-Angriffen und Race-Conditions ein, weil ein Angreifer den Namen erraten und vorab eine Falle in /tmp platzieren kann. mktemp erzeugt stattdessen einen zufälligen Suffix, legt die Datei atomar mit Modus 600 (Verzeichnisse mit 700) an und gibt dir den Pfad zurück. Mit `-d` bekommst du ein Verzeichnis statt einer Datei. Dieser Guide zeigt dir die Grundlagen, Vorlagen, die Unterschiede zwischen GNU (Linux) und BSD (macOS) sowie das unverzichtbare Aufräumen per `trap`.
<!-- PROSE:intro:end -->

## Grundlagen

`mktemp` — Erstellt eine eindeutige temporäre Datei in $TMPDIR (oder /tmp). Gibt den vollen Pfad auf stdout zurück.

```bash
mktemp
# /tmp/tmp.A3kLp9
```

`mktemp -d` — Erstellt ein eindeutiges temporäres Verzeichnis statt einer Datei.

```bash
mktemp -d
# /tmp/tmp.xY7qZ2
```

`<var>=$(mktemp)` — Speichert den Pfad zur späteren Verwendung in einer Shell-Variablen.

```bash
tmp=$(mktemp)
echo "log data" > "$tmp"
```

`<var>=$(mktemp -d)` — Speichert den Pfad eines frischen Temp-Verzeichnisses in einer Variablen.

```bash
workdir=$(mktemp -d)
cd "$workdir"
```

`mktemp --help` — Zeigt alle verfügbaren Optionen mit Kurzbeschreibung.

```bash
mktemp --help
```

## Vorlagen (XXX-Platzhalter)

`mktemp <template>` — Verwendet eine eigene Namensvorlage. Die abschließenden X (mindestens 3) werden durch Zufallszeichen ersetzt.

```bash
mktemp mydata.XXXXXX
# mydata.k7Bq2p
```

`mktemp <prefix>.XXXXXXXXXX` — Mehr X bedeuten mehr Entropie und geringere Kollisionswahrscheinlichkeit. 10+ für langlebige Dateien empfohlen.

```bash
mktemp build.XXXXXXXXXX
# build.Hf3k9pXw2L
```

`mktemp -d <template>` — Erstellt ein Verzeichnis anhand einer eigenen Vorlage.

```bash
mktemp -d myapp-XXXXXX
# myapp-9bTq2K
```

`mktemp --suffix=<ext> <template>` — Hängt einen Suffix nach dem Zufallsteil an. Nützlich für Dateien, die eine bestimmte Endung brauchen. Nur GNU coreutils.

```bash
mktemp --suffix=.json data.XXXXXX
# data.k7Bq2p.json
```

`mktemp <prefix>XXXXXX<suffix>` — BSD-/macOS-Alternative: XXX in der Mitte des Namens platzieren, um einen festen Suffix zu erhalten.

```bash
mktemp build-XXXXXX.tar.gz
# build-k7Bq2p.tar.gz
```

## Verzeichnis-Optionen

`mktemp -p <dir>` — Erstellt die Temp-Datei bzw. das Verzeichnis in <dir> statt in $TMPDIR. GNU coreutils.

```bash
mktemp -p /var/tmp
# /var/tmp/tmp.A3kLp9
```

`mktemp --tmpdir=<dir> <template>` — Langform von -p. Mit einer Vorlage kombinierbar.

```bash
mktemp --tmpdir=/var/cache app.XXXXXX
```

`mktemp -t <template>` — Legt die Datei in $TMPDIR (oder einem Systemstandard) ab. Verhalten unterscheidet sich: Unter Linux ist -t meist ein veralteter Alias; unter BSD/macOS wird es üblicherweise zum Setzen des Präfixes genutzt.

```bash
mktemp -t myapp
```

`TMPDIR=<dir> mktemp` — Überschreibt das Standard-Temp-Verzeichnis per Umgebungsvariable für einen einzelnen Befehl.

```bash
TMPDIR=/fast/ssd mktemp -d
```

`mktemp -p "" <template>` — Erzwingt relative Platzierung: erstellt im aktuellen Arbeitsverzeichnis statt in $TMPDIR.

```bash
mktemp -p "" cache-XXXXXX
```

## Weitere Optionen

`mktemp -u` — Trockenlauf: gibt einen eindeutigen Namen aus, ohne die Datei anzulegen. UNSICHER – der Name kann von einem anderen Prozess belegt werden, bevor du ihn nutzt. Für echte Arbeit meiden.

```bash
mktemp -u
# /tmp/tmp.A3kLp9 (not created)
```

`mktemp --dry-run` — Langform von -u. Gleiche Warnung: nur zur Vorschau sicher.

```bash
mktemp --dry-run --suffix=.log test.XXXXXX
```

`mktemp -q` — Stiller Modus. Unterdrückt Fehlermeldungen, falls die Erstellung scheitert. Nützlich in Skripten mit eigener Fehlerbehandlung.

```bash
tmp=$(mktemp -q) || exit 1
```

`mktemp --version` — Zeigt die installierte mktemp-Version. Unter Linux verrät das die coreutils-Version; unter macOS meldet es den BSD-Build.

```bash
mktemp --version
```

## GNU (Linux) vs. BSD (macOS)

`mktemp (portabel)` — Schlichte Form ohne Vorlage funktioniert auf GNU und BSD. Sicherste Voreinstellung, wenn du kein eigenes Präfix brauchst.

```bash
tmp=$(mktemp) || exit 1
```

`mktemp -t <prefix>` — GNU: Präfix ist optional; Pfad geht nach $TMPDIR. BSD/macOS: -t ERFORDERT ein Präfix und stellt es dem Zufallssuffix voran.

```bash
# macOS:
mktemp -t myapp
# /var/folders/.../myapp.XXXXXX
```

`mktemp <prefix>.XXXXXX` — Vorlagenform funktioniert auf beiden. Auf BSD müssen mindestens 3 X am ENDE der Namenskomponente stehen (Suffix über explizite Zeichen nach XXXXXX).

```bash
mktemp app.XXXXXX       # both
mktemp app-XXXXXX.log  # BSD ok, GNU needs --suffix
```

`mktemp --suffix=.ext` — Nur GNU. BSD/macOS unterstützt --suffix NICHT. Für plattformübergreifende Skripte einen Inline-Suffix nutzen: prefix-XXXXXX.ext.

```bash
# Linux only:
mktemp --suffix=.sql dump.XXXXXX
```

`mktemp -p <dir>` — Nur GNU. BSD unterstützt -p nicht. Für plattformübergreifende Skripte das Verzeichnis in die Vorlage packen oder TMPDIR setzen.

```bash
# Portable:
TMPDIR=/var/tmp mktemp
```

## Aufräum-Muster (trap)

`trap 'rm -f "$tmp"' EXIT` — Entfernt eine Temp-Datei beim Skriptende – normal, bei Fehler oder bei Strg+C. Den trap direkt nach dem Anlegen der Datei setzen.

```bash
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXIT
```

`trap 'rm -rf "$dir"' EXIT` — Rekursives Aufräumen für ein Temp-Verzeichnis. -rf nutzen, weil das Verzeichnis beim Auslösen des traps meist Dateien enthält.

```bash
dir=$(mktemp -d) || exit 1
trap 'rm -rf "$dir"' EXIT
```

`cleanup() { rm -rf "$dir"; }; trap cleanup EXIT` — Eine Funktion für komplexeres Aufräumen verwenden (Dateideskriptoren schließen, Hintergrundjobs beenden, Loop-Devices aushängen, dann das Verzeichnis entfernen).

```bash
cleanup() {
  [[ -n $pid ]] && kill $pid 2>/dev/null
  rm -rf "$dir"
}
trap cleanup EXIT
```

`trap '...' EXIT INT TERM HUP` — Auch bei gängigen Signalen aufräumen. EXIT allein genügt in der bash (EXIT feuert auch nach Signalen), explizite Signale helfen aber in POSIX-sh.

```bash
trap 'rm -rf "$dir"' EXIT INT TERM HUP
```

`tmp=$(mktemp) || { echo "mktemp failed" >&2; exit 1; }` — Immer prüfen, ob mktemp erfolgreich war, bevor du der Variablen vertraust. Fehler sind selten, aber möglich (volle Platte, falsche Berechtigungen).

```bash
tmp=$(mktemp) || { echo "mktemp failed" >&2; exit 1; }
trap 'rm -f "$tmp"' EXIT
```

## Typische Anwendungsfälle

`Scratch-Datei für Befehlsausgabe` — Ausgabe zur späteren Verarbeitung erfassen, ohne eine Namenskollision in /tmp zu riskieren.

```bash
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
curl -s https://example.com > "$tmp"
grep -c "<h1>" "$tmp"
```

`Atomisches Ersetzen einer Datei` — In eine Temp-Datei im selben Verzeichnis schreiben, dann über das Ziel umbenennen. Das Umbenennen ist im selben Dateisystem atomar.

```bash
tmp=$(mktemp -p "$(dirname "$target")")
./generate > "$tmp" && mv "$tmp" "$target"
```

`Sortieren/Deduplizieren direkt in der Datei` — sort -o / sed -i existieren, aber mktemp liefert das Muster für Werkzeuge ohne In-place-Unterstützung.

```bash
tmp=$(mktemp)
sort -u input.txt > "$tmp" && mv "$tmp" input.txt
```

`Temporärer Arbeitsbereich zum Entpacken` — Ein Archiv in einem isolierten Verzeichnis entpacken, prüfen und danach automatisch aufräumen.

```bash
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
tar -xzf archive.tar.gz -C "$dir"
find "$dir" -name '*.conf'
```

`Alternative zur Named Pipe über Temp-Datei` — Zwei Befehlsausgaben an ein Werkzeug übergeben, das zwei Dateien erwartet (diff, cmp, comm).

```bash
a=$(mktemp); b=$(mktemp)
trap 'rm -f "$a" "$b"' EXIT
curl -s url1 > "$a"
curl -s url2 > "$b"
diff "$a" "$b"
```

`Temporäre Named Pipe (FIFO)` — mktemp erstellt eine reguläre Datei; für ein FIFO ein Temp-Verzeichnis mit mktemp -d anlegen und darin mkfifo aufrufen.

```bash
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
mkfifo "$dir/pipe"
producer > "$dir/pipe" &
consumer < "$dir/pipe"
```

## Sicherheit & Fallstricke

`Standardmodus ist 0600 (600)` — mktemp erstellt Dateien mit Modus 600 (rw nur für den Eigentümer) und Verzeichnisse mit 700. Das ist der Hauptgrund, mktemp gegenüber improvisierten /tmp/$$-Mustern zu bevorzugen.

```bash
stat -c %a "$(mktemp)"
# 600
```

`Niemals /tmp/$$.<name> verwenden` — PID-basierte Namen sind vorhersagbar. Ein Angreifer kann Symlinks in /tmp anlegen, denen dein Skript folgt und die es überschreibt. Mit mktemp einen nicht erratbaren Namen erhalten.

```bash
# BAD:  /tmp/mydata.$$
# GOOD: $(mktemp mydata.XXXXXX)
```

`-u / --dry-run für echte Dateien meiden` — -u gibt nur einen Namen aus; zwischen „ausgeben" und „anlegen" klafft ein TOCTOU-Race-Fenster. Wenn du -u nutzen musst, kenne das Risiko.

```bash
# Race condition:
name=$(mktemp -u)
# ... attacker creates $name as a symlink ...
echo data > "$name"   # follows symlink
```

`Variable immer quoten` — Pfade können Leerzeichen enthalten (besonders auf macOS, wo /var/folders/.../ verwendet wird). Unquotierte Expansion bricht.

```bash
# GOOD:
rm -f "$tmp"
# BAD:
rm -f $tmp   # breaks on space
```

`Bei vorzeitigem Abbruch aufräumen` — Ohne trap hinterlassen abgebrochene Skripte Dateien, die nie gelöscht werden (/tmp wird beim Neustart geleert, /var/tmp NICHT).

```bash
# Without trap, Ctrl+C leaves $tmp behind:
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXIT
```

`Dateisystemgrenzen bei atomarem mv beachten` — mv ist nur atomar, wenn Quelle und Ziel auf demselben Dateisystem liegen. Beim atomaren Ersetzen die Temp-Datei im selben Verzeichnis wie das Ziel anlegen.

```bash
# Same filesystem as target:
tmp=$(mktemp -p "$(dirname "$target")")
```

<!-- PROSE:outro -->
## Fazit

mktemp ist kein Komfort-, sondern ein Sicherheitswerkzeug: Es ersetzt die fehleranfälligen, vorhersagbaren /tmp/$$-Muster durch unratbare Namen, legt Dateien atomar mit Modus 600 an und schließt damit Symlink- und TOCTOU-Angriffe in gemeinsam genutzten Verzeichnissen aus. Merke dir drei Regeln: Prüfe immer den Rückgabewert (`|| exit 1`), setze direkt danach einen `trap` zum Aufräumen, und quote die Variable in jeder Verwendung. Für ein Verzeichnis nimm `-d`, für plattformübergreifende Skripte beachte die Unterschiede zwischen GNU und BSD (kein `-p`/`--suffix` auf macOS) und meide `-u`/`--dry-run` für echte Dateien.

## Weiterführende Links

- [ubuntuusers-Wiki: mktemp](https://wiki.ubuntuusers.de/mktemp/) – deutschsprachige Erklärung mit Sicherheitshinweisen
- [GNU coreutils: mktemp invocation](https://www.gnu.org/software/coreutils/manual/html_node/mktemp-invocation.html) – offizielle Referenz aller Optionen (englisch)
<!-- PROSE:outro:end -->

## Verwandte Kommandos

- [touch](https://www.jpkc.com/db/cheatsheets/files-text/touch/) – leere Dateien anlegen und Zeitstempel setzen
- [mkdir](https://www.jpkc.com/db/cheatsheets/files-text/mkdir/) – Verzeichnisse anlegen (auch mit mktemp -d)
- [mv](https://www.jpkc.com/db/cheatsheets/files-text/mv/) – Dateien für atomares Ersetzen verschieben

