Reputation: 43
My file looks like this:
1 15
2 16
3 18
4 19
5 25
6 30
7 55
8 45
9 34
10 52
If the matched pattern is 30 in line 6, I would like to grab N lines before and M lines after the line 6, for example if N=3 and M=4 so the result is expected to be like this:
3 18
4 19
5 25
6 30
7 55
8 45
9 34
10 52
I am a very new beginner in Perl and any advice would be appreciated.
﹟UPDATE Many thanks for these helpful advice below and I really appreciate them. Here is my updated code for this and any suggestions are welcome!
my $num;
while(<>)
{
if ( /pattern/)
{$num = $. ;}
}
open (,"") || die ("Can't open the file");
while(<>)
{
if ( $. >= $num-N and $. <=$num+M)
{
print OUT "$_ \r";
}
}
Upvotes: 0
Views: 1439
Reputation: 753
my @lines = <>;
foreach $idx (grep { $lines[$_] =~ /pattern/ } 0..$#lines) {
print join (map {$lines[$_]} grep { $_ >= $idx - $B && $_ <= $idx +$A } 0..$#lines)."\n";
}
You can also use the GNU grep command, with -A,-B flags for that exact purpose.
-A NUM, --after-context=NUM
Print NUM lines of trailing context after matching lines.
Places a line containing -- between contiguous groups of
matches.
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines.
Places a line containing -- between contiguous groups of
matches.
Upvotes: 0
Reputation: 16519
Maintain an array (I'll call it @preceding
) of the last N
lines read. When the pattern is matched, stop updating this array and start inserting lines into another array (@following
). Do this until @following
has M
lines in it.
It should look something like this (fixed now thanks to ikegami):
my $matched = 0;
my @preceding;
my @following;
while(<>){
if ($matched){
push ( @following, $_);
last if @following == M;
next;
}
else {
push ( @preceding, $_);
shift(@preceding) if @preceding > N;
}
$matched = 1 if /pattern/;
}
Upvotes: 1