So löschen Sie ein Verzeichnis automatisch, wenn eine ausführbare Datei beendet wird

9

Sehr oft führen wir eine ausführbare Datei aus, die einige temporäre Dateien schreiben / lesen muss. Normalerweise erstellen wir ein temporäres Verzeichnis, führen die ausführbare Datei dort aus und löschen das Verzeichnis, wenn das Skript fertig ist.

Ich möchte das Verzeichnis löschen, auch wenn die ausführbare Datei beendet ist. Ich habe versucht, es einzuwickeln:

#!/bin/bash
dir=$(mktemp -d /tmp/foo.XXXXXXX) && cd $dir && rm -rf $dir
/usr/local/bin/my_binary

Wenn my_binarydies stirbt, löscht der Kernel als letztes das Verzeichnis, da das Skript der letzte Prozess ist, der dies enthält inode. Ich kann jedoch keine Datei im gelöschten Verzeichnis erstellen.

#!/bin/bash
dir=$(mktemp -d /tmp/foo.XXXXXXX) && cd $dir && rm -rf $dir
touch file.txt

Ausgänge touch: file.txt: No such file or directory

Das Beste, was ich mir einfallen lassen kann, ist, das temporäre Verzeichnis zu löschen, wenn der Prozess abbricht, die häufigsten Signale abzufangen und einen Bereinigungsprozess mit cron auszuführen:

#!/bin/bash
dir=$(mktemp -d /tmp/d.XXXXXX) && cd "$dir" || exit 99
trap 'rm -rf "$dir"' EXIT
/usr/local/bin/my_binary

Gibt es eine einfache Möglichkeit, ein wirklich temporäres Verzeichnis zu erstellen, das automatisch gelöscht wird, wenn die aktuelle Binärdatei stirbt, egal was passiert?

Joaquin Cuenca Abela
quelle
1
Beachten Sie, dass Sie ein kleines Fenster haben, in dem cleanupes ausgeführt werden kann, bevor das Mktemp abgeschlossen ist. Möglicherweise möchten Sie, unset dirbevor Sie die Falle einstellen.
Stéphane Chazelas
netter Fang, ich habe das Skript aktualisiert, um dies und einen Fehler in mktemp zu behandeln.
Joaquin Cuenca Abela
Ich dachte, dass der Ausstieg obligatorisch ist. Fest.
Joaquin Cuenca Abela
Ihr letztes Beispiel erwähnt Cron, hat aber nichts mit Cron zu tun. Das letzte Beispiel ist auch das ausfallsicherste. Das einzige, was es nicht handhaben kann, ist SIGKILL.
Patrick
Ich habe das Cron-Skript, das ich ausführe, nicht eingefügt, um es kurz zu halten. Es ist eine Entdeckung über dieses Muster, Dirs zu finden, die älter als 1 Stunde sind, und sie zu rm. Ich möchte wissen, ob es eine Lösung gibt, die auch den Sigkill-Fall oder sogar ein brutales Herunterfahren mitten im Skript abdeckt.
Joaquin Cuenca Abela

Antworten:

3

Ihr letztes Beispiel ist das ausfallsicherste.

trap 'rm -rf "$dir"' EXIT

Dies wird ausgeführt, solange die Shell selbst noch funktionsfähig ist. Grundsätzlich ist SIGKILL das einzige, was es nicht handhaben kann, da die Shell zwangsweise beendet wird.
(Vielleicht hat SIGSEGV es auch nicht versucht, aber es kann gefangen werden)

Wenn Sie es nicht der Shell überlassen, nach sich selbst aufzuräumen, besteht die einzig mögliche Alternative darin, den Kernel dies tun zu lassen. Dies ist normalerweise keine Kernelfunktion, es gibt jedoch einen Trick, den Sie ausführen können, der jedoch seine eigenen Probleme hat:

#!/bin/bash
mkdir /tmp/$$
mount -t tmpfs none /tmp/$$
cd /tmp/$$
umount -l /tmp/$$
rmdir /tmp/$$

do_stuff

Grundsätzlich erstellen Sie ein tmpfs-Mount und heben es dann faul auf. Sobald das Skript fertig ist, wird es entfernt.
Der Nachteil, der nicht zu komplex ist, ist, dass Sie kein Mount herumliegen haben, wenn das Skript aus irgendeinem Grund vor dem Unmount stirbt.
Dies verwendet auch tmpfs, die Speicher verbrauchen. Sie können den Prozess jedoch komplexer gestalten, ein Loop-Dateisystem verwenden und die Datei entfernen, die ihn nach dem Mounten sichert.


Letztendlich trapist das Beste in Bezug auf Einfachheit und Sicherheit, und wenn Ihr Skript nicht regelmäßig SIGKILLed wird, würde ich dabei bleiben.

Patrick
quelle
Ist es wichtig, ob die Falle davor mktempoder danach platziert wird? Ich würde denken, wenn die Falle direkt vor der platziert wird mktemp, dann würde, selbst wenn das Ausgangssignal nach der Falle und vor der empfangen mktempwürde, nur ein rm -rfBefehl mit einem leeren Argument ausgeführt, der nichts bewirkt. Aber wenn die Falle nach dem wäre mktemp, könnte es ein winziges Fenster geben, in dem die Chance besteht, dass das temporäre Verzeichnis verlassen wird. Oder bin ich völlig aus der Basis?
Wildcard
1

Mit der integrierten Wartezeit können Sie warten, bis ein Hintergrundjob abgeschlossen ist:

blah &
wait
rm -rf $DIR
Matthew Cline
quelle
Aber das ist gleichbedeutend mit blah; rm -rf $DIR, oder? Es hat das Problem, dass $ DIR ausläuft, wenn das Skript beendet wird.
Joaquin Cuenca Abela
Wenn das untergeordnete Skript beendet wird, ist das übergeordnete Skript weiterhin verfügbar, um danach zu bereinigen. Wenn das übergeordnete Skript ebenfalls beendet wird, bleibt das Verzeichnis zurück.
Matthew Cline