使用sed替换含全类型特殊字符的字符串时现有方案失效如何解决
错误原因
现有方案失效核心是两点:
- sed的搜索模式(正则语法)和替换字符串(纯文本语法)需要转义的特殊字符集合完全不同,混用同一套转义规则必然遗漏场景
- 未处理sed替换语法的分隔符冲突:你用
/作为分隔符,若内容中包含/也会导致语法解析错误
可行解决方案
方案1:修正转义规则的sed实现
分别针对搜索key和替换value做转义,同时选用不会出现在内容中的字符作为分隔符,避免冲突:
#!/bin/sh # 注意:变量赋值时如果用双引号,对$、`等shell元字符需要加反斜杠转义,避免被shell提前解析 key="12'{}34[];|^)(*&^!^#~`!-567" value="345\$`{}[]|%';" # 转义搜索key:把所有字符包装为字符集,彻底避免正则元字符解析 escappedKey=$(printf '%s' "$key" | sed -e 's/[^^]/[&]/g; s/\^/\\^/g') # 转义替换value:仅处理sed替换语法的特殊字符&、\和分隔符 escappedValue=$(printf '%s' "$value" | sed -e 's/[&\\|]/\\&/g') # 用|作为分隔符,不同平台sed -i语法有差异:GNU sed直接用,macOS需要改为sed -i '' sed -i "s|$escappedKey|$escappedValue|g" hello.txt
方案2:固定字符串匹配方案(全场景推荐)
如果允许使用awk,直接用字符串匹配替换逻辑,完全不需要处理任何转义,适配所有含任意特殊字符的替换场景,稳定性更高:
#!/bin/sh key="12'{}34[];|^)(*&^!^#~`!-567" value="345\$`{}[]|%';" awk -v k="$key" -v v="$value" '{ res = "" while (pos = index($0, k)) { res = res substr($0, 1, pos - 1) v $0 = substr($0, pos + length(k)) } print res $0 }' hello.txt > tmp && mv tmp hello.txt
执行结果
运行后hello.txt内容符合预期:
ABC="345$`{}[]|%';"
内容的提问来源于stack exchange,提问作者Edison Lo
相关产品推荐
相关产品推荐

