madtoperl has asked for the wisdom of the Perl Monks concerning the following question:

This node falls below the community's threshold of quality. You may see it by logging in.

Replies are listed 'Best First'.
Re: File Manipulation Issue
by McDarren (Abbot) on Jun 14, 2006 at 04:06 UTC
Re: File Manipulation Issue
by GrandFather (Saint) on Jun 14, 2006 at 04:10 UTC
Re: File Manipulation Issue
by liverpole (Monsignor) on Jun 14, 2006 at 11:31 UTC
    Hi madtoperl,

    Here's a subroutine I use on occasion, called tail_closure.  You call the subroutine with 2 arguments, the name of the file to tail, and an optional flag (0 = read from beginning, nonzero = read from end).  The subroutine returns a closure which you can call with a value N, to get at most the next N lines (N defaults to 0 => no limit).

    #!/usr/bin/perl -w # Strict use strict; use warnings; # Libraries use File::Basename; use FileHandle; # Main program $| = 1; # Create a closure 'psub', which will effectively "tail -f test.txt". my $psub = tail_closure("test.txt", 0); # Print the last 10 lines of the file my $ptext = $psub->(0); if ($ptext && @$ptext > 0) { my @last_10 = (@$ptext > 10)? splice(@$ptext, -10, 10): @$ptext; map { print "$_\n" } @last_10; } # Monitor any more text written to the file while (1) { my $ptext = $psub->(256); # Get any more text $ptext and map { print "$_\n" } @$ptext; # And print it select(undef, undef, undef, 0.05); # Short delay } # Subroutines # # Inputs: $1 ... a file to 'tail' (like "tail -f" in Unix) # $2 ... (optional) a flag; if zero, reads from the beginni +ng # of the file; otherwise reads from the end # # Outputs: $1 ... a pointer to a subroutine to read successive # lines of text from the file. # # Parameters to the closure are: # # Inputs: $1 ... (optional) maximum number of lines # to read at a time (zero = unlimited) # # Outputs: $1 ... pointer to the lines read (zero on # error) # sub tail_closure { my ($fname, $b_from_eof) = @_; $b_from_eof ||= 0; my $fh = new FileHandle; open($fh, "<", $fname) or die "Failure to read file '$fname' ($!)\ +n"; $b_from_eof and seek $fh, 0, 2; require IO::Select; my $select = IO::Select->new(); $select->add($fh); my $text = ""; my $psub = sub { my ($max) = @_; $max ||= 0; my $count = 0; my $plines = [ ]; while (1) { my $c; # Next character my @ready = $select->can_read(0); # Ready to read from f +ile? @ready or return $plines; # Not ready - return a +ny lines my $nread = sysread $fh, $c, 1; # Read next character defined($nread) or return 0; # End of file ($nread > 0) or return $plines; # Done reading for now if ($c eq "\n") { # If newline ... push @$plines, $text; # Save line of tex +t $text = ""; # and blank-out te +xt # Return the lines when we reach the max ($max > 0 && ++$count == $max) and return $plines; } else { $text .= $c; # Add character to tex +t } } }; return $psub; }

    The main program is a test wrapper which calls the closure on a file "test.txt".  In this case, the flag to the closure is zero, so it reads from the beginning of the file, and then prints the last 10 lines (the usual behavior of the "tail" program).  Then it monitors the file each time $psub is invoked, grabbing up to 256 lines of text and displaying the lines.

    You can test the program by running it in one shell, and appending lines to test.txt in another shell.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/