I was asked how to implement the unix tail command in perl $ tail.pl t.txt 10 (display last 10 lines) I kind of managed with the simple ARRAY and they playing around with the $#Array etc. But they wanted without an array. Any inputs ?

Showing Answers 1 - 75 of 82 Answers

Guest

  • Oct 25th, 2007
 

This may not be accepted as well. But this can be done in numerous ways ! One way is here :

maintain a structure which stores the line number and the size of the file at that time.
eg 1 - 10bytes, 2 - 18 bytes ... you'll have to have a counter to increase the number of lines to find out the number of lines in the file. once you are through the file, you'll know the size of the file at any nth line. use sysseek to move the file pointer back to that position ( last 10 )and then start reading till the end.

  Was this answer useful?  Yes

imavasu

  • May 13th, 2008
 

Please try this capan module

  use File::Tail;
  $file=File::Tail->new("/some/log/file");
  while (defined($line=$file->read)) {
      print "$line";
  }

  use File::Tail;
  $file=File::Tail->new(name=>$name, maxinterval=>300, adjustafter=>7);
  while (defined($line=$file->read)) {
      print "$line";
  }

  Was this answer useful?  Yes

rahulashu

  • Jun 10th, 2008
 

if we  will passed 2  argument , in that first is  filename  and  second  is no. of  last line then  u can use following  program :

#! /bin/perl

open(MYFILE,$ARGV[0]);

@array = <MYFILE> ;
#print @array ;
$numline = @array;
$numprintline = $numline - $ARGV[1] ;
while($numprintline != $numline)
{
        print "$array[$numprintline]" ;
        $numprintline++;
}

  Was this answer useful?  Yes

nitashaa

  • Jul 16th, 2008
 

#!/usr/bin/perl 
my $count = $ARGV[1];  ---> the number of lines to be printed
while(<>) { ----> reading file passed as arg
my $x = $.;  -----> assigning line number to $x
if ( $count >= $x )
{ print "line number $x: $_n"; }
else { exit; }
}

  Was this answer useful?  Yes

lbsign

  • Nov 2nd, 2009
 

I think the point to not using arrays is the fact that loading large files in to an array is expensive.
$times = 10; # this is the number of lines

open(FILE, "$file") or die ("...");
seek(FILE, 0,2);
my $counter =0;
while ($counter < $times && seek(FILE, -2,1)) {
  read(FILE, $chr, 1);
  if ($chr eq "n") { $counter++ }
}

while (<FILE>) {
  print;
}

close(FILE);

  Was this answer useful?  Yes

diszgaurav

  • Apr 13th, 2010
 

How about opening the file twice and get two filehandles, and then navigate:
#!/usr/bin/env perl
# Usage: $0 <filename> <count>
use warnings;
use strict;

open(FILE1,"$ARGV[0]") or die $!;
open(FILE2,"$ARGV[0]") or die $!;

my $count = $ARGV[1];

while($count--) {
    <FILE1>;
}

while(<FILE1>) {
    <FILE2>;
}

print <FILE2>;

close(FILE1);
close(FILE2);

  Was this answer useful?  Yes

lbsign

  • Dec 15th, 2010
 

#!/usr/bin/perl

if (@ARGV < 1) {
  die ("Usage: $0 filename [number of lines]n");
}
my $fileName = $ARGV[0];
# defaults to 5 lines if not set
my $noLines = $ARGV[1] || 5;

# Guess how many characters are in a line
my $bytesInLine = 128;
my $bytesInLines = $bytesInLine * $noLines;

open (FILE, "$fileName") or die ("Cannot read $fileNamen");

seek(FILE, 0,2);
my $maxBytes = tell(FILE);

my @fileLines;

my $passCount=0;
my $atBeginFile = 0;

# We want to get the full first line so we get number of lines + 1 
while (@fileLines < $noLines+1) {
  if (!seek(FILE, -1 * $bytesInLines,1)) {
    seek(FILE, 0,0);
    $atBeginFile = 1;
  }
  @fileLines = <FILE>;
  $bytesInLines *= 2;
  $passCount++;
  # you passed the beginning of the file
  if ($atBeginFile) {
    # if the requested lines is above the actual file change it
    $noLines = @fileLines;
    last;
  }
}
my $startIndex = @fileLines - $noLines;
@fileLines = splice(@fileLines, $startIndex,$noLines);
print @fileLines;
print "Tailed $noLines lines in $passCount passesn";
close(FILE);

  Was this answer useful?  Yes

