Nov 262010
 

inotifyinotify is a Linux kernel subsystem that acts to extend filesystems to notice changes to the filesystem, and report those changes to applications. It replaces an earlier facility, dnotify, which had similar goals.

The original developers of inotify were John McCutchan, Robert Love and Amy Griffis. It has been included in the mainline Linux kernel from release 2.6.13 (June 18, 2005), and could be compiled into 2.6.12 and possibly earlier releases by use of a patch.

One major use is in desktop search utilities like Beagle, where its functionality permits reindexing of changed files without scanning the filesystem for changes every few minutes, which would be very inefficient. By being told that a file has changed directly by the kernel, rather than actively looking, Beagle and such utilities can achieve change-to-reindexing times of only about a second.



It can also be used to automatically update directory views, reload configuration files, log changes, backup, synchronize, and upload.

Shell examples
To use the power of inotify you must install the package inotify-tools (available for all the main distribution), after that you can use the function “inotifywait “which makes it easy to integrate it with shell scripts.

inotifywait
This command simply blocks for inotify events, making it appropriate for use in shell scripts. It can watch any set of files and directories, and can recursively watch entire directory trees.

Example 1

#!/bin/sh

# get the current path
CURPATH=`pwd`

inotifywait -mr --timefmt '%d/%m/%y %H:%M' --format '%T %w %f'
-e close_write /tmp/test | while read date time dir file; do

FILECHANGE=${dir}${file}
# convert absolute path to relative
FILECHANGEREL=`echo "$FILECHANGE" | sed 's_'$CURPATH'/__'`

rsync --progress --relative -vrae 'ssh -p 22' $FILECHANGEREL [email protected]:/backup/root/dir &&
echo "At ${time} on ${date}, file $FILECHANGE was backed up via rsync"
done

In this example we watch /tmp/test and if an event of “close_write” is caught we rsync that file to a remote location.

Example 2

Consider the simple example of wanting to monitor files created in /tmp and print on standard output a message any time a file is created.


#!/bin/sh

# CONFIGURATION
DIR="/tmp"
EVENTS="create"
FIFO="/tmp/inotify2.fifo"

# FUNCTIONS
on_exit() {
kill $INOTIFY_PID
rm $FIFO
exit
}

on_event() {
local date=$1
local time=$2
local file=$3

sleep 5

echo "$date $time Fichier créé: $file"
}

# MAIN
if [ ! -e "$FIFO" ]
then
mkfifo "$FIFO"
fi

inotifywait -m -e "$EVENTS" --timefmt '%Y-%m-%d %H:%M:%S' --format '%T %f' "$DIR" > "$FIFO" &
INOTIFY_PID=$!

trap "on_exit" 2 3 15

while read date time file
do
on_event $date $time $file &
done < "$FIFO"

on_exit

Detail:

  • Function on_event is launched in the background (a sub-shell process is actually created)
  • operations are now performed in parallel processing practical for long or multiple processors eligible
  • The use of the named pipe $FIFO can run the command inotifywait background and get its PID
  • It is  possible to install a “trap”, ie the function on_exit () “, which will kill the command inotifywait (and also delete the named pipe) when the script is killed by a signal 2 (INT ), 3 (QUIT) or 15 (TERM).
  • The events are played through the named pipe, without creating a shell, through the end of “while” done <$ FIFO

Stay “inotified”

There are other inotify-based utilities to consider adding to your bag of tricks. The incron utility is a corollary to cron but reacts to inotify events instead of a schedule. The inoticoming utility is specifically designed to monitor dropboxes. And if you’re a Perl, Ruby, or Python developer, you can find modules and libraries to call inotify from the comfort of your favorite scripting language.

For instance, Perl coders can use Linux::Inotify2 (see Resources for details) to embed inotify features in any Perl application.

This code, taken from the Linux::Inotify2 README file, demonstrates a callback interface to monitor events:


use Linux::Inotify2;

my $inotify = new Linux::Inotify2
or die "Unable to create new inotify object: $!";

