在Bash中使用sed时如何保留转义的双引号?
问题
我先转义JSON字符串里的所有双引号,再用转义后的结果替换文本中的占位符,但最后一次sed替换中转义符被移除了,请问原因是什么?该如何避免?
Bash示例:
TEST_OBJECT='{"val1": "a", "val2": "b"}' ESCAPED_OBJ="$(echo $TEST_OBJECT | sed 's/"/\\"/g')" echo $ESCAPED_OBJ # 输出:{\"val1\": \"a\", \"val2\": \"b\"} echo 'value: "_REPLACE_ME"' | sed "s@_REPLACE_ME@$ESCAPED_OBJ@g" # 实际输出:value: "{"val1": "a", "val2": "b"}" # 期望输出:value: "{\"val1\": \"a\", \"val2\": \"b\"}"
补充说明
转义操作和替换操作必须分两步执行(这是GitHub工作流的一部分),最终要替换YAML文件中的占位符:
sed "s@_REPLACE_ME@$ESCAPED_OBJ@g" input.yml > ${{ github.action_path }}/config/job.yml
目标YAML文件job.yml内容:
... env: - name: CUSTOM_DATA_OBJECT value: "_REPLACE_ME"
需要保留转义后的格式,避免破坏YAML结构。
原因
问题出在bash对双引号内变量的解析逻辑:
当你用双引号包裹sed命令(sed "s@...@$ESCAPED_OBJ@g")时,bash会先展开变量ESCAPED_OBJ,并解析其中的转义符——把\"直接转换成",传给sed的内容已经是没有转义符的原始JSON了,所以替换后自然看不到转义效果。
解决方案
要让sed最终保留\",需要让bash解析后传给sed的内容仍然是\",所以需要对转义符再转义一次:把\变成\\,这样bash解析时会把\\"转换成\",最终sed就能正确输出带转义的字符串。
具体实现步骤
- 重新生成转义后的字符串,同时转义转义符:
TEST_OBJECT='{"val1": "a", "val2": "b"}' # 先转义双引号为\",再把\转义为\\,最终得到\\" ESCAPED_OBJ="$(echo "$TEST_OBJECT" | sed 's/"/\\\\"/g')"
或者分两步处理:
# 第一步转义双引号 TEMP_OBJ="$(echo "$TEST_OBJECT" | sed 's/"/\\"/g')" # 第二步转义转义符 ESCAPED_OBJ="$(echo "$TEMP_OBJ" | sed 's/\\/\\\\/g')"
- 执行替换命令:
echo 'value: "_REPLACE_ME"' | sed "s@_REPLACE_ME@$ESCAPED_OBJ@g" # 输出:value: "{\"val1\": \"a\", \"val2\": \"b\"}"
GitHub工作流中的适配写法
直接在工作流里使用:
TEST_OBJECT='{"val1": "a", "val2": "b"}' ESCAPED_OBJ="$(echo "$TEST_OBJECT" | sed 's/"/\\\\"/g')" sed "s@_REPLACE_ME@$ESCAPED_OBJ@g" input.yml > ${{ github.action_path }}/config/job.yml
这样替换后的YAML文件里,value字段会保留正确的转义双引号,不会破坏YAML结构。
内容的提问来源于stack exchange,提问作者KungWaz
相关产品推荐
相关产品推荐

