仅查找和替换字符串值中定界符之间的完全匹配

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