Как автоматически запустить скрипт, когда содержимое каталога меняется в Linux?

17

Я хочу автоматически запускать скрипт всякий раз, когда новые файлы копируются в определенный каталог. Другими словами, есть ли способ в Linux «наблюдать» каталог за изменениями, а затем запускать что-то в ответ на изменения?

GeneQ
источник
Это обсуждение было проведено на каждом stackexchange сайте;) см superuser.com/questions/181517/... stackoverflow.com/questions/4380527/... и т.д.
masterxilo

Ответы:

17

Если вам повезет , достаточно , чтобы быть на распределении DEBiAN на основе apt-get install dnotify. Другие дистрибутивы, вероятно, имеют что-то похожее - ищите dnotifyназвание.

dnotify - простая программа, основанная на ядре Linux 2.4.19 + API dnotify. Команда dnotify может выполнять указанную команду каждый раз, когда изменяется содержимое определенного каталога. Он запускается из командной строки и принимает два аргумента: один или несколько каталогов для мониторинга и команду, выполняемую при каждом изменении каталога. Параметры определяют, какие события вызывать: когда файл был прочитан в каталоге, когда он был создан, удален и т. Д.

Если вы хотите обрабатывать это в своей собственной программе, dnotify также является API, который вы хотите использовать.

MikeyB
источник
4
@MikeB, после того, как Googling dnotify вы предложили, я вместо этого использовал inotify, который явно превосходит его. Спасибо, что указали мне правильное направление. apt-get install inotify-tools
GeneQ
7
@GeneQ, inotify заменил dnotify.
Дэвид
1
Аналогично на Gentoo:emerge inotify-tools
Джеймс Снирингер
Да, я хотел сказать, что ядро ​​2.4.19 довольно древнее ;-) inotify - это путь.
Дэвид З
Ах да ... Я забыл, что было более новым :)
MikeyB
12

Вы можете запустить скрипт с помощью инструментов inotify, что-то вроде этого. Он будет отслеживать каталог на наличие изменений в измененных файлах, новых файлах и удаленных файлах, а затем выполнит сценарий.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
user7119
источник
Просто учтите, что если исходный каталог изменяется во время его копирования, inotifywait НЕ будет его видеть, и эти изменения не будут скопированы до тех пор, пока не будут произведены дальнейшие изменения после завершения копирования. Вероятно, не проблема, хотя.
Рауль Салинас-Монтеагудо
Как вы можете запустить это в режиме демона?
Крис Ф
4

я думаю, incron - это то, что вы хотите. Он использует inotify в качестве механизма уведомления (который, как указали другие, заменяет dnotify), но не требует скрипта, который выполняется постоянно с использованием inotifywait или аналогичного (хотя, очевидно, демон incron работает все время). Общесистемные 'crontabs' и пользовательские 'crontabs' поддерживаются аналогично стандартному cron, но вместо указания времени в качестве триггеров используются события inotify и имена файлов / каталогов.

Incron упакован для многих дистрибутивов, включая Ubuntu и Debian, я считаю.

Эндрю Ферье
источник
0

Для этой цели есть программа, autoenv. Вы можете проверить это.

DukeLion
источник
0

entr - это самый простой и составной инструмент для уведомления о файлах, который я когда-либо видел. Его использование оптимизировано для просмотра файлов, а не каталогов, но оно также может решить вашу проблему.

Чтобы обнаружить и обработать добавленный файл, объедините его с другими инструментами, такими как, например make. entrне отправляет имя или что-то в этом роде, оно просто запускает то, что вы сказали, чтобы оно запускалось.

Чтобы проверить наличие добавленных файлов в каталоге:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Если вы также хотите действовать при изменении существующего файла:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... и вот тут вам пригодится механизм цикла, так как findвыражение будет запущено снова, если файл будет добавлен.

Если вам нужна лучшая обработка ошибок и вы хотите, чтобы все выполнялось только один раз для каждого добавленного / удаленного файла, все становится немного странным, но для этих простых случаев это замечательно.


РЕДАКТИРОВАТЬ: Если вы хотите сделать это на системном уровне, что-то вроде incron , просто добавьте скрипт в ваш любимый менеджер процессов (например, s6 , runit , systemd или sysvinit и пропустите цикл:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

Функция execи замена процесса ( <(...)) важны при запуске из диспетчера процессов для правильной обработки сигналов (т. Е. Для удаления оболочки).

clacke
источник