webentwicklung-frage-antwort-db.com.de

Wie führe ich ein Shell-Skript aus, wenn sich eine Datei oder ein Verzeichnis ändert?

Ich möchte ein Shell-Skript ausführen, wenn sich eine bestimmte Datei oder ein bestimmtes Verzeichnis ändert.

Wie kann ich das leicht machen?

54
Drew LeSueur

Verwenden Sie inotify-tools .

21

Ich verwende dieses Skript, um ein Build-Skript für Änderungen in einer Verzeichnisstruktur 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. Überprüfen Sie auf inotifywaitman page , wie Sie anpassen können, was den Build auslöst.

22

Sie können versuchen, mit entr tool beliebige Befehle auszuführen, wenn sich Dateien ändern. Beispiel für Dateien:

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

oder:

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

Für Verzeichnisse verwenden Sie -d, aber Sie müssen es in der Schleife verwenden, z.

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

oder:

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

Checken Sie den Monitor-Daemon des Kernel-Dateisystems aus

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

Hier ist eine Anleitung:

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

3
Brian Clements

Wie gesagt, inotify-tools ist wahrscheinlich die beste Idee. Wenn Sie jedoch zum Spaß programmieren, können Sie versuchen, Hacker-XPs durch sinnvolle Anwendung von tail -f zu verdienen.

2
Yoric

Hier ist eine weitere Option: http://fileschanged.sourceforge.net/

Siehe insbesondere "Beispiel 4", das "ein Verzeichnis überwacht und neue oder geänderte Dateien archiviert".

1
slowdog

Wie wäre es mit diesem Skript? Verwendet den Befehl 'stat', um die Zugriffszeit einer Datei abzurufen, und führt einen Befehl aus, wenn sich die Zugriffszeit ändert (wenn auf die 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
1
VDR

inotifywait kann Sie zufrieden stellen.

Hier ist ein allgemeines Beispiel dafür:

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

Nur zum Debuggen: Wenn ich ein Shell-Skript schreibe und beim Speichern ausführen möchte, verwende ich Folgendes:

#!/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

Führen Sie es als aus

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

Edit: Oben auf Ubuntu 12.04 getestet, für Mac OS, ändern Sie die ls-Zeilen in:

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

Fügen Sie ~/.bashrc folgendes hinzu:

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="[email protected]"
        while sleep 1; do
            ATIME=$(stat -c %Z "$TARGET")
            if [[ "$ATIME" != "${LTIME:-}" ]]; then
                LTIME=$ATIME
                $ACTION
            fi
        done
    fi
}
0
Dan Garthwaite

Beispiel für die Verwendung von inotifywait: 

Angenommen, ich möchte Rails test jedes Mal ausführen, wenn ich eine relevante Datei ändere.

1. Erstellen Sie eine Liste der relevanten Dateien, die Sie ansehen möchten:

Sie könnten dies manuell tun, aber ich finde ack sehr hilfreich, um diese Liste zu erstellen.

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

2. Bitten Sie inotifywait, die Arbeit zu erledigen

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

Das ist es!

ANMERKUNG: Falls Sie Vagrant verwenden, um den Code auf einer VM auszuführen, ist möglicherweise die Erweiterung mhallin/vagrant-notify-forwarder nützlich.

UPDATE: Besser noch eine alias und die Datei loswerden:

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