web-dev-qa-db-fra.com

Comment exécuter un script Shell lorsqu'un fichier ou un répertoire est modifié?

Je souhaite exécuter un script Shell lorsqu'un fichier ou un répertoire spécifique est modifié.

Comment puis-je facilement faire ça?

54
Drew LeSueur

Utilisez inotify-tools .

21
Frédéric Hamidi

J'utilise ce script pour exécuter un script de construction sur les modifications dans une arborescence de répertoires:

#!/bin/bash -eu
DIRECTORY_TO_OBSERVE="js"      # might want to change this
function block_for_change {
  inotifywait --recursive \
    --event modify,move,create,delete \
    $DIRECTORY_TO_OBSERVE
}
BUILD_SCRIPT=build.sh          # might want to change this too
function build {
  bash $BUILD_SCRIPT
}
build
while block_for_change; do
  build
done

Utilise inotify-tools. Consultez inotifywaitpage de manuel pour savoir comment personnaliser ce qui déclenche la construction.

22

Vous pouvez essayer entr tool pour exécuter des commandes arbitraires lorsque les fichiers sont modifiés. Exemple pour les fichiers:

$ ls -d * | entr sh -c 'make && make test'

ou:

$ ls *.css *.html | entr reload-browser Firefox

Pour les répertoires, utilisez -d, mais vous devez l’utiliser dans la boucle, par exemple:

while true; do find path/ | entr -d echo Changed; done

ou:

while true; do ls path/* | entr -pd echo Changed; done
12
kenorb

Découvrez le démon de surveillance du système de fichiers du noyau

http://freshmeat.net/projects/kfsmd/

Voici un guide pratique:

http://www.linux.com/archive/feature/124903

3
Brian Clements

Comme mentionné, inotify-tools est probablement la meilleure idée. Cependant, si vous programmez pour le plaisir, vous pouvez essayer de gagner des XP de piratage informatique en appliquant judicieusement le tail -f .

2
Yoric

Voici une autre option: http://fileschanged.sourceforge.net/

Voir notamment "exemple 4", qui "surveille un répertoire et archive tous les fichiers nouveaux ou modifiés".

1
slowdog

Que diriez-vous de ce script? Utilise la commande 'stat' pour obtenir le temps d'accès d'un fichier et exécute une commande chaque fois que le temps d'accès est modifié (chaque fois qu'un fichier est utilisé).

#!/bin/bash

while true

do

   ATIME=`stat -c %Z /path/to/the/file.txt`

   if [[ "$ATIME" != "$LTIME" ]]

   then

       echo "RUN COMMNAD"
       LTIME=$ATIME
   fi
   sleep 5
done
1
VDR

inotifywait peut vous satisfaire.

Voici un exemple commun pour cela:

inotifywait -m /path -e create -e moved_to -e close_write | # -m is --monitor, -e is --event
    while read path action file; do
        if [[ "$file" =~ .*rst$ ]]; then             # if suffix is '.rst'
            echo ${path}${file} ': '${action}        # execute your command
            echo 'make html'
            make html
        fi
    done
1
pwxcoo

Juste à des fins de débogage, lorsque j'écris un script Shell et que je veux qu'il s'exécute, je l'utilise:

#!/bin/bash
file="$1" # Name of file
command="${*:2}" # Command to run on change (takes rest of line)
t1="$(ls --full-time $file | awk '{ print $7 }')" # Get latest save time
while true
do
  t2="$(ls --full-time $file | awk '{ print $7 }')" # Compare to new save time
  if [ "$t1" != "$t2" ];then t1="$t2"; $command; fi # If different, run command
  sleep 0.5
done

Exécuter en tant que

run_on_save.sh myfile.sh ./myfile.sh arg1 arg2 arg3

Edit: ci-dessus testé sur Ubuntu 12.04, pour Mac OS, modifiez les lignes ls en:

"$(ls -lT $file | awk '{ print $8 }')"
0
jonatan

Ajoutez ce qui suit à ~/.bashrc:

function react() {
    if [ -z "$1" -o -z "$2" ]; then
        echo "Usage: react <[./]file-to-watch> <[./]action> <to> <take>"
    Elif ! [ -r "$1" ]; then
        echo "Can't react to $1, permission denied"
    else
        TARGET="$1"; shift
        ACTION="$@"
        while sleep 1; do
            ATIME=$(stat -c %Z "$TARGET")
            if [[ "$ATIME" != "${LTIME:-}" ]]; then
                LTIME=$ATIME
                $ACTION
            fi
        done
    fi
}
0
Dan Garthwaite

Exemple d'utilisation de inotifywait: 

Supposons que je veuille exécuter Rails test chaque fois que je modifie un fichier pertinent.

1. Faites une liste des fichiers que vous souhaitez regarder:

Vous pouvez le faire manuellement, mais je trouve ack très utile pour faire cette liste.

ack --type-add=Rails:ext:rb,erb --Rails -f > Inotifyfile

2. Demander à inotifywait de faire le travail

while inotifywait --fromfile Inotifyfile; do Rails test; done

C'est tout!

REMARQUE: Si vous utilisez Vagrant pour exécuter le code sur une machine virtuelle, le fichier mhallin/vagrant-notify-forwarder peut être utile.

UPDATE: Encore mieux, créez une alias et supprimez le fichier:

alias rtest="while inotifywait $(ack --type-add=Rails:ext:rb,erb --Rails -f | tr \\n \ ); do Rails test; done"
0
Is Ma