How to run commands on File or Directory changes with Incron on Ubuntu
This tutorial exists for these OS versions
- Ubuntu 16.04 (Xenial Xerus)
- Ubuntu 15.10 (Wily Werewolf)
On this page
This tutorial shows you how you can use incron on an Ubuntu system to run commands when a file or Directory is changed. The incron daemon is similar to cron, but instead of running commands based on time, it can trigger commands when a file or directory event occurs (e.g. a file modification, changes of permissions, etc.).
1 Installing Incron
The following steps have to be run as root user. Please login to the shell of your Ubuntu system and become root with:
sudo su
The Incron software is available in the Ubuntu repository. Therefore, I will install it with apt like this:
apt-get install incron
3 How to use Incron
As mentioned in the first chapter, Incron has many similarities to the Cron tool. Where Cron has its crontab command to manage cronjobs, Incron has the command incrontab. You can use the incrontab command options list (-l), edit (-e), and remove (-r) to show and alter incrontab entries.
Run the following command to get a full overview over incrontab:
man incrontab
In the man page you will find the following note:
If /etc/incron.allow exists only users listed here may use incron. Otherwise if /etc/incron.deny exists only users NOT listed here may use incron. If none of these files exists everyone is allowed to use incron. (Important note: This behavior is insecure and will be probably changed to be compatible with the style used by ISC Cron.) Location of these files can be changed in the configuration.
This means that if we want to use incrontab as root, we have to delete /etc/incron.allow (which is unsafe)...
rm -f /etc/incron.allow
... or we add the root user to the incron.allow file ( which is the recommended option). Open the /etc/incron.allow file:
nano /etc/incron.allow
And add the following line.
root
Before you do this, you will get error messages like this one when trying to use incrontab:
server1:~# incrontab -l
user 'root' is not allowed to use incron
server1:~#
Afterwards it works:
server1:~# incrontab -l
no table for root
server1:~#
We can now use this command:
incrontab -e
To create incron jobs. Now let's take a deeper look at the man page to understand the Syntax.
man 5 incrontab
The manpage shows the format of the cron tab lines. The format follows this scheme:
<path> <mask> <command>
...where <path> is a directory or a file. Please note that incron is not able to watch files in sub directories of the directory that you have set, so only files in that directory will be observed.
<mask> can be one of the following options:
IN_ACCESS File was accessed (read) (*)
IN_ATTRIB Metadata changed (permissions, timestamps, extended attributes, etc.) (*)
IN_CLOSE_WRITE File opened for writing was closed (*)
IN_CLOSE_NOWRITE File not opened for writing was closed (*)
IN_CREATE File/directory created in watched directory (*)
IN_DELETE File/directory deleted from watched directory (*)
IN_DELETE_SELF Watched file/directory was itself deleted
IN_MODIFY File was modified (*)
IN_MOVE_SELF Watched file/directory was itself moved
IN_MOVED_FROM File moved out of watched directory (*)
IN_MOVED_TO File moved into watched directory (*)
IN_OPEN File was opened (*)
When monitoring a directory, the events marked with an asterisk (*) above can occur for files in the directory, in which case the name field in the
returned event data identifies the name of the file within the directory.
The IN_ALL_EVENTS symbol is defined as a bit mask of all of the above events. Two additional convenience symbols are IN_MOVE, which is a combination of IN_MOVED_FROM and IN_MOVED_TO, and IN_CLOSE which combines IN_CLOSE_WRITE and IN_CLOSE_NOWRITE.
The following further symbols can be specified in the mask:
IN_DONT_FOLLOW Don't dereference pathname if it is a symbolic link
IN_ONESHOT Monitor pathname for only one event
IN_ONLYDIR Only watch pathname if it is a directory
Additionaly, there is a symbol which doesn't appear in the inotify symbol set. It is IN_NO_LOOP. This symbol disables monitoring events until the current one is completely handled (until its child process exits).
<command> is the command that should be run when the event occurs. The following wildards may be used inside the command specification:
$$ dollar sign
$@ watched filesystem path (see above)
$# event-related file name
$% event flags (textually)
$& event flags (numerically)
If you watch a directory, then $@ holds the directory path and $# the file that triggered the event. If you watch a file, then $@ holds the complete path to the file and $# is empty.
If you need the wildcards but are not sure what they translate to, you can create an incron job like this.
Create a directory that shall be watched:
mkdir /tmp/testdir
Then open the incrontab:
incrontab -e
and add the following line:
/tmp/testdir/ IN_MODIFY echo "$$ $@ $# $% $&"
Then you create or modify a file in the /tmp/testdir/ directory and take a look at /var/log/syslog - this log shows when an incron job was triggered, if it succeeded or if there were errors, and what the actual command was that it executed (i.e., the wildcards are replaced with their real values).
For testing purposes, I'll add two files, helloworld.txt and helloworld2.txt in /tmp/testdir/ with the echo command:
echo 'How are you?' > /tmp/testdir/helloworld.txt
echo 'How are you?' > /tmp/testdir/helloworld2.txt
So let's check the syslog with tail for incron ecents:
tail /var/log/syslog
...
Apr 12 18:49:22 server1 incrond[6441]: (root) CMD (echo "$ /tmp/testdir/ helloworld.txt IN_MODIFY 2")
Apr 12 18:50:31 server1 incrond[6441]: (root) CMD (echo "$ /tmp/testdir/ helloworld2.txt IN_MODIFY 2")
Now enough theory. Let's create our first incron jobs. I'd like to monitor the file /etc/apache2/apache2.conf and the directory /etc/apache2/vhosts/, and whenever there are changes, I want incron to restart Apache. This is how we do it:
incrontab -e
/etc/apache2/apache2.conf IN_MODIFY /usr/sbin/service apache2 restart /etc/apache2/sites-available/ IN_MODIFY /usr/sbin/service apache2 restart
That's it. For test purposes you can modify your Apache configuration and take a look at /var/log/syslog, and you should see that incron restarts Apache.
NOTE: Do not do any action from within an incron job in a directory that you monitor to avoid loops. Example: When you monitor the /tmp directory for changes and each change triggers a script that writes a log file in /tmp, this will cause a loop and might bring your system to high load or even crash it.
To list all defined incron jobs, you can run:
incrontab -l
server1:~# incrontab -l
/etc/apache2/apache2.conf IN_MODIFY /usr/sbin/service apache2 restart
/etc/apache2/vhosts/ IN_MODIFY /usr/sbin/service apache2 restart
server1:~#
To delete all incron jobs of the current user, run:
incrontab -r
server1:~# incrontab -r
removing table for user 'root'
table for user 'root' successfully removed
server1:~#