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.
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.
Grundlagen
mktemp — Erstellt eine eindeutige temporäre Datei in $TMPDIR (oder /tmp). Gibt den vollen Pfad auf stdout zurück.
mktemp
# /tmp/tmp.A3kLp9mktemp -d — Erstellt ein eindeutiges temporäres Verzeichnis statt einer Datei.
mktemp -d
# /tmp/tmp.xY7qZ2<var>=$(mktemp) — Speichert den Pfad zur späteren Verwendung in einer Shell-Variablen.
tmp=$(mktemp)
echo "log data" > "$tmp"<var>=$(mktemp -d) — Speichert den Pfad eines frischen Temp-Verzeichnisses in einer Variablen.
workdir=$(mktemp -d)
cd "$workdir"mktemp --help — Zeigt alle verfügbaren Optionen mit Kurzbeschreibung.
mktemp --helpVorlagen (XXX-Platzhalter)
mktemp <template> — Verwendet eine eigene Namensvorlage. Die abschließenden X (mindestens 3) werden durch Zufallszeichen ersetzt.
mktemp mydata.XXXXXX
# mydata.k7Bq2pmktemp <prefix>.XXXXXXXXXX — Mehr X bedeuten mehr Entropie und geringere Kollisionswahrscheinlichkeit. 10+ für langlebige Dateien empfohlen.
mktemp build.XXXXXXXXXX
# build.Hf3k9pXw2Lmktemp -d <template> — Erstellt ein Verzeichnis anhand einer eigenen Vorlage.
mktemp -d myapp-XXXXXX
# myapp-9bTq2Kmktemp --suffix=<ext> <template> — Hängt einen Suffix nach dem Zufallsteil an. Nützlich für Dateien, die eine bestimmte Endung brauchen. Nur GNU coreutils.
mktemp --suffix=.json data.XXXXXX
# data.k7Bq2p.jsonmktemp <prefix>XXXXXX<suffix> — BSD-/macOS-Alternative: XXX in der Mitte des Namens platzieren, um einen festen Suffix zu erhalten.
mktemp build-XXXXXX.tar.gz
# build-k7Bq2p.tar.gzVerzeichnis-Optionen
mktemp -p <dir> — Erstellt die Temp-Datei bzw. das Verzeichnis in
mktemp -p /var/tmp
# /var/tmp/tmp.A3kLp9mktemp --tmpdir=<dir> <template> — Langform von -p. Mit einer Vorlage kombinierbar.
mktemp --tmpdir=/var/cache app.XXXXXXmktemp -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.
mktemp -t myappTMPDIR=<dir> mktemp — Überschreibt das Standard-Temp-Verzeichnis per Umgebungsvariable für einen einzelnen Befehl.
TMPDIR=/fast/ssd mktemp -dmktemp -p "" <template> — Erzwingt relative Platzierung: erstellt im aktuellen Arbeitsverzeichnis statt in $TMPDIR.
mktemp -p "" cache-XXXXXXWeitere 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.
mktemp -u
# /tmp/tmp.A3kLp9 (not created)mktemp --dry-run — Langform von -u. Gleiche Warnung: nur zur Vorschau sicher.
mktemp --dry-run --suffix=.log test.XXXXXXmktemp -q — Stiller Modus. Unterdrückt Fehlermeldungen, falls die Erstellung scheitert. Nützlich in Skripten mit eigener Fehlerbehandlung.
tmp=$(mktemp -q) || exit 1mktemp --version — Zeigt die installierte mktemp-Version. Unter Linux verrät das die coreutils-Version; unter macOS meldet es den BSD-Build.
mktemp --versionGNU (Linux) vs. BSD (macOS)
mktemp (portabel) — Schlichte Form ohne Vorlage funktioniert auf GNU und BSD. Sicherste Voreinstellung, wenn du kein eigenes Präfix brauchst.
tmp=$(mktemp) || exit 1mktemp -t <prefix> — GNU: Präfix ist optional; Pfad geht nach $TMPDIR. BSD/macOS: -t ERFORDERT ein Präfix und stellt es dem Zufallssuffix voran.
# macOS:
mktemp -t myapp
# /var/folders/.../myapp.XXXXXXmktemp <prefix>.XXXXXX — Vorlagenform funktioniert auf beiden. Auf BSD müssen mindestens 3 X am ENDE der Namenskomponente stehen (Suffix über explizite Zeichen nach XXXXXX).
mktemp app.XXXXXX # both
mktemp app-XXXXXX.log # BSD ok, GNU needs --suffixmktemp --suffix=.ext — Nur GNU. BSD/macOS unterstützt --suffix NICHT. Für plattformübergreifende Skripte einen Inline-Suffix nutzen: prefix-XXXXXX.ext.
# Linux only:
mktemp --suffix=.sql dump.XXXXXXmktemp -p <dir> — Nur GNU. BSD unterstützt -p nicht. Für plattformübergreifende Skripte das Verzeichnis in die Vorlage packen oder TMPDIR setzen.
# Portable:
TMPDIR=/var/tmp mktempAufrä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.
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXITtrap '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.
dir=$(mktemp -d) || exit 1
trap 'rm -rf "$dir"' EXITcleanup() { 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).
cleanup() {
[[ -n $pid ]] && kill $pid 2>/dev/null
rm -rf "$dir"
}
trap cleanup EXITtrap '...' 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.
trap 'rm -rf "$dir"' EXIT INT TERM HUPtmp=$(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).
tmp=$(mktemp) || { echo "mktemp failed" >&2; exit 1; }
trap 'rm -f "$tmp"' EXITTypische Anwendungsfälle
Scratch-Datei für Befehlsausgabe — Ausgabe zur späteren Verarbeitung erfassen, ohne eine Namenskollision in /tmp zu riskieren.
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.
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.
tmp=$(mktemp)
sort -u input.txt > "$tmp" && mv "$tmp" input.txtTemporärer Arbeitsbereich zum Entpacken — Ein Archiv in einem isolierten Verzeichnis entpacken, prüfen und danach automatisch aufräumen.
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).
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.
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.
stat -c %a "$(mktemp)"
# 600Niemals /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.
# 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.
# Race condition:
name=$(mktemp -u)
# ... attacker creates $name as a symlink ...
echo data > "$name" # follows symlinkVariable immer quoten — Pfade können Leerzeichen enthalten (besonders auf macOS, wo /var/folders/.../ verwendet wird). Unquotierte Expansion bricht.
# GOOD:
rm -f "$tmp"
# BAD:
rm -f $tmp # breaks on spaceBei vorzeitigem Abbruch aufräumen — Ohne trap hinterlassen abgebrochene Skripte Dateien, die nie gelöscht werden (/tmp wird beim Neustart geleert, /var/tmp NICHT).
# Without trap, Ctrl+C leaves $tmp behind:
tmp=$(mktemp) || exit 1
trap 'rm -f "$tmp"' EXITDateisystemgrenzen 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.
# Same filesystem as target:
tmp=$(mktemp -p "$(dirname "$target")") 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 – deutschsprachige Erklärung mit Sicherheitshinweisen
- GNU coreutils: mktemp invocation – offizielle Referenz aller Optionen (englisch)