0Pricing
Linux Command Line & Bash Scripting Mastery · Lektion

Trap-Handler für Bereinigung und Signale

Registrieren Sie EXIT-, ERR- und INT-Traps, um temporäre Dateien zu entfernen und unvollständige Änderungen zuverlässig zurückzurollen.

Trap-Handler für Bereinigung und Signale ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 2 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 Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.

Warum Trap-Handler wichtig sind

Wenn ein Bash-Skript beendet wird — normal, aufgrund eines Fehlers oder weil Sie Strg+C gedrückt haben — können temporäre Dateien, unvollständig geschriebene Daten oder ein inkonsistenter Zustand zurückbleiben. Ohne Bereinigung sammeln sich diese Überbleibsel an und verursachen schwer zu debuggende Probleme.

Trap-Handler lösen dieses Problem, indem sie eine Funktion oder einen Befehl registrieren, den Bash automatisch ausführt, wenn ein bestimmtes Signal oder Pseudo-Signal empfangen wird.

  • EXIT — wird immer ausgelöst, wenn das Skript beendet wird, unabhängig vom Grund
  • ERR — wird ausgelöst, nachdem ein Befehl einen Exit-Status ungleich null zurückgibt
  • INT — wird ausgelöst, wenn der Benutzer SIGINT (Strg+C) sendet
  • TERM — wird bei SIGTERM ausgelöst (z. B. durch kill)

Ein gut geschriebenes Skript registriert diese Traps ganz am Anfang, bevor riskante Arbeiten beginnen.

Die Syntax des trap-Builtins

Das trap-Builtin registriert einen Handler für ein oder mehrere Signale oder Pseudo-Signale. Die allgemeine Syntax lautet:

trap 'command_or_function' SIGNAL [SIGNAL...]

Wichtige Regeln:

  • Das erste Argument ist eine in Anführungszeichen gesetzte Zeichenfolge mit Shell-Code (oder ein Funktionsname), der beim Auslösen des Signals ausgeführt wird.
  • Nach dem Handler können Sie mehrere Signale angeben.
  • trap '' SIGNAL ignoriert das Signal (leerer Handler).
  • trap - SIGNAL setzt das Signal auf sein Standardverhalten zurück.

Traps werden von Funktionen übernommen, die in derselben Shell aufgerufen werden, jedoch nicht von Subshells, die mit ( ) oder & gestartet werden.

#!/usr/bin/env bash
# Syntax examples — not a full script

# Register a cleanup function on EXIT
trap cleanup EXIT

# Inline handler for INT and TERM
trap 'echo "Interrupted!"; exit 1' INT TERM

# Ignore SIGHUP
trap '' HUP

# Reset SIGPIPE to default
trap - PIPE

Der EXIT-Trap — Ihr Sicherheitsnetz

Das EXIT-Pseudo-Signal ist der wichtigste Trap, den Sie registrieren sollten. Es wird ausgelöst, wenn die Shell aus jedem Grund beendet wird: nach normaler Ausführung, durch exit N, wegen eines unbehandelten Fehlers oder aufgrund eines Signals. Dadurch eignet es sich ideal zum Entfernen temporärer Dateien.

Bewährte Vorgehensweise:

  • Erstellen Sie temporäre Dateien mit mktemp, damit der Name eindeutig und nicht vorhersehbar ist.
  • Speichern Sie den Pfad sofort in einer Variablen.
  • Registrieren Sie den EXIT-Trap direkt nach der Erstellung, damit die Bereinigung immer ausgeführt wird.

Der Exit-Code des Skripts bleibt erhalten — der Exit-Code des Trap-Handlers wird ignoriert, sofern Sie darin nicht ausdrücklich exit aufrufen.

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

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

cleanup() {
    echo "Removing temp file: $TMPFILE" >&2
    rm -f "$TMPFILE"
}
trap cleanup EXIT

# Do real work
echo "Processing..." > "$TMPFILE"
sort "$TMPFILE" -o "$TMPFILE"
cp "$TMPFILE" /tmp/myapp_result.txt

echo "Done. Result saved."

Mehrere temporäre Dateien und Verzeichnisse verwalten

In realen Skripten werden häufig mehrere temporäre Objekte erstellt — Dateien, Verzeichnisse, FIFOs und Lock-Dateien. Statt jedes Objekt einzeln zu verwalten, sammeln Sie sie in einem Array und entfernen alles in einer einzigen Bereinigungsfunktion.

