jq 命令

 

jq 程序是一个 过滤器:接受输入并产生输出。它有很多内置过滤器用于提取对象的特定字段,将数字转换为字符串或各种其他标准任务。

过滤器可以通过多种方式组合,可以通过管道将一个过滤器的输出传递到另一个过滤器,或者将过滤器的输出收集到一个数组中。

一些过滤器会产生多个结果,例如过滤器会生成其输入数组的所有元素,然后对数组的每个元素运行第二个过滤器。通常,在其他语言中使用循环和迭代完成的事情在 jq 中只是通过管道将过滤器组合在一起来完成。

Baisc Filters

通用对象索引 .[<string>]

可以使用 .["foo"] 这样的过滤器来检索一个对象的字段。如果字段是个标识符类型的字符串时 ([a-zA-Z0-0_]),可以简写为 .foo,称为 对象标识符索引

检索多层字段时的格式为 .["foo"].["bar"],对象标识符索引为 .foo.bar,等价于管道格式 .foo | .bar

可选对象标识符索引 .foo?

.foo 过滤器作用一样,但在找不到检索字段时不会报错,通常用于递归检索。

数组索引 .[<value>]

如果索引值不是字符串而是数字,.[2] 可用于索引数组,数组索引从 0 开始。

迭代器 .[]

迭代对象或数组中的所有值并逐个输出,例如

echo '{"a": 1, "b": 2, "foo": "bar"}' | jq '.[]'

输出为

1
2
"bar"

输出指定对象或数组的所有值

# 对象
jq '.object_name[]' file.json

# 数组
jq '.array_name[]' file.json

逗号 ,

逗号 , 用于分隔多个过滤器,每个过滤器单独作用于相同的输入,多个过滤器输出结果会合并到一起。

管道 |

类似于 UNIX 管道,将上一过滤器的输出结果作为下一过滤器的输入。

递归下降 ..

递归索引所有值。注意不能使用 ..foo 这种写法,而应当使用 .. | .foo。更为常用的格式是 .. | .foo?,避免对象或数组中缺失字段 foo 而报错。

表达式比较

字符串比较 (==, !=, >, >=, <, <=) 按字母顺序进行比较,也适用于时间类字符串

==

jq 'select(.tagValue == "FALSE")' file.json

jq 'select(.retries == 1)' file.json

jq 'select(.timestamp == "20221201T12:00:00")' file.json

!=

jq 'select(.tagValue != "TRUE")' file.json

jq 'select(.retries != 0)' file.json

>, >=, <, <=

jq 'select(.timestamp >= "20221201T12:00:00")' file.json

jq 'select(.timestamp <= "20221201T12:00:00")' file.json

and, or, not

jq 'select(.foo=="bar" and (.path|contains("log")|not))' file.json

常用 functions

select(boolean_expression)

函数 select(boolean_expression) 会将表达式计算为 true 的输入原封不动的输出,否则不产生输出,用于过滤掉不符合条件的输入。

jq '.[] | select(.id == "second")'

keys, keys_unsorted

内置函数 keys,将对象的键以数组形式返回。keys_unsorted 函数和 keys 函数一样,但是对象的键不被排序,按原有顺序排列。

echo '{"b":1, "a":"2"}' | jq -c 'keys' # 输出 ["a","b"]

echo '{"b":1, "a":"2"}' | jq -c 'keys_unsorted' # 输出 ["b","a"]

map(f), map_values(f)

map(f)map_values(f) 用于将过滤器 f 应用于输入数组或对象中的每个值,因为迭代器 .[] 用于对数组或对象进行迭代,所以 map(f) 相当于 [.[] | f]map_values(f) 相当于 .[] |= f

最简单的过滤器 .arrays_input | map(.)object_input | map_values(.) 对每个值不做任何修改并原样输出

jq -R 'fromjson? | .tags | map_values(.)' file.json

将 tags 对象中的所有 tag 值设置为 FALSE

jq -R 'fromjson? | .tags | map_values("FALSE")' file.json

map(f) 函数通过 f 将数组或对象的每个值设置为该过滤器返回的新值,

echo '[1,2,3]' | jq 'map(.>1)' # 输出结果为 [false,true,true]

如果只是想对原数组或对象进行筛选,可以结合 select(boolean_expression) 函数来处理。

# 数组
echo '[1,2,3]' | jq -c 'map(select(.>1))' # 输出结果为 [2,3]
# 对象
jq -R 'fromjson? | .tags | map(select(.=="FALSE"))' file.json

to_entries, from_entries, with_entries(f)

如果向 to_entries 传递一个对象,则对于对象中的每个 k: v,输出由 {"key": k, "value": v} 组成的数组。

jq -rR 'fromjson? | select(.tags | to_entries | map(select(.value=="FASLE"))) | .id' file.json

from_entries 进行相反的转换。

with_entries(f)to_entries | map(f) | from_entries 的简写形式,主要应用于对象。

jq -R 'fromjson? | .tags | with_entries(select(.value=="FALSE"))' file.json

contains(element)

如果输入值中包含要查找的 element,返回 true,否则返回 false,常用于字符串类型的字段。

# 包含
jq 'select(.foo | contains("bar"))' file.json

# 不包含
jq 'select(.foo | contains("bar") | not)' file.json

type

jq select(.version | select(type == "String"))' file.json

type 函数返回其参数的类型,类型为 null, boolean, number, string, arrayobject 其中之一。

Cheat Sheet

忽略非 json 行

如果程序输出为多行,但不是每行都是 json 格式的字符串(例如有 warning 信息的行),可以通过 -R 选项配合 fromjson 内建函数进行过滤

–raw-input / -R: Don´t parse the input as JSON. Instead, each line of text is passed to the filter as a string. If combined with –slurp, then the entire input is passed to the filter as a single long string.

output | jq -R 'fromjson?'

fromjson 从 1.4 版本开始支持

输出 json 结果到一行

–compact-output / -c: By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line.

output | jq -c .

配合上面的 json 行过滤

–raw-output / -r: With this option, if the filter´s result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems. 输出的字符串不会带引号

output | jq -crR 'fromjson?'

按输入的 Keys 顺序输出 json

jq --sort-keys . file.json

jq -S . file.json

递归列出所有对象的 key

jq '.. | objects | keys_unsorted' file.json

jq '.. | keys_unsorted?' file.json

递归查找是否存在名为 “foo” 的 key

# recursive search for keys containing "string" stripping empty results
jq '.. | objects | with_entries(select(.key | contains("foo"))) | select(. != {})'