Bi.
Bi.

Reputation: 1906

How can I print a matching line and the next three lines in Perl?

I need to search for a pattern and write that line as well as the next 3 lines into a file (FILE). Is this a correct way to do it? Thanks.

print FILE if /^abc/;
$n=3 if /^abc/;
print FILE if ($n-- > 0);

Upvotes: 3

Views: 8192

Answers (6)

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26121

I like .. operator:

perl -ne 'print if (/abc/ and $n=3) .. not $n--'

but you doesn't have described what should happen if abc pattern is repeated in following three lines. If you want restart counter, your approach is correct if fix a little bug with double print.

perl -ne'$n=4 if/abc/;print if$n-->0'

Upvotes: 7

bichonfrise74
bichonfrise74

Reputation: 2197

Another possible solution...

#!/usr/bin/perl

use strict;

my $count = 0;
while (<DATA>) {
    $count = 1 if /abc/;
    if ($count >= 1 and $count <= 3) {
        next if /abc/;
        print;
        $count++;
    }
}

__DATA__
test
alpha
abc
1
234123
new_Data
test

Upvotes: 0

Igor Krivokon
Igor Krivokon

Reputation: 10275

You could simplify it to using a flag variable to know if you should print a line:

while( <$input> ) {
    $n=4 if /^abc/; 
    print FILE if ($n-- > 0);
    }

Besides simplification, it also fixes a problem: in your version the abc string will be printed twice.

Upvotes: 5

James Thompson
James Thompson

Reputation: 48182

I'd rather take a few extra lines of code and make everything more clear. Something like this should work:

my $count = 0;
while ( my $line = pop @file ) {
   if ( /^abc/ ) {
      $count = 4;
   }

   if ( $count > 0 ) {
       print FILE $line;
       $count--;
   }
}

Edit to respond to comments:

  • missing the regex was a bug, fixed now.
  • printing the newlines or not is certainly optional, as is slurping the file in. Different people have different styles, that's one of the things that people like about Perl!

Upvotes: -3

brian d foy
brian d foy

Reputation: 132812

This is a feature of the command-line grep(1). No programming needed:

grep abc --after-context=3

You do get '--' lines between groups of context, but those are easy enough to strip. It's also easy enough to do the whole thing in Perl. :)

The trick is what you want to do when one of the following three lines also contains the pattern you're looking for. grep(1) will reset the counter and keep printing lines.

Upvotes: 5

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

There is no need to slurp the file in or try to write your code on a single line:

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

while ( my $line = <DATA> ) {
    if ( $line =~ /^abc/ ) {
        print $line;
        print scalar <DATA> for 1 .. 3;
    }
}
__DATA__
x
y
z
abc
1
2
3
4
5
6

Upvotes: 2

Related Questions