0Pricing
DevOps Bootcamp · Lektion

Sichere temporäre Dateien und Sperrverzeichnisse

Verwenden Sie mktemp und flock, um vor Race Conditions geschützte temporäre Ressourcen zu erstellen und parallele Skriptausführungen zu verhindern.

Sichere temporäre Dateien und Sperrverzeichnisse ist eine kostenlose DevOps Bootcamp-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des DevOps Bootcamp-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der DevOps Bootcamp-Kurs umfasst insgesamt 4 Lektionen.

Warum temporäre Dateien ein Sicherheitsrisiko darstellen

Bash-Skripte benötigen häufig temporären Speicher — für Zwischenergebnisse, Sperrmarkierungen und Staging-Bereiche. Werden temporäre Dateien jedoch unachtsam erstellt, entstehen schwerwiegende Sicherheitslücken.

  • Race Conditions: Ein anderer Prozess kann den Dateinamen vorhersagen und die Datei zuerst erstellen, sodass Ihre Schreibvorgänge umgeleitet werden.
  • Symlink-Angriffe: Ein Angreifer erstellt am erwarteten Pfad einen Symlink, der auf eine sensible Datei wie /etc/passwd verweist.
  • Zurückgelassene Dateien: Wenn ein Skript abstürzt, sammeln sich temporäre Dateien an und können vertrauliche Daten offenlegen.

Die beiden zentralen Werkzeuge, die diese Probleme verhindern, sind mktemp und flock. In dieser Lektion lernen Sie, wie Sie beide sicher und robust einsetzen.

Sichere temporäre Dateien mit mktemp erstellen

mktemp erstellt eine temporäre Datei mit einem zufälligen, nicht vorhersehbaren Namen und gibt deren Pfad zurück. Die Datei wird atomar erstellt, sodass kein anderer Prozess den Namen zuerst verwenden kann.

  • Syntax: mktemp [TEMPLATE] — die Vorlage muss mit mindestens drei X-Zeichen enden.
  • Jedes X wird durch ein zufälliges Zeichen ersetzt, wodurch ein eindeutiger Name wie /tmp/script.aB3kQz entsteht.
  • Die Datei wird automatisch mit den Berechtigungen 0600 erstellt (nur der Eigentümer kann sie lesen).

Speichern Sie den zurückgegebenen Pfad immer sofort in einer Variablen, damit Sie später darauf zugreifen und die Datei bereinigen können.

#!/usr/bin/env bash
set -euo pipefail

# Create a secure temp file
TMPFILE=$(mktemp /tmp/myapp.XXXXXX)
echo "Temp file created at: $TMPFILE"

# Write data to it
echo "some intermediate result" > "$TMPFILE"

# Read it back
cat "$TMPFILE"

# Clean up
rm -f "$TMPFILE"

Immer mit einem trap bereinigen

Wenn Ihr Skript unerwartet beendet wird — aufgrund eines Fehlers, eines Signals oder weil set -e ausgelöst wurde — bleiben temporäre Dateien zurück, sofern Sie keinen Bereinigungs-Handler registrieren.

Das trap-Builtin führt einen Befehl aus, wenn die Shell ein Signal empfängt oder beendet wird. Das übliche Muster zur Bereinigung temporärer Dateien lautet:

  • Registrieren Sie den Trap direkt nach dem Erstellen der temporären Datei.
  • Verwenden Sie EXIT als Trap, damit die Bereinigung sowohl bei normaler als auch bei abnormaler Beendigung ausgeführt wird.
  • Verwenden Sie außerdem INT und TERM als Traps, wenn das Skript lange läuft oder interaktiv ist.

So bleiben auch dann keine verwaisten Dateien zurück, wenn das Skript während der Ausführung beendet wird.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/report.XXXXXX)

# Register cleanup before doing any real work
cleanup() {
    rm -f "$TMPFILE"
    echo "Cleaned up $TMPFILE" >&2
}
trap cleanup EXIT

# Do work — even if this fails, cleanup() will run
echo "Processing..." > "$TMPFILE"
grep "result" "$TMPFILE" || true

echo "Done. File will be removed on exit."

Temporäre Verzeichnisse mit mktemp -d erstellen

Manchmal benötigen Sie ein vollständiges Verzeichnis, um mehrere Dateien zwischenzuspeichern — beispielsweise beim Erstellen eines Archivs oder beim Entpacken eines Tarballs vor der Verarbeitung. Verwenden Sie mktemp -d, um ein sicheres temporäres Verzeichnis zu erstellen.

  • Das Verzeichnis wird mit den Berechtigungen 0700 erstellt (Zugriff nur für den Eigentümer).
  • Räumen Sie es in Ihrem Trap mit rm -rf auf — achten Sie darauf, ausschließlich die Variable und niemals einen fest codierten Pfad zu entfernen.
  • Verwenden Sie doppelte Anführungszeichen und prüfen Sie als zusätzliche Sicherheitsmaßnahme, dass die Variable nicht leer ist, bevor Sie rm -rf aufrufen.
