MWCodebymw.de ↗
Terminal

trap und mktemp – Skripte, die auch nach einem Abbruch aufräumen

Ein Skript legt eine temporäre Datei an, bricht in der Mitte ab – und die Datei bleibt liegen. Nach ein paar Wochen ist /tmp voll und niemand weiß, woher der Müll kommt. Zwei Zeilen lösen das dauerhaft.

Fast jedes Skript, das etwas herunterlädt, umwandelt oder vergleicht, braucht eine Zwischendatei. Und fast jedes räumt sie am Ende auf – am glücklichen Ende. Bricht es vorher ab, weil der Download scheiterte oder jemand Strg+C drückt, bleibt sie liegen.

Der feste Rahmen

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

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

curl -fsSL "$url" -o "$tmp/daten.json"
jq '.items[]' "$tmp/daten.json" > "$tmp/gefiltert.txt"
mv "$tmp/gefiltert.txt" ./ergebnis.txt

trap … EXIT wird immer ausgeführt, wenn die Shell das Skript verlässt: bei Erfolg, bei einem Fehler (dank set -e), bei Strg+C und bei kill. Ein Aufräumer, vier Fälle.

Warum mktemp und nicht /tmp/meins.txt

tmp="$(mktemp -d)"                       # /tmp/tmp.8Xk2pQ, nur für dich lesbar
datei="$(mktemp)"                        # eine einzelne Datei
datei="$(mktemp /tmp/export-XXXXXX.csv)" # mit sprechendem Namen

Ein fester Pfad hat zwei Probleme: Zwei gleichzeitige Läufe überschreiben sich gegenseitig, und ein vorhandener Symlink auf einen fremden Pfad macht aus deiner Zwischendatei eine Waffe. mktemp erzeugt den Namen zufällig und die Datei mit engen Rechten.

Mehrere Dinge aufräumen

aufraeumen() {
  rm -rf "${tmp:-}"
  [[ -n "${pidfile:-}" ]] && rm -f "$pidfile"
  docker rm -f testdb >/dev/null 2>&1 || true
}
trap aufraeumen EXIT

Eine Funktion statt einer langen Zeile – und || true sorgt dafür, dass ein fehlschlagender Aufräumschritt nicht den Rückgabewert des Skripts verdirbt.

Signale unterscheiden

trap 'echo "Abgebrochen."; exit 130' INT TERM
trap 'echo "Fehler in Zeile $LINENO"; ' ERR
trap 'rm -rf "$tmp"' EXIT
  • EXIT – immer, zum Aufräumen.
  • INT/TERM – Strg+C bzw. kill, für eine eigene Meldung.
  • ERR – bei jedem fehlgeschlagenen Befehl (zusammen mit set -e sehr nützlich für Protokolle).

Wichtig: Für dieselbe Falle gilt immer nur der letzte trap. Mehrere Aufräumer gehören in eine Funktion, nicht in mehrere Aufrufe.

Fallstrick

Zwei Stolpersteine. Erstens Anführungszeichen: trap "rm -rf $tmp" EXIT wertet $tmp sofort aus – ist die Variable da noch leer, steht in der Falle rm -rf. Mit einfachen Anführungszeichen wird sie erst beim Auslösen ausgewertet. Zweitens: set -e beendet keine Subshell-Pipelines wie erwartet, und in einer Funktion, deren Rückgabewert geprüft wird, greift es gar nicht – verlass dich also nicht allein darauf, sondern prüfe kritische Befehle ausdrücklich.

Skripte, die man nachts laufen lassen kann, ohne morgens aufzuräumen, schreibe ich gern. Melde dich über bymw.de.

Quellen

#Bash#trap#mktemp#Skripte#Fehlerbehandlung

Du brauchst mehr als ein Snippet?

Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.

Projekt anfragen →