Try this

#!/usr/bin/perl
use strict;
use warnings;

open(FH,"FILENAME") or die "$!";
while ()
{
chomp;
}
print "n$.";
my $x= $. - 10;

close (FH);

open(FH,"FILENAME") or die "$!";
while ()
{
chomp;
if ($.>=$x)
{
  print "$.->$_";
}

}
close (FH);

  Was this answer useful?  Yes

puneet agrawal

  • Mar 29th, 2012
 

I think below answer is suitable.

Code
  1. open FILE, "imp.txt" or die $!;

  2. while ($line=<FILE>) {

  3.  push @arr,$line;

  4. }


  5.  

  6.  

  7. ";

  8. $m=$ARGV[0];

  9. for(;$m > 0;$m--){

  10. print @arr[-$m];}

  Was this answer useful?  Yes

SH

  • Mar 29th, 2012
 

Open file, read and print until number of required lines is reached. Memory is saved by not slurping the entire file into an array.

Code
  1. $fileName = shift;

  2. $lines = shift;

  3. print "tailing file $fileName for $lines lines...

  4. ";

  5.  

  6. open FH, $fileName or die "Could not open $fileName";

  7.  

  8.     while ($l = <FH>) {

  9.         print $l; --$lines;

  10.         last if $lines == 0;

  11.     }

  12. close FH;

  Was this answer useful?  Yes

sergant

  • Apr 27th, 2012
 

Code
  1. #!/usr/bin/perl

  2.  

  3. $fileName = shift;

  4. $lines = shift;

  5. print "tailing file $fileName for $lines lines...

  6. ";

  7.  

  8. open FH, $fileName or die "Could not open $fileName";

  9.  

  10.     while ($l = <FH>) {

  11.         push @ar, $l; --$lines;

  12.         last if $lines == 0;

  13.     }

  14.  

  15.     while ($l = <FH>) {

  16.         push @ar, $l;

  17.         shift @ar;

  18.     }

  19.  

  20. close FH;

  21.  

  22. foreach (@ar) {

  23.     print;

  24. }

  25.  



  Was this answer useful?  Yes

SumitRoy

  • Sep 16th, 2012
 

You can also try this :
Create two pointers and make them $count apart.
Move one of the pointer to EOF and keep simultaneously moving the other pointer so that it is $count before.
Now use the second pointer to print the last $count lines.

Code
  1. #!/usr/bin/env perl

  2. use warnings;

  3. use strict;

  4.  

  5. open(FILE1,"$ARGV[0]") or die $!;

  6. open(FILE2,"$ARGV[0]") or die $!;

  7.  

  8. my $count = $ARGV[1];

  9.  

  10. #After this loop FILE1 points to line after $count

  11. while($count--) {

  12. my $line = <FILE1>;

  13.     ;

  14. }

  15.  

  16. #After this loop FILE1 points to EOF and FILE2 points $count before EOF

  17. while(<FILE1>) {

  18. my $line = <FILE2>;

  19.     ;

  20. }

  21.  

  22. #Print the last $count lines before EOF

  23. while(<FILE2>){


  24. }

  25.  

  26. close(FILE1);

  27. close(FILE2);

  Was this answer useful?  Yes

shiva

  • Nov 22nd, 2012
 

Just use .. opertor using array just check the length of the array minus with input give by the user
take a difference and do it sample code is below.

Code
  1.  

  2. #! /usr/bin/perl

  3.  

  4. my @arry=qw(1 2 3 4 5 6 7 8 9);

  5.  

  6. my $len=$#arry;

  7.  

  8. print "Enter the number";

  9.  

  10. $l=<stdin>;

  11.  

  12. $result=$len-$l;

  13.  

  14. $res=@arry[$len] -@arry[$result];

  15.  

  16.  

  17. foreach my $i (@arry[$result+1].. @arry[$len])

  18. {

  19.   print "

  20. ";

  21.  print $i;

  22.  

  23. }

  Was this answer useful?  Yes

