打印基于两个模式的 sed 搜索中的第二个或第 n 个匹配项

打印基于两个模式的 sed 搜索中的第二个或第 n 个匹配项

我想打印基于两种模式的 sed 搜索的第 n 个匹配项,如下所示:

sed -n '/start here/,/end here/p'  'testfile.txt' 

假设testfile.txt包含以下文本:

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here
00000000

00000000

并且我不想打印两种模式之间的零。

根据上面的命令,我将获得所有模式之间的匹配,其输出如下所示:

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here

而我想要的输出是:

start here
123
1234
12345

123456
end here

请注意,各行需要按原样打印testfile.txt,而不是连接起来。

答案1

我会用 Perl 来解决这个问题,因为@terdon明智地建议。或者使用 AWK:

awk '/start here/&&++k==2,/end here/' testfile.txt

如果我不得不单独使用 sed (正如 OP 在评论中所述),我会想出一些更复杂、更难读和更难定制的东西:

sed -n '/start here/{:A n; /end here/b B; b A}; :B n; /start here/{p; :C n; p; /end here/q; b C}; b B' testfile.txt

答案2

我会换用其他工具。例如,Perl:

perl -ne '$k++ if /Pattern1/; if(/Pattern1/ .. /Pattern2/){print if $k==3}' file

这将打印出第 3 个匹配项。将 更改$k==3为您想要的任何值。逻辑是:

  • $k++ if /Pattern1/:如果此行匹配,则将变量的值加$kPattern1
  • if(/Pattern1/ .. /Pattern2/){print if $k==3}/Pattern1/:如果此行在到的范围内/Pattern2/,则打印它,但仅当$k为 3 时才打印。将此值更改为您想要的任何匹配。

您可以将其包装在一个小的 shell 函数中,以便更轻松地获取第 N 个匹配:

getNth(){
  pat1="$1"
  pat2="$2"
  n="$3"
  file="$4"

  perl -ne '$k++ if /'"$pat1"'/;if(/'"$pat1"'/ .. /'"$pat2"'/){print if $k=='"$n"'}' file

}

然后你可以像这样运行它:

getNth Pattern1 Pattern2 3 'huge file.txt' 

使用您的示例数据:

$ perl -lne '$k++ if /start here/;if(/start here/ .. /end here/){print if $k==2}' testfile.txt
start here
123
1234
12345

123456
end here

或者:

$ getNth 'start here' 'end here' 2 testfile.txt
start here
123
1234
12345

123456
end here

只是为了好玩,这里是另一种 perl 方法:

$ perl -lne '($k++,$l++) if /start here/; print if $l && $k==2; $l=0 if /end here/' testfile.txt 
start here
123
1234
12345

123456
end here

或者,如果你喜欢打高尔夫球(感谢@simlev):

perl -ne 'print if /^start here$/&&++$k==2../^end here$/' testfile.txt 

相关内容