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

The intent of this snippit is to count all of the lines (timestamps) in the file from the bottom up. However it is continually coming back with a count of 27 for a file that has 2-3 lines.. Thank, Jonathan
$times = 2; $minutes_threshold = 7200; $now = time(); $oldest_time = $now - ($minutes_threshold*60); $user_status_file = "C:/temp/perl_logs/user_status.$user.txt"; open (USF, ">>", $user_status_file) or die "Failed to open User Status + File file: $!"; @lines = <USF>; close USF; # Now, read through the lines of the file from last (most recent) to f +irst (oldest) # and see if n times occured in the last m minutes. for ( $i=$#lines; $i>=0; $i-- ) { $timestamp = $lines[$i]; chomp $timestamp; last if ( $timestamp < $oldest_time ); $count++; } if ( $count > $times ) { print ADL "User exceeded threshold! $count \n"; } print USF "$now\n"; close USF;

Replies are listed 'Best First'.
Re: count lines, bottom to top
by davorg (Chancellor) on Aug 11, 2006 at 15:34 UTC

    If you had "use warnings" in your code, then Perl would tell you that you have opened a filehandle (USF) for writing and are then trying to read from it.

    "use strict" and "use warnings" allow Perl to help you find the problems in your code. It's crazy to try and write code without them.

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: count lines, bottom to top
by cdarke (Prior) on Aug 11, 2006 at 16:11 UTC
    You seem to want to read the file backwards (I guess that is why you have opened for append?). This is not really possible, use Super Search to find discussions on this. Have a look at File::ReadBackwards on CPAN, which might help.

    Update: Sorry, I missed that you were reading into an array. Wouldn't be easier to reverse @lines?
      I don't know, would it be easier to reverse @lines?
      Another programmer wrote this and I am trying work on it after the fact. And I don't know much perl..
      I do appreciate the help.
        You obviously have other issues with hamdling files and the words of our sage monks has given the clues there. As for reversing the order of arrays:
        #!/usr/bin/perl -w use strict; use warnings; my @array1 = (1, 2, 3, 4, 5); my @array2 = reverse( @array1 ); print join(", ", @array1), "\n"; print join(", ", @array2), "\n"; exit;
        jdtoronto
Re: count lines, bottom to top
by swampyankee (Parson) on Aug 11, 2006 at 16:34 UTC

    There is a way to open a file for both reading and writing (see the description of open), however, I've never used it (and a read|write open will not, according to the docs, usually work on text files). When I need to do this, I tend to use Tie::File.

    One obvious thing to try is to explicitly set $count to 0 ( ($count = 0;) before starting to count the lines which are more recent than $oldest_time. Also, you may be better off using (as you said)
    foreach reverse @lines
    or

    while(@lines){ $timestamp = pop(@lines);

    My tendency is to prefer the latter (but not when using Tie::File!). I think the reverse will create a temporary array, while nibbling away at the end doesn't. If the files are very large, you may need to use Tie::File or File::ReadBackwards.

    emc

    Experience is a hard teacher because she gives the test first, the lesson afterwards.

    Vernon Sanders Law
Re: count lines, bottom to top
by Ieronim (Friar) on Aug 11, 2006 at 17:59 UTC
    This looks like a typical XY problem. You don't neeed to read the file backwards at all. You can loop through the file throwing away all lines with timestamps greater than you want and then count all lines left.

    The next problem is that you want to read data from file and then append a new timestamp at the end. For this, you need to open the file for both reading and writing, and AFAIK call seek to swith from reading to writing. In general, calling seek will not cause more problems if it is not necessary.

    my $times = 2; my $minutes_threshold = 7200; my $now = time(); my $oldest_time = $now - ($minutes_threshold*60); my $user_status_file = "C:/temp/perl_logs/user_status.$user.txt"; open (USF, "+<", $user_status_file) or die "Failed to open User Status + File file: $!"; # Now, read through the lines of the file # and see if n times occured in the last m minutes. my $count = 0; while ( <USF> ) { chomp $_; next if ( $_ < $oldest_time ); $count++; } if ( $count > $times ) { print ADL "User exceeded threshold! $count \n"; } seek USF, 0, 2; #go to the end of the file - maybe you can remove + this line print USF "$now\n"; close USF;

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: count lines, bottom to top
by sh1tn (Priest) on Aug 11, 2006 at 17:28 UTC
    perl -ne '@_=($_,@_)}{ # file is read in @_ in reverse order # for (@_) loop # data manipulation ... $count > $time and print "exceeded threshold!";' filename