如何用jq高效将文件夹组织的JSON文件合并为带路径键的单一JSON文件
使用jq遍历文件夹树合并JSON文件的方案
问题描述
我有一个存储着从数据集转换而来的各类JSON文件的文件夹树,结构示例如下:
/(top folder) |-- folder1/ | |- file1.json {"a":1,"b":[1,2]} | |- file2.json {"a":12,"c":[]} |-- folder2/ |- file1.json {"ta":1,"tb":[1,2]} |- file2.json {"ta":12,"tc":1} |- folder21/ |- file3.json {"test":true}
期望合并成单一JSON文件,结构如下:
{ "folder1": { "file1.json": {"a":1,"b":[1,2]}, "file2.json": {"a":12,"c":[]} }, "folder2": { "file1.json": {"ta":1,"tb":[1,2]}, "file2.json": {"ta":12,"tc":1}, "folder21" : { "file3.json": {"test":true} } } }
我已通过Python/Perl的显式循环实现该需求,也在Octave/MATLAB中完成了功能,但MATLAB版本运行速度较慢。想确认jq是否支持遍历子文件夹并完成合并,若可行,希望得到相关示例或指引。
解决方案
jq本身没有原生的文件夹遍历能力,但可以结合shell的find命令实现高效的遍历与合并,整体性能会优于Octave/MATLAB的实现。
核心逻辑
- 用
find遍历目标文件夹下所有.json文件,获取每个文件的相对路径和内容 - 借助jq将文件路径拆解为层级结构,把JSON内容挂载到对应路径的键下
- 通过jq的
reduce表达式合并所有局部结构,最终生成完整的嵌套JSON对象
基础实现命令
假设你的顶层文件夹为./top-folder,在终端执行以下命令:
find ./top-folder -type f -name "*.json" -exec jq -n --arg path {} --argjson content "$(cat {})" ' [$path | split("/") | .[1:]] as $parts | reduce $parts[] as $part ({}; if $part | endswith(".json") then .[$part] = $content else .[$part] //= {} end ) ' \; | jq -s 'reduce .[] as $item ({}; reduce paths($item) as $path (.; setpath($path; getpath($path) // $item|getpath($path)) ) )' > merged.json
大文件优化版本
如果处理的JSON文件较大,上述命令中$(cat {})会带来额外的shell子进程开销,可改用让jq直接读取文件内容的方式,提升效率:
find ./top-folder -type f -name "*.json" -exec jq -n --arg path {} ' [$path | split("/") | .[1:]] as $parts | reduce $parts[] as $part ({}; if $part | endswith(".json") then .[$part] = input else .[$part] //= {} end ) ' {} \; | jq -s 'reduce .[] as $item ({}; reduce paths($item) as $path (.; setpath($path; getpath($path) // $item|getpath($path)) ) )' > merged.json
命令拆解
find部分:遍历指定文件夹下所有.json文件,对每个文件触发一次jq处理- 第一个jq调用:将文件的相对路径拆分为层级数组,构建该文件对应的局部嵌套结构(例如
folder1/file1.json会生成{"folder1": {"file1.json": {...}}}) - 第二个jq调用:将所有局部结构合并为一个完整的JSON对象,最终输出到
merged.json文件中
内容的提问来源于stack exchange,提问作者FangQ
相关产品推荐
相关产品推荐

