PAYATHON 2026

如何使用 jq 将一个 JSON 文件中的值合并到另一个 JSON 文件的新字段中?

技术老齐

用 --slurpfile 读取 ip.json,再用 with_entries 遍历 specs.json 中的条目,按主机名查找 IP,写入对应对象的 address 字段。

题目中的预期结果有一处笔误:ip.json 中 host3 的地址是 1.1.1.3,合并后也应为 1.1.1.3。

合并命令

在两个文件所在目录执行:

jq --slurpfile ip ip.json '
  with_entries(
    .key as $host
    | .value.address = $ip[0][$host]
  )
' specs.json > result.json

命令以 specs.json 为主输入,将结果保存到 result.json。这里假设两个文件都只包含一个顶层 JSON 对象,且 specs.json 中每个主机对应的值都是对象。

命令如何匹配主机名

--slurpfile ip ip.json 会读取文件中的 JSON 值,放入数组变量 $ip。示例文件只有一个 JSON 对象,所以用 $ip[0] 访问主机名与 IP 的映射。

with_entries(...) 会逐项处理对象,每一项都表示为包含 key 和 value 的对象。例如,host1 对应的条目是:

{
  "key": "host1",
  "value": {
    "cores": 2,
    "memory": 4
  }
}

过滤器先用 .key as $host 保存主机名,再用 $ip[0][$host] 查找地址,赋值给 .value.address。处理完成后,with_entries 将这些条目重新组成对象。

匹配依据是键名,两个文件中的主机排列顺序可以不同。

生成结果

result.json 的内容如下:

{
  "host1": {
    "cores": 2,
    "memory": 4,
    "address": "1.1.1.1"
  },
  "host2": {
    "cores": 4,
    "memory": 8,
    "address": "1.1.1.2"
  },
  "host3": {
    "cores": 2,
    "memory": 6,
    "address": "1.1.1.3"
  }
}

注意事项

  • 如果 specs.json 中的主机在 ip.json 中不存在,命令会将其 address 设为 null。
  • 如果主机已有 address 字段,查找结果会覆盖该字段,其他字段保留。
  • 只存在于 ip.json 的主机不会添加到结果中。
  • 不要直接使用 > specs.json 覆盖输入文件。Shell 会先清空重定向目标,再运行 jq,导致原始数据丢失。

如果希望在找不到主机名时保留原对象,可以先用 has 检查键是否存在:

jq --slurpfile ip ip.json '
  with_entries(
    .key as $host
    | if ($ip[0] | has($host)) then
        .value.address = $ip[0][$host]
      else
        .
      end
  )
' specs.json > result.json

这样,只有 ip.json 包含对应主机名时才会设置 address;没有匹配项时,原对象保持不变。

备注:内容仅供参考。