I've been Googling and Overflowing for a bit and couldn't find anything usable.
I need a script that monitors a public folder and triggers on new file creation and then moves the files to a private location.
I have a samba shared folder /exam/ple/
on unix mapped to X:\
on windows. On certain actions, txt files are written to the share. I want to kidnap any txt file that appears in the folder and place it into a private folder /pri/vate
on unix. After that file is moved, I want to trigger a separate perl script.
EDIT
Still waiting to see a shell script if anyone has any ideas... something that will monitor for new files and then run something like:
#!/bin/ksh
mv -f /exam/ple/*.txt /pri/vate
Check incron. It seems to do exactly what you need.
If I understand correctly, you just want something like this?
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy
my $poll_cycle = 5;
my $dest_dir = "/pri/vate";
while (1) {
sleep $poll_cycle;
my $dirname = '/exam/ple';
opendir my $dh, $dirname
or die "Can't open directory '$dirname' for reading: $!";
my @files = readdir $dh;
closedir $dh;
if ( grep( !/^[.][.]?$/, @files ) > 0 ) {
print "Dir is not empty\n";
foreach my $target (@files) {
# Move file
move("$dirname/$target", "$dest_dir/$target");
# Trigger external Perl script
system('./my_script.pl');
}
}
File::ChangeNotify allows you to monitor files and directories for changes.
https://metacpan.org/pod/File::ChangeNotify
I'm late to the party, I know, but in the interests of completeness and providing info to future visitors;
#!/bin/ksh
# Check a File path for any new files
# And execute another script if any are found
POLLPATH="/path/to/files"
FILENAME="*.txt" # Or can be a proper filename without wildcards
ACTION="executeScript.sh argument1 argument2"
LOCKFILE=`basename $0`.lock
# Make sure we're not running multiple instances of this script
if [ -e /tmp/$LOCKFILE ] ; then
exit 0
else
touch /tmp/$LOCKFILE
fi
# check the dir for the presence of our file
# if it's there, do something, if not exit
if [ -e $POLLPATH/$FILENAME ] ; then
exec $ACTION
else
rm /tmp/$LOCKFILE
exit 0
fi
Run it from cron;
*/1 7-22/1 * * * /path/to/poll-script.sh >/dev/null 2>&1
You'd want to use the lockfile in your subsequent script ( $ACTION ), and then clean it up on exit, just so you don't have any stacking processes.
$ python autocmd.py /exam/ple .txt,.html /pri/vate some_script.pl
Advantages:
- easier to install than
incron
due to pyinotify is pure Python
- event-driven -- less impact than the perl script
autocmd.py:
#!/usr/bin/env python
"""autocmd.py
Adopted from autocompile.py [1] example.
[1] http://git.dbzteam.org/pyinotify/tree/examples/autocompile.py
Dependencies:
Linux, Python, pyinotify
"""
import os, shutil, subprocess, sys
import pyinotify
from pyinotify import log
class Handler(pyinotify.ProcessEvent):
def my_init(self, **kwargs):
self.__dict__.update(kwargs)
def process_IN_CLOSE_WRITE(self, event):
# file was closed, ready to move it
if event.dir or os.path.splitext(event.name)[1] not in self.extensions:
# directory or file with uninteresting extension
return # do nothing
try:
log.debug('==> moving %s' % event.name)
shutil.move(event.pathname, os.path.join(self.destdir, event.name))
cmd = self.cmd + [event.name]
log.debug("==> calling %s in %s" % (cmd, self.destdir))
subprocess.call(cmd, cwd=self.destdir)
except (IOError, OSError, shutil.Error), e:
log.error(e)
def process_default(self, event):
pass
def mainloop(path, handler):
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm, default_proc_fun=handler)
wm.add_watch(path, pyinotify.ALL_EVENTS, rec=True, auto_add=True)
log.debug('==> Start monitoring %s (type c^c to exit)' % path)
notifier.loop()
if __name__ == '__main__':
if len(sys.argv) < 5:
print >> sys.stderr, "USAGE: %s dir ext[,ext].. destdir cmd [args].." % (
os.path.basename(sys.argv[0]),)
sys.exit(2)
path = sys.argv[1] # dir to monitor
extensions = set(sys.argv[2].split(','))
destdir = sys.argv[3]
cmd = sys.argv[4:]
log.setLevel(10) # verbose
# Blocks monitoring
mainloop(path, Handler(path=path, destdir=destdir, cmd=cmd,
extensions=extensions))
This will result in a fair bit of io - stat() calls and the like. If you want rapid notification without the runtime overhead (but more upfront effort), take a look at FAM/dnotify: link text or link text
I don't use ksh but here's how i do it with sh. I'm sure it's easily adapted to ksh.
#!/bin/sh
trap 'rm .newer' 0
touch .newer
while true; do
(($(find /exam/ple -maxdepth 1 -newer .newer -type f -name '*.txt' -print \
-exec mv {} /pri/vate \; | wc -l))) && found-some.pl &
touch .newer
sleep 10
done
#!/bin/ksh
while true
do
for file in `ls /exam/ple/*.txt`
do
# mv -f /exam/ple/*.txt /pri/vate
# changed to
mv -f $file /pri/vate
done
sleep 30
done