#!/usr/bin/env bash
set -euo pipefail

TMPDIR=$(mktemp -d /tmp/extract.XXXXXX)

cleanup() {
    # Guard: only rm if variable is set and non-empty
    [[ -n "${TMPDIR:-}" ]] && rm -rf "$TMPDIR"
}
trap cleanup EXIT

echo "Working in $TMPDIR"

# Simulate staging files
echo "file one" > "$TMPDIR/part1.txt"
echo "file two" > "$TMPDIR/part2.txt"

ls "$TMPDIR"
echo "All done."

Das Problem gleichzeitig ausgeführter Skripte

Cron-Jobs, systemd-Timer und manuell gestartete Skripte können problemlos mehrere Instanzen desselben Skripts gleichzeitig starten. Dies führt zu:

  • Doppelter Verarbeitung: Dieselben Datenbankeinträge oder Dateien werden zweimal verarbeitet.
  • Beschädigter Ausgabe: Zwei Instanzen schreiben gleichzeitig in dieselbe Ausgabedatei.
  • Deadlocks oder unvollständigem Zustand: Beide Instanzen ändern gemeinsam genutzte Ressourcen in einer verschachtelten, nicht vorhersehbaren Reihenfolge.

Die traditionelle Lösung bestand darin, eine PID-Datei zu schreiben und sie beim Start zu prüfen — dieser Ansatz hat jedoch ein Race Window zwischen Prüfung und Schreibvorgang. Die korrekte moderne Lösung ist flock. Es verwendet den Advisory-Locking-Mechanismus des Kernels und ermöglicht eine garantiert race-freie Sperre.

Sperren mit flock: Das Einzeilen-Muster

flock erwirbt eine Advisory-Sperre für einen Dateideskriptor, bevor ein Befehl ausgeführt wird. Die einfachste Verwendung besteht darin, Ihr gesamtes Skript über die Befehlszeile zu umschließen:

flock -n /var/lock/myscript.lock bash myscript.sh

  • -n (nicht blockierend): wird sofort mit Status 1 beendet, wenn die Sperre bereits gehalten wird, statt zu warten.
  • Ohne -n blockiert flock, bis die Sperre verfügbar wird — nützlich zum Einreihen von Ausführungen.
  • Die Sperrdatei selbst ist nur eine Markierung; ihr Inhalt spielt keine Rolle. Sie kann problemlos zwischen den Ausführungen bestehen bleiben.
  • Wenn der Prozess, der die Sperre hält, beendet wird, gibt der Kernel sie automatisch frei — eine manuelle Bereinigung ist nicht erforderlich.
#!/usr/bin/env bash
# launcher.sh — prevents concurrent runs of worker.sh
set -euo pipefail

LOCKFILE="/tmp/myworker.lock"

if ! flock -n "$LOCKFILE" bash -c 'echo "Running worker..."; sleep 2; echo "Done."'; then
    echo "Another instance is already running. Exiting." >&2
    exit 1
fi

flock innerhalb eines Skripts mit einem Dateideskriptor

Wenn Sie innerhalb eines Skripts statt durch externes Umschließen sperren möchten, verwenden Sie exec, um einen Dateideskriptor zu öffnen, und rufen Sie anschließend flock für diesen Deskriptor auf. Dies ist das idiomatische Muster in produktiv eingesetzten Skripten.

  • exec 200>"$LOCKFILE" öffnet die Datei zum Schreiben auf Deskriptor 200 (und erstellt sie bei Bedarf).
  • flock -n 200 versucht, Deskriptor 200 nicht blockierend zu sperren.
  • Da die Sperre an den Dateideskriptor (nicht an den Dateinamen) gebunden ist, wird sie automatisch freigegeben, wenn der Shell-Prozess beendet wird.
  • Deskriptornummern von 200 bis 299 werden üblicherweise verwendet, um Konflikte mit stdin/stdout/stderr zu vermeiden.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/myjob.lock"

# Open lock file on FD 200
exec 200>"$LOCKFILE"

# Attempt non-blocking lock
if ! flock -n 200; then
    echo "ERROR: Another instance of this script is running." >&2
    exit 1
fi

echo "Lock acquired. Starting work..."
sleep 1
echo "Work complete. Lock will be released on exit."

mktemp und flock in einem Skript kombinieren

