http://www.perlmonks.org?node_id=1005513


in reply to How to print the lines immediately above and below a matching line?

You mention wanting to print the lines above and below a matching line, but your code prints the matching line, too. In case you wanted to print all (two or) three lines, consider the following that you can adapt for files:

use strict; use warnings; my ( $prevLine, $nextLine ); for ( ; ; ) { last if eof DATA; chomp( my $currLine = defined $nextLine ? $nextLine : <DATA> ); if ( $currLine =~ /match this/ ) { print '-' x 25, "\n"; chomp( $nextLine = <DATA> ) if !eof DATA; print $prevLine, "\n" if defined $prevLine; print $currLine, "\n"; print $nextLine, "\n" if defined $nextLine; print '-' x 25, "\n"; } else { undef $nextLine; } $prevLine = $currLine; } __DATA__ The first line match this Not this abcdefg The one above Another match this 1 Another match this 2 the one below match this 2 zxcvbnn Another match this blank above Second to the last line The last line match this

Output:

------------------------- The first line match this Not this ------------------------- ------------------------- The one above Another match this 1 Another match this 2 ------------------------- ------------------------- Another match this 1 Another match this 2 the one below match this 2 ------------------------- ------------------------- Another match this 2 the one below match this 2 zxcvbnn ------------------------- ------------------------- Another match this blank above Second to the last line ------------------------- ------------------------- Second to the last line The last line match this -------------------------

The dashes are printed to show the desired output. If the first or last line is a match, only two lines are printed. If you only want the lines above and below a matching line, delete print $currLine, "\n";.

Hope this helps!

Addition: If you want to avoid printing the same line more than once--like in the example above--and have output that more closely resembles grepping the file, you can do the following:

use strict; use warnings; my ( $prevLine, $nextLine, %printed ); for ( ; ; ) { last if eof DATA; chomp( my $currLine = defined $nextLine ? $nextLine : <DATA> ); if ( $currLine =~ /match this/ ) { chomp( $nextLine = <DATA> ) if !eof DATA; print $prevLine, "\n" if defined $prevLine and !$printed{$prev +Line}++; print $currLine, "\n" if !$printed{$currLine}++; print $nextLine, "\n" if defined $nextLine and !$printed{$next +Line}++; } else { undef $nextLine; } $prevLine = $currLine; } __DATA__ The first line match this Not this abcdefg The one above Another match this 1 Another match this 2 the one below match this 2 zxcvbnn Another match this blank above Second to the last line The last line match this

Output:

The first line match this Not this The one above Another match this 1 Another match this 2 the one below match this 2 zxcvbnn Another match this blank above Second to the last line The last line match this

This uses a hash to keep track of previously printed lines, so they're shown only once.