6

Есть ли способ установить что-то вроде триггера для файла, чтобы при каждом изменении файла выполнялся скрипт или программа?

Я нашел механизм для этого только в сценарии оболочки, но хотел бы знать, существует ли механизм для этого на основе операционной системы (чтобы мне не приходилось вручную запускать фоновую программу). Решением на основе операционной системы будет задание cron, которое выполняется каждые несколько секунд, но для меня это не выглядит адекватным решением.

Это для Debian, кстати.

Спасибо за помощь.

3 ответа3

8

один из ваших вариантов - подсистема inotify ядра linux:

inotify - это подсистема ядра Linux, которая расширяет файловые системы, чтобы замечать изменения в файловой системе и сообщать об этих изменениях приложениям.

но поскольку inotify - это ядро, вам нужно что-то в пользовательском пространстве, чтобы фактически использовать это:

Демон inotify cron(incrond) - это демон, который отслеживает события файловой системы и выполняет команды, определенные в системных и пользовательских таблицах. Его использование в целом похоже на cron(8).

Gamin - это система мониторинга файлов и каталогов, которая независимо реализует подмножество FAM, Монитор изменения файлов. Работая как служба, она позволяет обнаруживать изменения в файле или каталоге. gam_server функционирует как демон для Gamin.

inoticoming - запускать действия, когда файлы попадают во входящий каталог

на аскубунту был ответ на похожий вопрос:

https://askubuntu.com/a/43848/1223

2

Еще один быстрый и грязный способ сделать это - использовать inotifywait из пакета inotify-tools (на fedora).

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

while [[ 1 ]]; do inotifywait -e modify <filename>; make && ./helloworld; done
1

Я бы сказал, что механизм для этого в сценарии оболочки является вполне адекватным решением, и что механизм для этого на основе операционной системы (чтобы мне не приходилось вручную запускать фоновую программу) просто означает помещение этого решения в процесс. менеджер, такой как s6, runit, системный модуль или даже запись inittab, если вы работаете в системе sysvinit.

Независимо от механизма поддержания его работы, мне нравится entr для просмотра файлов. Простой, по сути, составной (например, тривиально, чтобы положить в диспетчере процессов).

Вот скрипт для просмотра /path/to/file и запуска /usr/local/bin/do_stuff при его изменении:

#!/bin/bash
exec entr /usr/local/bin/do_stuff < <(echo /path/to/file)

Это все, что нужно сделать. Поместите это в файл run runit или s6, поместите его в строку ExecStart модуля systemd или вызовите этот скрипт из строки в inittab . Хотя, если вы поместите его в inittab вы, вероятно, захотите добавить где-нибудь sleep , так как sysvinit не ограничивает скорость процессов, которые сразу же завершаются неудачей из-за ошибок в написании, отсутствующих файлов или чего-то подобного.


Почему бы просто не echo /path/to/file | entr /usr/local/bin/do_stuff? При работе под управлением процесса важно, чтобы управляемый процесс находился непосредственно под супервизором, чтобы он работал правильно, например, при завершении работы. Если оболочка работает под супервизором, она будет перехватывать любые сигналы TERM , INT или KILL а не процесс, который она выполняет, и не будет их передавать. Или он выйдет и оставит процесс осиротевшим. exec удаляет оболочку из цепочки процессов. (exec на правой стороне | не имеет значения)

Или просто используйте оболочку, которая никогда не окажется посредине, execline:

#!/bin/execlineb
pipeline -d {
  echo /path/to/file
} entr /usr/local/bin/do_stuff

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .