
Я хотел бы отслеживать файл с помощью inotify
и запускать какой-то код, когда кто-то меняет содержимое ( IN_MODIFY
или IN_CLOSE_WRITE
), но я сталкиваюсь с проблемами, когда inotify
перестает возвращать события, когда пользователи редактируют файл с помощью своего любимого инструмента. Файл должен быть простым (одна строка, без пробелов, максимум 20 символов). Я бы предпочел не ограничивать их использование, но я не уверен, как обрабатывать различные ситуации.
Я использую inotify
, и вот события, которые я получаю, когда различные приложения редактируют файл:
Действие | События inotify |
---|---|
touch file |
IN_OPEN |
echo "data" > file |
IN_MODIFY , IN_OPEN , IN_ACCESS , затемIN_CLOSE_NOWRITE |
nano file (при открытии) |
IN_OPEN |
nano file (на ^O ) |
IN_MODIFY , IN_CLOSE_WRITE , IN_OPEN ,IN_ACCESS |
vim file (при открытии) |
IN_OPEN ,IN_CLOSE_NOWRITE |
vim file (на :w ) |
IN_MOVE_SELF , IN_ATTRIB , то события перестают поступать из этого файла |
gedit file (при открытии) |
IN_OPEN , IN_CLOSE_NOWRITE ,IN_ACCESS |
gedit file (при сохранении) |
IN_OPEN , IN_CLOSE_WRITE , IN_ATTRIB , то события перестают поступать из этого файла |
mv newfile file |
IN_ATTRIB , то события из этого файла перестают поступать |
В какой-то момент мне показалось, что я увидел gedit
триггер, а IN_DELETE_SELF
затем он затих.
В случае, когда пользователь использует vim
и gedit
, я перестаю получать inotify
события после того, как пользователь закончил редактирование. Как мне с этим бороться?
Единственное, что я вижу общего, это IN_ATTRIB
событие. Я подозреваю, что когда я получаю событие IN_ATTRIB
, я должен inotify_rm_watch()
это wd
, а затем заново создать новое inotify_add_watch()
на основе того же пути. Но правильный ли это подход?
Другим вариантом может быть просмотр родительского каталога. Имя затронутого файла включено в inotify_event::name
, и поэтому я мог бы отфильтровать интересующий меня файл и запустить любой IN_MODIFY
или IN_CLOSE_WRITE
там, где name
совпадает с моим интересующим меня файлом.
решение1
Как упоминает ikkachu, некоторые редакторы создают новый файл, затем заменяют оригинальный, изменяя inode. Это означает, что любые часы на исходном дескрипторе часов истекут.
Ответ — посмотреть родительский каталог и проверить изменения в любом файле с целевым именем. Что-то вроде этого:
namespace fs = std::filesystem;
fs::path path = "./file1";
assert( !path.is_directory() );
int fd = inotify_init();
int wd = inotify_add_watch(
fd,
path.parent_path().c_str(),
IN_MODIFY | IN_CREATE | IN_CLOSE_WRITE
);
...
inotify_event event;
read(fd, &event, BUF_SIZE);
if (wd == event->wd && path.filename() == event->name) {
emit_file_changed();
}
Эти события ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE
) фиксируют методы, которые я опробовал выше ( touch
, echo "" >
, vim
, nano
, gedit
). Держу пари, что я также смогу захватить измененные символические ссылки с их помощью.
решение2
Или вы можете использовать fatrace, который намного быстрее и не имеет таких проблем, например, что-то вроде этого:
fatrace --timestamp --filter='WD<>+'