jq的基本用法:读取访问
jq参考文档: https://stedolan.github.io/jq/manual/v1.4/
代码中使用到的json文本。
{
"F1": 9,
"F2": "F21",
"F3": [
"F31",
"F32"
],
"F4": {
"F41": 411,
"F42": "F421"
},
"F5": [
{
"F51": 511,
"F52": "F521"
},
{
"F51": 512,
"F52": "F522"
}
]
}
提取基本元素
句号(.)表示最外围元素;依次访问:.Field1.Field11.Field112....
$ jq '.F1' t.json
9
$ jq '.F2' t.json
"F21"
提取字符串值, 删除前后双引号
前面例子中返回的F21包括双引号,如何把双引号去掉呢:
$ jq --raw-output '.F2' t.json
F21
判断元素是否存在
$ jq '.F9' t.json
null
$ echo $?
0
我们看到如果元素不存在jq返回null值,并且结果值返回0;有些情况下我们需要判断如果元素不存在,让它返回错误:
$ jq --exit-status '.F9' t.json
null
$ echo $?
1
使用命令行参数--exit,详细说明请参阅jq的manual。
访问数组
.F3是一个元素,当然类型是数组。
.F3[]指的是数组的所有成员元素;这种用法只能用在F3是一个数组的情况下,如果F3不是数组类型,会出错。
$ jq '.F3' t.json
[
"F31",
"F32"
]
$ jq '.F3[]' t.json
"F31"
"F32"
$ jq --raw-output '.F3[0]' t.json
F31
$ jq --raw-output '.F3[1]' t.json
F32
提取第一个和最后一个元素:
$ jq '.F3[0]' t.json
F31
$ jq '.F3[-1]' t.json
F32
获取数组长度:
$ jq '.F3 | length' t.json
2
访问map
$ jq '.F4.F41' t.json
411
$ jq '.F4.F42' t.json
"F421"
$ jq '.F5[0].F51' t.json
511
$ jq '.F5[1].F52' t.json
"F522"
也可以判断map是否包含指定的key:
$ jq -e '.F4.F43' t.json
null
$ echo $?
1
在map字段F4中F43这个key并不存在,所以返回错误码为1。
使用has函数判断key是否存在:
$ jq 'has("F9")' t.json
true
$ jq 'has("F10")' t.json
false
$ jq '.F4 | has("F41")' t.json
true
$ jq '.F4 | has("F43")' t.json
false
注意has只能访问对象本身是否包含key,不能访问子对象属性,即不能级联访问,像:has(F4.F41),会把"F4.F41"整个作为key来判断(自然是不存在的),而不会认为这是一个级联key。
另一个map的例子:
$ cat t.json
{
"A": "a",
"B": {
"B1": "b1",
"B2": "b2",
"B3": "b3"
}
}
用法例子:
$ jq -r '.B' t.json # get all map key-value mapping
{
"B1": "b1",
"B2": "b2",
"B3": "b3"
}
$ jq -r '.B[]' t.json # get all map values
b1
b2
b3
$ jq -r '.B | keys' t.json # get all map keys
[
"B1",
"B2",
"B3"
]
$ jq -r '.B | keys[0]' t.json # get specific keys
B1
多个字段拼接
把多个字段值拼成一个输出;涉及把数字转换成字符串,然后字符串拼接。
$ jq '"Hello " + .F2 + " !"' t.json
"Hello F21 !"
$ jq -r '"Hello " + .F2 + " !"' t.json
Hello F21 !
$ jq '.F2 + ":" + (.F1|tostring)' t.json
"F21:9"
$ jq '.F5[1] | (.F51|tostring) + ":" + .F52' t.json
"512:F522"
上述类型只有事先知道带拼接的元素个数的情况下,也就是确切的知道要拼接哪几个字段;
相反如果不知道元素个数,例如数组,但不知道数组有多少个元素,就需要用到join函数:
$ jq '.F3 | join("")' t.json
"F31F32"
$ jq '.F3 | join("-")' t.json
"F31-F32"
$ jq -r '.F3 | join("-")' t.json
F31-F32
数组的拼接
例子中F5是一个数组,如何把数组元素按行打出来;便于后续的命令处理;我们需要做两件事:
- 把F5的数组,按个每一个占用一行。
- F5数组的每一元素输出一行。
$ jq '.F5[]|(.F51|tostring)+"-"+.F52' t.json
"511-F521"
"512-F522"
有了这个命令之后,后面可以用管道来循环处理每一个数组元素。
进一步想,能不能把上述的两行,也拼成一行呢,也就是说把数组的所有元素拼成一行输出。原理就是利用join函数,把数组连接在一起;分两步:
- 处理F5的单个数组元素。
- 把处理完的元素组织成一个数组。
- 利用join函数把数组元素合并成一行。
$ jq '[.F5[]|(.F51|tostring)+"-"+.F52]|join("|")' t.json
"511-F521|512-F522"
元素类型转换
把数字转换成字符串。
当需要多个字段拼接的时候,数字必须先转换成字符串,然后完成字符串的拼接。
函数tostring用来转换成字符串。
$ jq '.F5[] | [(.F51|tostring), .F52] | join(":")' t.json
"511:F521"
"512:F522"
此例子中, F5是数组,F51是数字,F52是字符串,要把F51和F52拼接,必须先把F51转换成字符串。
函数length
针对不同的数据类型返回不一样。
- 数字:返回数字值 (我不知道为什么)
- 字符串:返回字符串长度
- 数组:返回数组长度
- map:返回元素个数。
$ jq '. | length' t.json # map count
6
$ jq '.F1 | length' t.json # number
9
$ jq '.F2 | length' t.json # string length
3
$ jq '.F3 | length' t.json # array count
2
$ jq '.F4 | length' t.json # map count
2
$ jq '.F5 | length' t.json # array count
2
$ jq '.F5[0] | length' t.json # map count
2
条件判断
$ jq 'select (.F1 > 10)' t.json
$ jq '.F5[] | select (.F51 >= 512)' t.json
{
"F51": 512,
"F52": "F522"
}
$ jq '.F5[] | select ((.F52 | length) >= 4 and (.F51 > 511))' t.json
{
"F51": 512,
"F52": "F522"
}