jq: 一个灵活的轻量级命令行JSON处理器。用于处理JSON输入,将给定过滤器应用于其JSON文本输入并在标准输出上将过滤器的结果生成为JSON。最简单的过滤器是.,它将jq的输入未经修改地复制到其输出中(格式设置除外)。 场景:项目中很多地方用到了json数据(包括接口日志、数据库字段)等,有些时候要对这些数据进行筛选过滤等处理,使用jq命令可以方便很多
1 语法
它可以直接用于 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
|
如果还有其他的用例,会再次补充,也欢迎大家一起交流。