Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

print line 5 lines previous to comaprison line!

by pat (Initiate)
on Jun 07, 2001 at 16:31 UTC ( #86524=perlquestion: print w/replies, xml ) Need Help??
pat has asked for the wisdom of the Perl Monks concerning the following question:

I have a script which looks through a file line by line looking for a particular string. if it finds that string it prints that line ..... Now I want to amend the script so that if a string is found in a line then the line 5 lines previous to the one being searched is printed?????? thanks Pat p.s great site!
  • Comment on print line 5 lines previous to comaprison line!

Replies are listed 'Best First'.
Re: print line 5 lines previous to comaprison line!
by davorg (Chancellor) on Jun 07, 2001 at 16:51 UTC

    You don't say what to do if the match is found in the first five lines of the file. I'm going to assume that this can't happen. I'm also going to assume that you don't want to read the whole file into memory at once.

    I'd build a buffer that always contains the previous five lines and work with that. Something like this:

    #!/usr/bin/perl -w use strict; my @buffer; push @buffer, scalar <DATA> for 1 .. 5; my $pat = 8; # adjust to value to search for while (<DATA>) { print $buffer[0] if /$pat/; push @buffer, $_; shift @buffer; } __END__ 1 2 3 4 5 6 7 8 9 10

    Perl Training in the UK <>

      Nice. One suggestion:
      # change: print $buffer[0] if /$pat/; # to: print $buffer[0] if /\Q$pat\E/o;
      The \Q and \E presume that $pat is just a string, not a regex. So you would want to escape any special characters (like '.' or '+' ) and the o tells Perl that $pat isn't going to change in the loop, so it won't keep recompiling the pattern.
Re: print line 5 lines previous to comaprison line!
by tomhukins (Curate) on Jun 07, 2001 at 16:41 UTC

    Try this:

    my @previous; while (<LINE>) { if ($_ eq "STRING TO COMPARE WITH\n") { print $previous[0]; last; } push @previous, $_; shift @previous if @previous > 5; }

    Update: Thanks to jeroenes for spotting a couple of things that could be done better - I've incorporated your suggestions into the code.

    Update 2: Thanks to davorg for noticing that print @previous prints out all of the last 5 lines, but pat asked for the line 5 lines previous to the one being searched. I've changed the print @previous line to read print $previous[0] instead.

      This is a very elegant solution, ++


Re: print line 5 lines previous to comaprison line!
by Chady (Priest) on Jun 07, 2001 at 16:41 UTC

    if the file isn't big, read it all in an array, then when you find your match, save your location, and retrieve it directly from the array..

    Update:Here it is, completely untested for bugs:

    # assuming the file is already opened and has a <IN> filehandle my @temp; # and assuming that you won't match before the first 5 lines.. while (my $line = <IN>) { push @temp, $line; shift @temp if (scalar @temp > 5); if ($line =~ /foo/) { # we've got a match. print $temp[0]; } }

    Update 2: This looks like davorg's more elegant solution.

    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady |
Re: print line 5 lines previous to comaprison line!
by marcink (Monk) on Jun 07, 2001 at 20:57 UTC

    this code seems to do the trick quite effectively:

    while (<>) { $a[$i++%6] = $_; print $a[$i%6] if /match/; }

    Just change the if condition to something reasonable.

Re: print line 5 lines previous to comaprison line!
by gollem (Acolyte) on Jun 07, 2001 at 16:42 UTC
    Something like this should work
    open X,"<$file"; @rows = <X>; close X; for($i=0;$i<$#rows;$i++) { if($rows[$i] =~ /something/) { print $rows[$i-5]; } }
        (I cleared this post. Note to self: never post when hungover)

        Update:I agree, it's wasteful
      when I was opening the file it would not open as you had written above so I changed to open (X, $inputfile); and it opened fine and did what it was meant to do thanks but i have seen this before where the syntax you used to open the file did not work, have you seen this and any idea why it is so thanks once again! Pat ( go raibh mile maith agat)
Re: print line 5 lines previous to comaprison line!
by DrSax (Sexton) on Jun 07, 2001 at 17:09 UTC
    As others have said, you can just read the whole file in at once, and then be able to access all elements of the array. If you also want to remove newline characters to make the array easier to process, here is a handy one-liner.
    chomp(@myArray = <FILEHANDLE>);
    Good luck!

    Brian - a.k.a. DrSax
      If file is really huge, you do not want to read whole file into memory.

      davorg rules!


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://86524]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (7)
As of 2018-06-22 19:50 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (124 votes). Check out past polls.