【问题标题】:how can I get sed to quit after the first matching address range?在第一个匹配的地址范围之后如何让 sed 退出?
【发布时间】:2014-01-23 10:43:55
【问题描述】:

我有一个文件:

header
trigger
text1
text2
trigger
text5
trigger
...
trigger
...

我希望 sed 只匹配前两次出现的“触发器”。所以我尝试了:

sed -n '/trigger/,/trigger/p'

但正如 sed 的手册页所说,这将两行内的所有匹配项与“触发器”匹配。我希望 sed 在第一场比赛后退出,所以输出将是:

trigger
text1
text2
trigger

我该如何做到这一点?

【问题讨论】:

标签: regex sed


【解决方案1】:

您可以在 GNU sed 中使用循环来做到这一点:

sed -n '/trigger/{p; :loop n; p; /trigger/q; b loop}'

解释:

  1. 当您看到第一个 /trigger/ 时,启动一个命令块
  2. p -- 打印该行
  3. :loop -- 设置一个名为loop的标签
  4. n -- 获取下一行
  5. p -- 打印该行
  6. /trigger/q -- 如果该行匹配 /trigger/ 然后退出 sed
  7. b -- 跳转到loop

【讨论】:

    【解决方案2】:

    虽然您正在寻找 jason 的 ans,但我更喜欢使用 awk 来完成此任务

    awk '/trigger/{p++} p==2{print; exit} p>=1' file
    

    输出:

    trigger
    text1
    text2
    trigger
    

    这将为在 nth 和 mtrigger 的出现之间选择行提供更大的灵活性。

    例如

    $ awk -v n=2 -v m=3 '/trigger/{p++} p==m{print; exit} p>=n' file
    trigger
    text5
    trigger
    

    【讨论】:

    • 谢谢。在这种特殊情况下,我实际上需要 sed 因为我没有在问题中显示的其他命令,但在一般情况下我肯定会找到基于 awk 的解决方案。对于第 n/m 次出现的灵活性,绝对如此。再次感谢!
    【解决方案3】:

    另一个awk 变体:

    awk '/trigger/{f++} f; f>1 {exit}' file
    
    • /trigger/{f++} 如果发现单词 triggerf 增加 1 (第一次看到是 1,第二次看到 2 等等)
    • f; 测试f 是否为真,如果是,则执行默认操作,打印该行。
    • f>1 {exit} 如果f 大于 1(第二次命中时为 2)退出程序。

    【讨论】:

    • 你甚至不需要计数器...awk '/trigger/{print $0; exit}'
    • @JasonKohles 你是对的 :)
    • @JasonKohles 你确实需要计数器,否则它只会打印一行(触发线),然后退出。
    • @MartinPoelstra 这正是我评论的代码的作用
    • @JasonKohles 您正在评论的代码(即答案中的代码)还打印两个触发器之间的所有行,然后在第二次找到触发器时停止.你的只打印触发器本身,然后立即停止。
    猜你喜欢
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    • 1970-01-01
    • 2016-02-09
    • 2018-12-18
    • 2014-05-06
    • 2017-04-03
    相关资源
    最近更新 更多