当年刚出道的时候,整天使用 grep/cut/awk 处理各种纯文本日志。那时候的日志都是一行一条,内容使用特定分割符。使用各种 unix 命令配合管道真可谓得心应手。
然而,到了 9102 年,好多数据都以 json 形式传输和存储。awk 这类工具在 json 处理方面就有点力不从心了,毕竟是几十年前开发的工具。那有没有针对 json 专门开发的工具呢?答案是肯定的,这就是本文要介绍的 jq 命令。
jqstedolan.github.iojq 支持各种 unix 系统,请自行安装。现在单讲几种使用场景。
先来一个段 json 数据,内容如下(并写入 a.json 文件):
{"code":0,"message":"0","ttl":1,"data":{"results":[{"item_id":1342,"type":1},{"item_id":1785,"type":2},{"item_id":1413,"type":3}]}}
首先要做的就是格式化,这是 jq 最简单的功能:
cat a.json | jq ''
输出效果如下(还有语法高亮):
如果 json 很长,则可以使用管道传给 less 命令:
cat a.json | jq '' | less
如果你自己试一下就会发现,less 展示的结果没有颜色,这怎么能忍?
终端下的颜色是由转义序列控制的。有兴趣的同学可以参考我的拙作
涛叔:多彩的终端zhuanlan.zhihu.com像 jq 这类的工具会检测输出目的地是否为终端环境(tty),如果不是(比如管道或普通文件)则不会输出颜色转义序列,否则这些转义序列会破坏文件内容。
但如果确定读写双方都支持转义序列,我们就可以强制开启颜色输出:
jq -C '' a.json|less -R
这里用到了 jq 的 -c
参数和 less 的 -R
参数。
现在介绍 jq 的高级操作。还是以上面的 json 为例。
{"code": 0,"message": "0","ttl": 1,"data": {"results": [{"item_id": 1342,"type": 1},{"item_id": 1785,"type": 2},{"item_id": 1413,"type": 3}]}
}
显然,这是一个比较负杂的数据结构。我们可以使用 jq 提取部分字段
$ cat a.json | jq '.code, .ttl'
0
1
提取字段使用.
操作,提取多个字段可以使用,
连接。
如果我们想提取 results 内容,则可以这样:
$ cat a.json | jq '.data.results'
[{"item_id": 1342,"type": 1},{"item_id": 1785,"type": 2},{"item_id": 1413,"type": 3}
]
是不是清真多了?
传统的 unix 工具是以行为单位,而 json 数组的每个元素可能有复杂的数据结构(多行),我们能否以元素为单位处理 json 数据呢?当然可以。
提取数组的元素字段
$ cat a.json | jq '.data.results' | jq '[].item_id'
1342
1785
1413
提取多个数组元素字段
$ cat a.json | jq '.data.results' | jq '[]|.item_id,.type'
1342
1
1785
2
1413
3
结果是 item_id 和 type 交替出现,传统的 unix 工具依然不好处理。能将同一元素的不同字段放到一行吗?当然可以:
$ cat a.json | jq '.data.results' |jq '.[] |"item_id:(.item_id) type:(.type)"'
"item_id:1342 type:1"
"item_id:1785 type:2"
"item_id:1413 type:3"
这里用到了所谓的 string interpolation 语法,有点像 swift 语言。好了,现在你可以再配合其他 uinx 工具对数据进行处理了。
jq 还支持很多高级特性,有兴趣的同学可以参考官方手册。本文的重点是介绍 jq 最核心的 20% 功能,基本可以解决 80% 的问题。
先写这么多,有问题请留言讨论。