Версия с одним вкладышем (где -l
= chomp
и -n
= while(<>){}
. См. perldoc
perlrun
для дополнительных параметров):
perl -lnE '$h{$.}=$_; END {
for ( grep { $h{$_} eq "target" } sort{ $a <=> $b } keys %h ) {
say for @h{$_-2..$_-1 , $_+1..$_+2} } }' data.txt
Сценарий с объяснением:
#!perl
use feature 'say';
while (<DATA>) {
chomp;
$hash{$.} = $_ ; # hash entry with line number as key; line contents as value
}
# find the target in the hash and sort keys or line numbers into an array
@matches = sort {$a <=> $b} grep { $hash{$_} eq 'target' } keys %hash;
for (@matches) {
say "before\n" ;
say for @hash{$_-2..$_-1} ; # print the context lines as a hash slice
say ">>>>\" $hash{$.} \"<<<< " ;
say "after\n" ;
say for @hash{$_+1..$_+2} ;
say "";
}
__DATA__
line 1
line 2
line 3
target
line 5
line 6
line 7
target
line of context1
line of context2
target
Вывод :
before
line 2
line 3
>>>>" target "<<<<
after
line 5
line 6
before
line 6
line 7
>>>>" target "<<<<
after
line of context1
line of context2
before
line of context1
line of context2
>>>>" target "<<<<
after
Более простая версия, использующая только массивы и с выводом, исключающим цель в качестве запрашиваемого вопроса ОП:
#!perl -l
chomp( my @lines = <DATA> ) ;
my $n = 2 ; # context range before/after
my @indexes = grep { $lines[$_] =~ m/target/ } 0..$#lines ;
foreach my $i (@indexes) {
print for @lines[$i-$n..$i-1], @lines[$i+1..$i+$n],"";
}
__DATA__
line 1
line 2
line 3
target
line 5
line 6
line 7
target
line of context1
line of context2
target
Это позволяет избежать создания хэша, но может быть медленнее для очень больших файлов / массивов.
На CPAN List::MoreUtils
имеет indexes()
и всегда есть splice()
, но я не уверен, что это упростит задачу.