【问题标题】:Replace first occurrence of a pattern if not preceded with another pattern如果前面没有另一个模式,则替换第一次出现的模式
【发布时间】:2019-05-20 06:36:19
【问题描述】:

使用 GNU sed,我尝试替换文件中第一次出现的模式,但如果匹配之前有另一个模式,我不想替换。

例如,如果文件包含带有“bird [number]”的行,如果此模式之前没有任何“cat”字样,我想用“0”替换数字。

示例文字

dog cat - fish bird 123
dog fish - bird 1234567
dog - cat fish, lion bird 3456

预期结果:

dog cat - fish bird 123
dog fish - bird 0
dog - cat fish, lion bird 3456

我尝试结合 How to use sed to replace only the first occurrence in a file?Sed regex and substring negation 解决方案并想出了类似的东西

sed -E '0,/cat.*bird +[0-9]+/b;/(bird +)[0-9]+/ s//\10/'

如果cat.*bird +[0-9]+ 模式不匹配,0,/cat.*bird +[0-9]+/b;/(bird +)[0-9]+/ 应该匹配第一次出现的(bird +)[0-9]+,但我明白了

dog cat - fish bird 123
dog fish - bird 0
dog - cat fish, lion bird 0

第三行也改变了。我该如何预防?我认为它与地址范围有关,但我不明白如何否定地址范围的第二部分。

【问题讨论】:

    标签: sed


    【解决方案1】:

    这可能对你有用(GNU sed):

    sed '/\<cat\>.*\<bird\>/b;s/\<\(bird\) \+[0-9]\+/\1 0/;T;:a;n;ba' file
    

    如果一行在单词bird 之前包含单词cat,则结束对该行的处理。 尝试将单词bird 后面的数字替换为零。如果没有成功结束该行的处理。否则读取/打印以下所有行,直到文件末尾。

    也可以写成:

    sed -E '/cat.*bird/b;/(bird +)[0-9]+/{s//\10/;:a;n;ba}' file
    

    【讨论】:

    • 谢谢,它按预期工作。但是,我想知道这里是否真的需要;T,我认为没有它也可以。
    • @RyszardCzech 如果没有T 命令,它可能会很好地工作,但这取决于您的数据。您只希望替换第一场比赛而不是每场比赛。在第一次匹配之后,文件的其余部分保持原样。
    【解决方案2】:

    sed 用于进行简单的 s/old/new 替换,仅此而已。对于其他任何事情,只需使用 awk,例如使用 GNU awk 而不是您使用的 GNU sed:

    $ awk 'match($0,/(.*bird\s+)[0-9]+(.*)/,a) && (a[1] !~ /cat/) {$0=a[1] 0 a[2]} 1' file
    dog cat - fish bird 123
    dog fish - bird 0
    dog - cat fish, lion bird 3456
    

    【讨论】:

      猜你喜欢
      • 2019-12-11
      • 2017-09-10
      • 2022-01-11
      • 2013-06-07
      • 2013-04-03
      • 2017-01-25
      • 2016-01-20
      • 1970-01-01
      • 2011-12-19
      相关资源
      最近更新 更多