如果没有其他模式,则替换第一次出现的模式

时间:2019-05-19 12:56:08

标签: sed

使用 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/'

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

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

第三行也被更改。我该如何预防?我认为这与地址范围有关,但我不知道如何取反地址范围的第二部分。

2 个答案:

答案 0 :(得分:1)

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

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

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

也可能写成:

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

答案 1 :(得分:0)

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