• Post author:
  • Post category:Apps

fsniper is a tool that monitors a given set of directories for new or modified files. Then, based on the file’s type or name, it invokes a script to be run on that file. Directories are monitored using inotify, instead of simply continuously polling them for changes. Common uses include making a single download directory for all things from a Web browser and having semi-intelligent scripts figure out what to do with those files. You write the scripts yourself.

fsniper uses inotify to watch for when a file is closed after being written to. This means utilities such as touch will cause the event to trigger.

fsniper can watch any number of directories for any number of pattern matches on the files.

Download the sniper.tar.gz here (may be old)
Latest version of fsniper-1.3.1.tar.gz

Example Configuration File

Let’s jump into an example configuration file.

watch {

~/tmp/s {
image/* {
handler = echo

*.extension {
handler = ./foo1 a %% b
handler = mv %% arc-%%.txt

/.*regex.*/ {
handler = ./foo2 a %% b

*/* {
handler = echo 2


To start defining directories to watch, you must have a watch block. Each block underneath a watch block is a directory that fsniper monitors for files that are closed.

In this configuration, we are watching only one dir, ~/tmp/s. Underneath that directory block, we are watching for 4 different patterns of files. The first pattern, image/*, looks for files that match a mime-type pattern. Any image file will go into this block. The handler is echo, a standard system command that writes to stdout. fsniper looks for “%%” in the handler line. The name of the file that was just closed is substituted in for the %%. If no %% is found in the handler line, it appends it on the end.

The second pattern, *.extension, matches a shell glob for any file with the .extension extension. This pattern has two handlers. ./foo1 is a custom script we write. If that script returns a return code that is not 0 or 2, it moves on to the next handler. See the Handler Return Codes section.

The third pattern, /.regex./, matches the file name against a regular expression pattern. PCRE support must be compiled in for this pattern to work.

The fourth pattern, /, matches any file (by mime-type wildcards). You could also use *, which would be a file glob.

Configuration: This section details all the available configuration options.

Matching Patterns – There are three types of patterns that fsniper can match against.

fsniper can match mime-types, like text/plain, image/png, etc. You can use the file utility to figure out the mime-type, use file -ib to get the mime-type that fsniper sees.
You can also have wildcards on each side of the mime-type, so image/* would match all images, etc.

Shell Globs
The most common pattern would be shell globs, like .txt or .html. This matches any shell like file pattern.

Regular Expressions
fsniper can be compiled with PCRE support to allow more complicated regular expression matching. Regex patterns are enclosed in forward slashes. Consult the PCRE documentation for the flavor of regular expressions supported. Remember, the entire filename (including path) is matched against the regex.

The handler scripts do not always have to be custom written. You can use the %% replacement to do some script-like behavior. For example, this handler line:

handler = tar cvz archive-%%.tar.gz %%
This will create a tar/gz file of the files that match the file pattern.

Often, custom scripts are easier if they need to perform some complicated tests, or indicate that they will delay.

Handler Search Paths
Since fsniper uses the shell to execute handlers, the shell’s PATH environment variable is respected to find the handlers. fsniper automatically prepends ~/.config/fsniper/scripts into PATH, so it is common to place custom scripts in that directory.

Handler Return Codes
0 : the handler handled this file.

2 : the handler will handle this event, but not right now. Retry again later.

other: this handler can not handle this file.

It is possible that a handler can handle a file, but not at this moment. A common example would be that the handler is supposed to scp a file to a remote server, but that server is currently not available. The handler script returns a 2 to indicate that it can handle it, just not right now. fsniper detects this return code and sleeps for a period of time, then retries the handler.

There are two parameters that control delay handling. These parameters are placed in the configuration file on the top level, aka the same level as the watch block.

delay_time : the amount of time, in seconds, to wait before trying the handler again. If not specified, it defaults to 300, which is 5 minutes.

delay_repeats : the number of repeats it should try before giving up. This can be 0, meaning infinite retries.

fsniper Files

By default, fsniper tries to load its configuration from ~/.config/sniper/config. You can override this by specifying a configuration file on the command line.

fsniper keeps a log file in ~/.config/sniper/log. You can use tail -f to monitor fsniper’s output.

Command Line Options

Prints this help text.
Prints version information.
Run as a daemon.
Turns on debug text.
Sync mode (for debugging).
Log to stdout alongside the usual log file.

Init Script
Here is an init script from From blog.secaserver.com

1. Create the init script in init.d directory:
$ touch /etc/init.d/fsniper

2. Using your favourite text editor, open the file /etc/init.d/fsniper and paste following code:

export HOME=/root

case "$1" in
echo -n "Starting Fsniper: "
/usr/local/bin/fsniper --daemon
echo -e "... [ \e[00;32mOK\e[00m ]"
echo -n "Shutdown Fsniper: "
kill -9 `ps aux | grep "fsniper --daemon" | grep -v grep | awk {'print $2'}`
echo -e "... [ \e[00;32mOK\e[00m ]"
$0 stop
sleep 1
$0 start
echo "Usage: `basename $0` start|stop|restart"
exit 1

exit 0

3. Change the permission to executable:

$ chmod 755 /etc/init.d/fsniper

Done! You can now use following command to start fsniper:

$ service fsniper start
$ /etc/init.d/fsniper start


I am a g33k, Linux blogger, developer, student and Tech Writer for Liquidweb.com/kb. My passion for all things tech drives my hunt for all the coolz. I often need a vacation after I get back from vacation....