如何使用 inotify 可靠地維護已編輯文件的監視?

如何使用 inotify 可靠地維護已編輯文件的監視?

我想使用 來監視文件inotify,並在有人更改內容(IN_MODIFY或)時觸發一些程式碼,但是當使用者使用他們最喜歡的工具編輯文件時,IN_CLOSE_WRITE我遇到了停止返回事件的問題。inotify該檔案應該很簡單(單行、無空格、最多 20 個字元)。我不想限制它們的使用,但我不確定如何處理不同的情況。

我正在使用inotify這些是當各種應用程式編輯文件時我收到的事件:

行動 inotify 事件
touch file IN_OPEN
echo "data" > file IN_MODIFYIN_OPENIN_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在使用者使用and的情況下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<>+'

相關內容