sed '
# replace *all* OLDs with newline:
s/OLD/\
/g
:1
# replace one newline back to a OLD as long as it is
# followed by at least 3 newlines, relying on the fact
# that the first .* will match greedily as much as possible.
s/\(.*\)\n\(.*\n.*\n.*\n\)/\1OLD\2/
# repeat as long as the above was successful:
t1
# replace the remaining newlines with NEW:
s/\n/NEW/g'
更改与特定模式匹配的字符串的最后三个实例的最简单方法是反转每行输入并替换反转的字符串:
如果已知相关行的具体格式,可能会有更好的方法来执行此操作。例如,在我上面使用的测试字符串中,我们可以简单地替换
OLD OLD OLD
为NEW NEW NEW
.还要注意,由于正则表达式是从左到右方向应用的,因此替换反转的字符串可能需要与原始表达式的简单反转不同的模式。例如,考虑替换 中的前两个字母
abab
,当反转时必须替换中的最后两个字母baba
。sed
反转一行可以这样完成,使用@
作为枢轴字符将字符串分为未反转和反转的部分:一种方法可能是:
使用 时
perl
,进行两次替换,一次不做任何更改以记录出现的次数,第二次仅替换第 (n-2)到第 n次出现:对于任意字符串和最大出现次数:
s/OLD/$&/g
将所有出现的内容替换为自身(包含's$&
等匹配内容)并返回替换数。或者,您可以使用which 将后面的Nothing替换为Nothing,用于标记要替换的内容的开始。sed
&
s/OLD\K//g
OLD
\K
使用 GNU awk 来
patsplit()
:while (match())
您可以在任何带有orwhile(index())
和s 循环的 awk 中执行相同的操作substr()
,只是需要编写更多代码。上面的内容被OLD
视为正则表达式,如果这不是您想要的,则使用循环while(index())
或编写代码来转义OLD
可能包含的任何元字符,例如在使用文字字符串的任何 awk 中:虽然此操作没有直接的 sed 选项,但这里有一个实用的方法:将最后一次出现的字符串替换为:
由于 n 通常很小,您可以简单地将其传递到同一个命令 n 次:
或者更简单地重复此命令 n 次:
(请注意,在这种情况下 input_file 会发生变化)