jq: 一个灵活的轻量级命令行JSON处理器。用于处理JSON输入,将给定过滤器应用于其JSON文本输入并在标准输出上将过滤器的结果生成为JSON。最简单的过滤器是.,它将jq的输入未经修改地复制到其输出中(格式设置除外)。 场景:项目中很多地方用到了json数据(包括接口日志、数据库字段)等,有些时候要对这些数据进行筛选过滤等处理,使用jq命令可以方便很多

1 语法

1
jq [options]  [file...]

它可以直接用于 JSON 文件,也可以结合其他几个命令来解释 JSON 数据。JQ 命令可以与不同的过滤器一起使用,例如“.”、“”、“,”或“.[]”过滤器来组织 JSON 数据。

2 简单使用

2.1 美化输出:.

我们有一个名为 employee.json 的 JSON 文件,我们需要将数据输出到标准输出:

1
{"workers":{"name": "John Brooks","id": "003"}}

我们可以使用 cat 命令来显示数据:

1
2
[root@localhost ~]# cat employee.json 
{"workers":{"name": "John Brooks","id": "003"}}

使用 cat 命令打印到标准输出的数据是无组织和混乱的。我们可以使用 JQ 命令和“.”来组织这些数据,使用.来筛选:

1
2
3
4
5
6
7
[root@localhost ~]# jq '.' employee.json 
{
"workers": {
"name": "John Brooks",
"id": "003"
}
}

2.2 访问属性:.字段

.字段过滤器和 JQ 命令可用于访问 shell 中的对象属性。 如果我们只想访问单个属性并将其打印到标准输出,那么我们可以使用.字段运算符。例如,要访问工人的属性,我们可以使用以下命令:

1
2
3
4
5
[root@localhost ~]# jq '.workers' employee.json 
{
"name": "John Brooks",
"id": "003"
}

另,如果.字段也可访问嵌套对象的属性。要访问工人属性中的名称项,我们将使用:

1
2
[root@localhost ~]# jq '.workers.name' employee.json 
"John Brooks"

2.3 访问数组: .[]

使用.[]运算符访问和输出 JSON 文件中数组中存在的元素。对于这个例子,我们将修改我们的 JSON 文件,添加下面内容:

1
[{"name": "John Brooks","id": "003"},{"name": "Randy Park","id": "053"},{"name": "Todd Gray","id": "009"}]

查看一下employee.json文件:

1
2
[root@localhost ~]# cat employee.json 
[{"name": "John Brooks","id": "003"},{"name": "Randy Park","id": "053"},{"name": "Todd Gray","id": "009"}]

如果我们继续用.命令访问,输出就是一个数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# jq '.' employee.json 
[
{
"name": "John Brooks",
"id": "003"
},
{
"name": "Randy Park",
"id": "053"
},
{
"name": "Todd Gray",
"id": "009"
}
]

2.3.1 想遍历数组内元素,就用.[]: 注意对比上面的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# jq '.[]' employee.json 
{
"name": "John Brooks",
"id": "003"
}
{
"name": "Randy Park",
"id": "053"
}
{
"name": "Todd Gray",
"id": "009"
}

2.3.2 想仅输出第二个数组,可以执行以下命令:

1
2
3
4
5
[root@localhost ~]# jq '.[1]' employee.json 
{
"name": "Randy Park",
"id": "053"
}

注意: 数组从索引 0 开始的。

2.3.3 要访问数组中的所有名称属性,可以执行以下命令:

1
2
3
4
[root@localhost ~]# jq '.[].name' employee.json 
"John Brooks"
"Randy Park"
"Todd Gray"

2.3.4 如果想要把数组中的某些属性提取出来重新组成数组, 可以执行以下命令:

1
2
3
4
5
6
$ echo '[{"name": "foo"},{"name": "bar"},{"name": "foobar"}]' jq [.[].name]
[
"foo",
"bar",
"foobar"
]

与上类似,如果想要把json数组中的某些属性提取出来重新组成json数组, 可以执行以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "John Brooks",
"id": "003"
}
{
"name": "Randy Park",
"id": "053"
}
{
"name": "Todd Gray",
"id": "009"
}

3 高级操作

3.1 管道(对处理后的结果做二次或多次处理)

类似于shell的 (当然也可以直接用)

1
2
3
4
5
6
$ echo '{"url": "mozillazg.com", "tests": [{"foobar": "v1"}, {"foobar": "v2"}]}' jq '.tests .[] .foobar'
"v1"
"v2"
$ echo '{"url": "mozillazg.com", "tests": [{"foobar": "v1"}, {"foobar": "v2"}]}' jq '.tests' jq '.[]' jq '.foobar'
"v1"
"v2"

