如何将文件夹组织的.json文件合并为一个以文件夹/文件名为键的 JSON 文件

how to merge folder-organized .json file into a single JSON file with folder/file names as keys

提问人:FangQ 提问时间:11/18/2023 最后编辑:FangQ 更新时间:11/18/2023 访问量:62

问:

我有一个文件夹树,用于存储从数据集转换的各种.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}

我希望将此文件夹合并为

{
   "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 来完成,方法是通过 1) 解析 json 文件,2) 使用文件/文件夹名称作为键将解析的数据与本机数据结构/对象合并,以及 3) 将合并的数据结构保存到单个 JSON 文件中。我已经为 Octave/MATLAB 实现了一个,它可以工作,但它有点慢。

我想知道是否可以使用 jq 有效地做到这一点。

我看到可以使用表达式在同一文件夹中合并 json 文件,请参阅 https://stackoverflow.com/a/59769797/4271392reduce

我想知道 jq 是否允许扫描和迭代子文件夹并合并每个文件夹。

如果可能的话,如果有人能给我指出相关的示例或文档,我将不胜感激。

json shell 命令行界面 jq

评论

0赞 Inian 11/18/2023
是否应该在 JSON 输出中保留目录的顺序?
0赞 Inian 11/18/2023
另外,您是否希望有多个深度级别,或者问题中显示的深度级别是最大允许级别?
0赞 FangQ 11/18/2023
@Inian,保留订单是首选,但如果这会增加大量开销,则不是必须的。另外,对于您的第二个问题 - 最高级别尚未确定,但我使用的特定数据文件夹通常少于 5 个级别。
0赞 FangQ 11/18/2023
如果我愿意将 bash 与 jq 结合起来,有没有办法遍历文件夹级别并合并?

答:

4赞 Philippe 11/18/2023 #1

正如您在评论区中提到的,您可以尝试调用 jq 的脚本:bash

#!/bin/bash

shopt -s globstar
jq -n 'reduce inputs as $s ({}; setpath(input_filename|split("/");$s) )' */**/*.json

我的测试输出:

{
  "folder1": {
    "file1.json": {
      "a": 1,
      "b": [
        1,
        2
      ]
    }
  },
  "folder2": {
    "folder21": {
      "file3.json": {
        "test": true
      }
    }
  }
}

评论

2赞 Inian 11/18/2023
很好的使用setpath()
0赞 FangQ 11/18/2023
上面的脚本就像魔术一样工作!非常感谢!(请忽略我之前的帖子 - 脚本确实在输出中包含文件夹名称)
0赞 FangQ 11/18/2023
只是一个快速的后续问题:在我的每个文件转换过程中,如果我有一些 JSON 文件使用不同的后缀,例如 or,并且我想使用原始文件名而不是用作键,我应该在哪里添加您的示例脚本来执行此操作?a.gz.jbidsb.tsv.jsona.gza.gz.jbidsrtrimstr()
1赞 Philippe 11/18/2023
split("/")生成一个数组,如 ,你可以处理它。["folder2","folder21","a.gz.jbids"]
0赞 FangQ 11/19/2023
谢谢@Philippe,做到了。input_filename|sub(".tsv.json";".tsv")|sub(".jbids";"")|split("/")