Robuste defensive Skripte benötigen beides: eine Sperre, um gleichzeitige Ausführungen zu verhindern, und sichere temporäre Dateien für Zwischendaten. Hier ist das vollständige Muster, das beide Techniken kombiniert:

  • Erwerben Sie zuerst die Sperre — bevor Sie temporäre Dateien erstellen —, damit überhaupt nur eine Instanz Arbeit ausführt.
  • Erstellen Sie temporäre Ressourcen erst, nachdem die Sperre bestätigt wurde.
  • Registrieren Sie den trap unmittelbar nach dem Erstellen der temporären Ressourcen, damit die Bereinigung unabhängig von der Art des Skriptendes garantiert ist.
  • Die Sperrdatei darf niemals im temporären Verzeichnis liegen — sie muss zwischen den Ausführungen bestehen bleiben, damit flock darauf verweisen kann.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/report_builder.lock"
exec 200>"$LOCKFILE"

if ! flock -n 200; then
    echo "Already running — aborting." >&2
    exit 1
fi

# Now safe to create temp resources
TMPDIR=$(mktemp -d /tmp/report.XXXXXX)
TMPLOG=$(mktemp /tmp/report_log.XXXXXX)

cleanup() {
    rm -rf "${TMPDIR:-}"
    rm -f  "${TMPLOG:-}"
}
trap cleanup EXIT

echo "Building report in $TMPDIR" | tee "$TMPLOG"
echo "Step 1 complete"             >> "$TMPLOG"
cat "$TMPLOG"

Sperrverzeichnisse als alternativer Sperrmechanismus

Auf Systemen, auf denen flock nicht verfügbar ist (etwa auf manchen eingebetteten Systemen oder bei Netzwerkdateisystemen wie NFS), können Sie stattdessen Sperrverzeichnisse verwenden. mkdir ist auf POSIX-Systemen atomar: Der Befehl ist nur erfolgreich, wenn das Verzeichnis noch nicht existiert.

  • Erstellen Sie das Sperrverzeichnis mit mkdir /tmp/myscript.lock.d — falls eine andere Instanz es bereits erstellt hat, schlägt mkdir sofort fehl.
  • Speichern Sie Metadaten (etwa die PID) zu Diagnosezwecken im Verzeichnis.
  • Entfernen Sie das Verzeichnis in einem trap für EXIT immer.
  • Wichtiger Hinweis: Anders als flock wird eine Verzeichnissperre nicht automatisch freigegeben, wenn der Prozess mit -9 beendet wird oder der Rechner neu startet — fügen Sie eine Prüfung auf veraltete Sperren hinzu.
#!/usr/bin/env bash
set -euo pipefail

LOCKDIR="/tmp/myscript.lock.d"

# Atomic mkdir — fails if directory already exists
if ! mkdir "$LOCKDIR" 2>/dev/null; then
    # Check if the holding PID is still alive
    HOLDER_PID=$(cat "$LOCKDIR/pid" 2>/dev/null || echo "")
    if [[ -n "$HOLDER_PID" ]] && kill -0 "$HOLDER_PID" 2>/dev/null; then
        echo "Locked by PID $HOLDER_PID. Exiting." >&2
        exit 1
    else
        echo "Stale lock detected. Removing and continuing." >&2
        rm -rf "$LOCKDIR"
        mkdir "$LOCKDIR"
    fi
fi

echo "$$" > "$LOCKDIR/pid"
trap 'rm -rf "$LOCKDIR"' EXIT

echo "Lock acquired via directory. Running..."
sleep 1
echo "Done."

Warten mit Timeout mithilfe von flock

Manchmal möchten Sie auf eine Sperre warten, statt sofort fehlzuschlagen — aber nicht unbegrenzt lange. flock unterstützt mit der Option -w ein Timeout.

  • flock -w 10 200 wartet bis zu 10 Sekunden auf die Sperre und wird anschließend mit Status 1 beendet, wenn sie weiterhin nicht verfügbar ist.
  • Dies eignet sich ideal für Skripte, die sich hinter einem kurz laufenden Vorgänger einreihen, aber aufgeben sollen, wenn der Vorgänger feststeckt.
  • Kombinieren Sie -w mit einer aussagekräftigen Fehlermeldung, die den Kontext enthält — den Pfad der Sperrdatei und die Wartezeit —, damit Betreiber hängende Prozesse schnell diagnostizieren können.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/data_sync.lock"
TIMEOUT=15

exec 200>"$LOCKFILE"

echo "Waiting up to ${TIMEOUT}s for lock on $LOCKFILE..."

if ! flock -w "$TIMEOUT" 200; then
    echo "ERROR: Could not acquire lock after ${TIMEOUT}s." \
         "Another instance may be hung." >&2
    exit 1
fi

echo "Lock acquired. Syncing data..."
sleep 1
echo "Sync complete."

