如何使用 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;没有匹配项时,原对象保持不变。
备注:内容仅供参考。
