我想打印匹配行之前的第 n 行、匹配行和匹配行中的第 n 行,其中“n”大于 2。
这是我的数据文件的示例(下面的行号不是数据的一部分,仅用于标识),我正在文件中搜索的模式是“blah” example.txt
。
$ cat example.txt
1. a
2. b
3. c
4. d
5. blah
6. e
7. f
8. g
9. h
10. blah
11. i
12. f
13. g
14. h
我希望输出为:
1. b
2. blah
3. g
4. f
5. blah
6. g
请推荐任何一款衬垫!
答案1
awk -vn=3 '/blah/{print l[NR%n];print;p[NR+n]};(NR in p);{l[NR%n]=$0}'
假设没有重叠。如果存在重叠,所有相关行都将被打印,但可能会打印几次,并且不一定按照输入中的顺序打印。
为了避免这种情况,你可以这样写:
awk -vn=3 '/blah/{p[NR-n]p[NR]p[NR+n]};(NR-n in p){print l[NR%n]}
{l[NR%n]=$0};END{for(i=NR-n+1;i<=NR;i++)if (i in p) print l[i%n]}'
在这样的输入上:
1
2
3
4
blah1
5
6
blah2
blah3
7
8
9
10
第一个给出:
2
blah1
blah1
blah2
blah2
5
blah3
8
9
而第二个会打印:
2
blah1
5
blah2
blah3
8
9
答案2
这是 perl 一行:
$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
if ($lines[$i]=~/blah/){
print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
}' example.txt
b
blah
g
f
blah
g
要更改周围行的数量,请更改$n=3;
为所需数量的$n=N
位置。N
要更改匹配的模式,请更改if ($lines[$i]=~/blah/)
为if ($lines[$i]=~/PATTERN/)
。
如果数字实际上是文件的一部分,您可以执行以下操作:
$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
if ($lines[$i]=~/blah/){
print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
}' example.txt | perl -pne 's/\d+/$./'
1. b
2. blah
3. g
4. f
5. blah
6. g
答案3
这是与 @terdon 类似的答案,但它只在内存中保留 2n+1 相关行:
my $n = shift;
my $pattern = shift;
my @lines = ("\n") x (2*$n+1);
while (<>) {
shift @lines;
push @lines, $_;
if ($lines[$n] =~ m/$pattern/) {
print $lines[0], $lines[$n], $lines[-1];
}
}
你会像这样运行它:perl example.pl 3 blah example.txt
答案4
效率不是很高。使用 grep 获取行号,使用 sed 打印行号。
for n in `grep -n blah example.txt | sed -e s/:.*//`
do
sed -n -e "$[$n-3]p" -e "$[$n]p" -e "$[$n+3]p" example.txt
done
结果是
2. b
5. blah
8. g
7. f
10. blah
13. g
如果这些数字中的任何一个最终超出范围,它可能会失败。