【问题标题】:How to merge thousands of json documents in Bash?如何在 Bash 中合并数千个 json 文档?
【发布时间】:2016-03-15 08:33:49
【问题描述】:

我通过连接到某些 API 的脚本创建了超过 500 000 个 JSON 文档。我想将这些文件导入RethinkDB,但RethinkDB似乎无法大量导入文件,所以我考虑将所有这些文件合并成一个大的JSON文件(比如bigf​​ile.json)。这是它们的结构:

文件 1.json:

{
  "key_1": "value_1.1",
  "key_2": "value_1.2",
  "key_3": "value_1.3",
    ...
  "key_n": "value_1.n"
}

文件 2.json:

{
  "key_1": "value_2.1",
  "key_2": "value_2.2",
  "key_3": "value_2.3",
    ...
  "key_n": "value_2.n"
}
...

文件 n.json:

{
  "key_1": "value_n.1",
  "key_2": "value_n.2",
  "key_3": "value_n.3",
    ...
  "key_n": "value_n.n"
}

我想知道哪个是创建大 JSON 文件的最佳结构(完整地说,每个文件都有一个由 3 个变量组成的特定名称,第一个是时间戳 (YYYYMMDDHHMMSS)),以及哪个命令或脚本(直到现在我只为 bash 编写脚本......)可以让我产生合并。

【问题讨论】:

  • 输出文件应该是什么样子?文件名与它有什么关系 - 为什么这很重要?它出现在文件中还是应该出现在文件中?
  • 输出将是一个大的 json 文件。我想到了一些看起来像 {"bigfile":[file_1,file_2,...,file_n]} 的东西,但我不知道它是否是大文件的最佳结构(输出将超过 1 giga)。文件名没有出现在文件中,但我想也许我应该让它们出现在大文件中,因为它们部分描述了输入文件。
  • 你帮不上什么忙。 yes > file.json 生成一个很大的 JSON 文件。
  • 好的,抱歉,我编辑了帖子。我认为这很清楚,因为 Rethink 只处理 JSON,并且我想知道“创建大型 JSON 文件的最佳结构”
  • 你看rethinkdb import了吗? rethinkdb.com/docs/importing

标签: json bash rethinkdb bigdata


【解决方案1】:

你提到了 bash,所以我假设你使用 *nix,你可以使用 echocatsed 来实现你想要的。

$ ls   
file1.json  file2.json  merge_files.sh  output
$ cat file1.json 
{
    "key_1": "value_1.1",
    "key_2": "value_1.2",
    "key_3": "value_1.3",
    "key_n": "value_1.n"
}
$ ./merge_files.sh
$ cat output/out.json
{
"file1":
{
  "key_1": "value_1.1",
  "key_2": "value_1.2",
  "key_3": "value_1.3",
  "key_n": "value_1.n"
},
"file2":
{
  "key_1": "value_2.1",
  "key_2": "value_2.2",
  "key_3": "value_2.3",
  "key_n": "value_2.n"
}
}

下面的脚本读取一个文件夹中的所有 json 文件,并将它们连接成一个以文件名为键的“大”文件。

#!/bin/bash

# create the output directory (if it does not exist)
mkdir -p output
# remove result from previous runs
rm output/*.json
# add first opening bracked
echo { >> output/tmp.json
# use all json files in current folder
for i in *.json
do 
    # first create the key; it is the filename without the extension
    echo \"$i\": | sed 's/\.json//' >> output/tmp.json
    # dump the file's content
    cat "$i" >> output/tmp.json
    # add a comma afterwards
    echo , >>  output/tmp.json
done
# remove the last comma from the file; otherwise it's not valid json
cat output/tmp.json | sed '$ s/.$//' >> output/out.json
# remove tempfile
rm output/tmp.json
# add closing bracket
echo } >> output/out.json

【讨论】:

  • for i in *.json 会更好。另外,你应该双引号 $i 所以它看起来像这样 cat "$i" >> ...
  • 哇!太感谢了。不仅效果很好,而且由于您的教学技巧,我理解了一切。有史以来最好的答案!只是一个问题, sed '$ s/.$//' 中的“.$”到底是什么(如果没有提到逗号,它如何删除逗号,是否删除最后一个字符串?)?
  • @crocefisso,几乎正确。它是一个正则表达式,用于删除输入的最后一行的最后一个字符。看看here
  • 很好,谢谢!
【解决方案2】:

可以在 linux 上使用单个命令行来完成。从所有 json 文件所在的目录中,创建一个新目录(比如“输出”),然后启动

jsonlint -v -f *.json > output/bigfile.json

jsonlint source

Jsonlint manual for ubuntu

【讨论】:

  • 请补充说明,并说明jsonlint的获取途径,以及支持的平台。
  • 希望它适用于数千个文件,但我想在我的情况下它不适用于 100k 到数百万个文件。 argument list too long: jsonlint
【解决方案3】:

如果您需要将一堆 JSON 文件作为单个对象读入内存,其中文件名作为键,内容作为对应值,请考虑使用 jq

jq -n '[inputs|{(input_filename):.}]|add' FILE...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多