一个计算机技术爱好者与学习者

0%

好好学Linux:jq命令

1. jq命令简介

jq 是一款命令行下处理 JSON 数据的工具。其可以接受标准输入,命令管道或者文件中的 JSON 数据,经过一系列的过滤器(filters)和表达式的转后形成我们需要的数据结构并将结果输出到标准输出中。jq 的这种特性使我们可以很容易地在 Shell 脚本中调用它。

参考文档:

2. 安装jq

2.1. macos

1
brew install jq

2.2. linux通用安装

1
2
wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod a+x jq-linux64 && mv jq-linux64 /usr/bin/jq

2.3. centos

1
2
yum install epel-release
yum install jq

2.4. ubuntu

1
2
apt update
apt install -y jq

3. jq表达式

3.1. 举个栗子

1
2
3
4
echo '{"name":"voidking"}' | jq .
echo '{"name":"voidking"}' | jq .name
echo '{"name":"voidking"}' | jq -r .name
echo '{"name":"voidking"}' | jq -c

用户在使用jq时,需要使用jq支持的语法来构建表达式(filters)并将其传给jq。jq根据语法规则解析表达式,并应用在输入的JSON数据上从而得到需要的结果。

上面例子中的 ..name 就是表达式。
. 符号表示对表达式输入的整个JSON对象的引用,.name.name?表示获取JSON对象的属性。当输入不是JSON对象或数组时,带着问号的方式不会抛出异常。

选项的含义查看jq帮助即可,比如-r表示输出raw格式内容,-c表示去空格和换行压缩输出。

3.2. 串行操作

1
2
3
4
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq .name.firstname
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name | .firstname'
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name | .firstname,.lastname'
echo '[{"firstname":"Void","lastname":"King"},{"firstname":"Hao","lastname":"Jin"}]' | jq '.[] | .firstname,.lastname' | sed -n "N;s/\n/ /p"

jq表达式支持串行化操作。一个复杂的表达式可以由多个简单的表达式组成,以管道符号 | 分割,串行化执行。管道前面表达式的输出,是管道后面表达式的输入。

逗号 , 表示对同一个输入应用多个表达式。

3.3. 数组操作

1
2
3
4
5
6
7
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq .
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[]'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[0:2]'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[0,1]'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[].name'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[] | .name'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[] | .["name"]'

jq 提供三种基础表达式来操作数组:
迭代器操作.[],该表达式的输入可以是数组或者JSON对象,输出的是基于数组元素或者JSON对象属性值的迭代器(iterator)。
访问特定元素的操作.[index].["attributename"]。用来访问数组元素或者JSON对象的属性值,输出是单个值。
数组切片操作.[startindex:endindex]',其行为类似于 python 语言中数组切片操作。

一个表达式产生的结果是迭代器时,迭代器的每一个值会分别作为的输入,传给后面的表达式。

4. jq运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
echo '{"num":3,"str":"343"}' | jq '.num*3'
echo '{"num":3,"str":"343"}' | jq '.num/3'

echo '{"num":3,"str":"343"}' | jq '.str+"3"'
echo '{"num":3,"str":"343"}' | jq '.str*3'
echo '{"num":3,"str":"343"}' | jq '.str/"4"'

echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.+[{"name":"voidking"}]'
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.-[{"name":"voidking"}]'

echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.+{"name":{"nickname":"Hankin"}}'
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.*{"name":{"nickname":"Hankin"}}'

echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name.nickname//"Hankin"'

jq -n '([1,2]|.[])+([4,6]|.[])'

jq 内部支持的数据类型有:数字,字符串,数组和对象(object)。

数字运算:jq支持加减乘除(/)和求余(%)运算。
字符串运算:jq 提供字符串的连接、复制、分割运算。
数组运算:并集、差集运算。
对象运算:合并。
比较运算:jq 内部支持的比较运算,规则与js基本相同。
逻辑运算: and/or/not。在 jq 逻辑运算中,除了 false 和 null 外,其余的任何值都等同于 true。
默认值运算符:双斜杠。
迭代器运算:每一个元素拿出来分别运算。

5. jq函数

jq 支持函数。在使用 jq 函数时,我们应该注意区分两个概念:输入和参数。输入可能是整个表达式的输入数据也可能是表达式别的部分的输出。而参数和函数一起构成新的filter来处理输入。
和其他编程语言不同的是,在调用函数时,多个参数之间以分号分隔。jq通过内置函数提供了数据处理时常用的操作,例如:删除、映射,过滤、路径操作等。

5.1. 删除

1
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq 'del(.name.firstname)'

删除不需要的元素。

5.2. 映射

1
echo '[1,2,3,4]'| jq -r 'map(.+1)'

在数据处理过程中,我们经常需要将数据从一种形式转换成另外一种形式,或者改变数据的值。
jq提供了两个内置映射函数来实现这种转换:map 和 map_values。其中,map处理的对象是数组,而map_values则处理对象属性的值。map 函数的参数为 filter 表达式。

