警告
本文最后更新于 2023-02-13 20:23,文中内容可能已过时。
jq命令一般用来读取json数据,日常用法比较简单,有时候会有些特殊需求,每次都是用的时候查文档,过一段时间再用又忘了,效率太低,决定写个文章记录下来,方便以后自查。
官方文档: https://stedolan.github.io/jq/manual/v1.6/#Basicfilters
在线测试工具:
https://sandbox.bio/playgrounds?id=jq
https://jqkungfu.com/
https://jiehong.gitlab.io/jq_offline/
https://jqplay.org/
参数介绍
--stream
: 处理大量数据的时候使用
--slurp
/ -s
: 当输入内容是多个json对象时,将多个json对象视为1个json数组。这样就可以用一个jq过滤器来处理所有的输入,而不是每个JSON值都要处理一次。比如
1
2
3
4
5
6
7
| {"name": "test1"}
{"name": "test2"}
#jq -s会将上面的内容处理成下面这样###############
[
{"name": "test1"},
{"name": "test2"}
]
|
--raw-input
/ -R
: 不要将输入解析为 JSON。相反,每一行文本都作为字符串传递给过滤器。如果与 --slurp
结合使用,则整个输入将作为单个长字符串传递给过滤器。
例如将大写字母转换为小写字母: echo -e "ONE\nTWO\nTHREE" | jq -R ascii_downcase
--null-input
/ -n
: 不读取任何内容, 使用jq构造数据时可以使用,例如jq -n 1+1
--compact-output
/ -c
: 紧凑的打印输出内容
--tab
: 缩进使用制表符而不是两个空格
--indent n
: 使用指定的空格作为锁紧, 范围-1到7
--color-output
/-C
: 强制高亮显示,默认只在终端输出才会高亮显示,一个很好的例子:
1
2
3
| echo '{"name": 1}' | jq | cat # 不会高亮显示
echo '{"name": 1}' | jq -C | cat # 高亮显示
|
--monochrome-output
/ -M
: 强制不输出颜色,即使使用了-C也不会输出颜色
--ascii-output
/ -a
: 将ASCII码之外的Unicode符号显示为转义的形式,默认是会将Unicode符号按照UTF8输出
1
2
3
4
5
6
7
8
| [root@mytest ~]# echo '{"name": "SoulChild\u968f\u7b14\u8bb0"}' | jq -a
{
"name": "SoulChild\u968f\u7b14\u8bb0"
}
[root@mytest ~]# echo '{"name": "SoulChild\u968f\u7b14\u8bb0"}' | jq
{
"name": "SoulChild随笔记"
}
|
--unbuffered
: 不使用缓冲区,实时输出处理结果, 在默认情况下,jq在处理完所有输入数据后才将其输出,以便进行必要的排序和格式化。
--sort-keys
/ -S
: 按照key升序输出,更高级的排序可以使用sort和sort_by,配合reverse反转
1
2
3
4
5
6
7
8
9
10
| [root@mytest ~]# echo '{"name": "SoulChild", "age": "10"}' | jq
{
"name": "SoulChild",
"age": "10"
}
[root@mytest ~]# echo '{"name": "SoulChild", "age": "10"}' | jq -S
{
"age": "10",
"name": "SoulChild"
}
|
--raw-output
/ -r
: 获取的结果如果是字符串,去掉字符串中的引号
--join-output
/ -j
: 类似于-r,但不会在最后打印换行符。
-f filename
/ --from-file filename
: 从文件读取过滤器,而不是从命令行读取,比如awk的-f选项。你也可以使用"#“来做注释。
-Ldirectory
/ -L directory
: 复杂的jq脚本可能依赖其他的jq脚本,这种情况下可以设置jq脚本文件的搜索路径
-e
/ --exit-status
: 根据获取到的结果决定退出码是多少
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
| # 输出值既不是 false 也不是 null,退出状态码为 0
[root@mytest ~]# echo '{"foo": false}' | jq -e . ;echo $?
{
"foo": false
}
0
# 输出值是 false 或 null,则设置为 1
[root@mytest ~]# echo '{"foo": false}' | jq -e .foo ;echo $?
false
1
# 出现任何使用问题或系统错误,jq 将以 2 退出
[root@mytest ~]# jq '.' aa;echo $?
jq: error: Could not open file aa: No such file or directory
2
# 如果存在 jq 程序编译错误(语法错误),则返回 3
[root@mytest ~]# echo '{"foo": false}' | jq -e xxx ;echo $?
jq: error: xxx/0 is not defined at <top-level>, line 1:
xxx
jq: 1 compile error
3
# 非有效数据,则设置为 4。
[root@mytest ~]# echo '{"foo": false' | jq '.hello';echo $?
parse error: Unfinished JSON term at EOF at line 2, column 0
4
内置函数`halt_error`也可以修改exit code。
|
--arg name value
: 变量传递,例如
1
2
3
4
5
6
7
8
9
10
| # 传递两个变量name和name2
# .hello as $greeting将获取的结果赋值给$greeting变量
[root@mytest ~]# echo '{"hello": "world"}' | jq --arg name "John Doe" --arg name2 "SoulChild" '.hello as $greeting | $greeting + ", " + $name + ", " + $name2'
"world, John Doe, SoulChild"
# 修改原内容
[root@mytest ~]# echo '{"name": "xxx"}' | jq --arg newName "SoulChild" '.name = $newName'
{
"name": "SoulChild"
}
|
--argjson name JSON-text
: 变量传递,值是json对象
1
2
3
4
5
6
| [root@mytest ~]# echo '{"name": "xxx"}' | jq --argjson data '{"book": "hello", "name": "SoulChild", "age": 10}' '.book=$data.book | .name=$data.name | .age=$data.age'
{
"name": "SoulChild",
"book": "hello",
"age": 10
}
|
--slurpfile variable-name filename
: 读取整个文件并将其内容作为一个数组存储在指定的变量中。(文件格式是json)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| [root@mytest ~]# cat test.json
[
{"name1": "a"},
{"name2": "b"}
]
# 查看读入后的内容
[root@mytest ~]# echo '{"age": 1}' | jq --slurpfile content test.json '$content'
[
[
{
"name1": "a"
},
{
"name2": "b"
}
]
]
|
--rawfile variable-name filename
: 读取整个文件并将其内容作为一个字符串存储在指定的变量中。(字符串比较复杂时可以用这个参数,把它存入文件中再读取)
1
2
3
4
5
6
7
| [root@mytest ~]# cat test.json
[
{"name1": "a"},
{"name2": "b"}
]
[root@mytest ~]# echo '{"age": 1}' | jq --rawfile content test.json '$content'
"[\n {\"name1\": \"a\"},\n {\"name2\": \"b\"}\n]\n"
|
--argfile variable-name filename
: 将文件内容作为一个变量传给指定的变量。(文件格式是json)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| [root@mytest ~]# cat test.json
[
{"name1": "a"},
{"name2": "b"}
]
[root@mytest ~]# echo '{"age": 1}' | jq --argfile content test.json '$content'
[
{
"name1": "a"
},
{
"name2": "b"
}
]
|
--args
: 将命令行的位置参数作为数组传入(传入内容被识别为字符串)
1
2
3
4
5
6
7
| # 这里的args是"John Doe" 30,就像shell中的$1,$2
# 在jq中通过$ARGS.positional[0]获取第一个变量
[root@mytest ~]# echo '{ "name": "", "age": "" }' | jq --args '.name=$ARGS.positional[0] | .age=$ARGS.positional[1]' "John Doe" 30
{
"name": "John Doe",
"age": "30"
}
|
--jsonargs
: 将命令行的位置参数作为数组传入(传入内容被识别为json对象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # 这里的--jsonargs是'{"name": "John Doe", "age": 30}' '{"name": "SoulChild", "age": 31}',就像shell中的$1,$2
# 在jq中通过$ARGS获取所有的变量,通过$ARGS.positional[0]可以获取第一个
[root@mytest ~]# echo '{ "name": "", "age": "" }' | jq --jsonargs '$ARGS' '{"name": "John Doe", "age": 30}' '{"name": "SoulChild", "age": 31}'
{
"positional": [
{
"name": "John Doe",
"age": 30
},
{
"name": "SoulChild",
"age": 31
}
],
"named": {}
}
|
--run-tests [filename]
: 执行测试用例
内置函数
内容较多,官方文档:
https://stedolan.github.io/jq/manual/v1.6/#Builtinoperatorsandfunctions
运算符+
,-
,*
,/
,%
,>
,<
,==
1
2
3
4
5
6
7
8
| [root@mytest ~]# echo '{"age": 10}' | jq '.age + 2'
12
[root@mytest ~]# echo '{"age": 10}' | jq '.age > 2'
true
[root@mytest ~]# jq -n '"x" * 10'
"xxxxxxxxxx"
....
|
length计算长度
1
2
3
4
| [root@mytest ~]# jq -n '"x" * 10 | length'
10
[root@mytest ~]# echo '[1,2,3,4,5]' | jq 'length'
5
|
keys、keys_unsorted获取对象的key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 默认会对key按照Unicode码点排序
[root@mytest ~]# echo '{"abc": 1, "abcd": 2, "Foo": 3}' | jq 'keys'
[
"Foo",
"abc",
"abcd"
]
# 不排序
[root@mytest ~]# echo '{"abc": 1, "abcd": 2, "Foo": 3}' | jq 'keys_unsorted'
[
"abc",
"abcd",
"Foo"
]
|
map(x), map_values(x)
map(x) 遍历每个元素,拿到value,并对value执行x操作, 返回一个数组。操作数组一般用这个
map_values(x) 遍历map对象元素,拿到value,并对value执行x操作, 返回一个对象,保持原来的key不变。操作对象一般用这个
1
2
3
4
5
6
7
8
9
10
11
12
| [root@mytest ~]# echo '[1,2,3]' | jq 'map(. + 1)'
[
2,
3,
4
]
[root@mytest ~]# echo '{"a": 1, "b": 2, "c": 3}' | jq 'map_values(. + 1)'
{
"a": 2,
"b": 3,
"c": 4
}
|
has(key)
key或者指定位置的元素是否存在
1
2
3
4
5
6
7
8
9
10
11
12
| # 先用map遍历列表中的元素,对每个元素使用has("foo"), 判断foo这个key是否存在
[root@mytest ~]# echo '[{"foo": 42}, {}]' | jq 'map(has("foo"))'
[
true,
false
]
# 先用map遍历列表中的元素,对每个元素使用has(2), 判断下标为2的位置有没有元素
[root@mytest ~]# echo '[[0,1], ["a","b","c"]]' | jq 'map(has(2))'
[
false,
true
]
|
tostring
转换为字符串
例子
获取对象
1
2
3
4
5
| # 直接通过.获取
echo '{"a/": "aaa"}' | jq '."a/"'
# 也支持类似python字典的用法
echo '{"a/": "aaa"}' | jq '.["a/"]'
|
列表操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 通过下标获取元素
echo '[1,2,3,4,5]' | jq .[0]
# 切片
echo '[1,2,3,4,5]' | jq .[0:-1]
# 获取列表所有元素
echo '[1,2,3,4,5]' | jq .[]
# 忽略错误
echo '1' | jq '.[]?'
# 获取所有元素的某个属性
echo '[{"name": "a"},{"name": "b"},{"name": "c"}]' | jq .[].name
|
或操作
1
2
| # 输出name1或者name2字段
echo '{"name1": "a"}{"name2": "b"}' | jq '.name1 // .name2'
|
输出多个字段
1
| echo '{"foo": 42, "bar": "something else", "baz": true}' | jq '.foo, .bar'
|