Inotify for bash programmers

There are amazing system calls on a modern system nowadays. Unfortunately, not all of them are exposed as a unix style program. One such system call is inotify.

Have you ever needed to watch a file or a directory for changes? I have. I've written software that needs to be called whenever there's new data for processing in a directory. My usual approach to this is to add the command in cron and keep on polling for new files. That works, but wouldn't it be nicer if the system told us about changes, so we could process the new file right away? Linux already has a mechanism for that (I don't know if there's such a call in BSD world, I don't use them anyway), it's the inotify system call.

I wrote code (I used C++ merely because I needed a map and C is so bad with such data structure) which exposes inotify for scripts. It allows me to write a script to call a command whenever a new file is created in /tmp. Here's how to do that using awk:

$ inotifier /tmp IN_CREATE | awk '{ system("cat "$3$4); }'

If I execute the command echo bla > /tmp/test, then the example above will print bla.

inotifier allows me to watch all events as well. One can use it to decide which event to filter and even to debug what a certain software is doing.

$ inotifier /tmp IN_ALL_EVENTS
IN_ISDIR,IN_OPEN    0   /tmp/
IN_CLOSE_NOWRITE,IN_ISDIR   0   /tmp/
IN_CREATE   0   /tmp/   test2
IN_OPEN 0   /tmp/   test2
IN_ATTRIB   0   /tmp/   test2
IN_CLOSE_WRITE  0   /tmp/   test2

That's the output after executing ls /tmp and touch /tmp/test2.

The output of inotifier comes from inotify(7) interface. inotify gives me a inotify_event struct every time an event is fired. The tab separated output of inotifier are the following struct members (in order): mask, cookie, wd, and name.

While inotify gives me a bit mask, I transform it into a comma-separated list of event names (IN_ISDIR,IN_OPEN). I do that because I believe it's easier to work with bash that way (and it's easier on the eyes as well).

When using inotifier, it's possible to watch for more than one event, for example:

$ inotifier /tmp IN_OPEN,IN_CREATE

watches for files created inside /tmp and for the open event in the directory /tmp (usually used for listing its contents).

It's possible to watch a file instead of a directory:

$ inotifier /tmp/foo IN_OPEN

watches /tmp/foo for open events. Whenever someone opens /tmp/foo, inotifier will output.

We can als watch more than one file at time:

$ inotifier /tmp/foo IN_ALL_EVENTS /tmp/test IN_ALL_EVENTS

notifies us about all events in files /tmp/foo and /tmp/test.

Download

I didn't bothered creating a repository for this one. You can download the software here: inotifier-1.1.tar.gz. Inside the package there's a README file explaining how to compile it (there's a manual page as well, inotifier.1). All you got to do is make inside the untared directory and you're good to go.

I'm using a permissive license for this one, as usual.