首页 > 解决方案 > Bash SED 字符串替换 - 删除正则表达式前后的字符

问题描述

我有这个简单的 bash (3) 脚本来扫描目录中的所有文件,并用新的 CSS 类替换一些旧的 CSS 类。

export LC_ALL=C

ARRAY=(
    "a-oldclass:new-class"
    "m-oldclass:new-class"
)

for className in "${ARRAY[@]}" ; do
    REGEX=[^a-zA-Z0-9]${className%%:*}[^a-zA-Z0-9]
    CHANGE="s/${REGEX}/${className##*:}/g"

    find src -type f -exec sed -i '' "${CHANGE}" '{}' +
done

它是键:值对和正则表达式的组合。问题是它还会删除匹配模式之前和之后的特殊字符,例如:

class="a-oldclass" => class=new-class (Quotes are gone)

class=" a-oldclass " => class="new-class" (spaces are gone)

我需要这个结果:

class="a-oldclass m-oldclass" => class="new-class new-class".

[^a-zA-Z0-9]有必要避免这种情况:我想替换a-oldclassnew-class,但我不想触摸 class data-oldclass。由于此字符串包含a-oldclass它将被修改。所以[^a-zA-Z0-9]我排除了这种情况。

标签: regexbash

解决方案


这应该是正则表达式:

REGEX='\([^a-zA-Z0-9]\)'"${className%%:*}"'\([^a-zA-Z0-9]\)'
CHANGE="s/${REGEX}/\1${className##*:}\2/g"

这使用\( \)\1 \2重现类名之前和之后的匹配。

此外,我建议不要使用全大写变量,因为它们可能与 BASH 默认变量冲突。


如果您还需要匹配换行符终止的字符串,您可以添加

REGEX='\([^a-zA-Z0-9]\)'"${className%%:*}"'\([^a-zA-Z0-9]\)'
CHANGE="s/${REGEX}/\1${className##*:}\2/g"
REGEXNL='\([^a-zA-Z0-9]\)'"${className%%:*}"'$'
CHANGENL="s/${REGEXNL}/\1${className##*:}/g"

并将sed命令更改为

sed -i -e "${CHANGE}" -e "${CHANGENL}"

我敢打赌,有一个更优雅的解决方案,但这sed经受住了-posix考验。


推荐阅读