使用 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
)中的软件的解决方案?另外,我不想依赖第三方包。
我的环境:
- CentOS 7.3 [kernel-3.10.0-514.6.1.el7.x86_64]
- sed(GNU sed)4.2.2 [sed-4.2.2-5.el7.x86_64]
- Bash 4.2.46(1) [bash-4.2.46-21.el7_3.x86_64]
您可以使用带有捕获组的正则表达式来匹配您想要的行的一部分,并且只替换它的一部分。
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"
我能否将字符串替换限制为仅匹配正则表达式的行的一部分?
例如:
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
)中的软件的解决方案?另外,我不想依赖第三方包。
我的环境:
- CentOS 7.3 [kernel-3.10.0-514.6.1.el7.x86_64]
- sed(GNU sed)4.2.2 [sed-4.2.2-5.el7.x86_64]
- Bash 4.2.46(1) [bash-4.2.46-21.el7_3.x86_64]
您可以使用带有捕获组的正则表达式来匹配您想要的行的一部分,并且只替换它的一部分。
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"