我想打印基于两种模式的 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/
:如果此行匹配,则将变量的值加$k
一Pattern1
。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