sed:具有反向前瞻匹配的嵌套组
Posted
技术标签:
【中文标题】sed:具有反向前瞻匹配的嵌套组【英文标题】:sed: Nested group with inverse lookahead matching 【发布时间】:2022-01-07 02:46:40 【问题描述】:我正在尝试用图像bar
替换除 URL 之外的所有 URL 的图像标记。但是,它说正则表达式无效。
只检查 regex101.com 上的正则表达式 (image:(?!.*bar).*:).*
看起来不错。将 sed 表达式的第二部分替换为组 (image:(?!.*bar).*:)
时出现错误。
$ echo '
image: mydomain/subdomain/foo:old_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:old_tag
' | sed --regexp-extended "s|(image:(?!.*bar).*:).*|\1new_tag|g"
sed: -e expression #1, char 36: Invalid preceding regular expression
预期的最终结果是:
image: mydomain/subdomain/foo:new_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:new_tag
正则表达式(image:(?!.*bar).*:).*
的解释
搜索所有包含image:.*:.*
的行,但包含image:.*bar
的行除外
【问题讨论】:
(?!...)
是 Perl 扩展,--regexp-extended
不会将sed
转换成 Perl。
【参考方案1】:
POSIX ERE 仍然不支持环视。幸运的是,您可以匹配具有特定模式的行并跳过它,然后匹配您需要的任何内容:
sed -E "/image:.*bar/!s/(image:.*:).*/\1new_tag/"
见online demo:
echo '
image: mydomain/subdomain/foo:old_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:old_tag
' | sed -E "/image:.*bar/!s/(image:.*:).*/\1new_tag/"
输出:
image: mydomain/subdomain/foo:new_tag
image: mydomain/subdomain/bar:dont_update_me_tag
image: mydomain/subdomain/baz:new_tag
【讨论】:
也许您应该在使用.*
正则表达式时删除 g
标志,并且替换命令的不匹配地址在整个行中都是全局的。
@potong 这是 OP 命令的余数。我认为即使有g
也没有什么坏处,但留在那里肯定是没有意义的。【参考方案2】:
这可能对你有用(GNU sed):
sed -E 's/^/\n/
:a;ta
s/\n(image: \S*bar\S*)/\1\n/;ta
s/\n(image: \S*:)\S*/\1new_tag\n/;ta
s/\n(.)/\1\n/;ta
s/\n$//' file
一次处理一行。
在行首引入换行符。
如果换行符后面的字符串是带有bar
的图像,则跳过它,移动换行符并重复。
如果换行符后面的字符串是没有bar
的图像,则用新标签替换它,移动换行符并重复。
否则,将换行符移到下一个字符并重复。
当换行符不能再移动时,删除它,打印当前行并重复。
注意不能使用替换命令的g
标志,因为必须单独比较图像的每个实例。如果每行只有一个图像而没有其他图像,则使用@Wiktor Stribiżew 解决方案。
【讨论】:
感谢您分享详细的解释和答案。如果\n
仅被 GNU sed
识别,您能否告诉我?或者还有其他可以识别它的 sed 版本?
@RavinderSingh13 我只使用过 GNU sed,而且我知道其他 sed 确实存在问题,这就是为什么我总是(可能!)按上述方式限定我的解决方案。另一个question 可能会更清楚地说明这个问题。以上是关于sed:具有反向前瞻匹配的嵌套组的主要内容,如果未能解决你的问题,请参考以下文章