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
, array
或 object
其中之一。
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(. != {})'