用 jq 修改嵌套 JSON

Modify Nested JSON with jq

我正在尝试使用 bash/shell 脚本中的 jq <map> 函数修改嵌​​套的 JSON 对象;与 this blog entry 类似,但试图将此处的示例调整为嵌套对象。

返回的JSON修改如下:

{
  "name": "vendor-module",
  "dependencies": {
    "abc": {
      "from": "abc@2.4.0",
      "resolved": "https://some.special.url",
      "version": "2.4.0"
    },
    "acme": {
      "from": "acme@1.2.3",
      "resolved": "<CHANGE_THIS>",
      "version": "1.2.3"
    }
  }
}

这将是我的尝试:

modules="`node -pe 'JSON.parse(process.argv[1]).dependencies.$dependency' \
  "$(cat $wrapped)"`"
version="1.2.3"
resolved="some_url"

cat OLD.json | 
  jq 'to_entries | 
       map(if .dependencies[0].$module[0].from == "$module@$version"
          then . + {"resolved"}={"$resolved"}
          else . 
          end
         ) | 
      from_entries' > NEW.json

显然这行不通。当我 运行 脚本 NEW.json 被创建但没有修改或返回错误。如果我不以嵌套对象为目标(例如,"name": "vendor-module"),脚本会按预期工作。我确定有一种方法可以使用本机 bash 和 jq..??任何帮助(通过适当的转义)将不胜感激。

更新:

感谢 的帮助,以及他使用 sponge 的建议,对我来说效果很好的解决方案是:

jq --arg mod "acme" --arg resolved "Some URL" \
   '.dependencies[$mod].resolved |= $resolved' \
   OLD.json | sponge OLD.json

对于您现有的示例数据,以下内容就足够了:

jq --arg mod "acme" \
   --arg resolved "some_url" \
  '.dependencies[$mod].resolved=$resolved' \
  <in.json >out.json

...过滤 from,相比之下:

jq --arg new_url "http://new.url/" \
   --arg target "acme@1.2.3" \
  '.dependencies=(.dependencies
                  | to_entries
                  | map(if(.value.from == $target)
                        then .value.resolved=$new_url
                        else . end)
                  | from_entries)' \
  <in.json >out.json

如果您知道要更新的依赖项的名称,您可以直接对其进行索引。

$ jq --arg dep "$dep" --arg resolved "$resolved" \
    '.dependencies[$dep].resolved = $resolved' \
    OLD.json > NEW.json

否则,要根据名称(或其他属性)修改依赖项,搜索依赖项并更新。

$ jq --arg version "$version" --arg resolved "$resolved" \
    '(.dependencies[] | select(.version == $version)).resolved = $resolved' \
    OLD.json > NEW.json