Bash脚本调用psql传环境变量时字符串模板单引号转义问题
问题场景
在Bash脚本中加载.env文件的环境变量后执行psql命令时,因字符串模板构造、转义逻辑错误,psql命令始终无法正常执行,相关代码与配置如下:
故障脚本代码
#!/bin/bash set -o allexport source .env if [[ $SHOULD_UPDATE_CONTENT==1 ]] then # 1. Truncate all the tables before inserting data r="select $DB_SCHEMA.truncate_tables('user','$DB_SCHEMA');" docker exec $CONTAINER_NAME psql -U dev -d data -v ON_ERROR_STOP=1 -c "${r}" fi set +o allexport
对应.env配置
DB_HOST=db DB_PORT=5432 DB_DATABASE=dbTest DB_SCHEMA=schema SHOULD_UPDATE_CONTENT=1
故障原因
原代码存在两个核心问题:
[[ $SHOULD_UPDATE_CONTENT==1 ]]语法不符合bash规范:[[ ]]条件判断结构中,比较运算符==两侧必须保留空格,否则bash会将整段$SHOULD_UPDATE_CONTENT==1识别为单个字符串做非空判断,会导致条件逻辑永远成立,判断失效。- 直接拼接裸字符串构造SQL传参的方式,在经过本地shell解析、docker exec参数传递、容器内进程解析多层处理时,很容易出现单引号截断、参数错位问题,靠手动加反斜杠转义的方式维护成本极高,很容易出隐蔽错误。
修复方案
方案1:修正语法+规范变量引用(适配简单场景)
双引号包裹的bash字符串中,单引号属于普通字符,不需要额外转义,只需要修正条件判断的空格问题,给所有变量引用加上双引号避免参数拆分即可,修改后代码如下:
#!/bin/bash set -o allexport source .env # 注意[[ ]]内==两侧必须加空格 if [[ $SHOULD_UPDATE_CONTENT == 1 ]] then sql_stmt="select ${DB_SCHEMA}.truncate_tables('user','${DB_SCHEMA}');" docker exec "$CONTAINER_NAME" psql -U dev -d data -v ON_ERROR_STOP=1 -c "$sql_stmt" fi set +o allexport
方案2:标准输入传SQL(适配复杂场景,彻底规避转义问题)
如果SQL中包含大量特殊字符、单引号,推荐通过管道将SQL传入psql的标准输入,完全绕开命令行参数的转义逻辑,写法更稳定:
#!/bin/bash set -o allexport source .env if [[ $SHOULD_UPDATE_CONTENT == 1 ]] then echo "select ${DB_SCHEMA}.truncate_tables('user','${DB_SCHEMA}');" | \ docker exec -i "$CONTAINER_NAME" psql -U dev -d data -v ON_ERROR_STOP=1 fi set +o allexport
注意:通过管道传参时必须给
docker exec加-i参数,开启标准输入挂载,否则SQL无法正常传入容器内的psql进程。
注意事项
- 所有变量引用建议统一加双引号包裹,避免变量值包含空格、特殊字符时出现非预期的参数拆分。
- 涉及多层shell/进程嵌套的命令传参,优先选择标准输入传参、数组传参的方式,不要靠堆叠反斜杠做转义,嵌套层级超过2层后转义逻辑会变得极难维护。
内容的提问来源于stack exchange,提问作者Ren
相关产品推荐
相关产品推荐

