How to run a shell script when a file or directory changes?

女生的网名这么多〃 提交于 2019-12-27 10:52:42

问题


I want to run a shell script when a specific file or directory changes.

How can I easily do that?


回答1:


Use inotify-tools.




回答2:


I use this script to run a build script on changes in a directory tree:

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

Uses inotify-tools. Check inotifywait man page for how to customize what triggers the build.




回答3:


You may try entr tool to run arbitrary commands when files change. Example for files:

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

or:

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

or print Changed! when file file.txt is saved:

$ echo file.txt | entr echo Changed!

For directories use -d, but you've to use it in the loop, e.g.:

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

or:

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



回答4:


Check out the kernel filesystem monitor daemon

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

Here's a how-to:

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




回答5:


How about this script? Uses the 'stat' command to get the access time of a file and runs a command whenever there is a change in the access time (whenever file is accessed).

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



回答6:


As mentioned, inotify-tools is probably the best idea. However, if you're programming for fun, you can try and earn hacker XPs by judicious application of tail -f .




回答7:


Here's another option: http://fileschanged.sourceforge.net/

See especially "example 4", which "monitors a directory and archives any new or changed files".




回答8:


Just for debugging purposes, when I write a shell script and want it to run on save, I use this:

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

Run it as

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

Edit: Above tested on Ubuntu 12.04, for Mac OS, change the ls lines to:

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



回答9:


Add the following to ~/.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
}



回答10:


inotifywait can satisfy you.

Here is a common sample for it:

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



回答11:


Example of using inotifywait:

Suppose I want to run rails test every time I modify a relevant file.

1. Make a list of the relevant files you want to watch:

You could do it manually, but I find ack very helpful to make that list.

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

2. Ask inotifywait to do the job

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

That's it!

NOTE: In case you use Vagrant to run the code on a VM, you might find useful the mhallin/vagrant-notify-forwarder extension.

UPDATE: Even better, make an alias and get rid of the file:

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


来源:https://stackoverflow.com/questions/4060212/how-to-run-a-shell-script-when-a-file-or-directory-changes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!