3.2 获取内容的长度(字符串,数组的长度)

1
2
3
4
$ echo '{"url": "mozillazg.com", "name": "mozillazg"}' jq '.urllength'
13
$ echo '["mozillazg.com", "mozillazg"]' jq '.length'
2

3.3 map()可以实现对数组的每一项进行操作,然后合并结果的功能:

1
2
3
4
5
$ echo '["mozillazg.com", "mozillazg"]'  jq 'map(length)'
[
13,
9
]

3.4 select(foo)可以实现对输入项进行判断,只返回符合条件的项:

1
2
3
4
$ echo '["mozillazg.com", "mozillazg"]'  jq 'map(select(.length > 9))'
[
"mozillazg.com"
]
1
2
3
4
5
6
7
8
9
10
11
$ less employee.json jq 'map(select(.id > "004"))'
[
{
"name": "Randy Park",
"id": "053"
},
{
"name": "Todd Gray",
"id": "009"
}
]

3.5 字符串拼接

可以使用\()实现字符串插值功能:

1
2
$ echo '{"url": "mozillazg.com", "name": "mozillazg"}' jq '"hi \(.name)"'
"hi mozillazg"

注意要用双引号包围起来,表示是一个字符串。 使用+实现字符串拼接:

1
2
$ echo '{"url": "mozillazg.com", "name": "mozillazg"}' jq '"hi " + .name'
"hi mozillazg"

3.6 输出字符串原始值而不是字符串 JSON 序列化后的值

使用-r选项输出字符串原始值而不是 json 序列化后的值:

1
2
3
4
$ echo '{"value": "{\"url\": \"mozillazg.com\"}"}' jq .value
"{\"url\": \"mozillazg.com\"}"
$ echo '{"value": "{\"url\": \"mozillazg.com\"}"}' jq -r .value
{"url": "mozillazg.com"}

3.7 if/elif/else

可以使用if .. then .. elif .. then .. else .. end实现条件判断:

1
2
3
4
5
6
7
8
$ echo '[0, 1, 2, 3]' \
jq 'map(if . == 0 then "zero" elif . == 1 then "one" elif . == 2 then "two" else "many" end)'
[
"zero",
"one",
"two",
"many"
]

3.8 构造 object 或数组

可以通过{}和[]构造新的 object 或 数组。 object:

1
2
3
4
$ echo '["mozillazg.com", "mozillazg"]' jq '{name: .[1]}'
{
"name": "mozillazg"
}

数组:

1
2
3
4
5
$ echo '{"url": "mozillazg.com", "name": "mozillazg"}' jq '[.name, .url]'
[
"mozillazg",
"mozillazg.com"
]
1
2
3
4
5
6
7
8
9
$ echo '{"name": "mozillazg", "ages": [1, 2]}'  jq '{name, age: .ages[]}'
{
"name": "mozillazg",
"age": 1
}
{
"name": "mozillazg",
"age": 2
}

3.9 join / split

1
2
$ echo '["mozillazg.com", "mozillazg"]'  jq '.join("  ")'
"mozillazg.com mozillazg"
1
2
3
4
5
$ echo '"mozillazg.com  mozillazg"' jq 'split("  ")'
[
"mozillazg.com",
"mozillazg"
]

4.案例:

4.1 获取数据列表中某一字段缺失的数据

找出数据id,该数据的assets包含非10类型的资产, 数据格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[
{
"id": 1,
"ext_info": {
"assets": [
{
"ext_info": {},
"asset_type": {
"code": 10,
"desc": "test"
}
}
]
}
},
{
"id": 2,
"ext_info": {
"assets": [
{
"ext_info": {},
"asset_type": {
"code": 10,
"desc": "test"
}
},
{
"ext_info": {
},
"asset_type": {
"code": 11,
"desc": "test2"
}
}
]
}
},
{
"id": 3,
"ext_info": {
"assets": [
{
"ext_info": {
"cost_price": 123
},
"asset_type": {
"code": 11,
"desc": "test2"
}
},
{
"ext_info": {
"cost_price": 123
},
"asset_type": {
"code": 11,
"desc": "test2"
}
}
]
}
}
]
1
2
3
4
less test.json  jq '.[]{id, ext_info}{id, asset: .ext_info.assets[]}'  jq '{id, asset_type:.asset.asset_type.code}'  jq 'select(.asset_type > 10)' jq '.id'uniq
# 输出:
2
3

如果还有其他的用例,会再次补充,也欢迎大家一起交流。