【问题标题】:Struggling with parsing JSON with jq努力用 jq 解析 JSON
【发布时间】:2017-05-17 16:07:24
【问题描述】:

我已经阅读了所有与它相关的帖子,我玩了几个小时,但仍然无法掌握这个工具,如果我只是找到一个似乎正是我所需要的让它按照我的需要工作的方法...... 所以这是我的 JSON 示例:

{
    "res": "0",
    "main": {
        "All": [
      {
        "field1": "a",
        "field2": "aa",
        "field3": "aaa",
        "field4": "0",
        "active": "true",
        "id": "1"
      },
      {
        "field1": "b",
        "field2": "bb",
        "field3": "bbb",
        "field4": "0",
        "active": "false",
        "id": "2"
      },
      {
        "field1": "c",
        "field2": "cc",
        "field3": "ccc",
        "field4": "0",
        "active": "true",
        "id": "3"
      },
      {
        "field1": "d",
        "field2": "dd",
        "field3": "ddd",
        "field4": "0",
        "active": "true",
        "id": "4"
      }
        ]
    }

}

我想有选择地提取一些字段并得到这样的 csv 输出:

field1,field2,field3,id
a,aa,aaa,1
b,bb,bbb,2
c,cc,ccc,3
d,dd,ddd,4

请注意我跳过了一些字段,而且我对父数组等也不感兴趣。 提前非常感谢。

【问题讨论】:

  • 你尝试了什么命令?

标签: json bash parsing jq


【解决方案1】:

首先您的JSON 需要按以下方式修复:

{
  "main": {

  },
  "table": {
    "All": [
      {
        "field1": "a",
        "field2": "aa",
        "field3": "aaa",
        "field4": "0",
        "active": "true",
        "id": "1"
      },
      {
        "field1": "b",
        "field2": "bb",
        "field3": "bbb",
        "field4": "0",
        "active": "false",
        "id": "2"
      },
      {
        "field1": "c",
        "field2": "cc",
        "field3": "ccc",
        "field4": "0",
        "active": "true",
        "id": "3"
      },
      {
        "field1": "d",
        "field2": "dd",
        "field3": "ddd",
        "field4": "0",
        "active": "true",
        "id": "4"
      }

    ]
  },
  "res": "0"
}

第二次使用 jq 您可以执行以下操作以使用 column 生成表格输出:

{ echo Field1 Field2 Field3 ID ; cat data.json  | jq -r '.table.All[] | (.field1, .field2, .field3, .id)' | xargs -L4 } | column -t

输出:

Field1  Field2  Field3  ID
a       aa      aaa     1
b       bb      bbb     2
c       cc      ccc     3
d       dd      ddd     4

使用 sed

echo "field1,field2,field3,id" ;cat data.json  | jq -r '.table.All[] | (.field1, .field2, .field3, .id)' | xargs -L4 | sed 's/ /,/g'

输出:

field1,field2,field3,id
a,aa,aaa,1
b,bb,bbb,2
c,cc,ccc,3
d,dd,ddd,4

更新:

在不使用 sedxargs 的情况下,jq 能够将输出格式化为 csv,如下所示:

cat data.json  | jq -r '.table.All[] | [.field1, .field2, .field3, .id] | @csv'

输出:

"a","aa","aaa","1"
"b","bb","bbb","2"
"c","cc","ccc","3"
"d","dd","ddd","4"

感谢chepner,正如他在 cmets 中提到的,可以直接使用 jq 添加标题,如下所示:

jq -r '(([["field1", "field2", "field3", "id"]]) + [(.table.All[] | [.field1,.field2,.field3,.id])])[]|@csv' data.json 

输出:

"field1","field2","field3","id"
"a","aa","aaa","1"
"b","bb","bbb","2"
"c","cc","ccc","3"
"d","dd","ddd","4"

根据您在问题中提供的最后一个 JSON 数据,此命令应该可以正常工作:

jq -r '(([["field1", "field2", "field3", "id"]]) + [(.main.All[] | [.field1,.field2,.field3,.id])])[]|@csv' data.json

([["field1", "field2", "field3", "id"]]) : 命令的第一部分用于 csv 标头

(.main.All[] | [.field1,.field2,.field3,.id])]) :因为main 是 您的 JSON 的父级,然后您可以使用 .main 选择它,这将 打印数组All 然后打印这个数组的内容你 必须将[] 添加到该数组的名称中,完整的命令将 是.main.All[],它将打印多个字典,我们可以 通过将.main.All[] 的输出传送到 另一个带有我们想要的键的数组 [.field1,.field2,.field3,.id]

【讨论】:

  • 您还可以从jq 过滤器中添加标题行(尽管我认为这比需要的更复杂):jq -r '(([["field1", "field2", "field3", "id"]]) + [(.table.All[] | [.field1,.field2,.field3,.id])])[]|@csv' tmp.json
  • 嘿@MostafaHussein 这看起来很棒,似乎“几乎”做了我需要的一切!我在“真实”JSON 上运行它时遇到了几个问题(因为它有机密数据,所以不能在这里分享) 1. “你的 JSON 需要修复”是什么意思?这正是我将它作为对 REST API 调用的响应的方式,“res 0”在顶部,而不是在末尾...... 2. 其中一些字段包含带空格的字符串,所以在执行“sed”时用逗号替换它会变坏。 3.尝试'@csv'时出现错误:“jq: error: string cannot be csv-formatted, only array”
  • 您在问题中发布的原始 JSON 格式错误,缺少花括号,我已在线修复。对于 csv 错误。您需要在将其传递给 @csv 之前将其列在列表中,检查我的答案的更新部分,其中我添加了 csv 实现
  • 这就是为什么我使用[.field1, .field2, .field3, .id] 而不是(.field1, .field2, .field3, .id)@csv
  • 是的,@MostafaHussein!最后的编辑确实成功了!!!非常感谢!
【解决方案2】:

这是一个 only-jq 解决方案,只需要指定一次所需的键,例如在命令行上:

jq -r --argjson f '["field1", "field2", "field3", "id"]' '
  $f, (.table.All[] | [getpath( $f[]|[.])]) | @csv'

输出:

"field1","field2","field3","id"
"a","aa","aaa","1"
"b","bb","bbb","2"
"c","cc","ccc","3"
"d","dd","ddd","4"

引号丢失

避免引用字符串的一种方法是通过管道输入join(",")(或join(", "))而不是@csv

field1,field2,field3,id
a,aa,aaa,1
b,bb,bbb,2
c,cc,ccc,3
d,dd,ddd,4

当然,如果值包含逗号,这可能是不可接受的。一般来说,如果避免在字符串周围使用引号很重要,那么可以考虑使用@tsv

【讨论】:

  • 有一个 jq 解决方案已经添加到我的答案中,类似于你的答案,但没有传递参数
  • MostafaHussein - 我想你可能错过了我的方法的重点。当我查看时,您在输出中包含标题行的所有解决方案都需要指定键列表两次。
猜你喜欢
  • 2017-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 2011-04-25
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多