You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash/JQ脚本问题:无法替换JSON命令中的变量为实际值

问题解决:JSON命令中的变量未被替换

问题描述

编写脚本时,从JSON文件提取play_music命令,该命令包含device_directory、music_file、audio_type等变量。脚本已成功读取这些变量的实际值,但提取出的命令中的变量未被替换为对应值,输出仍为原始模板字符串。

data.json片段

"play_music": {
            "name": "play_music",
            "command" : "adb shell am start -a android.intent.action.VIEW -d file:///${device_directory}${music_file} -t audio/${audio_type}",
            "variables" : {
                "device_directory" : {
                    "name" : "device_directory",
                    "variable" : "/Downloads/"
                },
                "music_file" : {
                    "name" : "music_file",
                    "variable" : "test.mp3"
                },
                "audio_type" : {
                    "name" : "audio_type",
                    "variable" : "mp3"
                }
            }

脚本片段

while true; do
    variables=( $(jq -r ".commands.$option.variables | map(.name) | .[]" data.json))
    ##echo ${variables[@]}
    
    for i in ${variables[@]}; do
        ##echo -e "\n$i"
        var=$(jq -r ".commands.$option.variables.$i.variable" data.json)
        if [[ -z $var ]]; then
            ##echo -e "var is empty"
            echo -e "Enter $i: "
            read $i
        else
            ##echo -e "var is full"
            declare $i=$var
        fi
    done

echo -e "\nmusic file='${music_file}'"
echo -e "\naudio type='${audio_type}'"
echo ""

command="$(jq -r ".commands.$option.command" data.json)"
echo $command

当前变量已正确读取:

music file='test.mp3'

audio type='mp3'

但输出的命令仍为:
adb shell am start -a android.intent.action.VIEW -d file:///${device_directory}${music_file} -t audio/${audio_type}

期望输出:
adb shell am start -a android.intent.action.VIEW -d file:////Downloads/test.mp3 -t audio/mp3

解决方案

核心原因是直接从JSON读取的命令字符串是静态文本,Bash不会自动解析其中的变量。以下是三种可行的解决方法:

方法一:使用eval执行变量替换

修改读取命令的代码行,让Bash解析命令字符串中的变量:

command=$(eval echo "$(jq -r ".commands.$option.command" data.json)")

说明:先通过jq获取原始命令模板,再用eval echo触发Bash的变量替换逻辑,将模板中的变量替换为实际值。

方法二:使用envsubst工具(更安全)

如果系统安装了envsubst(通常属于gettext包),可以用它来替换环境变量。首先需要将脚本中定义的shell变量导出为环境变量:

# 在循环中定义变量时,改用export或declare -x
for i in ${variables[@]}; do
    var=$(jq -r ".commands.$option.variables.$i.variable" data.json)
    if [[ -z $var ]]; then
        echo -e "Enter $i: "
        read $i
    else
        export $i=$var # 导出为环境变量
    fi
done

然后读取并替换命令:

command=$(jq -r ".commands.$option.command" data.json | envsubst)

说明:envsubst会自动识别并替换字符串中的环境变量,避免了eval带来的安全风险。

方法三:手动遍历变量替换

通过Bash的参数替换功能,逐个替换模板中的变量:

command=$(jq -r ".commands.$option.command" data.json)
# 遍历所有变量,替换模板中的${变量名}
for i in "${variables[@]}"; do
    command=${command//\$\{$i\}/${!i}}
done

说明:${command//\$\{$i\}/${!i}}是Bash的全局替换语法,${!i}是间接引用,获取变量i对应的实际值。

执行任意一种方法后,输出的command都会替换为期望的结果。

内容的提问来源于stack exchange,提问作者Siân

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:05:35