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

如何在jq中通过变量解析多级键并修改JSON对应值?

问题描述

我有如下JSON文件:

{
  "rec_9M":
    {
    "id":"000",
    "rec_E":
        [
          {
            "id":"111"
          } ,
          {
            "id":"222"
          }           
        ]
    }
}

我需要修改rec_9M.rec_E[].id的值,并且希望编写一个通用的bash函数,可用于修改不同层级路径(如rec_9M.id或rec_9M.rec_E[].files[].id)的JSON值。

我尝试了以下命令:

VAR=rec_9M.rec_E[]
NUM=555

echo $(cat config.json) | jq --arg VAR_I $VAR --arg NUM_I $NUM '.[$VAR_I].id = $NUM_I' > config_t.json
cat config_t.json 

预期输出:

{
  "rec_9M": {
    "id": "000",
    "rec_E": [
      {
        "id": "555"
      },
      {
        "id": "555"
      }
    ]
  }
}

实际输出:

{
  "rec_9M": {
    "id": "000",
    "rec_E": [
      {
        "id": "111"
      },
      {
        "id": "222"
      }
    ]
  },
  "rec_9M.rec_E[]": {
    "id": "555"
  }
}

硬编码键路径时命令可正常执行:

echo $(cat config.json) | jq --arg VAR_I $VAR --arg NUM_I $NUM '.rec_9M.rec_E[].id = $NUM_I' > config_t.json

尝试过VAR_I的各种引号和特殊符号组合(如"($VAR_I)"),结果要么和上述一致,要么出现jq解析错误,请问该如何解决?

解决方案

问题核心是jq无法将字符串形式的路径直接解析为层级访问表达式,.[$VAR_I]会把整个变量值当作单个键名,而非层级路径。以下是两种可行的通用解决方法:

方法1:使用jq内置setpath函数(推荐)

setpath函数支持通过数组形式的路径定位到目标字段,我们可以先将路径字符串转换为jq能识别的数组格式,再传入函数:

直接使用示例

# 把路径拆分为数组,数组索引用[]表示
VAR='["rec_9M", "rec_E", [], "id"]'
NUM=555

jq --argjson path "$VAR" --arg value "$NUM" 'setpath($path; $value)' config.json > config_t.json

封装为通用bash函数

如果需要自动处理类似rec_9M.rec_E[].id的路径字符串,可以加一层字符串转换逻辑,把路径转为数组格式:

# 定义通用修改函数:参数1=JSON文件路径,参数2=目标字段路径,参数3=新值
json_set() {
    local json_file=$1
    local path_str=$2
    local new_value=$3

    # 将路径字符串转换为jq的路径数组格式
    local path_arr=$(echo "$path_str" | sed -E '
        s/([^\.\[]+)(\[.*?\])?/\1\2/g;
        s/\./", "/g;
        s/\[]/","[]/g;
        s/^/["/;
        s/$/"]/
    ')
    
    # 执行修改并覆盖原文件(先写临时文件再替换,避免原文件损坏)
    jq --argjson path "$path_arr" --arg value "$new_value" 'setpath($path; $value)' "$json_file" > "${json_file}.tmp" && mv "${json_file}.tmp" "$json_file"
}

# 使用示例
json_set config.json "rec_9M.rec_E[].id" "555"
json_set config.json "rec_9M.id" "666"

方法2:动态生成jq表达式(快捷但有风险)

如果能确保路径字符串的安全性(无恶意内容),可以直接将路径拼接到jq表达式中:

VAR=rec_9M.rec_E[].id
NUM=555

jq --arg value "$NUM" ".$VAR = \$value" config.json > config_t.json

注意:此方法会直接执行路径对应的jq代码,若路径包含恶意内容可能导致不可预期的结果,仅适合可控场景。

内容的提问来源于stack exchange,提问作者kolt912

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:56:39