Dieses Muster lässt sich problemlos erweitern: Hängen Sie jedes neue temporäre Objekt beim Erstellen an das Array an. Der EXIT-Trap verarbeitet unabhängig davon, an welcher Stelle das Skript beendet wird, immer die vollständige Liste.

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

CLEANUP_TARGETS=()

add_cleanup() {
    CLEANUP_TARGETS+=("$1")
}

cleanup() {
    echo "Running cleanup..." >&2
    for target in "${CLEANUP_TARGETS[@]:-}"; do
        rm -rf "$target"
        echo "Removed: $target" >&2
    done
}
trap cleanup EXIT

# Create and track temp resources
TMPDIR_WORK=$(mktemp -d /tmp/work.XXXXXX)
add_cleanup "$TMPDIR_WORK"

TMPFILE_LOG=$(mktemp /tmp/run.XXXXXX.log)
add_cleanup "$TMPFILE_LOG"

echo "Working in $TMPDIR_WORK" | tee "$TMPFILE_LOG"
touch "$TMPDIR_WORK/output.txt"
echo "Step complete."

Der ERR-Trap — Fehler abfangen

Das ERR-Pseudo-Signal wird ausgelöst, nachdem ein einfacher Befehl einen Exit-Status ungleich null zurückgibt, sofern die Shell-Option set -e (errexit) aktiv ist oder sich der Befehl nicht innerhalb eines if, while oder einer mit ||/&& gebildeten zusammengesetzten Anweisung befindet.

Verwenden Sie den ERR-Trap, um:

  • mithilfe von $LINENO und $BASH_COMMAND zu protokollieren, in welcher Zeile der Fehler aufgetreten ist.
  • vor dem Ausführen des EXIT-Traps eine Rollback-Logik auszulösen.
  • strukturierte Fehlermeldungen nach stderr auszugeben.

Wichtig: ERR-Traps werden innerhalb von Funktionen nicht ausgelöst, sofern Sie nicht ausdrücklich set -E (errtrace) ausführen, damit Funktionen den ERR-Trap der aufrufenden Shell übernehmen.

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

on_error() {
    local exit_code=$?
    local line=$1
    echo "ERROR: command failed with exit code $exit_code at line $line" >&2
    echo "  Command: $BASH_COMMAND" >&2
}
trap 'on_error $LINENO' ERR

echo "Starting task..."
cp /nonexistent/file /tmp/   # This will fail
echo "This line is never reached."

Der INT-Trap — Strg+C ordnungsgemäß behandeln

Durch das Drücken von Strg+C wird SIGINT an die Prozessgruppe im Vordergrund gesendet. Ohne Trap beendet sich Bash sofort, wobei möglicherweise unvollständige Arbeiten zurückbleiben.

Durch das Registrieren eines INT-Traps können Sie:

  • eine verständliche Abbruchmeldung für Benutzer ausgeben.
  • vor der Übergabe an den EXIT-Trap ein eventuell erforderliches Zwischen-Rollback durchführen.
  • mit einem aussagekräftigen Statuscode beenden (130 ist der übliche Code für SIGINT: 128 + 2).

Rufen Sie nach Abschluss Ihres INT-Handlers exit 130 auf, um den korrekten Exit-Code weiterzugeben. Der EXIT-Trap wird anschließend automatisch ausgeführt.

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

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

cleanup() {
    rm -f "$TMPFILE"
    echo "Temp file removed." >&2
}

on_interrupt() {
    echo "" >&2
    echo "Caught SIGINT — cancelling gracefully." >&2
    exit 130   # EXIT trap (cleanup) runs automatically after this
}

trap cleanup EXIT
trap on_interrupt INT

echo "Running long task. Press Ctrl+C to cancel."
for i in $(seq 1 10); do
    echo "Step $i/10..."
    sleep 1
done
echo "All steps complete."

EXIT-, ERR- und INT-Traps kombinieren

In Produktionsskripten registrieren Sie normalerweise alle drei Traps gemeinsam, um jeden Beendigungspfad abzudecken:

  • EXIT — wird immer ausgeführt und übernimmt die Dateibereinigung.
  • ERR — protokolliert den fehlerhaften Befehl und die Zeilennummer.
  • INT — gibt eine Abbruchmeldung aus und beendet sich mit dem Code 130.

Da EXIT immer zuletzt ausgeführt wird, muss Ihre Bereinigungslogik nur an einer Stelle stehen. ERR- und INT-Handler können sich auf das Protokollieren und das Setzen des Zustands konzentrieren und die eigentliche Bereinigung an EXIT delegieren, indem sie exit aufrufen.

