Automatic synchronization using recursive inotify change detection

Ryan Babchishin <rbabchishin@win2ix.ca>

Win2ix Systems Inc. http://www.win2ix.ca

Below is a simple Perl script that automatically synchronizes two directories recursively. Changes to the source directory are detected using the Linux kernel inotify feature.

The inotify API is a kernel feature that allows you to monitor filesystem events. You can monitor files or folders for things like create, delete, access, move, etc… inotify does not support monitoring directories recursively, so that needs to be handled by the programmer. The script below synchronizes two directories (local or remote via rsync). The source directory is re-synchronized only on startup and when changes are detected by inotify.

To try the script, create source and destination directories, set $syncDir and $syncDest in the script and run it. Then in another application/terminal, try creating, copying, moving, renaming files in the source directory. You should see the script react and all changes replicated in the destination directory as they happen.

#!/usr/bin/perl # # This script is public domain. May, 2013. # # Ryan Babchishin <rbabchishin@win2ix.ca> # http://www.win2ix.ca # # Load the inotify perl module use Linux::Inotify2; my $syncDir = "sync"; # Source directory my $syncDest = "sync-new"; # Destination directory or user@host:/path (rsync/ssh) # Create inotify object my $inotify = Linux::Inotify2->new or die "unable to create new inotify object: $!"; # Get a list of subdirectories to watch for changes open(FIND, "find $syncDir -type d |"); while(my $dir = ) { chomp($dir); # Remove newline print "Adding watcher for: $dir\n"; # Create new inotify watcher for this directory $inotify->watch($dir, IN_CLOSE_WRITE | IN_MODIFY | IN_CREATE | IN_DELETE| IN_MOVED_FROM | IN_MOVED_TO); } # Sync once on startup system("rsync $syncDir --delete -av $syncDest"); # Process inotify events while () { # Get a new inotify event my @events = $inotify->read; unless (@events > 0){ print "read error: $!"; last ; } # Loop for each event encountered foreach my $event (@events) { print $event->fullname . " was modified\n" ; # If a new directory is created, add a watcher for it if (($event->IN_ISDIR) && ($event->IN_CREATE)) { print "Is a new directory, adding watcher\n"; # Create new inotify watcher for this directory $inotify->watch($event->fullname, IN_CLOSE_WRITE | IN_MODIFY | IN_CREATE | IN_DELETE| IN_MOVED_FROM | IN_MOVED_TO); } # Perform a sync system("rsync $syncDir --delete -av $syncDest"); } }