[英]How to use sed to search and replace a pattern who appears multiple times in the same line?
因为这个问题可能会产生误导,所以这里有一个小例子。 我有这种文件:
some text
some text @@some-text-KEY-some-other-text@@
text again @@some-text-KEY-some-other-text@@ @@some-text-KEY-some-other-text@@
again @@some-text-KEY-some-other-text-KEY-text@@
some text with KEY @@KEY-some-text@@
blabla @@KEY@@
在此示例中,我想将一对@@
中每次出现的KEY-
替换为VALUE-
。 我从这个 sed 命令开始:
sed -i 's/\(@@[^@]*\)KEY-\([^@]*@@\)/\1VALUE-\2/g'
下面是它的工作原理:
\(@@[^@]*\)
:创建由两个@
和除@
之外的任何字符组成的第一组...KEY-
: ... 直到该行最后一次出现KEY-
\([^@]*@@\)
:并创建第二组,其中包含除@
之外的所有字符,直到下一对@
。 问题是我的命令无法正确处理以下行,因为我的一对@@
中有多个KEY-
:
again @@some-text-KEY-some-other-text-KEY-text@@
确实,我得到了这个结果:
again @@some-text-KEY-some-other-text-VALUE-text@@
如果我想替换该行中所有出现的KEY-
,我必须多次运行我的命令,我宁愿避免这种情况。 我也尝试过使用惰性运算符,但问题是一样的。
如何创建可以正确处理我所有文件的正则表达式和 sed 命令?
问题相当复杂:您需要替换相同多字符分隔符之间的文本块内出现的所有多字符文本。
解决任务最简单、最安全的方法是使用 Perl:
perl -i -pe 's/(@@)(.*?)(@@)/$end_delim=$3; "$1" . $2=~s|KEY-|VALUE-|gr . "$end_delim"/ge' file
请参阅在线演示。
(@@)(.*?)(@@)
模式将匹配两个相邻@@
子字符串之间的字符串,将起始分隔符捕获到第 1 组中,将结束分隔符捕获到第 3 组中,并将其间的所有文本捕获到第 2 组中。由于正则表达式替换重新设置所有占位符,临时变量用于保留结束分隔符的值( $end_delim=$3
),然后是"$1". $2=~s|KEY-|VALUE-|gr. "$end_delim"
"$1". $2=~s|KEY-|VALUE-|gr. "$end_delim"
"$1". $2=~s|KEY-|VALUE-|gr. "$end_delim"
将匹配替换为第一个匹配的组 1 中的值(第一个@@
),然后将所有KEY-
替换为VALUE-
的组 2 值,然后是结束分隔符。
如果在同一行的匹配之间没有KEY-
s,您可以使用带有sed
的分支,方法是用:A
和tA
括起来您的命令:
sed -i ':A; s/\(@@[^@]*\)KEY-\([^@]*@@\)/\1VALUE-\2/g; tA' file
请注意,您错过了\VALUE-\2
中的第一个占位符,它应该是\1VALUE-\2
。
查看在线演示:
s="some KEY- text
some text @@some-text-KEY-some-other-text@@
text again @@some-text-KEY-some-other-text@@ @@some-text-KEY-some-other-text@@
again @@some-text-KEY-some-other-text-KEY-text@@
some text with KEY @@KEY-some-text@@
blabla @@KEY@@"
sed ':A; s/\(@@[^@]*\)KEY-\([^@]*@@\)/\1VALUE-\2/g; tA' <<< "$s"
Output:
some KEY- text
some text @@some-text-VALUE-some-other-text@@
text again @@some-text-VALUE-some-other-text@@ @@some-text-VALUE-some-other-text@@
again @@some-text-VALUE-some-other-text-VALUE-text@@
some text with KEY @@VALUE-some-text@@
blabla @@KEY@@
更多详情:
sed
允许使用循环和分支。 上面代码中的:A
是label ,一个特殊的位置标记,可以使用适当的运算符“跳转”。 t
用于创建分支,此“命令仅在前一个替换命令成功时才跳转到 label ”。 因此,一旦模式匹配并发生替换, sed
就会回到原来的位置并重新尝试匹配。 如果不成功, sed
继续在字符串中进一步搜索匹配项。 因此, tA
表示go 回到标有A
的位置,如果有成功的搜索和替换操作。
这可能对您有用(GNU sed):
sed -E 's/@@/\n/g;:a;s/^([^\n]*(\n[^\n]*\n[^\n]*)*\n[^\n]*)KEY-/\1VALUE-/;ta;s/\n/@@/g' file
将@@
转换为换行符。 使用循环,将匹配的换行符之间的VAL-
替换为VALUE-
。 全部完成后,用@@
替换换行符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.