Wie ein Shell-Skript, wenn eine Datei oder ein Verzeichnis Änderungen ausgeführt werden?
Frage
Ich möchte ein Shell-Skript ausgeführt werden soll, wenn eine bestimmte Datei oder ein Verzeichnis ändert.
Wie kann ich das einfach tun?
Lösung
Verwenden Sie inotify-tools .
Andere Tipps
Ich benutze dieses Skript einen Build-Skript auf Änderungen in einem Verzeichnisbaum auszuführen:
#!/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
Verwendet inotify-tools
. Prüfen inotifywait
Manpage wie anpassen, was die Build auslöst.
Sie können versuchen, entr
Werkzeug beliebige Befehle auszuführen, wenn Dateien geändert werden. Beispiel für Dateien:
$ ls -d * | entr sh -c 'make && make test'
oder:
$ ls *.css *.html | entr reload-browser Firefox
oder Druck Changed!
wenn Datei file.txt
wird gespeichert:
$ echo file.txt | entr echo Changed!
Für Verzeichnisse verwenden -d
, aber Sie haben es in der Schleife zu verwenden, z.
while true; do find path/ | entr -d echo Changed; done
oder:
while true; do ls path/* | entr -pd echo Changed; done
Überprüfen Sie die Kernel-Dateisystem Monitor out-Daemon
http://freshmeat.net/projects/kfsmd/
Hier ist ein How-to:
Wie bereits erwähnt, ist inotify-Tools wahrscheinlich die beste Idee. Allerdings, wenn Sie die Programmierung für Spaß haben, können Sie versuchen, und Hacker-XPs durch eine vernünftige Anwendung von
Wie wäre es dieses Skript? Verwendet den ‚stat‘ Befehl, um die Zugriffszeit einer Datei zu erhalten und führt einen Befehl, wenn es eine Änderung in der Zugriffszeit (wann immer Datei zugegriffen wird). #!/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
Hier ist eine andere Option: http://fileschanged.sourceforge.net/
Siehe insbesondere „Beispiel 4“, die „überwacht ein Verzeichnis und Archive neue oder geänderte Dateien“.
inotifywait
können Sie erfüllen.
Hier ist eine gemeinsame Probe für sie:
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
Nur zum Debuggen, wenn ich einen Shell-Skript schreiben und will es speichern läuft auf, ich benutze diese:
#!/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
Ausführen als
run_on_save.sh myfile.sh ./myfile.sh arg1 arg2 arg3
Edit: Vor getestet auf Ubuntu 12.04, für Mac OS, die ls Zeilen ändern:
"$(ls -lT $file | awk '{ print $8 }')"
Fügen Sie folgende zu ~ / .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
}
Beispiel für die Verwendung inotifywait
:
Angenommen, ich rails test
ich eine entsprechende Datei ändern, jedes Mal ausgeführt werden soll.
1. Machen Sie eine Liste der relevanten Dateien, die Sie sehen wollen:
Sie können es manuell tun, aber ich finde ack
sehr hilfreich, diese Liste zu machen.
ack --type-add=rails:ext:rb,erb --rails -f > Inotifyfile
2. Stellen Sie inotifywait
die Arbeit zu tun
while inotifywait --fromfile Inotifyfile; do rails test; done
Das ist es!
Hinweis: Falls Sie Vagrant verwenden Sie den Code auf einer VM laufen, finden Sie vielleicht nützlich, die mhallin / Vagabund-notify-Spediteur Erweiterung.
UPDATE:
Noch besser ist, eine alias
machen und loszuwerden der Datei:
alias rtest="while inotifywait $(ack --type-add=rails:ext:rb,erb --rails -f | tr \\n \ ); do rails test; done"