Comment supprimer automatiquement un répertoire lorsqu'un exécutable est tué

9

Très souvent, nous exécutons un exécutable qui doit écrire / lire certains fichiers temporaires. Nous créons généralement un répertoire temporaire, y exécutons l'exécutable et supprimons le répertoire lorsque le script est terminé.

Je veux supprimer le répertoire même si l'exécutable est tué. J'ai essayé de l'envelopper:

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

Quand il my_binarymeurt, le dernier processus du noyau supprimera le répertoire, car le script est le dernier processus qui contient cela inode; mais je ne peux pas créer de fichier dans le répertoire supprimé.

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

les sorties touch: file.txt: No such file or directory

Le mieux que j'ai pu trouver est de supprimer le répertoire temporaire à la fin du processus, d'attraper les signaux les plus courants et d'exécuter un processus de nettoyage avec cron:

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

Existe-t-il un moyen simple de créer un répertoire vraiment temporaire qui est supprimé automatiquement lorsque le binaire actuel meurt, quoi qu'il arrive?

Joaquin Cuenca Abela
la source
1
méfiez-vous que vous avez une petite fenêtre où cleanuppeut être exécutée avant la fin de mktemp. Vous voudrez peut-être unset diravant de régler le piège.
Stéphane Chazelas
belle prise, j'ai mis à jour le script pour gérer cela et gérer un échec dans mktemp.
Joaquin Cuenca Abela
Je pensais que la sortie était obligatoire. Fixé.
Joaquin Cuenca Abela
Votre dernier exemple mentionne cron, mais n'a rien à voir avec cron. Ce dernier exemple est également le plus sûr. La seule chose qu'il ne gérera pas est SIGKILL.
Patrick
Je n'ai pas inclus le script cron que j'exécute pour qu'il reste succint. C'est une découverte sur ce modèle pour faire correspondre les répertoires de plus d'une heure et les rm. Je veux savoir s'il existe une solution qui couvrira également le cas sigkill, ou même un arrêt brutal au milieu du script.
Joaquin Cuenca Abela

Réponses:

3

Votre dernier exemple est le plus sûr.

trap 'rm -rf "$dir"' EXIT

Cela s'exécutera tant que le shell lui-même sera toujours fonctionnel. Fondamentalement, SIGKILL est la seule chose qu'il ne gérera pas car le shell est terminé de force.
(peut-être que SIGSEGV aussi, n'a pas essayé, mais il peut être attrapé)

Si vous ne laissez pas au shell le soin de nettoyer après lui-même, la seule autre alternative possible est de demander au noyau de le faire. Ce n'est normalement pas une fonctionnalité du noyau, mais il y a une astuce que vous pouvez faire, mais elle a ses propres problèmes:

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

do_stuff

Fondamentalement, vous créez un montage tmpfs, puis vous le démontez paresseusement. Une fois le script terminé, il sera supprimé.
L'inconvénient autre que d'être trop complexe, c'est que si le script meurt pour une raison quelconque avant le démontage, vous n'avez pas de monture qui traîne.
Cela utilise également tmpfs, qui consommera de la mémoire. Mais vous pourriez rendre le processus plus complexe et utiliser un système de fichiers en boucle, et supprimer le fichier le sauvegardant après son montage.


En fin de compte, le trapmeilleur en termes de simplicité et de sécurité, et à moins que votre script ne soit régulièrement SIGKILL, je m'en tiendrai à cela.

Patrick
la source
Est-il important que le piège soit placé avant mktempou après? Je pense que si le piège est placé juste avant le mktemp, alors même si le signal de sortie était reçu après le piège et avant le mktemp, tout ce qui se passerait serait qu'une rm -rfcommande serait exécutée avec un argument vide, sans rien faire. Mais si le piège était après le mktemp, il pourrait y avoir une minuscule fenêtre de chance que le répertoire temporaire soit laissé. Ou suis-je complètement hors de la base?
Wildcard
1

Vous pouvez utiliser la fonction d' attente intégrée pour attendre la fin d'un travail d'arrière-plan:

blah &
wait
rm -rf $DIR
Matthew Cline
la source
Mais ce sera équivalent à blah; rm -rf $DIR, non? Il a le problème de fuir $ DIR si le script est tué.
Joaquin Cuenca Abela
Si le script enfant est tué, le script parent sera toujours là pour le nettoyer. Si le script parent est également tué, alors oui, le répertoire sera laissé derrière.
Matthew Cline