将一个JSON文件拆分成多个文件

14

我有一个大的JSON文件,它是一个对象中的对象,我想将其拆分为以对象键命名的单独文件。 是否可以使用jq或任何其他现成的工具实现此目的?

原始的JSON格式如下:

{ "item1": {...}, "item2": {...}, ...}

给定这个输入,我想生成文件item1.json、item2.json等。


你想将它转换为不同的文件或变量吗?有很多方法可以将其转换为不同的变量。 - Rajeshwar
1
我想将每个由其自己的键表示的对象转换为单独的文件。是否有使用jq或类似工具完成此操作的方法? - kissaprofeetta
你一次只能生成一个输出。只需编写一个脚本,获取所有项目名称,然后分叉出 jq 调用以将这些项目取出并保存到文件中。 - Jeff Mercado
3个回答

18

这应该能为你提供一个开始:

for f in `cat input.json | jq -r 'keys[]'` ; do
  cat input.json | jq ".$f" > $f.json
done

或者当你坚持更喜欢某些人偏爱的bashy语法时:

for f in $(jq -r 'keys[]') ; do
  jq ".[\"$f\"]" < input.json > "$f.json"
done < input.json

2
为了确保在任何键名存在的情况下都能正确运行,需要编写".["$f"]"而不是".$f"。 - peak
cat file | command 是反模式,反引号是另一种。 - RomanPerekhrest
jq --arg f "$f" '.[$f]' 将是一个进一步的改进,可以防止任意代码注入(尽管在 jq 获取 system() 调用、打开文件进行写操作或其他当前不支持的功能之前,这并不是一个很大的安全问题),因为它确保被替换的值只能被视为字面字符串。 - Charles Duffy
jq -n --argjson f "$f" '$f' 还可以保证良好的解析;如果您不使用管道,则 -n 很重要。 - Thiago Conrado

9
这里有一个只需要调用一次jq的解决方案:
```

这是一种只需一次调用jq的解决方案:

```
jq -cr 'keys[] as $k | "\($k)\n\(.[$k])"' input.json |
  while read -r key ; do
    read -r item
    printf "%s\n" "$item" > "/tmp/$key.json"
  done

可能会更快将 jq 命令的输出传输到 awk,例如:
jq -cr 'keys[] as $k | "\($k)\t\(.[$k])"' input.json |
  awk -F\\t '{ print $2 > "/tmp/" $1 ".json" }'

当然,如果关键字包含不能用于文件名的字符,则需要修改这些方法。

1

使用jq或其他现成工具,是否可以实现这一点?

是的。 也可以非常高效地完成此任务。

假设'input.json'

{
  "item1": {
    "a": 1
  },
  "item2": {
    "b": 2
  },
  "item3": {
    "c": 3
  }
}

低效的Bash方法:

for f in $(xidel -s input.json -e '$json()'); do
  xidel -s input.json -e '$json("'$f'")' > $f.json
done

对于每个对象键,都会调用另一个xidel实例来解析该对象。特别是当您有一个非常大的JSON时,这会相当缓慢。
高效的file:write()方法:
xidel -s input.json -e '
  $json() ! file:write(
    .||".json",
    $json(.),
    {"method":"json"}
  )
'

xidel 调用会创建 'item{1,2,3}.json',它们的内容是紧凑/缩小的对象,例如{"a": 1}'item1.json' 的内容。

xidel -s input.json -e '
  for $x in $json() return
  file:write(
    concat($x,".json"),
    $json($x),
    {
      "method":"json",
      "indent":true()
    }
  )
'

一个 xidel 调用会创建 'item{1,2,3}.json'。它们的内容是一个漂亮格式化的对象(因为有 {"indent":true()}),如下所示...

{
  "a": 1
}

...对于'item1.json'。不同的查询(for循环),相同的结果。

这种方法速度快得多!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接