Defensive Checkliste: Sichere temporäre Ressourcen

Bevor Sie ein Skript ausliefern, das temporäre Dateien oder Sperren verwendet, gehen Sie diese Checkliste durch:

  • Verwenden Sie mktemp, niemals fest codierte Pfade — /tmp/myapp.tmp ist vorhersehbar und ausnutzbar.
  • Speichern Sie den Pfad sofort — TMPFILE=$(mktemp ...) vor jedem anderen Befehl.
  • Registrieren Sie trap cleanup EXIT unmittelbar nach der Erstellung — nicht erst am Ende des Skripts.
  • Setzen Sie alle Variablenverwendungen in doppelte Anführungszeichen — rm -f "$TMPFILE", niemals rm -f $TMPFILE.
  • Bevorzugen Sie flock gegenüber PID-Dateien — vom Kernel verwaltet und bei einem Absturz automatisch freigegeben.
  • Verwenden Sie standardmäßig das nicht blockierende -n — still blockierende Sperren verbergen Leistungsprobleme.
  • Platzieren Sie die Sperrdatei außerhalb des temporären Verzeichnisses — damit sie den Bereinigungs-Trap überdauert.
  • Testen Sie das Bereinigungsverhalten — führen Sie Ihr Skript aus und beenden Sie es während der Ausführung mit kill -9; prüfen Sie, dass keine Dateien zurückbleiben (bei Skripten auf Basis von flock; Verzeichnissperren erfordern besondere Sorgfalt).

Wissenscheck: Verhalten der flock-Optionen

Ein Cron-Job wird jede Minute ausgeführt und verarbeitet eine gemeinsam genutzte Datei. Sie möchten, dass jede neue Ausführung sofort mit einem Fehler beendet wird, wenn eine vorherige Ausführung noch aktiv ist, ohne zu warten. Welche flock-Invocation setzt dies korrekt um?

Zusammenfassung: Sichere temporäre Dateien und Sperrverzeichnisse

In dieser Lektion haben Sie die beiden wichtigsten Werkzeuge für die defensive Ressourcenverwaltung in Bash kennengelernt:

  • mktemp erstellt nicht vorhersehbare temporäre Dateien (0600) und Verzeichnisse (0700) mit sicheren Berechtigungen und verhindert so Race Conditions und Symlink-Angriffe, die bei fest codierten Pfaden auftreten.
  • trap cleanup EXIT garantiert die Entfernung temporärer Dateien bei jedem Beenden — normal, fehlerbedingt oder signalbedingt —, wenn der Trap unmittelbar nach der Erstellung registriert wird.
  • flock stellt vom Kernel erzwungenes Advisory Locking bereit: Verwenden Sie -n, um bei einer Konkurrenzsituation sofort fehlzuschlagen, -w N, um mit Timeout zu warten, und das Muster exec 200>file für Sperren innerhalb des Skripts, die der Kernel beim Beenden des Prozesses automatisch freigibt.
  • Sperrverzeichnisse (mkdir) bieten eine portable Ausweichlösung für Umgebungen, in denen flock nicht verfügbar ist, erfordern jedoch eine explizite Erkennung veralteter Sperren.
  • Halten Sie die Sperrdatei immer außerhalb des temporären Verzeichnisses und setzen Sie jede bei der Bereinigung verwendete Variable in doppelte Anführungszeichen.

Die Kombination aus mktemp + flock + trap liefert Skripte, die vor gleichzeitigen Ausführungen, unvorhersehbaren Abstürzen und manipulativen Eingriffen in das Dateisystem geschützt sind.

Häufig gestellte Fragen

Ist die Lektion „Sichere temporäre Dateien und Sperrverzeichnisse“ kostenlos?

Ja — der vollständige Text von „Sichere temporäre Dateien und Sperrverzeichnisse“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des DevOps Bootcamp-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der DevOps Bootcamp-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Sichere temporäre Dateien und Sperrverzeichnisse“?

Verwenden Sie mktemp und flock, um vor Race Conditions geschützte temporäre Ressourcen zu erstellen und parallele Skriptausführungen zu verhindern. Du übst DevOps Bootcamp mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um DevOps Bootcamp zu starten?

Keine Vorkenntnisse erforderlich. DevOps Bootcamp auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Sichere temporäre Dateien und Sperrverzeichnisse“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser DevOps Bootcamp-Lektion Code schreiben und ausführen?

Ja. Jede DevOps Bootcamp-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Strict Mode mit set -euo pipefail
  2. Trap-Handler für Bereinigung und Signale
  3. Sichere temporäre Dateien und Sperrverzeichnisse
  4. Idempotente Skripte und Wiederholungslogik mit Backoff
← Zurück zu DevOps Bootcamp