使用 sed,我可以只对一行的正则表达式匹配部分进行更改吗?

Using sed, can I make changes only to the regex match portion of a line?

我能否将字符串替换限制为仅匹配正则表达式的行的一部分?

例如:

A this matches Z this does not

而且,我想将 this 替换为 that,但只能在匹配的子字符串中:

A[^Z]*Z

也就是说,可以操作的行的唯一部分是如下粗体所示:

这个匹配 Z这个不匹配

所以,我正在寻找结果:

A that matches Z this does not

但是,请查看我尝试在整条线上操作的实际结果:

% sed '/A[^Z]*Z/ {
    s/this/that/g
    }' <<<"A this matches Z this does not"
A that matches Z that does not
%

以上示例仅供说明。

回顾: 是否有任何通用解决方案使用 sed 对一行的正则表达式匹配部分进行更改 ?如果答案是 "no," 那么是否有仅使用安装在 CentOS 7 最小配置(例如 awk)中的软件的解决方案?另外,我不想依赖第三方包。

我的环境:

您可以使用带有捕获组的正则表达式来匹配您想要的行的一部分,并且只替换它的一部分。

sed 's/\(A[^Z]*\)this\([^Z]*Z\)/that/'

使用以下方法:

echo "A this matches Z this does not" | sed -r 's/(A[^Z]*)\bthis\b([^Z]*Z)/that/g'

输出:

A that matches Z this does not

如果 perl 可用:

$ echo 'A this matches Z this does not' | perl -pe 's/A[^Z]*Z/$&=~s|this|that|gr/ge'
A that matches Z this does not
  • g 修饰符替换所有匹配文本
  • e 评估修饰符允许在 substitute
  • 的替换部分使用 Perl 代码
  • $&=~s|this|that|gr 表达式仅在匹配的文本中执行替换,r 修饰符返回结果而不更改 $&
  • 的值

进一步阅读:

如果您只能使用 sed,可以在 bash 中像这样完成:

#!/bin/bash
str="This does not A this matches Z this also does not"

regex='^\(.*\)\(A[^Z]*Z\)\(.*\)$'

a=$(sed  -e 's/'"$regex"'//' <<<"$str")
b=$(sed  -e 's/'"$regex"'//' -e 's/this/that/g' <<<"$str")
c=$(sed  -e 's/'"$regex"'//' <<<"$str")

echo "$a$b$c"

或者,您可以使用 awk(更快):

#!/bin/bash

str="This does not A this matches Z this also does not"

awk -vreg='A[^Z]*Z' '{
split([=11=],a,reg,s);
printf("%s%s%s\n",a[1],gensub(/this/,"that","g", s[1]),a[2])
}' <<<"$str"