Je souhaite exécuter un script Shell lorsqu'un fichier ou un répertoire spécifique est modifié.
Comment puis-je facilement faire ça?
Utilisez inotify-tools .
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 inotifywait
page de manuel pour savoir comment personnaliser ce qui déclenche la construction.
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
Découvrez le démon de surveillance du système de fichiers du noyau
http://freshmeat.net/projects/kfsmd/
Voici un guide pratique:
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 .
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".
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
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
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 }')"
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
}
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"