Namrata

  • Aug 14th, 2013
 

Code
  1. open(FILE, "tail -10f file1.txt |");

  2.  

  3. while(<FILE>){

  4. print $_;

  5. }



  Was this answer useful?  Yes

pp

  • Oct 15th, 2014
 

1) open the file
2) assign it to an array(each line will be an element)
3) Get the length of the array(L)
4) Starting from L-10 .. L , assign elements to another array @new = @old[L-10..L];
5) print the new array , separate elements by newline

  Was this answer useful?  Yes

vijth

  • Oct 19th, 2014
 

Code
  1. open(data, "<file.txt")

  2. $count=0;

  3. $value=<data>;

  4. $length=length(value);

  5. while (<data>)

  6. {

  7. if ($count >= length-10)

  8. {print "<data>";}

  9. }

  Was this answer useful?  Yes

perly

  • Mar 6th, 2015
 

Code
  1. #!/usr/bin/perl

  2.  

  3.  

  4. use warnings;

  5.  

  6. use strict;

  7.  

  8. open FILE, "test.txt" or die $!;

  9.  

  10. my @last = <FILE>;

  11.  

  12. print "Last five lines:

  13. ", @last[-5 ... -1];


  Was this answer useful?  Yes

VINOD

  • Apr 1st, 2015
 

You can use File::Readbackwards or File::Tail Cpan modules to read file backwords

  Was this answer useful?  Yes

  • Apr 18th, 2015
 

this may not be accepted as a right answer as we are directly using tail command instead of implementing it logically

  Was this answer useful?  Yes

RaghsChandu

  • May 16th, 2015
 

Code
  1.  

  2. @lines = <FILE>;

  3. @output = splice(@lines ,0,10);

  4. print "@output";


  Was this answer useful?  Yes

anirudh

  • May 30th, 2015
 

The command-line solution is strict/warnings enabled. The first argument = number of lines to tail
The second argument is the filename of the file for which tailing is required.
Basic algo: keep chopping every line from the end & increment a counter. Stop when either of these 2
conditions are met : i) reached the beginning of file or ii) counter value exceeds the number of lines to be
tailed.
perl -Mstrict -Mwarnings -le
($a, $_) = (shift||5, join"",<>); my($k, @A);
unshift @A, $1 while s/(.*)
$// && $k++ < $a;
print for @A;
num_of_lines_to_be_tailed file_to_be_tailed

  Was this answer useful?  Yes

anirudh

  • May 31st, 2015
 

Always keep the number of lines in array @A equal to $b.
Whenver, it crosses the threshold of ($b) clip from the top of array.
And at the end, print the array.
perl -lne BEGIN{ $b = shift; }
push @A, $_;
shift @A if @A > $b;
END { print for @A; } num_of_lines_to_tail yourfile

  Was this answer useful?  Yes

saminathan

  • Jun 4th, 2015
 

use the command "tail -10

  Was this answer useful?  Yes

Arunesh

  • Jun 15th, 2015
 

You can do it in one liner

Code
  1. perl -lne push(@tail,$_);shift @tail if($#tail >=10);END{print $_ foreach(@tail)} filename

  Was this answer useful?  Yes

soumdgr8

  • Aug 1st, 2015
 

If its UNIX (ish) Env., use below

Code
  1. #tail.pl

  2. #this will work for default behaviour of tail(i.e. last 10 lines), you can enhance it to tail certain no. of lines

  3. #usage : tail.pl <filename>

  4. #!/usr/bin/perl -w

  5.  

  6. use strict;

  7.  

  8. #take line count of file

  9. chomp(my $total_lines = `wc -l $ARGV[0] | cut -d" " -f1`);

  10. #caculate which line to start printing from

  11. my $start_printing = $total_lines - 10;

  12.  

  13. while(<>) {

  14. #if file is less than 10 lines, print everything else print last 10 lines

  15. next if ( ($start_printing > 0) && ($. < $start_printing) );


  16. }

  Was this answer useful?  Yes

Give your answer:

If you think the above answer is not correct, Please select a reason and add your answer below.

 

Related Answered Questions

 

Related Open Questions