如何用jq实现符合类型匹配的新旧JSON配置合并?
实现带类型校验的配置合并jq方案
需求回顾
- 对比旧配置文件
old.conf与新配置文件new.conf - 若新配置中存在某元素,且该元素与旧配置中对应元素的类型完全匹配,则将旧配置中该元素的值复制到新配置
- 新配置中未受影响的元素(包括新独有的元素)保持原有状态
配置文件内容
old.conf
{ "ru_conf": { "network": { "interface": "eth1", "mac_address": "FF:FF:FF:FF:FF:FF", "setup": true, "interfaceы": ["eth0", "eth1"], "numbers": [1, 2, 3], "float": 1111.1111, "partitions": [ { "dev1": "/mnt/data/", "threshold": 20 } ] } } }
new.conf
{ "ru_conf": { "network": { "interface": "str", "mac_address": "str", "setup": false, "interfaceы": ["str1", "str2"], "numbers": [0, 0, 0], "int": 0, "partitions": [ { "dev1": "str", "threshold": 0 } ] } } }
问题分析
你之前的第一个命令存在两个关键问题:
- 文件顺序搞反了:
./new.conf ./old.conf传入后,.[0]是新配置,.[1]是旧配置,但你的逻辑里把.[1].ru_conf赋值为$new,导致覆盖方向错误 - 仅处理了标量(scalars)路径,没有处理嵌套对象/数组的递归匹配
第二个命令则缺少了类型校验和深层嵌套结构的处理能力。
解决方案:递归合并+类型校验
使用以下jq命令可以实现需求:
jq -s ' # 定义递归合并函数:仅当新配置存在该字段且类型匹配时,用旧值覆盖 def merge_with_type_check(old, new): new * (old | with_entries( select( new[.key] != null and (.value | type) == (new[.key] | type) ) | ( .value |= if . | type == "object" then merge_with_type_check(.; new[.key]) elif . | type == "array" then new[.key] # 数组直接保留新配置(若需按元素类型匹配可调整) else . end ) )); # 执行合并:以新配置为基础,合并旧配置中符合条件的字段 .[0] as $new | .[1] as $old | $new | .ru_conf = merge_with_type_check($old.ru_conf; $new.ru_conf) ' new.conf old.conf > merged-config.conf
命令逻辑说明
- 递归函数
merge_with_type_check:- 以新配置(
new)为基础,遍历旧配置(old)的所有键 - 仅保留新配置中存在、且类型与旧配置完全一致的键
- 如果值是对象,递归调用自身处理嵌套结构;如果是数组,直接保留新配置的值(若需要数组元素级的类型匹配,可修改此逻辑);标量则直接用旧值覆盖
- 以新配置(
- 主逻辑:
- 读取两个配置文件,
.[0]是新配置,.[1]是旧配置 - 对
ru_conf节点应用递归合并函数,最终输出合并后的配置
- 读取两个配置文件,
执行结果
生成的merged-config.conf内容如下,与预期一致:
{ "ru_conf": { "network": { "interface": "eth1", "mac_address": "FF:FF:FF:FF:FF:FF", "setup": true, "interfaceы": ["str1", "str2"], "numbers": [0, 0, 0], "int": 0, "partitions": [ { "dev1": "/mnt/data/", "threshold": 20 } ] } } }
结果说明
setup字段成功从旧配置的true覆盖新配置的false(类型均为boolean)- 新配置独有的
int字段保持原值0 - 旧配置独有的
float字段被忽略 - 嵌套对象
partitions内的字段也完成了类型匹配后的覆盖 - 数组
interfaceы和numbers保留新配置的结构(若需要数组元素类型匹配,可调整递归函数中数组的处理逻辑)
内容的提问来源于stack exchange,提问作者DSTV
相关产品推荐
相关产品推荐

