tags:

views:

2467

answers:

6

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
+4  A: 

Check incron. It seems to do exactly what you need.

depesz
this looks pretty decent... too bad i can't install it :<
CheeseConQueso
+4  A: 

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');
    }
}
ire_and_curses
ill test it out.... this runs infinitely im guessing? also, im only looking for text files, but the grep bomb is cool to have
CheeseConQueso
@CheeseConQueso: Yes, it's an infinite while loop, polling at the frequency you specify. I haven't rigorously tested the code, but the idea is simple enough.
ire_and_curses
@CheeseConQueso: You can obviously modify the `grep` to ignore files with a particular suffix if that is your situation.
ire_and_curses
how can i kill the process so its not spinning its wheels in the middle of the night? I want it to run from 7am - 10pm and then hide in the corner for the night
CheeseConQueso
@CheeseConQueso: If you want time-specific functionality, then the simplest answer is probably to remove the `while` loop and `sleep` and set the script to run via `cron`. You can specify the interval to run and also constrain the times. As quack said, this is what `cron` was designed for.
ire_and_curses
i will probably use this - @files = glob "/exam/ple/*.txt"; - to build the array
CheeseConQueso
@ire - true... forgot about that
CheeseConQueso
and use system(mv etc....) to move the files so i dont have to use the file::copy
CheeseConQueso
wait... even if i cron this script to run between those times, it will still be running afterwards wont it? i think ill change the while(1) to a time-driven conditional from the hours in "date"
CheeseConQueso
+3  A: 

File::ChangeNotify allows you to monitor files and directories for changes.

http://search.cpan.org/~drolsky/File-ChangeNotify-0.07/lib/File/ChangeNotify.pm

jsoverson
+1  A: 

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

Mark Aufflick
A: 
#!/bin/ksh
while true
do
    for file in `ls /exam/ple/*.txt`
    do
          mv -f /exam/ple/*.txt /pri/vate
    done
    sleep 30
done
CheeseConQueso
here is a way to do a search every 30 seconds in korn shell that i found online.... it is not triggered by a new file, its more of a cron-type process.... i still cant find a korn shell script that runs on the presence of a new file
CheeseConQueso
@Cheese, that's a bit of a clunky example - if there are two files in /exam/ple on a single iteration then the for body will run twice, but both files will be mv'ed first time through. So you'll see errors in the second call of mv. Are those backticks needed?
martin clayton
@Martin - good point... I found it online and didn't test it out, so im not sure if the backticks are needed. I just put it up here because it was a shell approach. It's also clunky in that cron can do this same thing
CheeseConQueso
+1  A: 
$ python autocmd.py /exam/ple .txt,.html /pri/vate some_script.pl

Advantages:

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))
J.F. Sebastian
this looks spicy.... I don't have python, but from what you are saying about the notify being native, i might have to install it and try it out... thanks
CheeseConQueso
CheeseConQueso: if http://search.cpan.org/~drolsky/File-ChangeNotify-0.07/lib/File/ChangeNotify/Watcher/Inotify.pm subclass is available then File::ChangeNotify mentioned by @jsoversion can do the same as pyinotify. Quick CPAN search revealed yet another possible solution http://search.cpan.org/~mlehmann/Linux-Inotify2-1.21/Inotify2.pm
J.F. Sebastian
thanks... i will check it out
CheeseConQueso