I think your approach is correct, and tracking the cookie is a robust way of doing this. However, the only place in the source of inotify-tools (3.14) that cookie is referenced is in the header defining the struct to match the kernel API.
If you like living on the edge, this patch (issue #72) applies cleanly to 3.14 and adds a %c format specifier for the event cookie in hex:
--- libinotifytools/src/inotifytools.c.orig 2014-10-23 18:05:24.000000000 +0100 +++ libinotifytools/src/inotifytools.c 2014-10-23 18:15:47.000000000 +0100 @@ -1881,6 +1881,12 @@ continue; } + if ( ch1 == 'c' ) { + ind += snprintf( &out[ind], size-ind, "%x", event->cookie); + ++i; + continue; + } + if ( ch1 == 'e' ) { eventstr = inotifytools_event_to_str( event->mask ); strncpy( &out[ind], eventstr, size - ind );
This change modifies libinotifytools.so, not the inotifywait binary. To test before installation:
LD_PRELOAD=./libinotifytools/src/.libs/libinotifytools.so.0.4.1 \ inotifywait --format="%c %e %f" -m -e move /tmp/test Setting up watches. Watches established. 40ff8 MOVED_FROM b 40ff8 MOVED_TO a
Assuming that MOVED_FROM always occurs before MOVED_TO (it does, see fsnotify_move(), and it's an ordered queue, though independent moves might get interleaved) in your script you cache the details when you see a MOVED_FROM line (perhaps in an associative array indexed by ID), and run your processing when you see a MOVED_TO with the matching half of the information.
declare -A cache inotifywait --format="%c %e %f" -m -e move /tmp/test | while read id event file; do if [ "$event" = "MOVED_FROM" ]; then cache[$id]=$file fi if [ "$event" = "MOVED_TO" ]; then if [ "${cache[$id]}" ]; then echo "processing ..." unset cache[$id] else echo "mismatch for $id" fi fi done
(With three threads running to shuffle a pair of files each 10,000 times, I never saw a single out of order event, or event interleaving. It may depend on filesystem and other conditions of course.)