Verwenden Sie am Anfang set -eEuo pipefail, damit auch Fehler in Funktionen ERR auslösen und pipefail Fehler innerhalb von Pipelines erkennt.

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

TMPFILE=$(mktemp /tmp/combined.XXXXXX)
ROLLBACK_NEEDED=false

cleanup() {
    if [[ "$ROLLBACK_NEEDED" == true ]]; then
        echo "Rolling back partial changes..." >&2
    fi
    rm -f "$TMPFILE"
    echo "Cleanup done." >&2
}

on_error() {
    ROLLBACK_NEEDED=true
    echo "ERR at line $1: $BASH_COMMAND" >&2
}

on_interrupt() {
    echo "Interrupted by user." >&2
    exit 130
}

trap cleanup       EXIT
trap 'on_error $LINENO' ERR
trap on_interrupt  INT

echo "hello" > "$TMPFILE"
echo "Script finished successfully."

Traps dynamisch zurücksetzen und deaktivieren

Manchmal müssen Sie einen Trap mitten im Skript ändern — beispielsweise eine einmalige Bereinigung nach Abschluss eines kritischen Abschnitts, damit nachfolgende normale Vorgänge kein unnötiges Rollback auslösen.

  • trap - SIGNAL setzt das Signal auf sein integriertes Standardverhalten zurück.
  • trap '' SIGNAL ignoriert das Signal vollständig (der Prozess kann dadurch nicht beendet werden).
  • Sie können jederzeit einen neuen Handler registrieren; der letzte Aufruf von trap gilt.

Ein häufiges Muster besteht darin, den EXIT-Trap zu aktualisieren, sobald ein riskanter Vorgang erfolgreich war, und dabei von einem Rollback-Handler zu einem einfachen Bereinigungs-Handler zu wechseln.

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

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

