【问题标题】:How to create 2 CSV files from 1 JSON using JQ如何使用 JQ 从 1 个 JSON 创建 2 个 CSV 文件
【发布时间】:2018-05-23 22:19:00
【问题描述】:

我有很多相当大的 JSON 日志需要导入到多个数据库表中。 我可以轻松解析它们并创建 1 个 CSV 用于导入。 但是如何解析 JSON 并获得 2 个不同的 CSV 文件作为输出? 简单(废话)示例:

testJQ.log

{"id":1234,"type":"A","group":"games"}
{"id":5678,"type":"B","group":"cars"}

使用

cat testJQ.log|jq --raw-output '[.id,.type,.group]|@csv'>testJQ.csv

我得到一个文件 testJQ.csv

1234,"A","games
5678,"B","cars"

但我想得到这个

types.csv

1234,"A"
5678,"B"

groups.csv

1234,"games"
5678,"cars"

这可以在不必两次解析 JSON 的情况下完成吗?第一次创建 types.csv,第二次创建 groups.csv 像这样?

cat testJQ.log|jq --raw-output '[.id,.type]|@csv'>types.csv
cat testJQ.log|jq --raw-output '[.id,.group]|@csv'>groups.csv

【问题讨论】:

  • jq 不会输出到文件,因此您将无法这样做。如果你想写入不同的文件,你总是需要一个单独的实例。

标签: json csv jq


【解决方案1】:

我想你可以解决这个问题的一种方法是将一个文件的内容输出到 stdout,将其他文件的内容输出到 stderr 并重定向到单独的文件。当然,您只能使用两个文件。

$ <testJQ.log jq -r '([.id,.type]|@csv),([.id,.group]|@csv|stderr|empty)' \
    1>types.csv 2>groups.csv

stderr 输出到 stderr 但值会传播到输出,因此您需要使用empty 跟进以吞下它。

我个人不建议这样做,如果您需要输出到多个文件,我只会编写一个 python 脚本(或其他语言)来解析它。

【讨论】:

  • 目前无法在 stderr 上产生“原始输出”,因此在这种特殊情况下,(stderr|empty) 技术不会在 groups.csv 中产生所需的结果。
  • 嗯,是的,对于这种特殊情况,原始输出不起作用。但如果我们不需要原始输出(或其他不影响标准错误的输出选项),​​这可能是一个可行的选择。但是,根据 shell,我们可以重定向到一个进程,该进程可以将值作为原始输出传递。喜欢 bash:... 2&gt; &gt;(jq -r . &gt; groups.csv)
  • 是的,这是一种潜在有用的技术,尽管 jq 没有理由不做得更好。
  • 有趣; stderr 似乎在 1.5(如果不是更早版本)中受支持,但没有记录。
【解决方案2】:

您将需要运行 jq 两次,或者将 jq 与另一个程序一起运行以“拆分”对 jq 的调用的输出。例如,您可以使用以下形式的管道:jq -c ... | awk ...

管道方法的潜在缺点是如果 JSON 是最终输出,它将是 JSONL;但显然这不适用于这里。

有很多方法可以制作这样的管道。例如,假设 CSV 中没有原始换行符:

< testJQ.log jq -r '
    "types",  ([.id,.type] |@csv),
    "groups", ([.id,.group]|@csv)' |
  awk 'NR % 2 == 1 {out=$1; next} {print >> out".csv"}'

或者:

< testJQ.log jq -r '([.id,.type],[.id,.group])|@csv' |
    awk '{ out = ((NR % 2) == 1) ? "types" : "groups"; print >> out".csv"}'

有关其他示例,请参见例如

处理原始换行

无论您是否将 CSV 拆分为多个文件,都存在嵌入原始换行符的潜在问题。一种方法是将 JSON 字符串中的“\n”更改为“\\n”,例如

jq -r '([.id,.type],[.id,.group])
       | map(if type == "string" then gsub("\n";"\\n") else . end)
       | @csv'

【讨论】:

  • 听起来很有趣,但对于生产使用来说有点冒险。如果 JQ 可以生成格式为 --types-- 1234,"A" 5678,"B" --groups-- 1234,"games" 5678,"cars" 而不是 "--types-- " 1234,"A" "--groups--" 1234,"games" "--types--" 5678,"B" "--groups--" 5678,"cars" 作为(["--types--"],[.id,.type],["--groups--"],[.id,.group])|@csv 的结果将使生成的 csv 的拆分更加安全和快捷。我想我不得不忍受多次解析同一个日志。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-10
  • 2023-03-26
  • 2017-01-14
  • 2013-11-01
  • 2016-07-18
  • 2021-04-11
相关资源
最近更新 更多