如何在awk中实现以指定行号为起始、正则为终止的范围匹配
先搞懂你之前的写法为啥不符合预期
awk的范围匹配语法条件1, 条件2本质是个简单的双状态机运行逻辑,没有复杂的黑盒规则:
- 未进入匹配范围时,逐行检查是否满足
条件1,一旦命中就立刻切换到“匹配中”的状态 - 处于匹配中状态时,每一行都会执行对应的动作(比如默认的打印输出),同时检查当前行是否满足
条件2——只要命中,就把这行处理完,立刻切回“未匹配”的初始状态
你之前用1,/end/能打出全部内容,核心是1是永远为真的判断条件,逐行走一遍流程就一目了然:
- 第1行内容a:初始状态下满足
1的恒真要求,进入匹配态,输出a- 第2行b、第3行c:匹配态下没命中
/end/规则,逐行正常输出- 第4行内容end:匹配态下命中
/end/规则,输出end后立刻切回未匹配状态- 第5行内容e:未匹配状态下,恒真的
1条件再次命中,立刻重新进入匹配态,输出e- 第6行f、第7行g:重新进入匹配态后一直没碰到
/end/规则,就逐行全部输出了
这和你实际看到的全量输出结果完全吻合。而你之前用/b/,/end/能得到正确的截断效果,是因为碰到end行切回未匹配状态后,后面的e/f/g行都不匹配/b/的正则,不会再次触发起始条件,自然就停在end行不再输出。
指定行号作为起始条件的正确写法
awk内置的NR变量直接记录当前处理的行号,从1开始计数,你只需要把范围表达式的起始条件换成NR==你要的目标行号,就能实现“从指定行开始,一直输出到命中指定正则的行就停止”的效果。
举个和你测试样例完全对应的命令:
如果要从第2行(也就是内容为b的行)开始输出,直到碰到包含end的行为止,直接执行:echo -e 'a\nb\nc\nend\ne\nf\ng\n' | awk 'NR==2,/end/'
执行后的输出和你之前的双正则写法结果完全一致:
b c end
这种写法不会出现之前恒真条件的问题:因为行号判断只会在特定的那一行命中,当碰到end行切回初始状态后,后续所有行的行号都不会再等于你指定的起始行号,不会反复触发匹配范围,自然就能在命中end行后停止后续输出。
拓展灵活写法
起始的行号条件可以根据需要组合逻辑,完全不影响范围匹配的运行逻辑:
- 如果要从第3行开始匹配到
/end/,直接写NR==3,/end/ - 如果要从第10行开始,才开始匹配直到碰到
/end/,直接写NR>=10,/end/ - 如果要在固定行号区间内(比如20到100行)匹配到第一个
/end/就停止,可以在动作块里加判断限制,避免匹配区间外的内容
内容的提问来源于stack exchange,提问作者user15148997
相关产品推荐
相关产品推荐

