所有操作默认非root用户,本文中用 zhe.lin 用户。

jq

jq 命令是Linux下的一个命令,mac用户可以用brew install jq来安装

jq通过 jq表达式 来对Json格式的数据做处理,接下来的操作以此Json文本(json.txt)作为输入:

{"person":[{"firstname":"Z","lastname":"L"},{"firstname":"M","lastname":"J"}],"game":{"name":"yys"}}

基本jq操作

现在对这个文件使用jq命令 cat Json.txt | jq .

{
  "person": [
    {
      "firstname": "Z",
      "lastname": "L"
    },
    {
      "firstname": "M",
      "lastname": "J"
    }
  ],
  "game": {
    "name": "yys"
  }
}

可以看到jq支持从管道操作符|接受输入,'.'是一个最简单的jq表达式,他表示选取这个Json并什么都不做

接下来做一个选取操作cat Json.txt | jq .person。另外jq表达式内也支持操作符进行串行化操作,管道前面表达式的输出可以作为管道后表达式的输入,所以上面的命令也可以写成cat Json.txt | jq '. | .person' (为了防止歧义这里将整个jq表达式用单引号’‘包住了),这两个命令可以得到相同的输出 :

[
  {
    "firstname": "Z",
    "lastname": "L"
  },
  {
    "firstname": "M",
    "lastname": "J"
  }
]

可以看到.person代表选取这个Json中key为person的元素,它是一个Json数组。

类似.[]的表达式可以操作数组(也就是上一个命令的输出),这个命令的输入既可以是数组也可以是Json对象,输出的是基于数组元素或对象属性值(只有value没有key)的迭代器。一个表达式产生的结果是迭代器时,迭代器的每一个值会分别作为的输入,传给后面的表达式。以cat Json.txt | jq '.person | .[]'命令为例 :

{
  "firstname": "Z",
  "lastname": "L"
}
{
  "firstname": "M",
  "lastname": "J"
}

注意上述输出既没有代表数组的[],同时两个Json对象之间也没有,分隔。

特别注意:对于.[]命令,如果输入是一个数组,返回的是一个数组里每个元素的迭代器;如果输入是一个Json对象,则生成的迭代器里只有values没有keys

验证命令1 cat Json.txt | jq '.game | .[]'

"yys"

验证命令2 cat Json.txt | jq '.person | .[]'

{
  "firstname": "Z",
  "lastname": "L"
}
{
  "firstname": "M",
  "lastname": "J"
}

.[index].[attributename]可以访问数组元素或者Json对象的属性值。以cat Json.txt | jq '.person | .[0]'为例演示index访问:

{
  "firstname": "Z",
  "lastname": "L"
}

可以看到index是从 0 开始的;接下来以cat Json.txt | jq '.person | .[0] | .["firstname"]'演示attributename访问 :

"Z"
  • 事实上以下两种写法也能达到相同效果:
    • cat Json.txt | jq '.person | .[0] | .firstname'
    • cat Json.txt | jq '.person | .[0].firstname'

.[startindex:endindex]可以实现数组切片操作,返回仍然是一个数组,以cat Json.txt | jq '.person | .[0:1]'为例,可以看到下标是左闭右开 :

[
  {
    "firstname": "Z",
    "lastname": "L"
  }
]

jq函数

删除

用法:jq expr | del(jq_expr)

命令cat Json.txt | jq '. | del(.person)'

{
  "game": {
    "name": "yys"
  }
}

映射

用法:map(jq_expr)

To Be Continued…

过滤

用法:jq expr | select(jq_expr)

命令cat Json.txt | jq '.["person"] | .[] | select(.lastname=="L")'

{
  "firstname": "Z",
  "lastname": "L"
}

命令cat Json.txt | jq '.["person"] | .[] | select(.lastname=="J")'

{
  "firstname": "M",
  "lastname": "J"
}

命令cat Json.txt | jq '.["person"] | .[] | select(.lastname=="l")'


数组函数

sort / sort_by / reverse

排序

用法:jq expr | sort

命令cat Json.txt | jq '.["person"] | sort'

[
  {
    "firstname": "M",
    "lastname": "J"
  },
  {
    "firstname": "Z",
    "lastname": "L"
  }
]

注意此命令后,数组内MJ位于ZL之前了,说明顺序的确被替换了。

正则表达式

jq正则表达式以如下语法出现:

STRING | FILTER( REGEX )
STRING | FILTER( REGEX; FLAGS )
STRING | FILTER( [REGEX] )
STRING | FILTER( [REGEX, FLAGS] )

其中FILTER可以是test / match / captureFLAGS暂且按下不表,以下分别展开说

test

test()只返回真假

用法jq expr | test( REGEX )

命令cat Json.txt | jq '.game.name | test(".ys$")'

true

命令cat Json.txt | jq '.game | select(.name | test("ys$"))'

{
  "name": "yys"
}

命令cat Json.txt | jq '.game | select(.name | test("^ys$"))'


众所周知^匹配字符串开头,$匹配字符串结尾,所以test("ys$")返回真而test("^ys$")返回假,配合select()可以完成从Json中匹配正则表达式的能力

match

类似test,只不过match返回的不再是真/假,而是返回匹配上的对象

用法jq expr | match( REGEX )

命令cat Json.txt | jq '.game.name | match(".*s$")'

{
  "offset": 0,
  "length": 3,
  "string": "yys",
  "captures": []
}

capture

太复杂了,自己体会吧…
大概是让你分段匹配

命令cat Json.txt | jq '.game.name | capture("(?<left>[a-z]+)y(?<right>[a-z]+)")'

{
  "left": "y",
  "right": "s"
}

参考文献