Я хочу запустить оболочку script при изменении определенного файла или каталога.
Как я могу это сделать?
Я хочу запустить оболочку script при изменении определенного файла или каталога.
Как я могу это сделать?
Используйте inotify-tools.
Я использую этот сценарий для запуска сценария сборки изменений в дереве каталогов:
#!/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
 Использует inotify-tools. Посетите страницу inotifywait чтобы узнать, как настроить сборку.
 Вы можете попробовать инструмент  entr для запуска произвольных команд при изменении файлов. Пример для файлов:
$ ls -d * | entr sh -c 'make && make test'
 или же:
$ ls *.css *.html | entr reload-browser Firefox
  или распечатать Changed! когда файл file.txt сохранен:
$ echo file.txt | entr echo Changed!
  Для каталогов используйте -d, но вы должны использовать его в цикле, например:
while true; do find path/ | entr -d echo Changed; done
 или же:
while true; do ls path/* | entr -pd echo Changed; done
		Проверьте демон демонстратора файловой системы ядра
http://freshmeat.net/projects/kfsmd/
Вот как это сделать:
Как уже упоминалось, inotify-tools - лучшая идея. Однако, если вы программируете для удовольствия, вы можете попробовать заработать хакерские XP с помощью разумного применения tail -f.
Как насчет этого script? Использует команду "stat", чтобы получить время доступа к файлу и запускает команду всякий раз, когда происходит изменение времени доступа (при каждом доступе к файлу).
#!/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
		Вот еще один вариант: http://fileschanged.sourceforge.net/
См. особенно "пример 4", который "контролирует каталог и архивирует любые новые или измененные файлы".
 inotifywait может удовлетворить вас.
Вот типичный пример для этого:
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
		Просто для целей отладки, когда я пишу оболочку script и хочу, чтобы она запускалась при сохранении, я использую это:
#!/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_on_save.sh myfile.sh ./myfile.sh arg1 arg2 arg3
Изменить: над тестированием на Ubuntu 12.04 для Mac OS измените строки ls на:
"$(ls -lT $file | awk '{ print $8 }')"
		Добавьте следующее в ~/.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="[email protected]"
        while sleep 1; do
            ATIME=$(stat -c %Z "$TARGET")
            if [[ "$ATIME" != "${LTIME:-}" ]]; then
                LTIME=$ATIME
                $ACTION
            fi
        done
    fi
}
		 Пример использования inotifywait :
 Предположим, я хочу запускать rails test каждый раз, когда меняю соответствующий файл.
1. Составьте список соответствующих файлов, которые вы хотите просмотреть:
 Вы можете сделать это вручную, но я считаю, ack очень полезно, чтобы сделать этот список.
ack --type-add=rails:ext:rb,erb --rails -f > Inotifyfile
  2. Попросите inotifywait сделать работу
while inotifywait --fromfile Inotifyfile; do rails test; done
 Это!
ПРИМЕЧАНИЕ. Если вы используете Vagrant для запуска кода на виртуальной машине, может оказаться полезным расширение mhallin/vagrant-notify-forwarder.
 ОБНОВЛЕНИЕ: еще лучше, сделайте alias и избавьтесь от файла:
alias rtest="while inotifywait $(ack --type-add=rails:ext:rb,erb --rails -f | tr \\n \ ); do rails test; done"