【问题标题】:How do I extract a JSON list into a CSV in command line using JQ?如何使用 JQ 在命令行中将 JSON 列表提取到 CSV 中?
【发布时间】:2020-11-06 08:47:36
【问题描述】:

我有以下 JSON 数据:

% cat test2 

{"day":"2020-07-15","map":
{"a":"ask","b":"bid","t":"timestamp"},"msLatency":52,"pair":"EUR/USD","status":"success","ticks":[
{"b":1.14105,"a":1.14106,"x":48,"t":1594771200000},
{"b":1.14105,"a":1.14106,"x":48,"t":1594771201000},
{"b":1.14103,"a":1.14104,"x":48,"t":1594771202000},
{"b":1.141,"a":1.1413,"x":48,"t":1594771203000},
{"b":1.14103,"a":1.14104,"x":48,"t":1594771205000},
{"b":1.14094,"a":1.14095,"x":48,"t":1594778803000}],"type":"forex"}

我想得到:

1.14105,1.14106,1594771200000
1.14105,1.14106,1594771201000
1.14103,1.14104,1594771202000
1.141,1.1413,1594771203000
1.14103,1.14104,1594771205000
1.14094,1.14095,1594778803000

理想情况下,输出也应该用零填充,1 和 5 是参数,以指定前两列是具有 1 个自然位和 5 个小数位的数字(尽管此步骤可以使用 awk 轻松完成):

1.14105,1.14106,1594771200000
1.14105,1.14106,1594771201000
1.14103,1.14104,1594771202000
1.14100,1.14130,1594771203000
1.14103,1.14104,1594771205000
1.14094,1.14095,1594778803000

我用 JQ 试过这个:

 % cat test2 | jq '.ticks'
[
  {
    "b": 1.14105,
    "a": 1.14106,
    "x": 48,
    "t": 1594771200000
  },
  {
    "b": 1.14105,
    "a": 1.14106,
    "x": 48,
    "t": 1594771201000
  },
  {
    "b": 1.14103,
    "a": 1.14104,
    "x": 48,
    "t": 1594771202000
  },
  {
    "b": 1.141,
    "a": 1.1413,
    "x": 48,
    "t": 1594771203000
  },
  {
    "b": 1.14103,
    "a": 1.14104,
    "x": 48,
    "t": 1594771205000
  },
  {
    "b": 1.14094,
    "a": 1.14095,
    "x": 48,
    "t": 1594778803000
  }
]

但我不知道如何将其转换为 CSV。

编辑: 作为参考,我之前有以下解析,这里使用 JQ 是更简单的选择:

cat test2 |
sed -e 's/{\"/#{\"/g' |
tr '#' '\n' |
grep -v "timestamp" |
grep -v "day" |
sed '/^[[:space:]]*$/d' |
sed 's/].*$//g' |
sed 's/{//g' |
sed 's/},//g' |
sed 's/}//g' |
sed 's/\"//g' |
awk -F '[:,]' -v decimal_places=5 -v integer_places=1 '{
        for(i=1; i<=NF; i=i+2) {
                value[$i]=$(i+1);
        };
        format_price="%0" integer_places "." decimal_places "f"
        format=format_price " " format_price " %d\n"
        printf(format,value["b"],value["a"],value["t"]);
}'

【问题讨论】:

  • 我知道我以前做过这件事,而且用jq 做起来非常困难。老实说,我会忘记使用jq 来完成这项任务并使用python(或几乎任何其他语言)。只需将 JSON 解组为 dict,然后挑选出您想要的元素并打印它们。这会容易得多。
  • 感谢您的建议,让我们看看是否有其他关于如何使用 JQ 执行此操作的意见或示例。作为参考,管道sedawk 相对容易,因为您通过小步骤构建解析。然而,在询问awk 中的最后一步时,有人建议我 JQ 也可能对这种情况有所帮助。 stackoverflow.com/questions/62925668/…

标签: json export-to-csv precision jq


【解决方案1】:

这里有一个解决方案:

jq -r '.ticks[] | [.b, .a, .t] | join(",")' test2

1.14105,1.14106,1594771200000
1.14105,1.14106,1594771201000
1.14103,1.14104,1594771202000
1.141,1.1413,1594771203000
1.14103,1.14104,1594771205000
1.14094,1.14095,1594778803000

它不会填充到 5 位数字。我不知道如何在jq 中做到这一点。我仍然认为另一种语言会更容易。

【讨论】:

  • 它看起来是一个简单的解决方案(可能一旦您知道如何链接 jq 中的不同步骤)。非常感谢,我认为这对解析这类 JSON 文件很有用。
【解决方案2】:

这是该问题的惯用 jq-only 解决方案,被理解为要求小数点右侧的位数(如果存在)与指定的位数相同。应该使用 -r 命令行选项。

# format numbers whose tostring representation has a decimal point
# so that the number of digits to the right of the decimal point is $dd
# assuming $dd >= 0
def format($dd):
  def rpad: (. + $dd * "0") | .[:$dd];
  tostring
  | index(".") as $dec
  | if $dec then .[0:$dec+1] + (.[$dec+1:]|rpad)
    else .
    end ;

.ticks[]
| [(.b | format(1)), (.a | format(5)), .t ]
| join(",")

【讨论】:

    【解决方案3】:

    您可以很好地为此编写自己的填充函数。首先提取小数位后的位数,并据此决定填充位数。

    您可以编写一个脚本,将其命名为script.jq,然后执行以下操作。请注意,以下逻辑不适用于科学计数法数字。

    #!/usr/bin/jq -f
    
    def pad($len): 
      tostring | 
      match("^([0-9]*).([0-9]+)$").captures[1].length as $dec |
      ($len - $dec) as $l  |
      . + ("0" * ($l)) [:$l];
    
    .ticks[] | [ (.b|pad(5)), (.a|pad(5)), .t ] | join(",")
    

    并使用jq 可执行文件调用它

    jq -r -f script.jq json
    

    现在产生一个正确填充的输出

    1.14105,1.14106,1594771200000
    1.14105,1.14106,1594771201000
    1.14103,1.14104,1594771202000
    1.14100,1.14130,1594771203000
    1.14103,1.14104,1594771205000
    1.14094,1.14095,1594778803000
    

    注意:pad($len) 的灵感来自 pkoppstein's comment 来自 stedolan/jq - pad function #2033

    【讨论】:

    • 感谢 Inian 的示例,我发现使用 awk 完成这项任务要容易得多,因为它使用 printf(请参阅已编辑的问题)。我终于将 jq 与 awk 结合起来以提供所需的结果。
    猜你喜欢
    • 2022-12-04
    • 2021-11-29
    • 2019-04-12
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多