仅查找和替换字符串值中定界符之间的完全匹配
find & replace only exact match between delimiters in string values
我在变量中存储了一个字符串值:
PTYPE="Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home"
我想查找 Other 并将其替换为诸如 NOTHING 之类的值。所有值都存储在变量中。
WhatToChange=Other
NewValue=NOTHING
echo $PTYPE|sed -e "s@${WhatToChange}@${NewValue}@g"
这将替换 Other 的所有出现并获得如下输出:
NOTHING Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
有什么方法可以让我只更改确切的那个吗? ${WhatToChange}
的位置是可变的。
要匹配确切的字符 |
或行的开头,请使用 ([|]|^)
.
要匹配确切字符 |
或行尾,请使用 ([|]|$)
.
要仅在适当的时候将 |
放回原位,将它们存储在匹配组中,并使用 </code> 或 <code>
:
引用这些组
PTYPE="Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home"
WhatToChange=Other
NewValue=NOTHING
sed -re "s@(^|[|])${WhatToChange}($|[|])@${NewValue}@g" <<<"$PTYPE"
...作为输出发出:
Other Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
...即使 WhatToChange
在列表的开头或结尾匹配,仍然有效。
由于您有明确定义的字段并且想要精确匹配,awk 可能比 sed 更容易使用;至少,您不必担心转义字符串以在 sed
表达式中使用它:
echo "Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home" |
awk -v old="Other" -v new="NOTHING" \
'BEGIN {FS = OFS = "|"} {for(i=1;i<=NF;i++) if($i == old) $i = new} 1'
输出:
Other Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
为了好玩,一些 perl:
这就像@Charles 的 sed 解决方案:注意 \Q...\E
以便“更改”值被视为文字文本。
echo "$PTYPE" | perl -spe '
s{ (?:^|\|)\K \Q$WhatToChange\E (?=\||$) }{$NewValue}gx
' -- -WhatToChange=Other -NewValue=NOTHING
这就像@Fravadona 的 awk 解决方案:
echo "$PTYPE" | perl -F'[|]' -sane '
print join "|", map {$_ eq $WhatToChange ? $NewValue : $_} @F
' -- -WhatToChange=Other -NewValue=NOTHING
怎么样
echo ${PTYPE//$WhatToChange/$NewValue}
更新:
我刚刚意识到只有当 WhatToChange
是两个分隔符 (|
) 之间的全部内容时才应该进行替换。在这种情况下,我们也可以在 bash 中执行(无需恢复到子进程):
if [[ $PTYPE =~ (.*[|]|^)$WhatToChange([|].*|$) ]]
echo "${BASH_REMATCH[1]}${NewValue}${BASH_REMATCH[2]}"
fi
更新(基于Fravadona的评论):
这样使用,WhatToChange
被解释为一个正则表达式。如果您想捕获字符串的变体,例如
,这可能很有用
WhatToChange='[Oo]ther' # to catch Other and other
如果你总是想要文字匹配,你必须引用变量:
[[ $PTYPE =~ (.*[|]|^)"$WhatToChange"([|].*|$) ]]
这可能对你有用(GNU sed & bash):
<<<"$PTYPE" sed 'y/|/\n/;s/^'"$WhatToChange"'$/'"$NewValue"'/mg;y/\n/|/'
将 $PTYPE
作为 here-string 输入 sed。
将 |
分隔符转换为换行符。
将每个匹配行的 $WhatToChange
替换为 $NewValue
。
将换行符翻译回 |
。
N.B。在替换命令中使用 m
标志允许 sed 在多行模式下工作,这会在其自己的行上显示分隔符之间的每个值。
备选方案:
sed -z 'y/|/\x00/;s/^'"$WhatToChange"'$/'"$NewValue"'/mg;y/\x00/|/;' file
我在变量中存储了一个字符串值:
PTYPE="Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home"
我想查找 Other 并将其替换为诸如 NOTHING 之类的值。所有值都存储在变量中。
WhatToChange=Other
NewValue=NOTHING
echo $PTYPE|sed -e "s@${WhatToChange}@${NewValue}@g"
这将替换 Other 的所有出现并获得如下输出:
NOTHING Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
有什么方法可以让我只更改确切的那个吗? ${WhatToChange}
的位置是可变的。
要匹配确切的字符 |
或行的开头,请使用 ([|]|^)
.
要匹配确切字符 |
或行尾,请使用 ([|]|$)
.
要仅在适当的时候将 |
放回原位,将它们存储在匹配组中,并使用 </code> 或 <code>
:
PTYPE="Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home"
WhatToChange=Other
NewValue=NOTHING
sed -re "s@(^|[|])${WhatToChange}($|[|])@${NewValue}@g" <<<"$PTYPE"
...作为输出发出:
Other Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
...即使 WhatToChange
在列表的开头或结尾匹配,仍然有效。
由于您有明确定义的字段并且想要精确匹配,awk 可能比 sed 更容易使用;至少,您不必担心转义字符串以在 sed
表达式中使用它:
echo "Other Farm|Raised Ranch|Farm house|Other|A-Frame|Log Home" |
awk -v old="Other" -v new="NOTHING" \
'BEGIN {FS = OFS = "|"} {for(i=1;i<=NF;i++) if($i == old) $i = new} 1'
输出:
Other Farm|Raised Ranch|Farm house|NOTHING|A-Frame|Log Home
为了好玩,一些 perl:
这就像@Charles 的 sed 解决方案:注意 \Q...\E
以便“更改”值被视为文字文本。
echo "$PTYPE" | perl -spe '
s{ (?:^|\|)\K \Q$WhatToChange\E (?=\||$) }{$NewValue}gx
' -- -WhatToChange=Other -NewValue=NOTHING
这就像@Fravadona 的 awk 解决方案:
echo "$PTYPE" | perl -F'[|]' -sane '
print join "|", map {$_ eq $WhatToChange ? $NewValue : $_} @F
' -- -WhatToChange=Other -NewValue=NOTHING
怎么样
echo ${PTYPE//$WhatToChange/$NewValue}
更新:
我刚刚意识到只有当 WhatToChange
是两个分隔符 (|
) 之间的全部内容时才应该进行替换。在这种情况下,我们也可以在 bash 中执行(无需恢复到子进程):
if [[ $PTYPE =~ (.*[|]|^)$WhatToChange([|].*|$) ]]
echo "${BASH_REMATCH[1]}${NewValue}${BASH_REMATCH[2]}"
fi
更新(基于Fravadona的评论):
这样使用,WhatToChange
被解释为一个正则表达式。如果您想捕获字符串的变体,例如
WhatToChange='[Oo]ther' # to catch Other and other
如果你总是想要文字匹配,你必须引用变量:
[[ $PTYPE =~ (.*[|]|^)"$WhatToChange"([|].*|$) ]]
这可能对你有用(GNU sed & bash):
<<<"$PTYPE" sed 'y/|/\n/;s/^'"$WhatToChange"'$/'"$NewValue"'/mg;y/\n/|/'
将 $PTYPE
作为 here-string 输入 sed。
将 |
分隔符转换为换行符。
将每个匹配行的 $WhatToChange
替换为 $NewValue
。
将换行符翻译回 |
。
N.B。在替换命令中使用 m
标志允许 sed 在多行模式下工作,这会在其自己的行上显示分隔符之间的每个值。
备选方案:
sed -z 'y/|/\x00/;s/^'"$WhatToChange"'$/'"$NewValue"'/mg;y/\x00/|/;' file