sed命令在bash/sh中失效、zsh中正常的问题排查
问题
在Bash/sh脚本中使用sed命令替换文件中sas_token后的字符串时遇到异常:
- 新令牌包含
&符号,已通过${NEW_TOKEN//&/\&}做转义处理,执行的sed命令如下:sed -i 's/\(^sas_token =\)\(\s*.*$\)/\1 "'${NEW_TOKEN//&/\\&}'"/' .ENV/app-backend.tfvars - 该命令在zsh环境中可正常完成替换,但在bash/sh环境中执行后,文件内的
sas_token值完全没有变化。
测试细节
Bash环境测试
- 确认当前解释器为bash;
- 文件内
sas_token字段存在旧值; - 新令牌内容:
se=1998-11-21T08%3A49Z&sp=rwl&sip=193.253.170.130&spr=https&sv=2022-11-02&sr=c&sig=DE7xk1ggg%3D; - 执行sed命令后,
sas_token值未发生改变。
Zsh环境测试
- 确认当前解释器为zsh;
- 文件原始内容与Bash测试场景一致;
- 新令牌内容完全相同;
- 执行sed命令后,
sas_token值成功替换为新令牌。
解决方案
问题核心是bash与zsh对转义字符的处理逻辑存在差异,当前的转义规则仅适配zsh,bash需要调整转义层级才能生效。
修正后的命令
有两种可行的修正方式:
方式一:调整单引号内的变量转义
sed -i 's/\(^sas_token =\)\(\s*.*$\)/\1 "'"${NEW_TOKEN//&/\\\&}"'"'/' .ENV/app-backend.tfvars
这里把${NEW_TOKEN//&/\\&}改成${NEW_TOKEN//&/\\\&},给&前多加一个反斜杠,确保bash展开后传递给sed的是\&。
方式二:改用双引号包裹sed脚本(更简洁稳妥)
sed -i "s/^sas_token = *\(.*\)/sas_token = \"${NEW_TOKEN//&/\\&}\"/" .ENV/app-backend.tfvars
双引号内bash会正确解析变量转义,同时简化sed的正则写法,避免多层单引号嵌套的转义混乱。
原因说明
- 在bash中,当变量在单引号外部展开时,
\\会被解析为单个\,导致原本的${NEW_TOKEN//&/\\&}展开后,传递给sed的是&而非\&。而sed中&是特殊符号(代表匹配到的整个内容),无法正确转义令牌中的&,最终导致替换失效。 - zsh对嵌套转义的处理更宽松,原本的转义规则刚好能生成sed需要的
\&,因此可以正常工作。
内容的提问来源于stack exchange,提问作者Greg'ory
相关产品推荐
相关产品推荐

