Gostaria de monitorar um arquivo com inotify
e acionar algum código quando alguém altera o conteúdo ( IN_MODIFY
ou IN_CLOSE_WRITE
), mas estou tendo problemas onde inotify
para de retornar eventos quando os usuários editam o arquivo com sua ferramenta favorita. O arquivo deve ser simples (linha única, sem espaços, no máximo 20 caracteres). Prefiro não restringir seu uso, mas não sei como lidar com diferentes situações.
Estou usando inotify
e estes são os eventos que recebo quando vários aplicativos editam o arquivo:
Ação | inotify Eventos |
---|---|
touch file |
IN_OPEN |
echo "data" > file |
IN_MODIFY , IN_OPEN , IN_ACCESS , entãoIN_CLOSE_NOWRITE |
nano file (em aberto) |
IN_OPEN |
nano file (sobre ^O ) |
IN_MODIFY , IN_CLOSE_WRITE , IN_OPEN ,IN_ACCESS |
vim file (em aberto) |
IN_OPEN ,IN_CLOSE_NOWRITE |
vim file (sobre :w ) |
IN_MOVE_SELF , IN_ATTRIB , então os eventos param de vir deste arquivo |
gedit file (em aberto) |
IN_OPEN , IN_CLOSE_NOWRITE ,IN_ACCESS |
gedit file (ao salvar) |
IN_OPEN , IN_CLOSE_WRITE , IN_ATTRIB , então os eventos param de vir deste arquivo |
mv newfile file |
IN_ATTRIB , então os eventos param de vir deste arquivo |
A certa altura, pensei ter visto gedit
o gatilho também disparar IN_DELETE_SELF
antes de ficar em silêncio.
No caso em que um usuário usa vim
e gedit
, paro de receber inotify
eventos depois que o usuário termina as edições. Como devo lidar com isso?
A única coisa que vejo em comum é o IN_ATTRIB
evento. Suspeito que quando receber o IN_ATTRIB
evento, devo fazer inotify_rm_watch()
isso wd
e depois recriar um novo inotify_add_watch()
com base no mesmo caminho. Mas essa é a abordagem correta?
Outra opção poderia ser observar o diretório pai. O nome do arquivo afetado está incluído no arquivo inotify_event::name
e, portanto, eu poderia filtrar o arquivo de interesse e acionar qualquer um IN_MODIFY
ou IN_CLOSE_WRITE
onde name
corresponda ao meu arquivo de interesse.
Como menciona ikkachu, alguns editores criam um novo arquivo e depois substituem o original, alterando o inode. Isso significa que todos os relógios no descritor de relógio original expirarão.
A resposta é examinar o diretório pai e verificar se há alterações em qualquer arquivo com o nome de destino. Algo assim:
Esses eventos (
IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE
) capturam as técnicas que tentei acima (touch
,echo "" >
,vim
,nano
,gedit
). Aposto que também poderia capturar links simbólicos alterados com eles.Ou você pode usar o fatrace, que é muito mais rápido e não apresenta esses problemas, por exemplo, algo assim: