如何在Shell脚本中使用sed替换含换行符\n的字符串?
问题原因及解决方法
问题原因
- 换行符被shell解析为命令分隔符:你的变量
conf中包含实际换行符(无论是通过$'...'语法定义,还是其他方式写入的换行),当shell展开$conf时,会把换行符当成命令行的换行分割点,导致sed命令被拆分成多行执行。最终sed会将换行前的内容替换到目标行,换行后的部分被当作独立的sed指令,造成替换内容被拆分。 - 匹配规则存在缺陷:原sed表达式中的
[^ ]*仅匹配非空格字符,一旦conf中包含空格,会提前终止匹配,导致替换不完整。
解决方法
方法1:使用awk处理(推荐,适配多行/特殊字符)
awk对多行变量和特殊字符的处理更友好,无需额外转义:
# 假设变量定义包含实际换行 conf=$'2bi5oIl0hldy/p3fe+KMQTVjUSg89ywhdMCaSOAopEVFM\nKlj4RDJcmNcEa1cgxL3sJNBHrw==\n' # 执行替换并覆盖原文件 awk -v new_pass="$conf" '!/^#/ && match($0, /^PASS[[:space:]]*=[[:space:]]*/) { $0 = substr($0, 1, RLENGTH) new_pass } 1' file.ini > temp.ini && mv temp.ini file.ini
-v new_pass="$conf":将shell变量传递给awk内部变量!/^#/:跳过以#开头的注释行match(...):精准匹配行首的PASS关键字,以及等号前后的任意空格- 替换逻辑:保留匹配到的前缀,拼接新的密码内容
- 用临时文件过渡是为了避免awk直接修改原文件可能导致的损坏
方法2:修正sed命令,转义变量中的特殊字符
通过转义变量里的换行符和sed特殊字符,确保变量被完整传入sed:
conf=$'2bi5oIl0hldy/p3fe+KMQTVjUSg89ywhdMCaSOAopEVFM\nKlj4RDJcmNcEa1cgxL3sJNBHrw==\n' # 转义sed特殊字符,并将换行符转为sed可识别的\n escaped_conf=$(printf '%s' "$conf" | sed 's/[\&/]/\\&/g; s/\n/\\n/g') # 执行替换(BSD sed需将-i改为-i "") sed -i "/^[^#]/ s|\(^PASS[[:space:]]*=[[:space:]]*\).*|\1$escaped_conf|g" file.ini
sed 's/[\&/]/\\&/g; s/\n/\\n/g':先转义sed中的特殊字符(&、/),再把实际换行符转为sed能解析的\n- 将原匹配规则
[^ ]*改为.*,确保替换掉PASS=后的所有内容
内容的提问来源于stack exchange,提问作者user1508682
相关产品推荐
相关产品推荐