# for Event:
Event->io (fd =>$inotify->fileno, poll => 'r', cb => sub { $inotify->poll });

# for Glib:
add_watch Glib::IO $inotify->fileno, in => sub { $inotify->poll };

# manually:
1 while $inotify->poll;

# add watchers
$inotify->watch ("/etc/passwd", IN_ACCESS, sub {
my $e = shift;
my $name = $e->fullname;
print "$name was accessedn" if $e->IN_ACCESS;
print "$name is no longer mountedn" if $e->IN_UNMOUNT;
print "$name is gonen" if $e->IN_IGNORED;
print "events for $name have been lostn" if $e->IN_Q_OVERFLOW;

# cancel this watcher: remove no further events
$e->w->cancel;
});

References:

http://kerlinux.org/2010/08/utilisation-de-inotifywait-dans-des-scripts-shell/

http://www.ibm.com/developerworks/linux/library/l-ubuntu-inotify/index.html?ca=drs-

Popular Posts:

Flattr this!

  8 Responses to “Introduction to inotify”

  1. I tried out inotify-tools with Example 1 edited to just /tmp folder, but got an Error when running my inotify-tools Example 1 Script…

    [don@fedora13gt5408 Shell Scripts]$ ./inotify-tools-Example-1-edited-to-just-tmp-folder.sh
    Setting up watches. Beware: since -r was given, this may take a while!
    Failed to watch /tmp/; upper limit on inotify watches reached!
    Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches’.
    [don@fedora13gt5408 Shell Scripts]$

    Max is already set to 8192. Tired to 9000 in Kursader root mode, to see if it works. Couldn’t save copy or edit at all, even by starting kwrite and gedit from root Terminal. I wonder if this is an SElinux issue. But I didn’t get any SELinux notices and I have mine set to Permissive mode…

    Don

    • Hello Don,

      Just re-tested on my ubunto 10.10, and example 1 seem to work fine here.
      I’ve just changed from a rsync to a cp and when i use the program i get:

      root@laptop:~# bash test-inotify.sh
      Setting up watches. Beware: since -r was given, this may take a while!
      Watches established.
      At 09:39 on 06/12/10, file /tmp/test-two was created and copied in /root/test
      At 09:39 on 06/12/10, file /tmp/test-three was created and copied in /root/test

      From another terminal i did a touch /tmp/test-two and touch /tmp/test-three.

      I tested it with root and a normal account and both worked fine.
      Also in Ubuntu /proc/sys/fs/inotify/max_user_watches is set to 8192.

      This work on your box ?

      root@laptop:~# echo 32000 > /proc/sys/fs/inotify/max_user_watches
      root@aptop:~# cat /proc/sys/fs/inotify/max_user_watches
      32000

      Thanks for the feedback, i usually don’t work with SElinux over time I’ve seen that gives me more problems than it solves.

  2. how this inotify script run at background? because when I exit/ log out from the server it stop working 🙂

  3. For exemple 2, if I want to change the event: modify, he will give me an infinite list of modified files, as soon as I open the directory. How can I fixe that?

  4. Hi, if anyone is able to give me some pointers on why the code below generates an infinite number of rsync actions I would very much appreciate it. I suppose that either I have an infinite loop in my bash script (I’ll confess I’m fresh to bash scripting) or I’m getting an infinite number of notifications from inotify. However, apart from having to add a backslash to a couple of lines to get the code working at all (I’m guessing that those lines may have been split automatically by the page formatting in the example above) it does seem to me that my extract is materially the same as the first example.

    #!/bin/sh

    inotifywait -m –timefmt ‘%d/%m/%y %H:%M’ –format ‘%T %w %f’ \
    -e modify /home/user/apps/db_backups/db_files/ | while read date time dir file; do

    FILECHANGE=${dir}${file}

    rsync –progress -rlptD -e “ssh -i /home/deploy/.ssh/id_rsa” $FILECHANGE user@server:/home/user/apps/db_backups/db_files && \
    echo “At ${time} on ${date}, file $FILECHANGE was backed up via rsync”
    done

Leave a Reply to Alex Cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

*