如何使用jq递归合并Bash JSON字符串与JSON文件?
解决JSON递归合并问题
问题分析
你之前的命令存在两个核心问题:
- Shell分词错误:
$(echo $default)会把JSON中的空格、换行作为分隔符,将完整JSON拆成多个片段传给jq,jq会把这些片段当成文件名,导致读取失败。 - 浅合并不满足需求:jq的
*操作符是浅合并,会直接用override的顶层键值对替换default的对应项,不会递归合并嵌套对象(比如horses下的子键)。
正确解决方案
方法一:使用jq内置deepmerge函数(jq 1.6及以上版本推荐)
jq 1.6及以上内置了deepmerge函数,可直接实现递归合并,同时通过--argjson正确传递Bash变量:
jq --argjson default "$default" '$default | deepmerge(input)' override.json
或者通过标准输入传递default变量:
echo "$default" | jq -n 'input | deepmerge(input)' - override.json
其中-代表从标准输入读取第一个JSON(即default的内容),override.json是第二个输入源。
方法二:自定义递归合并函数(兼容旧版本jq)
如果你的jq版本低于1.6,可以自定义递归合并函数实现需求:
jq --argjson default "$default" ' def deepmerge(a; b): reduce b[] as $item (a; reduce ($item | keys_unsorted[]) as $key (.; if ($item[$key] | type) == "object" and (.[$key] | type) == "object" then .[$key] = deepmerge(.[$key]; $item[$key]) else .[$key] = $item[$key] end ) ); deepmerge($default; input)' override.json
结果验证
执行上述命令后,会得到你期望的递归合并结果:
{ "horses": { "count": 1, "fizz": "buzz", "foo": "bar" }, "admin": { "enabled": true } }
内容的提问来源于stack exchange,提问作者blueski
相关产品推荐
相关产品推荐

