使用jq按顺序解析和显示JSON中的多个字段

478
{"name": "John", "age": 30, "city": "New York"}
我有这个 Json
{
    "users": [
        {
            "first": "Stevie",
            "last": "Wonder"
        },
        {
            "first": "Michael",
            "last": "Jackson"
        }
    ]
}
使用 jq,我希望能够按顺序显示名字和姓氏。就像这样 -
Stevie Wonder
Michael Jackson

这是我已经完成的进度 -

jq '.users[].first, .users[].last'

但它会显示出来。

"Stevie"
"Michael"
"Wonder"
"Jackson"

请注意以下内容:

  1. 我不需要双引号。
  2. 我不需要换行符。
  3. 它很混乱。我的查询先显示所有的名字,然后是所有的姓氏。然而,我想要先显示名字-姓氏对。
8个回答

665

我建议使用字符串插值:

jq '.users[] | "\(.first) \(.last)"'
我们将.users[]的结果通过字符串插值输出为 ".first .last" 字符串。在jq中,使用\(foo)语法进行字符串插值。所以,对于上面的例子,它变成了“Stevie Wonder”(按元素方式处理".users[].first .users[].second"),和 “Michael Jackson”。
jq参考文献:String interpolation

16
如果你的数据是数字,那么这样做会更好。 - ozOli
17
解释一下语法会使这个回答更有用。 - james.garriss
3
一个好的答案不应该只是一个链接解释。链接到的网站可能会发生任何事情,这样人们就会复制他们不理解的代码。 - annedroiid
21
如果你不想让输出结果被引号包裹,可以添加 '-r' 开关。 - jenda
1
将名称或ID与值jq '.[] | "id=\(.id) name=\(.name)"')附加。 - Adiii
这太完美了,谢谢!正是我所寻找的。 - Sebastian Garces

372
你可以使用加法来连接字符串。

字符串通过组合成一个更大的字符串来添加。

jq '.users[] | .first + " " + .last'

上面的方法只适用于 firstlast 都是字符串的情况。如果你要提取不同的数据类型(数字和字符串),那么就需要将它们转换为相应的类型。参考这个问题的解决方案。例如:

jq '.users[] | .first + " " + (.number|tostring)'

64
为了消除JSON引号,请使用带有-r选项的jq命令,例如,jq -r '.users[] | .first + " " + .last'。该命令会将所有值作为纯文本输出,而不是带有引号的字符串。 - peak
4
+1,但是针对我的应用场景,我想将两个数字格式化到同一行。这种方法失败了,因为它无法将“"”添加到数字上。Eric的答案对于这种情况给出了更好的结果。 - Synesso
10
@Synesso: (.numA|tostring) + " " + (.numB|tostring)应该可以工作。或者使用字符串插值:"\(.numA) \(.numB)" - Mr. Lance E Sloan
当我运行 jq '.users[] | .first + " " + .last' 时,它非常有效,但是在 .first.last 的值之间引入了一个换行符。我将 " " 更改为 "@",然后对输出进行了 sed 's/@/ /g' 处理,以获得“John Smith”作为输出结果。类似这样:jq '.users[] | .first + "@" + .last' | sed 's/@/ /g' - Kartik Pandya

75
jq '.users[]|.first,.last' | paste - -

这个代码片段可以以良好的格式打印数组字段,不像其他以字符串为中心的答案。谢谢。 - Elouan Keryell-Even

68

除了其他人所建议的内容之外,我认为还值得提及两个选项。

将其打印为CSV/TSV格式

$ cat file.json | jq -r '.users[] | [.first, .last] | @tsv'
Stevie  Wonder
Michael Jackson
cat file.json | jq -r '.users[] | [.first, .last] | @csv'
"Stevie","Wonder"
"Michael","Jackson"

第一个表达式.users[]将外层数组中的对象拆分,就像问题中给出的代码一样。接下来的表达式[.first, .last]为每个输入对象创建一个新数组的值,最后一个表达式使用内置函数@tsv@csv分别将所有输入数组打印为制表符分隔和逗号分隔的值。

作为JSON值打印

同样,可以再次构造JSON值,如果您只想保留字段的子集,则这很有趣:

$ cat file.json | jq -c '.users[] | {first}'
{"first":"Stevie"}
{"first":"Michael"}

20

我的方法是(你的JSON示例格式不正确...我猜那只是一个示例)

jq '.Front[] | [.Name,.Out,.In,.Groups] | join("|")'  front.json  > output.txt

返回类似于这样的内容

"new.domain.com-80|8.8.8.8|192.168.2.2:80|192.168.3.29:80 192.168.3.30:80"
"new.domain.com -443|8.8.8.8|192.168.2.2:443|192.168.3.29:443 192.168.3.30:443"

并使用正则表达式来grep输出结果。


我不知道这与问题有什么关系...?另外,为什么你声称OP给出的JSON示例“格式不正确”?在我看来它看起来很好 - 就像语法检查工具(如jq)一样。另外,你能展示一下front.json的内容吗? - Gwyneth Llewelyn
该评论是在2020年发表的,而某人在2021年编辑了这个问题。你所看到的是该问题的最新版本。 - Ganesh Chandrasekaran

18

这将产生一个名称数组

> jq '[ .users[] | (.first + " " + .last) ]' ~/test.json

[
  "Stevie Wonder",
  "Michael Jackson"
]

17

如果key和value都是字符串,那么上述两个答案都可以很好地工作,但是我遇到了一个情况,需要附加一个字符串和整数(使用上述表达式会导致jq错误)

要求:从以下JSON构造URL

pradeep@seleniumframework>curl http://192.168.99.103:8500/v1/catalog/service/apache-443 | jq .[0]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   251  100   251    0     0   155k      0 --:--:-- --:--:-- --:--:--  245k
{
  "Node": "myconsul",
  "Address": "192.168.99.103",
  "ServiceID": "4ce41e90ede4:compassionate_wozniak:443",
  "ServiceName": "apache-443",
  "ServiceTags": [],
  "ServiceAddress": "",
  "ServicePort": 1443,
  "ServiceEnableTagOverride": false,
  "CreateIndex": 45,
  "ModifyIndex": 45
}

解决方案:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'

请注意,不需要转义右括号,否则会出错。 - nymo
2
@nymo:这不是转义。\(...) 是字符串插值。在这里,它将数字的 .ServicePort 转换为字符串。可以使用插值代替 + 号,使解决方案更短。 - Mr. Lance E Sloan

6
我通过类似以下方式实现了我想要的效果:

我采用了类似这样的方法,接近了我想要的结果

cat my.json | jq '.my.prefix[] | .primary_key + ":", (.sub.prefix[] | "    - " + .sub_key)' | tr -d '"' 

这个工具的输出结果与yaml非常接近,我通常可以将其导入其他工具而不会遇到太多问题。(我仍在寻找一种方法来基本上导出输入json的子集)


2
这在我的情况下可以运行,只需在末尾去掉 | tr -d '"' ,并添加 -r 选项到 jq。 - Th3Ndr1X

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