Comment exécuter automatiquement un script lorsque le contenu d'un répertoire change sous Linux?

17

Je veux exécuter automatiquement un script chaque fois que de nouveaux fichiers sont copiés dans un répertoire particulier. En d'autres termes, y a-t-il un moyen sous Linux de "surveiller" un répertoire pour les changements, puis d'exécuter quelque chose en réponse au changement?

GeneQ
la source
Cette discussion a eu lieu sur chaque site stackexchange;) voir superuser.com/questions/181517/… stackoverflow.com/questions/4380527/… etc.
masterxilo

Réponses:

17

Si vous êtes assez chanceux d'être sur une distribution basée sur Debian, apt-get install dnotify. D'autres distributions ont probablement quelque chose de similaire - recherchez le dnotifynom.

dnotify est un programme simple basé sur l'API dnotify du noyau Linux 2.4.19 +. dnotify peut exécuter une commande spécifiée à chaque fois que le contenu d'un répertoire spécifique change. Il est exécuté à partir de la ligne de commande et prend deux arguments: un ou plusieurs répertoires à surveiller et une commande à exécuter chaque fois qu'un répertoire a changé. Les options contrôlent les événements à déclencher: quand un fichier a été lu dans le répertoire, quand un a été créé, supprimé, etc.

Si vous souhaitez gérer cela dans votre propre programme, dnotify est également l'API que vous souhaitez utiliser.

MikeyB
la source
4
@MikeB, après que Googling dnotify vous l'ait suggéré, j'ai fini par utiliser inotify à la place, ce qui le dépasse apparemment. Merci de m'avoir indiqué la bonne direction. apt-get install inotify-tools
GeneQ
7
@GeneQ, inotify a remplacé dnotify.
David
1
De même sur Gentoo:emerge inotify-tools
James Sneeringer
Oui, j'allais dire que le noyau 2.4.19 est un peu ancien ;-) inotify est la voie à suivre.
David Z
Oh ouais ... j'ai oublié lequel était le plus récent :)
MikeyB
12

Vous pouvez exécuter un script avec les outils inotify, quelque chose comme ça. Il surveillera le répertoire pour les changements dans les fichiers modifiés, les nouveaux fichiers et les fichiers supprimés, puis exécutera le script.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
user7119
la source
Tenez simplement compte du fait que si le répertoire source change pendant qu'il est copié, inotifywait ne le verra PAS et ces modifications ne seront pas copiées avant d'autres modifications une fois la copie terminée. Mais ce n'est probablement pas un problème.
Raúl Salinas-Monteagudo
Comment pouvez-vous l'exécuter en mode démon?
Chris F
4

l'incron est fondamentalement ce que vous voulez, je pense. Il utilise inotify comme mécanisme de notification (qui, comme d'autres l'ont souligné, remplace dnotify), mais ne nécessite pas de script qui s'exécute en continu, en utilisant inotifywait ou similaire (bien que, évidemment, le démon incron fonctionne tout le temps). Les «crontabs» à l'échelle du système et les «crontabs» utilisateur sont pris en charge de la même manière que les cron standard, mais plutôt que de spécifier des heures comme déclencheurs, des événements inotify et des noms de fichiers / répertoires sont utilisés.

incron est packagé pour de nombreuses distributions, y compris Ubuntu et Debian, je crois.

Andrew Ferrier
la source
0

Il existe un logiciel uniquement à cette fin, autoenv Vous voudrez peut-être le vérifier.

DukeLion
la source
0

entr est l'outil de notification de fichiers le plus simple et le plus composable que j'ai vu. Son utilisation est optimisée pour regarder des fichiers plutôt que des répertoires, mais elle peut également résoudre votre cas.

Pour détecter et agir sur le fichier ajouté, combinez-le avec d'autres outils comme par exemple make. entrn'envoie pas le nom ou quelque chose comme ça, il exécute simplement ce que vous lui avez dit d'exécuter.

Pour vérifier les fichiers ajoutés dans un répertoire:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Si vous souhaitez également agir lorsqu'un fichier existant change:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... et c'est là que le mécanisme de boucle est utile, car l' findexpression s'exécutera à nouveau si un fichier est ajouté.

Si vous voulez une meilleure gestion des erreurs et que vous voulez vous assurer que les choses ne s'exécutent qu'une fois par fichier ajouté / supprimé, les choses deviennent un peu bizarres, mais pour ces cas simples, c'est génial.


EDIT: Si vous voulez faire cela au niveau du système, quelque chose comme incron , ajoutez simplement le script à votre gestionnaire de processus préféré (comme s6 , runit , systemd ou sysvinit et sautez la boucle:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

Le execet la substitution de processus ( <(...)) sont importants lors de l'exécution à partir d'un gestionnaire de processus, pour gérer correctement la signalisation (c'est-à-dire pour éloigner le shell).

clacke
la source