Bash脚本中字符串比较失效问题排查
问题描述
编写的Bash脚本如下:
set -x myJson="echo '{\"data\":\"true\"}'" commandOutput=$(eval $myJson | jq '.data') echo $commandOutput while : do if [[ $commandOutput == "true" ]] then break fi sleep 1 done echo "Done"
脚本中的字符串比较始终不生效,只有将比较条件改为'\"true\"'时才能正常工作。开启set -x调试后输出如下:
+ myJson='echo '\''{"data":"true"}'\''' ++ eval echo ''\''{"data":"true"}'\''' +++ echo '{"data":"true"}' ++ jq .data + commandOutput='"true"' + echo '"true"' "true" + : + [[ "true" == \t\r\u\e ]] + sleep 1 + : + [[ "true" == \t\r\u\e ]] + sleep 1 + : + [[ "true" == \t\r\u\e ]] + sleep 1
看起来比较条件右侧的字符串总是被转义,请问这是什么原因?
原因分析
- 从调试输出能明确看到,
commandOutput的实际值是"true"(包含双引号),而你的比较条件[[ $commandOutput == "true" ]]中,双引号会被Bash解析移除,实际是拿带引号的"true"和不带引号的true做比较,自然不相等。 - 调试日志里的
[[ "true" == \t\r\u\e ]]是set -x的特殊显示方式,它把字符串true的每个字符转义显示了,并不是条件本身被转义,本质还是值不匹配导致比较失败。 - 另外,你用
eval构造命令的方式不仅容易引发转义问题,还存在安全风险,这也是导致后续字符串处理混乱的根源之一。
解决方案
方案1:匹配带引号的目标值
直接把比较条件改成匹配带引号的字符串,用单引号包裹避免转义:
if [[ $commandOutput == '"true"' ]]
方案2:用jq的原始输出(推荐)
使用jq的-r参数(raw output),让它输出不带引号的原始字符串,这样后续比较无需处理引号:
# 去掉不必要的eval,直接构造JSON字符串 commandOutput=$(echo '{"data":"true"}' | jq -r '.data') # 此时直接比较true即可 if [[ $commandOutput == "true" ]]
如果必须保留myJson变量的写法,也可以去掉eval,改用更安全的方式:
myJson='{"data":"true"}' commandOutput=$(echo "$myJson" | jq -r '.data')
内容的提问来源于stack exchange,提问作者Matheus
相关产品推荐
相关产品推荐

