Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Performing a tail(1) in Perl (reading the last N lines of a file)

by massa (Hermit)
on Jul 18, 2008 at 00:21 UTC ( [id://698477]=note: print w/replies, xml ) Need Help??


in reply to Performing a tail(1) in Perl (reading the last N lines of a file)

I would benchmark your "juggling around" solution. It seems to me that the inbuild PerlIO buffering could make it really efficient compared to the other solutions.
my ($file, $limit) = ('/var/log/messages', 100); open my $f, '<', $file or die; my @lines; $#lines = $limit; while( <$f> ) { shift @lines if @lines >= $limit; push @lines, $_ } print @lines
[]s, HTH, Massa
  • Comment on Re: Performing a tail(1) in Perl (reading the last N lines of a file)
  • Download Code

Replies are listed 'Best First'.
Re^2: Performing a tail(1) in Perl (reading the last N lines of a file)
by Anonymous Monk on Jul 29, 2009 at 12:24 UTC
    Here's a subroutine that does what you want, and optionally trims the file as well. It assumes a line length of 72 bytes and goes back number of lines * 72. If it doesn't get enough lines it goes back another block. This is quite efficient especially when you only want a few lines at the end of a file, even for huge files. It's only 'slow' when you want 1000's of lines
    ########################################################### sub read_log { my $logfile=shift; my $lines_wanted=shift; my $TRIM=shift; my $lines_found=0; my $BLOCK=$lines_wanted * 72; #Assume 72 chars (bytes) per line my $i=0; my @lines=(); my $GO_BACK=$BLOCK; my $SEEK_RESULT=1; if (open(LOG,$logfile) ) { ## Stop if we have enough lines, or go back past the start while ( $lines_found < $lines_wanted and $SEEK_RESULT) { $SEEK_RESULT=seek LOG,-$GO_BACK,2; # Goto back approx request +ed lines <LOG>; # Chuck the first line remnant @lines=<LOG>; # Get the rest of the lines $lines_found=scalar (@lines); # Count the lines $GO_BACK+=$BLOCK; $i++; } close LOG; # If too many lines, just splice the array my $diff=$lines_found - $lines_wanted; splice @lines,0,$diff if $diff; trim_file($logfile,\@lines) if $TRIM; } else { print "Couldn't open $logfile: $!<BR>"; } } ########################################################### # Takes a file name and array of lines, backs up the existing file # and trims it. sub trim_file { my $file =shift || die "No filename passed to trim_file()\n"; my $lines=shift || die "No lines passed to trim_file()\n"; my $backup="$file.bak"; unlink $backup if -e $backup; rename $file,$backup; open (OUT,">$file") or die "Couldn't create $file:$!\n"; print OUT foreach @$lines; close OUT; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://698477]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-04-19 08:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found