matt.schnarr has asked for the wisdom of the Perl Monks concerning the following question:

At present, I've opened a pipe bring the results of tail -f into my script. I'm then running a while loop on the handle. Unfortunately the loop only iterates if tail is providing data.

Is there are way for a while loop to continue to loop even though there is no data being passed to the handle?

open(TAIL, "tail --follow=name logfile.log|") or die "TAIL : $!"; while (<TAIL>) { print "matt: $_\n"; sleep(1); # # Should print "matt" once every second regardless if tail is +providing data or not }
Any help would be greatly appreciated! Thanks! Matt

Replies are listed 'Best First'.
Re: Piping Tail and while loops
by Paladin (Vicar) on Sep 01, 2004 at 21:02 UTC
    This doesn't directly answer your question, but may make it moot. Have you looked at the File::Tail module on CPAN?
      Unfortunately File::Tail still blocks, it'd be helpful if it had a non-blocking mode.

      Thanks!

        File::Tail has a "nowait" option, though even there (in the docs) it also suggests using select.
Re: Piping Tail and while loops
by BrowserUk (Patriarch) on Sep 01, 2004 at 22:12 UTC

    Try something like this:

    #! perl -slw use strict; use threads; use Thread::Queue; $|=1; sub tail { my( $file, $Q ) = @_; my $pid = open TAIL, "u:tail --follow=name $file |" or die $!; print "pid:$pid"; END{ kill 9, $pid } while( <TAIL> ) { $Q->enqueue( $_ ); } } my $Q = new Thread::Queue; my $t = threads->new( \&tail, $ARGV[ 0 ], $Q ); while( sleep 1 ) { print 'Here'; printf "Got: %s", $Q->dequeue() while $Q->pending; }

    Sample output


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Piping Tail and while loops
by ikegami (Patriarch) on Sep 01, 2004 at 21:58 UTC

    select can be used to check if a handle is ready to be read (but it doesn't work for pipes in Windows). Only call <TAIL> if select indicates data is waiting to be read.

    As an aside, I don't see the reason to fork off tail instead of opening the log file in perl.

      Thanks - I will give select a try!

      I need to read in the file via tail, as the file is consistantly being written to (the one I'm trying to read) so if I open it on my BSD box I am worried I will not get any new lines added to the file after the time of opening it.

      Matt

Re: Piping Tail and while loops
by mifflin (Curate) on Sep 01, 2004 at 21:38 UTC
    use the -f option on tail
    from the man pages...
    -f Follow. If the input-file is not a pipe, the program will not terminate after the line of the input-file has been copied, but will enter an endless loop, wherein it sleeps for a second and then attempts to read and copy further records from the input-file. Thus it may be used to monitor the growth of a file that is being written by some other process.
    This is not perfect as per your specs but it does work.
    Also, your while will then be infinite so you might need some condition to exit out of it.

    update:
    as ikegami points out your --follow=name is something (if not exactly) like the -f option. My system (sun) does not appear to have the same option.

    another update:
    here's an example of what ikegami is talking about...
    use IO::Select; open (F, 'tail -f somefile.log |') or die; $select = IO::Select->new(*F) or die "Unable to create select object"; while(<F>) { $lastrec = "matt: ".$_; print $lastrec; while (! $select->can_read(1)) { print $lastrec; } }
      He's already using -f (by the alternate name --follow). The OP's problem is that <> is blocking (as it usually is), and he wants it to be non-blocking.
Re: Piping Tail and while loops
by rinceWind (Monsignor) on Sep 02, 2004 at 08:52 UTC
    There's also the approach I gave in Re: Log file tailing, which is non-blocking and does not use a select.

    --
    I'm Not Just Another Perl Hacker

Re: Piping Tail and while loops
by genecutl (Beadle) on Sep 02, 2004 at 21:09 UTC
    I just did something very similar and tried out a couple different strategies before I came upon something i was happy with. It's all shown in gory detail in this recent thread: blocking, non-blocking, and semi-blocking
Re: Piping Tail and while loops
by Anonymous Monk on Sep 03, 2004 at 18:59 UTC
    Why open in a pipe at all? something like this basicly implements tail in perl:
    open (TAIL, "logfile.log"); seek (TAIL, 0, 2); # check the manpage for (;;) { sleep 1; # so we don't hog cpu if (seek(TAIL,0,1)) { while (<TAIL>) { # code to act on logfile here } } # execution continues here }