如何使用jq或其他工具合并两个JSON文件的非null嵌套字段
问题原因
你之前执行的jq -s '.[0] + .[1]'输出结果不符合预期,本质上是合并逻辑完全不匹配需求:
- jq内置的
+操作符对对象做的是浅合并,只会扫描最外层的键,不会递归深入遍历所有嵌套层级 - 合并过程不会自动判断b.json里的值是不是null,只要b.json里存在同名键,不管值是啥(哪怕是null),都会直接覆盖a.json的原有值
- 碰到数组、嵌套对象类型的值时,会整体替换原有内容,根本没法实现“只拿b的非null值更新、嵌套结构逐层匹配”的要求。
能实现需求的执行命令
我们可以自定义一套递归合并的jq过滤逻辑,完全贴合你定的合并规则:
- 递归遍历所有嵌套层级的对象节点,逐层对比同路径的键值
- 当b.json对应节点的值为null时,直接保留a.json的原值不做修改
- 当两边对应节点都是普通对象时,继续深入每个子键做合并判断
- 当b.json对应节点的值是数组、字符串、数字等非对象、非null类型时,直接替换a.json的同路径值
完整命令如下:
jq -s ' def merge(new): if new == null then . elif (type == "object") and (new | type == "object") then with_entries( . as $entry | ($entry.value) as $old_val | ($new[.key]) as $new_val | .value = ($old_val | merge($new_val)) ) else new end; .[0] | merge(.[1]) ' a.json b.json
实际效果验证
基础测试场景(a.json + b.json)
跑出来的结果和你给出的预期完全一致:
- apple、orange、pear 字段因为b.json中对应值为null,完整保留a.json的原有值
- lemon数组、config21 字段因为b.json中对应值非null,直接替换为b.json里的内容
- config22 字段因为b.json中对应值为null,保留a.json的原有值
补充测试场景(aa.json + bb.json)
执行结果完全符合规则要求:
- countrylist、languageorderlist、audio_audio 字段因为b侧值非null,替换为b侧的新值
- video节点下的mp4、mkv 字段因为b侧值为null,保留aa.json里的原有值
内容的提问来源于stack exchange,提问作者newbie
相关产品推荐
相关产品推荐

