jq:打印对象中每个条目的键和值

155

我该如何让 jq 处理这样的 JSON 数据:

{
  "host1": { "ip": "10.1.2.3" },
  "host2": { "ip": "10.1.2.2" },
  "host3": { "ip": "10.1.18.1" }
}

生成以下输出:
host1, 10.1.2.3
host2, 10.1.2.2
host3, 10.1.18.1

我对格式不感兴趣,我只是弄不清楚如何访问键名和值。
2个回答

255

要将顶层键作为流获取,可以使用内置函数 keys[]。因此,解决您特定问题的一个方法是:

```jq keys[] ```
jq -r 'keys[] as $k | "\($k), \(.[$k] | .ip)"' 

keys 以排序后的顺序返回键名;如果您想按原始顺序返回,则使用 keys_unsorted

另一种以原始顺序返回键的选择是:

jq -r 'to_entries[] | "\(.key), \(.value | .ip)"'

CSV和TSV输出

在这里也值得考虑使用@csv和@tsv过滤器,例如:

jq -r 'to_entries[] | [.key, .value.ip] | @tsv'

产生:

host1   10.1.2.3
host2   10.1.2.2
host3   10.1.18.1

嵌套对象

如果需要的键被嵌套在一个对象中,如下所示的例子,那么 jq 过滤器就需要按照以下方式进行修改。

输入:

{
  "myhosts": {
    "host1": { "ip": "10.1.2.3" },
    "host2": { "ip": "10.1.2.2" },
    "host3": { "ip": "10.1.18.1" }
  }
}

修改:

jq -r '.myhosts | keys[] as $k | "\($k), \(.[$k] | .ip)"'

1
假设“.ip”键中有空格,例如“IP地址”,如果您在引用字符串的第三级别上,如何转义围绕键的引号? - 170730350
2
是的,它很有道理,也是一个好问题,但请原谅我说,你本可以自己回答它,因为答案就是简单地忽略潜在的复杂性。也就是说,通常的做法应该是引用带有空格的字符串,然后就万事大吉了。 - peak
1
我曾经尝试过,但没有成功。我试图转义引号,但没有起作用,因此提出这个问题。 - 170730350
2
@Saichovsky - 我已经检查过它在 jq 1.4、1.5 和 1.6 中可以工作。如果你正在使用 jq 1.3,那么你必须编写 .["id address"],就像在正常情况下一样。 - peak

102

发现了一种非常优雅的解决方案

jq 'with_entries(.value |= .ip)'

输出什么

{
  "host1": "10.1.2.3",
  "host2": "10.1.2.2",
  "host3": "10.1.18.1"
}

这里是 jqplay 的测试代码片段:https://jqplay.org/s/Jb_fnBveMQ

with_entries 函数将列表中的每个对象转换为键值对,因此我们可以分别访问 .key.value,通过使用更新操作符 |=,我们正在更新(覆盖)每个 KV 项的 .value 字段与 .ip 字段。


3
这个解决方案是确切的答案。所选的解决方案有一些额外的帮助,但不如精确或优雅。您可能需要添加简明的解释和完整的命令。 - Mike D
2
太棒了!很多次我使用“to_entries []”只是因为我不知道这个。 - Lungang Fang

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