jq基本用法:读取访问

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是一个数组,如何把数组元素按行打出来;便于后续的命令处理;我们需要做两件事:

  1. 把F5的数组,按个每一个占用一行。
  2. F5数组的每一元素输出一行。
$ jq '.F5[]|(.F51|tostring)+"-"+.F52' t.json 
"511-F521"
"512-F522"

有了这个命令之后,后面可以用管道来循环处理每一个数组元素。

进一步想,能不能把上述的两行,也拼成一行呢,也就是说把数组的所有元素拼成一行输出。原理就是利用join函数,把数组连接在一起;分两步:

  1. 处理F5的单个数组元素。
  2. 把处理完的元素组织成一个数组。
  3. 利用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"
}

你可能感兴趣的:(jq基本用法:读取访问)