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

dro*_*own 5 command-line bash printing sed

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

sed -n '/start here/,/end here/p'  'testfile.txt' 
Run Code Online (Sandbox Code Playgroud)

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

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here
00000000

00000000
Run Code Online (Sandbox Code Playgroud)

并且我不想在两个模式之间打印零。

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

start here
0000000
0000000
end here
start here
123
1234
12345

123456
end here
start here
00000000
end here
Run Code Online (Sandbox Code Playgroud)

虽然我想要的输出是:

start here
123
1234
12345

123456
end here
Run Code Online (Sandbox Code Playgroud)

考虑到这些行需要按 in 打印testfile.txt而不是连接。

sim*_*lev 7

我会用 Perl 解决这个问题,正如@terdon明智地建议的那样。或者使用 AWK:

awk '/start here/&&++k==2,/end here/' testfile.txt
Run Code Online (Sandbox Code Playgroud)

如果我必须单独使用 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
Run Code Online (Sandbox Code Playgroud)

  • 真的很喜欢你的 awk 解决方案。调整为我在链/crt文件中获取第n个SSL证书的用例: `awk -vn=2 '/BEGIN CERTIFICATE/ && ++k == n, /END CERTIFICATE/' /etc/pki/ tls/certs/mychain.crt | openssl x509 -noout -文本 | grep -E '^ +(主题|颁发者|不早于|不晚于):'` (3认同)

ter*_*don 5

我只想切换到另一个工具。Perl,例如:

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

这将打印第 3 场比赛。将 更改为$k==3您想要的任何值。逻辑是:

  • $k++ if /Pattern1/:$k如果此行匹配,则将变量的值加一Pattern1
  • if(/Pattern1/ .. /Pattern2/){print if $k==3}: 如果此行在/Pattern1/to的范围内/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

}
Run Code Online (Sandbox Code Playgroud)

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

getNth Pattern1 Pattern2 3 'huge file.txt' 
Run Code Online (Sandbox Code Playgroud)

使用您的示例数据:

$ 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
Run Code Online (Sandbox Code Playgroud)

或者:

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

123456
end here
Run Code Online (Sandbox Code Playgroud)

只是为了好玩,这是另一种 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
Run Code Online (Sandbox Code Playgroud)

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

perl -ne 'print if /^start here$/&&++$k==2../^end here$/' testfile.txt 
Run Code Online (Sandbox Code Playgroud)