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

Hi Monks, I am trying to print last 10 lines from a file but hitting a strange problem. Can you please suggest what is wrong?
more last_ten.pl #! /usr/bin/perl -w use strict; use File::ReadBackwards; use diagnostics; open my $read_log_file, '<', '/home/jay/my_perl_programs/log.txt' or d +ie $!; open my $output_file, '>', '/home/jay/my_perl_programs/log_output.txt' + or die $!; my @log_last_ten; my $log_backwards = File::ReadBackwards->new($read_log_file) or die $! +; while (defined(my $log_lines = $log_backwards->readline)) { unshift @log_last_ten, $log_lines; last if @log_last_ten >= 10; } print $output_file "\n----------------------Last 10 Lines from log fil +e------------------------------\n"; for (@log_last_ten){ print $output_file $_; } close $read_log_file; close $output_file;
The error is:

$ perl last_ten.pl

Uncaught exception from user code: No such file or directory at last_ten.pl line 10. at last_ten.pl line 10

$

This same code works if I change the line:

open my $read_log_file, '<', '/home/jay/my_perl_programs/log.txt' or die $!;

To:

open my $read_log_file='/home/jay/my_perl_programs/log.txt';

Regards

Jay

Replies are listed 'Best First'.
Re: ReadBackwards usage
by Athanasius (Archbishop) on Mar 16, 2015 at 06:18 UTC

    Hello jayu_rao,

    The method File::ReadBackwards->new() takes a filename (i.e., a string) as its first (and only required) argument. But if you first say:

    open my $read_log_file, '<', '/home/jay/my_perl_programs/log.txt' or d +ie $!;

    you create $read_log_file as a file handle, which is something quite different. (It’s like a special kind of pointer that Perl uses to access a file.) You can see this if you try to print it as a string:

    16:13 >perl -Mstrict -wE "open(my $fh, '<', '1184_SoPW.pl') or die; sa +y qq[>$fh<];" >GLOB(0x7ec4f8)< 16:14 >

    If you then call File::ReadBackwards->new($fh) it will try to access a file named “GLOB(0x7ec4f8)” — and fail, because there is no file of that name.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thanks much for the explanation Athanasius. This clears the doubt. Any suggestion on how I can use the file handle with ReadBackwards?

      The reason is that I would have to work with a temporary file and I would not know the name of the file that is created for giving the actual string.

      Regards,

      Jay

        Hello jayu_rao,

        Here are two possible solutions:

        (1) Create the temporary file using the core module File::Temp and get the filename together with the handle:

        use File::Temp 'tempfile'; ... my ($fh, $filename) = tempfile(); my $bw = File::ReadBackwards->new($filename) or die "Cannot read '$filename' backwards"; while (my $log_line = $bw->readline) { ... }

        (2) Use the File::ReadBackwards TIED HANDLE INTERFACE, which accepts a filehandle:

        my $filename = 'data.txt'; open(my $bw, '<', $filename) or die "Cannot open file '$filename' for reading"; tie *$bw, 'File::ReadBackwards', $filename or die "Cannot read '$filename' backwards"; while (my $log_line = <$bw>) { ... }

        (Note the asterisk in tie *$bw — this is required. Also note the two different ways of reading the next line from the file: readline vs. <$bw>. N.B.: they are not interchangeable!)

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Readbackwards usage
by NetWallah (Canon) on Mar 16, 2015 at 06:03 UTC
    This same code works if I ...
    What is your definition of "works" ?

    Your statement :

    open my $read_log_file='/home/jay/my_perl_programs/log.txt';
    is not checking for errors, and ignoring any error it encounters.

    The error it would get if checked is:

    No such file or directory
    This would occur even if the file does exist, because the 'open' construct not meaningful.

            "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Re: Readbackwards usage
by Marshall (Canon) on Mar 16, 2015 at 12:02 UTC
    Standard Unix command to print the last 10 lines is "tail".

    http://en.wikipedia.org/wiki/Tail_%28Unix%29

    There are variations of this under Windows.

    To get the "reverse", capture that as @ARRAY and then print reverse.