
Me gustaría monitorear un archivo con inotify
y activar algún código cuando alguien cambia el contenido ( IN_MODIFY
o IN_CLOSE_WRITE
), pero tengo problemas que inotify
dejan de devolver eventos cuando los usuarios editan el archivo con su herramienta favorita. El archivo debe ser simple (una sola línea, sin espacios, máximo 20 caracteres). Preferiría no restringir su uso, pero no estoy seguro de cómo manejar diferentes situaciones.
Estoy usando inotify
y estos son los eventos que recibo cuando varias aplicaciones editan el archivo:
Acción | notificar eventos |
---|---|
touch file |
IN_OPEN |
echo "data" > file |
IN_MODIFY , IN_OPEN , IN_ACCESS , entoncesIN_CLOSE_NOWRITE |
nano file (en abierto) |
IN_OPEN |
nano file (en ^O ) |
IN_MODIFY , IN_CLOSE_WRITE , IN_OPEN ,IN_ACCESS |
vim file (en abierto) |
IN_OPEN ,IN_CLOSE_NOWRITE |
vim file (en :w ) |
IN_MOVE_SELF , IN_ATTRIB , entonces los eventos dejan de provenir de este archivo |
gedit file (en abierto) |
IN_OPEN , IN_CLOSE_NOWRITE ,IN_ACCESS |
gedit file (al guardar) |
IN_OPEN , IN_CLOSE_WRITE , IN_ATTRIB , entonces los eventos dejan de venir de este archivo |
mv newfile file |
IN_ATTRIB , entonces los eventos dejan de venir de este archivo |
En un momento me pareció ver que gedit
se disparaba también IN_DELETE_SELF
antes de quedarme en silencio.
En el caso de que un usuario use vim
y gedit
, dejo de recibir inotify
eventos una vez que el usuario haya terminado las ediciones. ¿Cómo debo lidiar con esto?
Lo único que veo en común es el IN_ATTRIB
evento. Sospecho que cuando reciba el IN_ATTRIB
evento, debería hacerlo inotify_rm_watch()
y wd
luego volver a crear uno nuevo inotify_add_watch()
basado en la misma ruta. ¿Pero es ese el enfoque correcto?
Otra opción podría ser observar el directorio principal. El nombre del archivo afectado está incluido en el archivo inotify_event::name
, por lo que puedo filtrar el archivo de interés y activar cualquier IN_MODIFY
lugar IN_CLOSE_WRITE
que name
coincida con mi archivo de interés.
Respuesta1
Como menciona ikkachu, algunos editores crean un nuevo archivo y luego reemplazan el original, cambiando el inodo. Eso significa que cualquier reloj con la descripción de reloj original caducará.
La respuesta es mirar el directorio principal y verificar si hay cambios en cualquier archivo con el nombre de destino. Algo como esto:
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();
}
Estos eventos ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE
) capturan las técnicas que probé anteriormente ( touch
, echo "" >
, vim
, nano
, gedit
). Apuesto a que también podría capturar enlaces simbólicos modificados con estos.
Respuesta2
O podrías usar fatrace, que es mucho más rápido y no tiene tales problemas, por ejemplo, algo como esto:
fatrace --timestamp --filter='WD<>+'