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而不是连接。
我会用 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)
我只想切换到另一个工具。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)