rollback() {
    echo "ROLLBACK: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

cleanup_only() {
    echo "CLEANUP: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

# Start with rollback in case something fails during the risky phase
trap rollback EXIT

echo "Performing risky operation..."
echo "critical data" > "$TMPFILE"
# ... imagine more risky steps here ...

# Risky phase succeeded — switch to simple cleanup
trap cleanup_only EXIT

echo "Risky phase done. Now doing safe finalization."
cp "$TMPFILE" /tmp/staged_result.txt
echo "All done."

Exit-Codes durch Traps weitergeben

Eine subtile Falle: Enthält Ihre Bereinigungsfunktion Befehle, die fehlschlagen können, wird möglicherweise der endgültige Exit-Code des Skripts überschrieben. Bewahren Sie den ursprünglichen Exit-Code ausdrücklich auf.

Innerhalb eines Trap-Handlers enthält $? den Exit-Code, der den Trap ausgelöst hat. Speichern Sie ihn in der allerersten Zeile des Handlers, bevor ein anderer Befehl seinen Wert ändert.

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

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

cleanup() {
    local original_exit=$?   # capture BEFORE any other command
    echo "Cleaning up (original exit: $original_exit)" >&2
    rm -f "$TMPFILE"
    # Exit with the original code so callers see the real result
    exit "$original_exit"
}
trap cleanup EXIT

echo "Doing work..."
echo "data" > "$TMPFILE"

# Simulate failure
if [[ ! -f /tmp/required_marker ]]; then
    echo "Required marker missing!" >&2
    exit 2
fi

echo "Done."

Traps in Funktionen und Subshells

Das Verständnis der Vererbung von Traps ist entscheidend, um korrekte Skripte zu schreiben:

  • Funktionen werden in derselben Shell ausgeführt und übernehmen Traps — ERR wird jedoch nur dann an Funktionen weitergegeben, wenn set -E (errtrace) aktiv ist.
  • Subshells (( ... )) beginnen mit einer Kopie der Traps des übergeordneten Prozesses, aber Änderungen innerhalb der Subshell wirken sich nicht auf den übergeordneten Prozess aus.
  • Hintergrundjobs (cmd &) sind Subshells und übernehmen die INT-/TERM-Traps des übergeordneten Prozesses nicht (für sie gilt die standardmäßige Signalbehandlung).

Praktische Regel: Registrieren Sie Ihre Traps im Hauptteil des Skripts, verwenden Sie set -E, wenn ERR an Funktionen weitergegeben werden soll, und verlassen Sie sich niemals auf die Vererbung von Traps über & hinweg.

#!/usr/bin/env bash
set -eEuo pipefail   # -E = errtrace: ERR propagates into functions

on_error() {
    echo "ERR in function or main at line $1" >&2
}
trap 'on_error $LINENO' ERR

risky_function() {
    echo "Inside risky_function"
    ls /nonexistent_path   # triggers ERR — works because of set -E
}

# Subshell: has its own copy; changes don't affect parent
(
    trap '' ERR   # disable ERR only inside subshell
    ls /nonexistent_path 2>/dev/null || true
    echo "Subshell completed without triggering parent ERR"
)

risky_function

Praxisbeispiel: Atomisches Ersetzen von Dateien

Ein klassisches robustes Bash-Muster ist das atomische Ersetzen von Dateien: Schreiben Sie in eine temporäre Datei und benennen Sie diese anschließend an die Zielposition um. Wenn vor dem Umbenennen etwas fehlschlägt, bleibt das Original unverändert. Traps machen dieses Verfahren besonders zuverlässig.

Schritte:

  1. Erstellen Sie eine temporäre Datei im gleichen Dateisystem wie das Ziel (damit mv atomar ist).
  2. Registrieren Sie einen EXIT-Trap, der die temporäre Datei entfernt, falls das Skript vorzeitig beendet wird.
  3. Schreiben und validieren Sie den neuen Inhalt.
  4. Benennen Sie die Datei atomar um (mv) — erst jetzt wird das Original ersetzt.
  5. Der EXIT-Trap entfernt die temporäre Datei nur, wenn sie noch vorhanden ist (nach einem erfolgreichen mv ist sie verschwunden).
#!/usr/bin/env bash
set -euo pipefail

DEST="/tmp/important_config.conf"
TMPFILE=$(mktemp "$(dirname "$DEST")/.tmp.XXXXXX")

cleanup() {
    rm -f "$TMPFILE"   # no-op if mv already moved it
}
trap cleanup EXIT

# Write new content to temp file
cat > "$TMPFILE" <<'EOF'
[settings]
version=2
mode=production
EOF

# Validate before replacing
if ! grep -q 'version=' "$TMPFILE"; then
    echo "Validation failed — aborting replacement" >&2
    exit 1
fi

# Atomic rename — DEST is replaced only here
mv "$TMPFILE" "$DEST"
echo "Config updated atomically: $DEST"

Wissenscheck: Vererbung des ERR-Traps

Testen Sie Ihr Verständnis dafür, wie sich der ERR-Trap bei Funktionen in Bash verhält.

Zusammenfassung: Trap-Handler für Bereinigung und Signale

In dieser Lektion haben Sie gelernt, wie Sie Bash-Skripte mithilfe von Trap-Handlern robust machen:

  • EXIT ist Ihr universelles Sicherheitsnetz — registrieren Sie ihn sofort nach dem Erstellen eines temporären Objekts und speichern Sie immer zuerst $?, um den ursprünglichen Exit-Code zu bewahren.
  • ERR ermöglicht das Protokollieren von Fehlern mit $LINENO und $BASH_COMMAND; verwenden Sie set -E, damit Funktionen den Trap übernehmen.
  • INT behandelt Strg+C ordnungsgemäß — geben Sie eine Meldung aus und beenden Sie sich mit dem Code 130, damit EXIT die Bereinigung übernimmt.
  • Sammeln Sie temporäre Objekte in einem Array und entfernen Sie sie alle in einer einzigen Bereinigungsfunktion.
  • Verwenden Sie trap - SIGNAL zum Zurücksetzen und trap '' SIGNAL zum dynamischen Ignorieren von Signalen.
  • Das atomare Umbenennungsmuster (mktemp → Schreiben → Validieren → mv) stellt zusammen mit einem EXIT-Trap sicher, dass unvollständige Schreibvorgänge niemals die Zieldatei beschädigen.

Die Kombination aus set -eEuo pipefail und gut platzierten Traps bietet eine solide Grundlage für robuste Bash-Produktionsskripte.

Häufig gestellte Fragen

Ist die Lektion „Trap-Handler für Bereinigung und Signale“ kostenlos?

Ja — der vollständige Text von „Trap-Handler für Bereinigung und Signale“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Trap-Handler für Bereinigung und Signale“?

Registrieren Sie EXIT-, ERR- und INT-Traps, um temporäre Dateien zu entfernen und unvollständige Änderungen zuverlässig zurückzurollen. Du übst Linux Command Line & Bash Scripting Mastery 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 Linux Command Line & Bash Scripting Mastery zu starten?

Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery 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 2 von 4.

Wie lange dauert die Lektion „Trap-Handler für Bereinigung und Signale“?

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 Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?

Ja. Jede Linux Command Line & Bash Scripting Mastery-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 Linux Command Line & Bash Scripting Mastery