5.3. 过滤

1
2
3
echo '[1,2,3,4]'| jq -r 'map(select(.>2))'
echo '[1,2,3,4]'| jq -r '.[]|select(.>2)'
echo '[{"name":"voidking","age": 18},{"name":"haojin","age": 28}]' | jq '.[]|select(.name=="haojin")'

jq中有两种类型的选择过滤操作。
第一种是基于数据类型的过滤,如表达式.[]|arrays的结果只包含数组。可以用来过滤的类型过滤器有:arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars。
第二种是select函数。select接受一个条件表达式作为参数。其输入可以是迭代器,或者和map函数配合使用来处理数组。当输入中的某个元素使select参数中的条件表达式结果为真时,则在结果中保留该元素,否则不保留该元素。

5.4. 路径

jq中的path是指从根到某个叶子属性的访问路径。
在jq中有两种表示路径的方式:数组表示法和属性表示法。
属性表示法类似于我们在filter中访问某个属性值的方式,如.a.b
数组表示法是将路径中的每一部分表示为数组的一个元素。
jq提供了一个内置函数path用来实现路径从属性表示法到数组表示法的转换。

jq还提供了函数用来读取路径的值(getpath), 设置路径的值(setpath)和删除路径(del)。
不过这三个函数对路径的处理并不一致。其中getpath和setpath只接受数组表示法的路径,而del函数只能正确处理属性表示法的路径。

jq还提供了一个函数paths用来枚举可能存在的路径。在没有参数的情况下,paths函数将输出JSON数据中所有可能的路径。paths函数可以接受一个过滤器,来只输出满足条件的路径。

jq中提供了一系列的函数用来判断某个元素或者属性是否存在于输入数据中。其中函数has和in用来判断JSON对象或数组是否包含特定的属性或索引。函数contains和inside用来判断参数是否完全包含在输入数据中。对于不同的数据类型,判断是否完全包含的规则不同。对于字符串,如果A是B的子字符串,则认为A完全包含于B。对于对象类型,如果对象A的所有属性在对象B中都能找到且值相同,则认为A完全包含于B。

5.5. 数组函数

1
2
3
4
5
6
jq -nr '[1,[2,3],4]|flatten'
jq -nr '[1,2,3]|reverse'
jq -nr '[3,1,2]|sort'
jq -nr '[{"a":1},{"a":2}]|sort_by(.a)'
jq -nr '"abcb"|indices("b")'
jq -nr '[1,3,2,3]|indices(3)'

jq 提供内置函数用于完成数组的扁平化(flatten),反序(reverse),排序(sort、sort_by),比较(min、min_by、max、max_by)和查找(indices、index、rindex)。其中indices函数的输入数据可以是数组,也可以是字符串。和 index函数不同的是,其结果是一个包含所有参数在输入数据中位置的数组。

6. jq高级特性

js高级特性包括:变量、Reduce、自定义函数和模块等。

已知file1.json内容为:

1
2
3
4
5
6
7
{
"auths": {
"harbor.voidking.com": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
}
}
}

file2.json内容为:

1
2
3
4
5
6
7
8
9
{
"auths": {
"harbor1.voidking.com": {
"username": "haojin",
"password": "haojin123",
"auth": "aGFvamluOmhhb2ppbjEyMwo="
}
}
}

6.1. json相加

json相加命令:

1
2
3
jq -s 'add' file1.json file2.json
# or
jq -n 'reduce inputs as $i ({}; . + $i)' file1.json file2.json

file1.json和file2.json相加的结果为:

1
2
3
4
5
6
7
8
9
{
"auths": {
"harbor1.voidking.com": {
"username": "haojin",
"password": "haojin123",
"auth": "aGFvamluOmhhb2ppbjEyMwo="
}
}
}

file2.json会覆盖file1.json的一部分。

6.2. json组合

json组合命令:

1
jq -s '.' file1.json file2.json

file1.json和file2.json组合的结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
{
"auths": {
"harbor.voidking.com": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
}
}
},
{
"auths": {
"harbor1.voidking.com": {
"username": "haojin",
"password": "haojin123",
"auth": "aGFvamluOmhhb2ppbjEyMwo="
}
}
}
]

6.3. json合并

json合并命令:

1
jq -n 'reduce inputs as $i ({}; . * $i)' file1.json file2.json

file1.json和file2.json合并的结果为:

1
2
3
4
5
6
7
8
9
10
11
12
{
"auths": {
"harbor.voidking.com": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
},
"harbor1.voidking.com": {
"username": "haojin",
"password": "haojin123",
"auth": "aGFvamluOmhhb2ppbjEyMwo="
}
}
}
  • 本文作者: 好好学习的郝
  • 原文链接: https://www.voidking.com/dev-linux-jq/
  • 版权声明: 本文采用 BY-NC-SA 许可协议,转载请注明出处!源站会即时更新知识点并修正错误,欢迎访问~
  • 微信公众号同步更新,欢迎关注~