tags:

views:

150

answers:

4

I'm writing a script that listens for changes to a log file and acts appropriately. At the moment I'm using open my $fh, "tail -f $logfile |"; but ideally I don't want to use system calls.

I've tried File::Tail but it has a minimum interval of 1 second (I've tried passing less but it defaults to 1 second, even if I pass 0). I've checked the source for it and it seems to be using sleep() which takes an integer. Before I try to write my own, are there any other options?

Thanks.

+2  A: 

CPAN has File::ChangeNotify

Ben Voigt
+6  A: 
  1. Did you know that tail -f also uses a 1-second sleep by default? It's true! (At least for GNU tail...)
  2. File::Tail actually uses Time::HiRes's sleep function, which means that the sleep time parameter isn't an integer; you can set it to any fractional number of seconds that your system can deal with.
hobbs
A: 

In my opinion there is nothing wrong with using tail -f pipe like you already do. In many situations going for language purity like "no system calls" is counterproductive.

Also, I've seen problems with File::Tail in long-running processes. Unfortunately I cannot corroborate this claim with any hard evidence since it happened quite some time ago, I did not debug the problems, replacing the use of File::Tail with a tail -F pipe instead.

Grrrr
+1  A: 

There's a lot of good stuff in the documentation, including an answer to this exact question. From perlfaq5's answer to How do I do a "tail -f" in perl?


First try

seek(GWFILE, 0, 1);

The statement seek(GWFILE, 0, 1) doesn't change the current position, but it does clear the end-of-file condition on the handle, so that the next makes Perl try again to read something.

If that doesn't work (it relies on features of your stdio implementation), then you need something more like this:

for (;;) {
  for ($curpos = tell(GWFILE); <GWFILE>; $curpos = tell(GWFILE)) {
    # search for some stuff and put it into files
  }
  # sleep for a while
  seek(GWFILE, $curpos, 0);  # seek to where we had been
}

If this still doesn't work, look into the clearerr method from IO::Handle, which resets the error and end-of-file states on the handle.

There's also a File::Tail module from CPAN.

brian d foy