jq 1.7 手册
其他版本,请参见1.7, 1.6, 1.5, 1.4, 1.3或开发版本.
一个 jq 程序是一个“过滤器”:它接收一个输入,并产生一个输出。有很多内建的过滤器用于提取对象的一个特定字段,或者将数字转换为字符串,或者执行各种其他标准任务。
过滤器可以以多种方式组合——你可以将一个过滤器的输出管道到另一个过滤器,或者将过滤器的输出收集到一个数组中。
有些过滤器会产生多个结果,例如有一个过滤器会产生其输入数组的所有元素。将这个过滤器管道到第二个过滤器,会对数组的每个元素运行第二个过滤器。通常,在其他语言中用循环和迭代完成的操作,在 jq 中只是通过将过滤器粘合在一起来完成。
重要的是要记住每个过滤器都有一个输入和一个输出。即使是像 "hello" 或 42 这样的字面量也是过滤器——它们接收一个输入,但始终产生相同的字面量作为输出。像加法这样组合两个过滤器的操作,通常会将相同的输入提供给两者,并组合结果。因此,你可以实现一个平均值过滤器,如下所示add / length
- 将输入数组同时提供给add
过滤器和length
过滤器,然后执行除法。
但那有点超前了。:) 让我们从一个简单的东西开始:
调用 jq
jq 过滤器在 JSON 数据流上运行。jq 的输入被解析为一系列空格分隔的 JSON 值,这些值逐个传递给提供的过滤器。过滤器的输出写入标准输出,作为一系列换行符分隔的 JSON 数据。
最简单和最常见的过滤器(或 jq 程序)是.
,它是身份运算符,将 jq 处理器的输入复制到输出流。由于 jq 处理器的默认行为是从输入流读取 JSON 文本并美化输出,因此.
程序的主要用途是验证和美化输入。jq 编程语言非常丰富,允许做的不只是验证和美化。
注意:注意 shell 的引号规则很重要。一般来说,最好始终用单引号(在 Unix shell 上)引号 jq 程序,因为太多对 jq 有特殊意义的字符也是 shell 元字符。例如,jq
"foo"
在大多数 Unix shell 上都会失败,因为那将等同于jq foo
,这通常会失败,因为foo is not
defined
。当使用 Windows 命令 shell (cmd.exe) 时,最好在命令行上用双引号包围你的 jq 程序(而不是-f program-file
选项),但然后 jq 程序中的双引号需要转义。当使用 Powershell (powershell.exe
) 或 Powershell Core (pwsh
/pwsh.exe
) 时,用单引号包围 jq 程序,并在 jq 程序内部使用转义的双引号 (\"
)。
- Unix shell:
jq '.["foo"]'
- Powershell:
jq '.[\"foo\"]'
- Windows 命令 shell:
jq ".[\"foo\"]"
注意:jq 允许用户定义函数,但每个 jq 程序都必须有一个顶层表达式。
你可以使用一些命令行选项来影响 jq 的读取和写入输入和输出:
--null-input
/-n
:
不要读取任何输入。相反,使用null
作为输入运行过滤器一次。这在将 jq 用作简单计算器或从零开始构建 JSON 数据时很有用。
--raw-input
/-R
:
不要将输入解析为 JSON。相反,将文本的每一行作为字符串传递给过滤器。如果与--slurp
结合使用,则整个输入将作为单个长字符串传递给过滤器。
--slurp
/-s
:
不是为输入中的每个 JSON 对象运行过滤器,而是将整个输入流读取到一个大数组中,只运行过滤器一次。
--compact-output
/-c
:
默认情况下,jq 美化输出 JSON。使用此选项将产生更紧凑的输出,通过将每个 JSON 对象放在单行上。
--raw-output
/-r
:
使用此选项,如果过滤器的结果是字符串,则它将直接写入标准输出,而不是格式化为带引号的 JSON 字符串。这可以用于使 jq 过滤器与非 JSON 基于的系统进行通信。
--raw-output0
:
. Like-r
但 jq 将在每个输出后打印 NUL 而不是换行符。这在输出的值可以包含换行符时很有用。当输出值包含 NUL 时,jq 将以非零代码退出。
--join-output
/-j
:
. Like-r
但 jq 不会在每个输出后打印换行符。
--ascii-output
/-a
:
jq 通常以 UTF-8 输出非 ASCII Unicode 码点,即使输入指定它们为转义序列(如
--sort-keys
/-S
:
以排序的顺序输出每个对象的字段键。
--color-output
/-C
和--monochrome-output
/-M
:
默认情况下,如果写入终端,jq 会输出彩色 JSON。你可以使用-C
强制它在管道或文件写入时产生颜色,并使用-M
禁用颜色。NO_COLOR
环境变量不为空时,jq 默认禁用彩色输出,但你可以通过-C
.
启用它。JQ_COLORS
环境变量配置(见下文)。
--tab
:
使用制表符而不是两个空格来表示每个缩进级别。
--indent n
:
使用给定的空格数(不超过 7)进行缩进。
--unbuffered
:
在打印每个 JSON 对象后刷新输出(如果你正在将慢速数据源管道到 jq,并将 jq 的输出管道到其他地方,这很有用)。
--stream
:
以流式方式解析输入,输出路径和叶值(标量和空数组或空对象)的数组。"a"
成为[[],"a"]
,和[[],"a",["b"]]
成为[[0],[]]
, [[1],"a"]
,和[[2,0],"b"]
.
这对于处理非常大的输入很有用。与过滤和reduce
和foreach
语法一起使用时,可以逐步减少大型输入。
--stream-errors
:
. Like--stream
,但无效的 JSON 输入会产生包含第一个元素为错误、第二个元素为路径的数组值。["a",n]
将字符串除以另一个字符串会使用第二个字符串作为分隔符分割第一个字符串。["Invalid literal at line 1,
column 7",[1]]
.
暗示--stream
。无效的 JSON 输入在--stream
没有--stream-errors
.
--seq
:
时不会产生错误值。application/json-seq
MIME 类型方案用于分隔 jq 输入和输出中的 JSON 文本。这意味着在每个值输出之前打印 ASCII RS(记录分隔符)字符,并在每个输出之后打印 ASCII LF(换行符)。无法解析的输入 JSON 文本被忽略(但会发出警告),丢弃所有后续输入,直到下一个 RS。此模式还会解析 jq 的输出,而无需--seq
选项。
-f filename
/--from-file filename
:
从文件而不是从命令行读取过滤器,类似于 awk 的 -f 选项。你也可以使用 '#' 来添加注释。
-L directory
:
将directory
添加到模块搜索列表。如果使用此选项,则不会使用内置搜索列表。有关模块的说明,请参阅下文。
--arg name value
:
此选项将值传递给 jq 程序作为预定义变量。如果你使用--arg foo bar
,然后$foo
在程序中可用,其值为"bar"
。请注意,value
将被视为字符串,因此--arg foo 123
将绑定$foo
到"123"
.
命名参数也作为$ARGS.named
.
--argjson name JSON-text
:
传递给 jq 程序。--argjson foo 123
,然后$foo
在程序中可用,其值为123
.
--slurpfile variable-name filename
:
此选项读取指定文件中的所有 JSON 文本,并将解析的 JSON 值数组绑定到给定的全局变量。如果你使用--slurpfile foo bar
,然后$foo
在程序中可用,其包含对应于文件bar
.
--rawfile variable-name filename
:
中文本的元素数组。--rawfile foo bar
,然后$foo
在程序中可用,其包含文件bar
.
--args
:
中文本的内容。$ARGS.positional[]
.
--jsonargs
:
传递给 jq 程序。$ARGS.positional[]
.
--exit-status
/-e
:
传递给 jq 程序。false
也不是null
, 1 if the last output value was
either false
或null
, or 4 if no valid result was ever
produced. Normally jq exits with 2 if there was any usage
problem or system error, 3 if there was a jq program compile
error, or 0 if the jq program ran.
另一种设置退出状态的方法是使用halt_error
内建函数。
--binary
/-b
:
Windows 用户使用 WSL、MSYS2 或 Cygwin,在使用原生 jq.exe 时应使用此选项,否则 jq 将将换行符(LFs)转换为回车符后跟换行符(CRLF)。
--version
/-V
:
输出 jq 版本并退出,状态码为 0。
--build-configuration
:
输出 jq 的构建配置并退出,状态码为 0。此输出没有支持的格式或结构,未来版本中可能会发生变化而无需通知。
--help
/-h
:
输出 jq 帮助并退出,状态码为 0。
--
:
终止参数处理。剩余参数是位置的,可以是字符串、JSON 文本或输入文件名,具体取决于是否给出了--args
或--jsonargs
。
--run-tests [filename]
:
运行给定文件或标准输入中的测试。这必须是给出的最后一个选项,并且不尊重所有前面的选项。输入由注释行、空行和程序行后跟一行输入行组成,然后是预期输出行(每行一个输出)和终止空行。编译失败测试以只包含%%FAIL
的行为开始,然后是包含要编译的程序行,然后是包含要与之比较的错误消息的行。
警告:此选项可能会向后不兼容地改变。
基本过滤器
身份:.
最简单的过滤器是.
。此过滤器接收其输入并产生相同的值作为输出。也就是说,这是身份运算符。
由于 jq 默认美化所有输出,一个只包含.
的简单程序可以用来格式化来自curl
.
的 JSON 输出。尽管身份过滤器从未修改其输入的值,但 jq 处理有时会使其看起来好像它确实进行了修改。例如,使用当前 jq 的实现,我们会看到表达式:
1E1234567890 | .
将字符串除以另一个字符串会使用第二个字符串作为分隔符分割第一个字符串。1.7976931348623157e+308
。这是因为,在解析数字的过程中,这个特定版本的 jq 将其转换为 IEEE754 双精度表示,从而丢失了精度。
jq 处理数字的方式随着时间的推移而改变,并且根据相关 JSON 标准的参数,可能会进一步改变。因此,以下注释是理解它们旨在描述当前 jq 版本的当前版本,并且不应将其解释为规定:
(1) 对尚未转换为 IEEE754 双精度表示的数字的任何算术运算都会触发转换为 IEEE754 表示。
(2) jq 将尝试保持数字字面量的原始十进制精度,但在表达式1E1234567890
中,如果指数太大,精度将丢失。
(3) 在 jq 程序中,一个负号将触发数字转换为 IEEE754 表示。
(4) 如果可用,比较将使用未截断的 big decimal 表示的数字进行,如以下示例之一所示。
命令 | jq '.' |
---|---|
输入 | "Hello, world!" |
输出 | "Hello, world!" |
运行 |
命令 | jq '.' |
---|---|
输入 | 0.12345678901234567890123456789 |
输出 | 0.12345678901234567890123456789 |
运行 |
命令 | jq '[., tojson]' |
---|---|
输入 | 12345678909876543212345 |
输出 | [12345678909876543212345,"12345678909876543212345"] |
运行 |
命令 | jq '. < 0.12345678901234567890123456788' |
---|---|
输入 | 0.12345678901234567890123456789 |
输出 | false |
运行 |
命令 | jq 'map([., . == 1]) | tojson' |
---|---|
输入 | [1, 1.000, 1.0, 100e-2] |
输出 | "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" |
运行 |
命令 | jq '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000)' |
---|---|
输入 | 10000000000000000000000000000001 |
输出 | [true, false] |
运行 |
对象标识符-索引:.foo
, .foo.bar
最简单的有用过滤器产生消息的形式.foo
形式。当给定一个 JSON 对象(又名字典或哈希)作为输入时,.foo
如果键存在,则产生键 "foo" 的值,否则产生 null。
A filter of the form .foo.bar
等同于.foo | .bar
.
元数据中的.foo
语法只适用于简单的、类似标识符的键,也就是说,键全部由字母数字字符和下划线组成,并且不以数字开头。
如果键包含特殊字符或以数字开头,你需要用双引号将其包围,像这样:."foo$"
,或者.["foo$"]
.
For example.["foo::bar"]
和.["foo.bar"]
可以工作,而.foo::bar
不行。
可选对象标识符-索引:.foo?
类似.foo
,但如果.
不是对象,则不会输出错误。
对象索引:.[<string>]
你也可以使用类似于.["foo"]
(.foo
上的语法来查找对象的字段,但只有对于类似标识符的字符串才是简写版本)。
数组索引:.[<number>]
当索引值是整数时,.[<number>]
可以索引数组。数组是零基的,所以.[2]
返回第三个元素。
允许负索引,-1 指向最后一个元素,-2 指向倒数第二个元素,以此类推。
数组/字符串切片:.[<number>:<number>]
元数据中的.[<number>:<number>]
语法返回数组的子数组或字符串的子字符串。由.[10:15]
返回的数组长度为 5,包含从索引 10(包含)到索引 15(排除)的元素。两个索引都可以是负数(在这种情况下,它从数组的末尾向后计数),或者省略(在这种情况下,它指的是数组的开始或结束)。
数组/对象值迭代器:.[]
如果你使用.[index]
语法,但完全省略了索引,它将返回数组的所有元素。使用 of the elements of an
array. Running .[]
输入[1,2,3]
将产生数字作为三个单独的结果,而不是一个数组。形式为.foo[]
等同于.foo | .[]
.
你也可以在对象上使用它,它将返回对象的所有值。
注意,迭代运算符是值的生成器。
.[]?
. Like.[]
,但如果 . 不是数组或对象,则不会输出错误。形式为.foo[]?
等同于.foo | .[]?
.
逗号:,
如果两个过滤器由逗号分隔,则相同的输入将被提供给两者,并且两个过滤器的输出值流将按顺序连接:首先,所有由左表达式产生的输出,然后是所有由右表达式产生的输出。例如,过滤器.foo,
.bar
,产生 "foo" 字段和 "bar 字"段作为单独的输出。
元数据中的,
operator is one way to construct generators.
管道:|
运算符通过将左侧过滤器的输出(s)输入到右侧过滤器的输入中来组合两个过滤器。它类似于 Unix shell 的管道,如果你习惯使用的话。
如果左侧过滤器产生多个结果,右侧过滤器将对每个结果运行。所以,表达式.[] | .foo
从输入数组的每个元素检索 "foo" 字段。这是一个笛卡尔积,可能会令人惊讶。
注意,a87502 内部定义为递归的 jq 函数。在.a.b.c
is the same as .a | .b | .c
.
注意,e08c57: 不会设置.
是管道中特定阶段的输入值,具体是:出现.
表达式的位置。因此.a | . | .b
is the same as .a.b
相同,因为.
在中间指的是.a
产生的值。
命令 | jq '.[] | .name' |
---|---|
输入 | [{"name":"JSON", "good":true}, {"name":"XML", "good":false} |
输出 | "JSON" |
"XML" | |
运行 |
括号
括号就像在任何典型的编程语言中一样作为分组运算符工作。
命令 | jq '(. + 2) * 5' |
---|---|
输入 | 1 |
输出 | 15 |
运行 |
类型与值
jq 支持与 JSON 相同的数据类型集 - 数字、字符串、布尔值、数组、对象(在 JSON 术语中是只有字符串键的哈希)和 "null"。
布尔值、null、字符串和数字的写法和 JSON 中相同。就像 jq 中的所有其他内容一样,这些简单值也接收输入并产生输出 -42
是一个有效的 jq 表达式,它接收输入,忽略它,并返回 42。
jq 中的数字内部由其 IEEE754 双精度近似值表示。对数字的任何算术运算,无论是字面量还是先前过滤器的结果,都会产生双精度浮点结果。
但是,在解析字面量 jq 会存储原始字面量字符串。如果没有对此值应用任何更改,则它将以原始形式输出,即使转换为双精度会导致损失。
数组构造:[]
与 JSON 类似,[]
用于构造数组,如[1,2,3]
。数组的元素可以是任何 jq 表达式,包括管道。所有表达式产生的所有结果都被收集到一个大数组中。你可以使用它来根据已知数量的值构造数组(如[.foo, .bar, .baz]
)或收集过滤器的所有结果到一个数组(如[.items[].name]
)
。一旦你理解了 "," 运算符,你就可以从不同的角度来看待 jq 的数组语法:表达式[1,2,3]
不是使用逗号分隔数组的内建语法,而是应用[]
运算符(收集结果)到表达式 1,2,3 (它会产生三个不同的结果)。
如果你有一个过滤器X
产生四个结果,那么表达式[X]
将产生一个结果,一个包含四个元素的数组。
对象构造:{}
与 JSON 类似,{}
用于构造对象(又名字典或哈希),如:{"a": 42, "b": 17}
.
如果键是 "标识符类似" 的,那么可以省略引号,像{a:42, b:17}
。变量引用作为键表达式使用变量的值作为键。除了常量字面量、标识符或变量引用的键表达式外,需要将它们括起来,例如,{("a"+"b"):59}
.
The value 可以是任何表达式(尽管你可能需要用括号将其括起来,例如,如果它包含冒号),它将应用于 {} 表达式的输入(记住,所有过滤器都有一个输入和输出)。
{foo: .bar}
将产生 JSON 对象{"foo": 42}
如果给定 JSON 对象{"bar":42, "baz":43}
作为输入。你可以使用它来选择对象的部分字段:如果输入是一个具有 "user"、"title"、"id" 和 "content" 字段的对象,并且你只需要 "user" 和 "title",你可以写
{user: .user, title: .title}
因为这非常常见,所以有一个快捷语法:{user, title}
.
如果表达式之一产生多个结果,将产生多个字典。如果输入的
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
,则表达式
{user, title: .titles[]}
将产生两个输出:
{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}
将键括起来意味着它将作为表达式进行评估。使用相同的输入,表达式
{(.user): .titles}
将字符串除以另一个字符串会使用第二个字符串作为分隔符分割第一个字符串。
{"stedolan": ["JQ Primer", "More JQ"]}
变量引用作为键使用变量的值作为键。如果没有值,则变量的名称成为键,其值成为值,
"f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo}
将字符串除以另一个字符串会使用第二个字符串作为分隔符分割第一个字符串。
{"foo":"f o o","b a r":"f o o"}
命令 | jq '{user, title: .titles[]}' |
---|---|
输入 | {"user":"stedolan","titles":["JQ Primer", "More JQ"]} |
输出 | {"user":"stedolan", "title": "JQ Primer"} |
{"user":"stedolan", "title": "More JQ"} | |
运行 |
命令 | jq '{(.user): .titles}' |
---|---|
输入 | {"user":"stedolan","titles":["JQ Primer", "More JQ"]} |
输出 | {"stedolan": ["JQ Primer", "More JQ"]} |
运行 |
递归下降:..
递归下降.
,产生每个值。这是与零参数recurse
内建函数相同。这是为了类似于 XPath//
运算符。注意..a
不工作;使用.. | .a
代替。在下面的示例中,我们使用.. | .a?
查找所有对象键的值.
.
这在与path(EXP)
(也见下文)和?
操作符一起使用时特别有用。
命令 | jq '.. | .a?' |
---|---|
输入 | [[{"a":1}]] |
输出 | 1 |
运行 |
内置操作符和函数
一些 jq 操作符(例如,+
)根据它们的参数类型(数组、数字等)执行不同的操作。然而,jq 从不执行隐式类型转换。如果你尝试将一个字符串添加到一个对象上,你会得到一条错误消息并且没有结果。
请注意,所有数字都转换为 IEEE754 双精度浮点表示。算术和逻辑操作符与这些转换后的双精度数一起工作。所有此类操作的结果也限制在双精度范围内。
数字行为的唯一例外是原始数字字面量的快照。当原始上作为字面量提供的数字直到程序结束都没有被修改时,它将以原始字面量形式打印到输出中。这也包括在转换为 IEEE754 双精度浮点数时原始字面量会被截断的情况。
加法:+
操作符+
接受两个过滤器,将它们都应用于相同的输入,并将结果相加在一起。"加" 的含义取决于所涉及的类型:
-
数字通过普通算术加法。
-
数组通过连接成一个更大的数组来加法。
-
字符串通过连接成一个更大的字符串来加法。
-
对象通过合并来加法,即插入两个对象的所有键值对到一个单一的组合对象中。如果两个对象都包含相同键的值,则右侧的对象会获胜。(对于递归合并使用
+
wins. (For recursive merge use the*
操作符。)
null
可以加到任何值,并返回其他值不变。
减法:-
除了数字的正常算术减法之外,还可以使用-
操作符在数组上移除第一数组中所有第二数组元素的实例。
乘法、除法、模运算:*
, /
, %
当给定两个数字时,这些中缀操作符按预期工作。除以零会引发错误。x % y
计算x模y。
将字符串乘以数字会产生该字符串重复指定次数的连接。"x" * 0
将字符串除以另一个字符串会使用第二个字符串作为分隔符分割第一个字符串。""
.
Dividing a string by another splits the first using the second as separators.
两个对象相乘会递归合并:这像加法一样工作,但如果两个对象都包含相同键的值,并且这些值是对象,则使用相同的策略合并它们。
abs
内置函数abs
被天真地定义为:if . < 0 then - . else . end
.
对于数值输入,这是绝对值。有关此定义对数值输入的影响,请参阅身份过滤器部分。
要将一个数字的绝对值计算为浮点数,您可能希望使用fabs
.
命令 | jq 'map(abs)' |
---|---|
输入 | [-10, -1.1, -1e-1] |
输出 | [10,1.1,1e-1] |
运行 |
length
内置函数length
获取各种不同类型值的长度:
-
数字的长度是它包含的 Unicode 代码点的数量(如果它是纯 ASCII,则等于其 JSON 编码的字节长度)。 is the number of Unicode codepoints it contains (which will be the same as its JSON-encoded length in bytes if it's pure ASCII).
-
数字的长度是其绝对值。 is its absolute value.
-
对象array,则输出
-
对象的长度是键值对的数量。 is the number of key-value pairs.
-
nullnull is zero.
-
在
length
上使用布尔值是错误的。.
命令 | jq '.[] | length' |
---|---|
输入 | [[1,2], "string", {"a":2}, null, -5] |
输出 | 2 |
6 | |
1 | |
0 | |
5 | |
运行 |
utf8bytelength
内置函数utf8bytelength
输出用于在 UTF-8 中编码字符串的字节数。
命令 | jq 'utf8bytelength' |
---|---|
输入 | "\u03bc" |
输出 | 2 |
运行 |
keys
, keys_unsorted
内置函数keys
,当给定一个对象时,它返回其键数组。
键按“字母顺序”排序,按 Unicode 代码点顺序排序。这不是任何特定语言中有特别意义的顺序,但您可以确信对于具有相同键集的任何两个对象,它都是相同的,而不管区域设置设置如何。
When keys
给定一个数组时,它返回该数组的有效索引:从 0 到 length-1 的整数。
元数据中的keys_unsorted
与keys
类似,但如果输入是对象,则键不会排序,相反,键将大致按插入顺序排列。
has(key)
内置函数has
返回输入对象是否具有给定键,或者输入数组是否在给定索引处有元素。
has($key)
与检查$key
是否是keys
返回的数组中的成员具有相同的效果,尽管has
会更快。
in
内置函数in
返回输入键是否在给定对象中,或者输入索引对应于给定数组中的元素。本质上,这是has
.
map(f)
, map_values(f)
对于任何过滤器f
, map(f)
和map_values(f)
将f
应用于输入数组或对象中的每个值,即.[]
.
的值,在错误不存在的情况下,map(f)
总是输出一个数组,而map_values(f)
如果给定的是数组,则输出数组;如果给定的是对象,则输出对象。
当map_values(f)
的输入是对象时,输出对象具有与输入对象相同的键,除了那些键的值在管道传递到f
时产生没有任何值的键。
betweenmap(f)
和map_values(f)
的主要区别在于($x|f)
的所有值形成数组,对于输入数组或对象中的每个值$x
,而map_values(f)
仅使用first($x|f)
.
Specifically, for object inputs,map_values(f)
通过依次检查输入对象的每个键first(.[$k]|f)
的值来构建输出对象。$k
如果此表达式不产生任何值,则相应的键将被删除;否则,输出对象将在键处具有该值,$k
.
这里有一些示例来阐明map
和map_values
应用于数组时的行为。这些示例假设输入在所有情况下都是[1]
:
map(.+1) #=> [2]
map(., .) #=> [1,1]
map(empty) #=> []
map_values(.+1) #=> [2]
map_values(., .) #=> [1]
map_values(empty) #=> []
map(f)
等同于[.[] | f]
和map_values(f)
等同于.[] |= f
.
实际上,这是它们的实现。
pick(pathexps)
输出输入对象或数组定义的投影,该投影由指定路径表达式序列定义,使得如果p
是这些规范中的任何一个,则(. | p)
将评估为与(. | pick(pathexps) | p)
相同的值。对于数组,不应使用负索引和.[m:n]
规范。
path(path_expression)
输出给定路径表达式.
中的数组表示形式。输出是字符串数组(对象键)和/或数字数组(数组索引)。
路径表达式是像.a
这样的 jq 表达式,但也是.[]
。有两种类型的路径表达式:可以完全匹配的和不能完全匹配的。例如,.a.b.c
是完全匹配的路径表达式,而.a[].b
不是。
path(exact_path_expression)
即使路径表达式在.
中不存在,也会产生路径表达式的数组表示,如果.
is null
或数组或对象。
path(pattern)
将产生与pattern
匹配的路径的数组表示,如果路径在.
.
中存在。注意,路径表达式与普通表达式没有区别。表达式path(..|select(type=="boolean"))
输出.
中所有到布尔值的路径,并且只有这些路径。
del(path_expression)
内置函数del
从对象中删除一个键及其对应的值。
getpath(PATHS)
内置函数getpath
输出在.
中每个路径处的值。ff7c0f: 示例PATHS
.
setpath(PATHS; VALUE)
内置函数setpath
将PATHS
中的.
到VALUE
.
delpaths(PATHS)
内置函数delpaths
删除PATHS
中的.
.
PATHS
必须是路径数组,其中每个路径都是字符串和数字的数组。
命令 | jq 'delpaths([["a","b"]])' |
---|---|
输入 | {"a":{"b":1},"x":{"y":2} |
输出 | {"a":{},"x":{"y":2}} |
运行 |
to_entries
, from_entries
, with_entries(f)
这些函数在对象和键值对数组之间进行转换。如果to_entries
接受一个对象,则对于输入中的每个k: v
条目,输出数组包括{"key": k, "value": v}
.
from_entries
,对于with_entries(f)
的每个值,输出数组包括to_entries | map(f) | from_entries
,对于from_entries
accepts "key"
, "Key"
, "name"
, "Name"
,
"value"
,和"Value"
的每个键。ff7c0f: 示例
select(boolean_expression)
函数select(f)
如果f
对于该输入返回 true,则输出其输入不变,否则不输出任何内容。
它在过滤列表时很有用:[1,2,3] | map(select(. >= 2))
将为您提供[2,3]
.
arrays
, objects
, iterables
, booleans
, numbers
, normals
, finites
, strings
, nulls
, values
, scalars
这些内置函数仅选择输入为数组、对象、可迭代(数组或对象)、布尔值、数字、普通数字、有限数字、字符串、null、非 null 值和非可迭代值。
命令 | jq '.[]|numbers' |
---|---|
输入 | [[],{},1,"foo",null,true,false] |
输出 | 1 |
运行 |
empty
empty
返回没有结果。完全没有任何。甚至null
.
它在某个时候很有用。如果您需要它,您就会知道。
error
, error(message)
使用输入值或作为参数给出的消息产生错误。错误可以用 try/catch 捕获;见下文。
halt
停止 jq 程序而不产生进一步输出。jq 将以退出状态0
.
halt_error
, halt_error(exit_code)
停止 jq 程序而不产生进一步输出。输入将作为原始输出打印在stderr
上(即字符串将没有双引号),没有任何装饰,甚至没有换行符。
给定的exit_code
(默认为5
)将是 jq 的退出状态。
例如,"Error: something went wrong\n"|halt_error(1)
.
$__loc__
产生一个具有 "file" 键和 "line" 键的对象,其值是$__loc__
发生时的文件名和行号。
命令 | jq 'try error("\($__loc__())" catch .' |
---|---|
输入 | null |
输出 | "{\"file\":\"<top-level>\",\"line\":1}" |
运行 |
paths
, paths(node_filter)
paths
输出其输入中所有元素的路径(除了它不输出表示
paths(f)
输出任何值f
is true
是paths(type == "number")
将输出所有数值的路径。
add
过滤器add
接受一个数组作为输入,并产生作为输出数组中元素的数组。这可能意味着求和、连接或合并,具体取决于输入数组元素的类型——这些规则与+
操作符(如上所述)的规则相同。
,则输出add
返回null
.
any
, any(condition)
, any(generator; condition)
过滤器any
接受一个嵌套数组数组作为输入,并产生一个扁平数组,其中原始数组中的所有嵌套数组都被递归地替换为它们的值。您可以传递一个参数来指定要扁平化的嵌套级别数。true
作为输出。如果输入是空数组,true
.
,则输出any
返回false
.
元数据中的any(condition)
形式应用于输入数组中的元素应用给定的条件。函数
元数据中的any(generator; condition)
形式应用于给定生成器的所有输出应用给定的条件。
all
, all(condition)
, all(generator; condition)
过滤器all
接受一个嵌套数组数组作为输入,并产生一个扁平数组,其中原始数组中的所有嵌套数组都被递归地替换为它们的值。您可以传递一个参数来指定要扁平化的嵌套级别数。true
作为输出。如果输入是空数组,true
.
元数据中的all(condition)
形式应用于输入数组中的元素应用给定的条件。函数
元数据中的all(generator; condition)
形式应用于给定生成器的所有输出应用给定的条件。
,则输出all
返回true
.
flatten
, flatten(depth)
过滤器flatten
接受一个嵌套数组数组作为输入,并产生一个扁平数组,其中原始数组中的所有嵌套数组都被递归地替换为它们的值。您可以传递一个参数来指定要扁平化的嵌套级别数。
flatten(2)
类似于flatten
类似,但只扁平化到两个级别深。
range(upto)
, range(from; upto)
, range(from; upto; by)
元数据中的range
生成一系列数字。range(4; 10)
生成 6 个数字,从 4(包含)到 10(不包含)。数字作为单独的输出生成。使用[range(4; 10)]
获取一个范围作为数组。
单参数形式生成从 0 到给定数字的数字,增量值为 1。
双参数形式生成从from
到upto
的数字,增量值为 1。
三参数形式生成from
到upto
的数字,增量值为by
.
floor
元数据中的floor
返回其数值输入的向下取整值。
命令 | jq 'floor' |
---|---|
输入 | 3.14159 |
输出 | 3 |
运行 |
sqrt
元数据中的sqrt
function returns the square root of its numeric input.
命令 | jq 'sqrt' |
---|---|
输入 | 9 |
输出 | 3 |
运行 |
tonumber
元数据中的tonumber
function parses its input as a number. It
will convert correctly-formatted strings to their numeric
equivalent, leave numbers alone, and give an error on all other input.
命令 | 将其输入解析为数字。它将正确格式化的字符串转换为它们的数值等效值,将数字保留不变,对所有其他输入给出错误。 |
---|---|
输入 | [1, "1"] |
输出 | 1 |
1 | |
运行 |
tostring
元数据中的tostring
function prints its input as a
string. Strings are left unchanged, and all other values are
JSON-encoded.
命令 | 将其输入打印为字符串。字符串保持不变,所有其他值都使用 JSON 编码。 |
---|---|
输入 | [1, "1", [1]] |
输出 | "1" |
"1" | |
"[1]" | |
运行 |
type
元数据中的type
返回其参数的类型作为字符串,它是 null、boolean、number、string、array 或 object 中的一个。
命令 | jq 'map(type)' |
---|---|
输入 | [0, false, [], {}, null, "hello"] |
输出 | ["number", "boolean", "array", "object", "null", "string"] |
运行 |
infinite
, nan
, isinfinite
, isnan
, isfinite
, isnormal
某些算术运算可能会产生无穷大和“不是数字”(NaN)值。内置函数isinfinite
如果其输入是 NaN,则返回true
。内置函数isnan
如果其输入是 NaN,则返回true
。内置函数infinite
返回一个正无穷大值。内置函数nan
返回一个 NaN。isnormal
内置函数返回 true 如果其输入是正常数字。
注意,除以零会引发错误。
目前大多数在无穷大、NaN 和次正规数上执行的算术运算都不会引发错误。
sort
, sort_by(path_expression)
元数据中的sort
对其输入进行排序,输入必须是数组。值按以下顺序排序:
null
false
true
- 数字
- 字符串,按字母顺序(按 unicode 代码点值)排序
- 数组,按词法顺序排序
- 对象
对象的排序顺序有点复杂:首先,它们通过比较它们的键集(按排序顺序的数组)进行比较,如果它们的键相等,则按键逐个比较值。
sort_by
可以用来按对象的特定字段排序,或应用任何 jq 过滤器。sort_by(f)
通过比较f
的结果来比较两个元素。当f
产生多个值时,它首先比较第一个值,如果第一个值相等,则比较第二个值,以此类推。
命令 | jq 'sort' |
---|---|
输入 | [8,3,null,6] |
输出 | [null,3,6,8] |
运行 |
命令 | jq 'sort_by(.foo)' |
---|---|
输入 | [{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1} |
输出 | [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10} |
运行 |
命令 | jq 'sort_by(.foo, .bar)' |
---|---|
输入 | [{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10} |
输出 | [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10} |
运行 |
group_by(path_expression)
group_by(.foo)
接受一个数组作为输入,将具有相同.foo
字段的元素分组到单独的数组中,并将所有这些数组作为更大的数组元素输出,按.foo
字段的值排序。可以替换
任何 jq 表达式,而不仅仅是字段访问,可以替换.foo
的任何 jq 表达式,而不仅仅是字段访问。排序顺序与上面描述的sort
函数相同。
命令 | jq 'group_by(.foo)' |
---|---|
输入 | [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1} |
输出 | [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}] |
运行 |
min
, max
, min_by(path_exp)
, max_by(path_exp)
Find the minimum or maximum element of the input array.
元数据中的min_by(path_exp)
和max_by(path_exp)
允许您指定要检查的特定字段或属性,例如min_by(.foo)
查找具有最小foo
字段的值排序。可以替换
unique
, unique_by(path_exp)
元数据中的unique
接受一个数组作为输入,并产生一个去重的数组,其中包含与每个值对应的相同元素。函数
元数据中的unique_by(path_exp)
将仅保留每个值获得的唯一值。将其视为从每个group
.
命令 | jq '.[] | tostring' |
---|---|
输入 | [1,2,5,3,5,3,1,3] |
输出 | [1,2,3,5] |
运行 |
命令 | jq 'unique_by(.foo)' |
---|---|
输入 | [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}] |
输出 | [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}] |
运行 |
命令 | jq 'unique_by(length)' |
---|---|
输入 | ["chunky", "bacon", "kitten", "cicada", "asparagus"] |
输出 | ["bacon", "chunky", "asparagus"] |
运行 |
reverse
函数
命令 | jq 'reverse' |
---|---|
输入 | [1,2,3,4] |
输出 | [4,3,2,1] |
运行 |
contains(element)
过滤器contains(b)
如果 b 完全包含在输入中,则输出 true。字符串 B 包含字符串 A 如果 B 是 A 的子字符串。数组 B 包含数组 A 如果 B 中的所有元素都包含 A 中的任何元素。对象 B 包含对象 A 如果 B 中的所有值都包含 A 中具有相同键的值。所有其他类型如果它们相等,则假定它们包含彼此。ff7c0f: 示例
命令 | jq 'contains("bar")' |
---|---|
输入 | "foobar" |
输出 | true |
运行 |
命令 | jq 'contains(["baz", "bar"])' |
---|---|
输入 | ["foobar", "foobaz", "blarp"] |
输出 | true |
运行 |
命令 | jq 'contains(["bazzzz", "bar"])' |
---|---|
输入 | ["foobar", "foobaz", "blarp"] |
输出 | false |
运行 |
命令 | jq 'contains({foo: 12, bar: [{barp: 12}])' |
---|---|
输入 | {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} |
输出 | true |
运行 |
命令 | jq 'contains({foo: 12, bar: [{barp: 15}])' |
---|---|
输入 | {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} |
输出 | false |
运行 |
indices(s)
函数.
其中s
occurs. The input may be an array, in which case if s
是数组,则输出索引将是.
中所有元素都匹配s
.
index(s)
, rindex(s)
函数index
本身)。rindex
)
occurrence of s
in the input.
命令 | jq 'rindex(", ")' |
---|---|
输入 | "a,b, cd, efg, hijk" |
输出 | 3 |
运行 |
命令 | jq 'rindex(1)' |
---|---|
输入 | [0,1,2,1,3,1,4] |
输出 | 1 |
运行 |
命令 | jq 'rindex([1,2])' |
---|---|
输入 | [0,1,2,3,1,4,2,5,1,2,6,7] |
输出 | 1 |
运行 |
命令 | jq 'rindex(", ")' |
---|---|
输入 | "a,b, cd, efg, hijk" |
输出 | 12 |
运行 |
命令 | jq 'rindex(1)' |
---|---|
输入 | [0,1,2,1,3,1,4] |
输出 | 5 |
运行 |
命令 | jq 'rindex([1,2])' |
---|---|
输入 | [0,1,2,3,1,4,2,5,1,2,6,7] |
输出 | 8 |
运行 |
inside
过滤器inside(b)
如果输入完全包含在 b 中,则将产生 true。它本质上是一个反转版本。contains
.
命令 | jq 'inside("foobar")' |
---|---|
输入 | "bar" |
输出 | true |
运行 |
命令 | jq 'inside(["foobar", "foobaz", "blarp"])' |
---|---|
输入 | ["baz", "bar"] |
输出 | true |
运行 |
命令 | jq 'inside(["foobar", "foobaz", "blarp"])' |
---|---|
输入 | ["bazzzzz", "bar"] |
输出 | false |
运行 |
命令 | jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' |
---|---|
输入 | {"foo": 12, "bar": [{"barp": 12}]} |
输出 | true |
运行 |
命令 | jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' |
---|---|
输入 | {"foo": 12, "bar": [{"barp": 15}]} |
输出 | false |
运行 |
startswith(str)
输出true
如果 . 以给定的字符串参数开头。
命令 | jq '[.[]|startswith("foo")]' |
---|---|
输入 | ["fo", "foo", "barfoo", "foobar", "barfoob"] |
输出 | [false, true, false, true, false] |
运行 |
endswith(str)
输出true
如果 . 以给定的字符串参数结尾。
命令 | jq '[.[]|endswith("foo")]' |
---|---|
输入 | ["foobar", "barfoo"] |
输出 | [false, true] |
运行 |
combinations
, combinations(n)
输出输入数组的元素的所有组合。如果给定参数n
,它将输出输入数组的所有组合n
重复。
ltrimstr(str)
输出其输入,如果它以给定的前缀字符串开头,则删除该前缀字符串。
命令 | jq '[.[]|ltrimstr("foo")]' |
---|---|
输入 | ["fo", "foo", "barfoo", "foobar", "afoo"] |
输出 | ["fo","","barfoo","bar","afoo"] |
运行 |
rtrimstr(str)
输出其输入,如果它以给定的后缀字符串结尾,则删除该后缀字符串。
命令 | jq '[.[]|rtrimstr("foo")]' |
---|---|
输入 | ["fo", "foo", "barfoo", "foobar", "foob"] |
输出 | ["fo","","bar","foobar","foob"] |
运行 |
explode
将输入字符串转换为字符串的码点数字数组。
命令 | jq 'explode' |
---|---|
输入 | "foobar" |
输出 | [102,111,111,98,97,114] |
运行 |
implode
explode 的逆。
命令 | jq 'implode' |
---|---|
输入 | [65, 66, 67] |
输出 | "ABC" |
运行 |
split(str)
将输入字符串按分隔符参数拆分。
split
当使用两个参数调用时,也可以根据正则表达式匹配进行拆分(见下文的正则表达式部分)。
命令 | jq 'split(", ")' |
---|---|
输入 | "a, b,c,d, e, " |
输出 | ["a","b,c,d","e",""] |
运行 |
join(str)
使用给定的参数作为分隔符连接输入的元素数组。它是split
的逆。对任何输入字符串运行split("foo") | join("foo")
都会返回该输入字符串。
输入中的数字和布尔值将转换为字符串。空值被视为空字符串。输入中的数组和对象不受支持。
ascii_downcase
, ascii_upcase
输出一个输入字符串的副本,将其字母字符(a-z 和 A-Z)转换为指定的案例。
命令 | jq 'ascii_upcase' |
---|---|
输入 | "useful but not for é" |
输出 | "USEFUL BUT NOT FOR é" |
运行 |
while(cond; update)
元数据中的while(cond; update)
function allows you to repeatedly
apply an update to .
直到cond
为假。
注意,a87502 内部定义为递归的 jq 函数。在while(cond; update)
is internally defined as a
recursive jq function. Recursive calls within while
内部的递归调用不会消耗额外的内存,如果update
对每个输入最多产生一个输出。请参阅高级主题部分。
命令 | jq '[while(.<100; .*2)]' |
---|---|
输入 | 1 |
输出 | [1,2,4,8,16,32,64] |
运行 |
repeat(exp)
元数据中的repeat(exp)
function allows you to repeatedly
apply expression exp
到.
直到引发错误。
注意,a87502 内部定义为递归的 jq 函数。在repeat(exp)
is internally defined as a
recursive jq function. Recursive calls within repeat
内部的递归调用不会消耗额外的内存,如果exp
对每个输入最多产生一个输出。请参阅高级主题部分。
命令 | jq '[repeat(.*2, error)?]' |
---|---|
输入 | 1 |
输出 | [2] |
运行 |
until(cond; next)
元数据中的until(cond; next)
function allows you to repeatedly
apply the expression next
,最初应用于.
,然后应用于它自己的输出,直到cond
为真。例如,这可以用来实现一个阶乘函数(见下文)。
注意,a87502 内部定义为递归的 jq 函数。在until(cond; next)
is internally defined as a
recursive jq function. Recursive calls within until()
内部的递归调用不会消耗额外的内存,如果next
对每个输入最多产生一个输出。请参阅高级主题部分。
命令 | jq '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' |
---|---|
输入 | 4 |
输出 | 24 |
运行 |
recurse(f)
, recurse
, recurse(f; condition)
元数据中的recurse(f)
function allows you to search through a
recursive structure, and extract interesting data from all
levels. Suppose your input represents a filesystem:
{"name": "/", "children": [
{"name": "/bin", "children": [
{"name": "/bin/ls", "children": []},
{"name": "/bin/sh", "children": []}]},
{"name": "/home", "children": [
{"name": "/home/stephen", "children": [
{"name": "/home/stephen/jq", "children": []}]}]}]}
现在假设您想提取所有出现的文件名。您需要检索.name
, .children[].name
,
.children[].children[].name
,等等。您可以用以下方式完成此操作:
recurse(.children[]) | .name
当不使用参数调用时,recurse
等同于recurse(.[]?)
.
recurse(f)
等同于recurse(f; true)
,并且可以在不考虑递归深度的情况下使用。
recurse(f; condition)
是一个生成器,它首先发出 .,然后依次发出 .|f、.|f|f、.|f|f|f,等等,只要计算值满足条件。例如,要生成所有整数,至少原则上,可以写recurse(.+1; true)
.
在recurse
中的递归调用不会消耗额外的内存,只要f
对每个输入最多产生一个输出。请参阅高级主题部分。
walk(f)
元数据中的walk(f)
递归地应用于输入实体的每个组件。当遇到数组时,首先将 f 应用于其元素,然后将其应用于数组本身;当遇到对象时,首先将 f 应用于所有值,然后将其应用于对象。在实践中,f 通常会测试其输入的类型,如下面的示例所示。第一个示例突出了在处理数组的数组元素之前处理数组本身的实用性。第二个示例显示了如何考虑更改输入中所有对象的键。
$JQ_BUILD_CONFIGURATION
这个内置绑定显示了 jq 可执行文件的构建配置。其值没有特定的格式,但可以预期它至少是./configure
命令行参数,并且将来可能会丰富,以包括用于构建工具的版本字符串。
注意,这可以在命令行中使用--arg
和相关选项覆盖。
$ENV
, env
$ENV
是一个表示环境变量的对象,这些变量是在 jq 程序启动时设置的。
env
输出一个表示 jq 当前环境的对象。
目前还没有内置函数来设置环境变量。
transpose
转置一个可能参差不齐的矩阵(一个数组的数组)。
命令 | jq 'transpose' |
---|---|
输入 | [[1], [2,3]] |
输出 | [[1,2],[null,3]] |
运行 |
bsearch(x)
bsearch(x)
在输入数组中搜索 x。如果输入已排序且包含 x,则bsearch(x)
将返回其在数组中的索引;否则,如果数组已排序,它将返回 (-1 - ix) ,其中 ix 是插入点,这样在 ix 处插入 x 后,数组仍然保持排序。如果数组未排序,0d40c4: 将返回一个整数,该整数可能没有兴趣。bsearch(x)
will return an integer that is probably of no
interest.
字符串插值:\(exp)
在字符串中,您可以在反斜杠后用括号括起来的表达式中放入一个表达式。表达式返回的内容将被插值到字符串中。
命令 | jq '"The input was \(.), which is one less than \(.+1)"' |
---|---|
输入 | 42 |
输出 | "The input was 42, which is one less than 43" |
运行 |
转换为/从 JSON
元数据中的tojson
和fromjson
分别将值作为 JSON 文本导出或解析 JSON 文本为值。函数tojson
与tostring
不同,因为tostring
返回未修改的字符串,而tojson
将字符串编码为 JSON 字符串。
格式化字符串和转义
元数据中的@foo
语法用于格式化和转义字符串,这对于构建 URL、语言(如 HTML 或 XML)中的文档等等非常有用。@foo
可以单独作为过滤器使用,可能的转义是:
@text
:
调用tostring
,参见该函数的详细信息。
@json
:
将输入序列化为 JSON。
@html
:
应用 HTML/XML 转义,通过将字符<>&'"
映射到它们的实体等效物<
, >
,
&
, '
, "
.
@uri
:
应用百分比编码,通过将所有保留的 URI%XX
序列。
@csv
:
输入必须是数组,它使用双引号对字符串进行分隔,并且通过重复来转义引号。
@tsv
:
输入必须是数组,它被渲染为 CSV0x09
). Input characters line-feed (ascii 0x0a
),
carriage-return (ascii 0x0d
), tab (ascii 0x09
) and
backslash (ascii 0x5c
) will be output as escape sequences
\n
, \r
, \t
, \\
respectively.
@sh
:
The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings.
@base64
:
输入是适合在 POSIX shell 的命令行中使用的转义。如果输入是数组,输出将是空格分隔的字符串序列。
@base64d
:
将输入转换为 base64,如 RFC 4648 所指定。@base64
的逆,输入按 RFC 4648 解码。注意:如果解码的字符串不是 UTF-16,则结果未定义。
这种语法可以与字符串插值以有用的方式组合。您可以跟随@foo
标记和一个字符串字面量。字符串字面量的内容not be
escaped. However, all interpolations made inside that string
literal will be escaped. For instance,
@uri "https://www.google.com/search?q=\(.search)"
将为输入{"search":"what is jq?"}
:
"https://www.google.com/search?q=what%20is%20jq%3F"
产生以下输出:
日期
jq 提供了一些基本日期处理功能,一些高级和低级内置函数。在所有情况下,这些内置函数都专门处理 UTC 中的时间。
元数据中的fromdateiso8601
将 ISO 8601 格式的 datetime 解析为自 Unix 纪元(1970-01-01T00:00:00Z)以来的秒数。函数todateiso8601
执行相反的操作。
元数据中的fromdate
解析 datetime 字符串。目前fromdate
仅支持 ISO 8601 datetime 字符串,但在将来它将尝试解析更多格式的 datetime 字符串。
元数据中的todate
是todateiso8601
.
元数据中的now
输出当前时间,以自 Unix 纪元以来的秒数。
低级 jq 接口也提供了到 C 库时间函数的接口:strptime
, strftime
, strflocaltime
,
mktime
, gmtime
,和localtime
。参考您的主操作系统文档中strptime
和strftime
使用的格式字符串。注意:这些不一定是 jq 中稳定的接口,特别是它们的本地化功能。
元数据中的gmtime
消耗自 Unix 纪元以来的秒数,并输出格林尼治标准时间(GMT)的“分解时间”表示,作为一个表示数字的数组:年份、月份(零基),月份中的天(一基),一天中的小时,一小时内的小时,一分钟内的小时,一分钟内的秒数,一周中的天,一年中的天——所有这些都以一基为基准,除非另有说明。周数可能对于某些系统在 1900 年 3 月 1 日之前的日期或 2099 年 12 月 31 日之后的日期是错误的。
元数据中的localtime
与gmtime
函数类似,但使用本地时区设置。
元数据中的mktime
消耗由gmtime
和strptime
.
元数据中的strptime(fmt)
解析匹配fmt
参数的输入字符串。输出是mktime
和gmtime
.
元数据中的strftime(fmt)
使用给定的格式格式化时间(GMT)。strflocaltime
类似,但使用本地时区设置。
be5d5d: 和strptime
和strftime
的格式字符串在典型的 C 库文档中描述。ISO 8601 datetime 的格式字符串是"%Y-%m-%dT%H:%M:%SZ"
.
jq 可能不支持某些系统上的一些或全部这些日期功能。特别是,%u
和%j
对于strptime(fmt)
的规范在 macOS 上不受支持。
SQL-Style Operators
jq 提供了一些 SQL 风格的运算符。
INDEX(stream; index_expression)
:
这个内置函数产生一个对象,其键由应用于每个值的给定索引表达式计算。
JOIN($idx; stream; idx_expr; join_expr)
:
这个内置函数将给定流中的值连接到给定的索引。索引的键由应用于给定流中每个值的给定索引表达式计算。一个值在流中和来自索引的相应值组成的数组被传递到给定的连接表达式以生成每个结果。
JOIN($idx; stream; idx_expr)
:
与JOIN($idx; stream; idx_expr; .)
.
JOIN($idx; idx_expr)
:
相同。.
to the given index, applying.
to compute the index key. The join operation is as described above.
IN(s)
:
This builtin outputstrue
相同,如果.
出现在给定的流中,否则它输出false
.
IN(source; s)
:
This builtin outputstrue
如果源流中的任何值出现在第二个流中,否则它输出false
.
builtins
返回一个列表,其中包含所有内置函数的名称,格式为name/arity
。由于具有相同名称但不同参数个数的函数被视为不同的函数,all/0
, all/1
,和all/2
都会出现在列表中。
条件和比较
==
, !=
表达式 'a == b' 如果评估 a 和 b 的结果相等(即,如果它们表示等效的 JSON 值)则将产生 'true' ,否则产生 'false' 。特别是,字符串永远不会被视为等于数字。在检查 JSON 对象的相等性时,键的顺序无关紧要。如果你来自 JavaScript,请注意 jq 的==
类似于 JavaScript 的===
,即“严格相等”运算符。
!= 是“不等于”,'a != b' 返回与 'a == b' 相反的值
if-then-else-end
if A then B else C end
将与B
相同,如果A
产生除 false 或 null 之外的值,但与C
相同,否则。c343c6: 与
if A then B end
is the same as if A then B else . end
相同。即,如果没有else
分支,则与.
相同。这也适用于elif
,如果没有else
分支。检查 false 或 null 是比 JavaScript 或 Python 中发现的“真值”更简单的概念,但这意味着您有时必须更明确地说明您想要的条件。您不能用
Checking for false or null is a simpler notion of
"truthiness" than is found in JavaScript or Python, but it
means that you'll sometimes have to be more explicit about
the condition you want. You can't test whether, e.g. a
string is empty using if .name then A else B end
测试字符串是否为空;您需要像if .name == "" then A else B end
代替。
If the condition A
产生多个结果,则B
将针对每个不是 false 或 null 的结果评估一次,并且C
将针对每个 false 或 null 评估一次。您可以使用
More cases can be added to an if using elif A then B
语法将更多情况添加到 if 中。
命令 | jq 'if . == 0 then |
---|---|
输入 | 2 |
输出 | "many" |
运行 |
>
, >=
, <=
, <
比较运算符>
, >=
, <=
, <
返回其左参数是否大于、大于或等于、小于或等于其右参数(分别)。相应的顺序与
The ordering is the same as that described for sort
中描述的相同。
命令 | jq '. < 5' |
---|---|
输入 | 2 |
输出 | true |
运行 |
and
, or
, not
jq 支持正常的布尔运算符and
, or
, not
。它们具有与 if 表达式相同的真值标准 -false
和null
被认为是“假值”,而
如果运算符的某个操作数产生多个结果,运算符本身将产生一个结果对于每个输入。f4f43d: 实际上是一个内置函数,而不是运算符,所以它可以作为过滤器调用,而不是像
not
is in fact a builtin function rather than an operator,
so it is called as a filter to which things can be piped
rather than with special syntax, as in .foo and .bar |
not
.
这样使用特殊语法。这些三个只产生true
和false
的值,所以只适用于真正的布尔运算,而不是常见的 Perl/Python/Ruby idiom of//
运算符下面。
替代运算符://
元数据中的//
产生其左边的所有值,这些值既不是false
也不是null
,或者,如果左边的值除了false
或null
,然后//
产生其右边的所有值。一个形式为
A filter of the form a // b
的过滤器产生a
的所有结果,这些结果既不是false
或null
。如果a
产生没有结果,或者没有结果,或者没有结果,则false
或null
,然后a
// b
产生b
.
的结果。这可用于提供默认值:.foo // 1
将评估为1
如果输入中没有.foo
元素。它类似于如何在 Python 中使用or
有时,'or' 形式的“或”与or
operator is reserved for strictly Boolean
operations).
Note: some_generator // defaults_here
is not the same
as some_generator | . // defaults_here
不同。后者将为所有非false
,非null
值提供默认值,而前者不会。优先级规则可能会使这令人困惑。例如,在false, 1 // 2
中,运算符//
is 1
,而不是false, 1
--false, 1 // 2
解析方式与false,
(1 // 2)
相同。在(false, null, 1) | . // 42
中,运算符//
is .
,它始终只产生一个值,而在(false, null, 1) // 42
中,运算符的左边是一个生成器,它生成三个值,并且由于它产生一个false
和null
,所以不会产生默认值。42
is not
produced.
try-catch
通过使用try EXP catch EXP
来捕获错误。第一个表达式被执行,如果它失败,则第二个表达式被执行,并带有错误消息。处理程序的输出,如果有的话,则作为如果它已经被输出的表达式输出。
元数据中的try EXP
使用empty
作为异常处理程序。
从控制结构中跳出
try/catch 的一个方便用法是跳出像reduce
, foreach
, while
这样的控制结构,等等。
例如:
# Repeat an expression until it raises "break" as an
# error, then stop repeating without re-raising the error.
# But if the error caught is not "break" then re-raise it.
try repeat(exp) catch if .=="break" then empty else error
jq 有一个命名词法标签的语法,用于“跳出”或“回到”(如果适用):
label $out | ... break $out ...
元数据中的break $label_name
将导致程序表现得好像最左边的 (到左边)label $label_name
生成的标签empty
.
一样。标签之间的关系是词法的:标签必须从 break 可见。break
and corresponding label
is lexical: the label has to be "visible" from the break.
要跳出reduce
,例如:
label $out | reduce .[] as $item (null; if .==false then break $out else ... end)
以下 jq 程序会产生语法错误:
break $out
因为没有可见的标签$out
。
错误抑制/可选运算符:?
元数据中的?
作为EXP?
使用,是try EXP
.
正则表达式
jq 使用Oniguruma 正则表达式库,与 PHP、TextMate、Sublime Text 等一样,因此这里的描述将侧重于 jq 的特定用法。
Oniguruma 支持多种正则表达式,因此重要的是要知道 jq 使用的是"Perl NG"(带有命名组的 Perl)6ef2cd: 风格。 flavor.
jq 正则表达式过滤器定义为可以使用以下模式之一:
STRING | FILTER(REGEX)
STRING | FILTER(REGEX; FLAGS)
STRING | FILTER([REGEX])
STRING | FILTER([REGEX, FLAGS])
其中:
- STRING, REGEX, and FLAGS 是 jq 字符串,受 jq 字符串插值的影响;
- REGEX, 在字符串插值后,应该是一个有效的正则表达式;
- FILTER 是
test
,match
, 或capture
,如上所述。
由于 REGEX 必须评估为 JSON 字符串,因此必须转义一些字符才能形成正则表达式。例如,表示空白字符的正则表达式\s
将写成"\\s"
.
。
g
- 全局搜索(找到所有匹配项,而不仅仅是第一个)i
- 不区分大小写的搜索m
- 多行模式 (.
将匹配换行符)n
- 忽略空匹配项p
- 同时启用 s 和 m 模式s
- 单行模式 (^
->\A
,$
->\Z
)l
- 找到最长可能的匹配项x
- 扩展正则表达式格式(忽略空白和注释)
要匹配空白字符,使用x
标志,例如\s
,例如
jq -n '"a b" | test("a\\sb"; "x")'
注意,某些标志也可以在 REGEX 中指定,例如
jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")'
evaluates to:true
, true
, false
, false
.
test(val)
, test(regex; flags)
. Likematch
, but does not return match objects, onlytrue
或false
for whether or not the regex matches the input.
match(val)
, match(regex; flags)
match输出每个匹配项的对象。匹配项具有以下字段:
offset
- UTF-8 代码点从输入开始的位置偏移量length
- UTF-8 代码点的匹配长度string
- 匹配的字符串captures
- 表示捕获组的对象数组。
捕获组对象具有以下字段:
offset
- UTF-8 代码点从输入开始的位置偏移量length
- UTF-8 代码点的捕获组长度string
- 捕获的字符串name
- 捕获组的名称(或null
如果它是未命名的)
未匹配任何内容的捕获组返回偏移量为 -1
命令 | jq 'match("(abc)+"; "g")' |
---|---|
输入 | "abc abc" |
输出 | {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]} |
{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]} | |
运行 |
命令 | jq 'match("foo")' |
---|---|
输入 | "foo bar foo" |
输出 | {"offset": 0, "length": 3, "string": "foo", "captures": []} |
运行 |
命令 | jq 'match(["foo", "ig"])' |
---|---|
输入 | "foo bar FOO" |
输出 | {"offset": 0, "length": 3, "string": "foo", "captures": []} |
{"offset": 8, "length": 3, "string": "FOO", "captures": []} | |
运行 |
命令 | jq 'match("foo (?<bar123>bar)? foo"; "ig")' |
---|---|
输入 | "foo bar foo foo foo" |
输出 | {"offset": 0, "length": 11, "string": "foo bar foo", "captures": [{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]} |
{"offset": 12, "length": 8, "string": "foo foo", "captures": [{"offset": -1, "length": 0, "string": null, "name": "bar123"}]} | |
运行 |
命令 | jq '[ match("."); "g")] | length' |
---|---|
输入 | "abc" |
输出 | 3 |
运行 |
capture(val)
, capture(regex; flags)
将命名的捕获组收集到一个 JSON 对象中,每个捕获组的名称作为键,匹配的字符串作为相应的值。
命令 | jq 'capture("(?<a>[a-z]+)-(?<n>[0-9]+)")' |
---|---|
输入 | "xyzzy-14" |
输出 | { "a": "xyzzy", "n": "14" } |
运行 |
scan(regex)
, scan(regex; flags)
发出一个输入的非重叠子字符串流,这些子字符串与根据任何指定的标志匹配的 regex 匹配。如果没有匹配,则流为空。为了捕获每个输入字符串的所有匹配项,使用 idiom[ expr ]
,例如[ scan(regex) ]
. 如果 regex 包含捕获组,则过滤器发出一个包含捕获字符串的数组流。
split(regex; flags)
将输入字符串在每个 regex 匹配处分割。
为了向后兼容性,当使用单个参数调用时,5cfe4c: 在字符串上分割,而不是在 regex 上。split
splits on a string, not a regex.
命令 | jq 'split(", *"; null)' |
---|---|
输入 | "ab,cd, ef" |
输出 | ["ab","cd","ef"] |
运行 |
splits(regex)
, splits(regex; flags)
这些提供与它们的split
对应项相同的结果,但作为流而不是数组。
命令 | jq 'splits(", *")' |
---|---|
输入 | "ab,cd, ef, gh" |
输出 | "ab" |
"cd" | |
"ef" | |
"gh" | |
运行 |
sub(regex; tostring)
, sub(regex; tostring; flags)
发出通过在输入字符串中替换 regex 的第一个匹配项来获得的字符串tostring
,之后进行插值。tostring
应该是一个 jq 字符串或这样的字符串流,每个字符串都可以包含对命名捕获组的引用。命名捕获组实际上被作为 JSON 对象(如capture
构建的)呈现给tostring
,因此对捕获的变量名为 "x" 的引用将采用以下形式:"\(.x)"
.
gsub(regex; tostring)
, gsub(regex; tostring; flags)
gsub
类似于sub
,但所有非重叠的 regex 出现都被替换为tostring
,之后进行插值。如果第二个参数是 jq 字符串流,那么gsub
将产生相应的 JSON 字符串流。
高级功能
变量是在大多数编程语言中绝对必要的,但在 jq 中被降级为“高级功能”。
在大多数语言中,变量是传递数据的唯一方式。如果你计算一个值,并且你想多次使用它,你需要将它存储在变量中。要将一个值传递到程序的另一部分,你需要那部分程序定义一个变量(作为函数参数、对象成员或任何其他内容)来放置数据。
也可以在 jq 中定义函数,尽管这特征最大的用途是定义 jq 的标准库(许多 jq 函数,例如map
和select
实际上是用 jq 编写的)。
jq 有归约运算符,它们非常强大但有点棘手。同样,这些主要在内部使用,以定义一些有用的 jq 标准库组件。
可能不会一开始就明显,但 jq 是关于生成器的(是的,就像在其他语言中经常找到的那样)。提供了一些工具来帮助处理生成器。
提供了一些最小的 I/O 支持(除了从标准输入读取 JSON 和向标准输出写入 JSON)。
最后,有一个模块/库系统。
变量/符号绑定运算符:... as $identifier | ...
在 jq 中,所有过滤器都有一个输入和一个输出,因此无需手动连接来传递一个值从程序的这一部分到下一部分。许多表达式,例如a + b
,将它们的输入传递给两个不同的子表达式(在这里a
和b
都传递了相同的输入),因此通常不需要变量来两次使用一个值。
例如,计算数组中数字的平均值需要大多数语言中的几个变量 - 至少一个来保存数组,也许一个用于每个元素或用于循环计数器。在 jq 中,它很简单add / length
- 表达式是给数组并产生它的和,表达式是给数组并产生它的长度。add
expression is given the array and
produces its sum, and the length
expression is given the array and
produces its length.
因此,通常比定义变量更干净的方式来在 jq 中解决大多数问题。尽管有时它们确实使事情变得更容易,所以 jq 允许你使用expression as $variable
定义变量。所有变量名都以$
开头。这是一个稍微丑陋的数组平均示例:
length as $array_length | add / $array_length
我们需要更复杂的问题才能找到一个使用变量实际上使我们的生活更容易的情况。
假设我们有一个博客文章的数组,其中包含“author”和“title”字段,以及另一个映射作者用户名到真实姓名的对象。我们的输入看起来像:
{"posts": [{"title": "First post", "author": "anon"},
{"title": "A well-written article", "author": "person1"}],
"realnames": {"anon": "Anonymous Coward",
"person1": "Person McPherson"}}
我们想要生成包含真实姓名的作者字段的帖子,如下所示:
{"title": "First post", "author": "Anonymous Coward"}
{"title": "A well-written article", "author": "Person McPherson"}
我们使用一个变量,$names
,来存储真实姓名对象,这样我们就可以在查找作者用户名时稍后引用它:
.realnames as $names | .posts[] | {title, author: $names[.author]}
表达式exp as $x | ...
的意思是:对于表达式exp
的每个值,运行其余的管道,使用整个原始输入,并将$x
设置为该值。因此as
充当某种形式的
正如{foo}
也是编写{foo: .foo}
的方便方式一样,所以{$foo}
也是编写{foo: $foo}
.
的方便方式。as
表达式通过提供匹配输入结构的模式来声明多个变量(这被称为“解构”):
. as {realnames: $names, posts: [$first, $second]} | ...
数组模式中的变量声明(例如,. as
[$first, $second]
)绑定到数组的元素,从索引零开始,按顺序。当数组模式元素的索引处没有值时,null
被绑定到该变量。
变量在其定义的其余表达式中作用域内,所以
.realnames as $names | (.posts[] | {title, author: $names[.author]})
将起作用,但
(.realnames as $names | .posts[]) | {title, author: $names[.author]}
不会。
对于编程语言理论家来说,更准确的说法是 jq 变量是词法作用域绑定。特别是没有办法改变绑定值;只能设置具有相同名称的新绑定,但这个新绑定在原来的位置是不可见的。
命令 | jq '.bar as $x | .foo | . + $x' |
---|---|
输入 | {"foo":10, "bar":200} |
输出 | 210 |
运行 |
命令 | jq '. as $i|[(.*2|. as $i| $i), $i]' |
---|---|
输入 | 5 |
输出 | [10,5] |
运行 |
命令 | jq '. as [$a, $b, {c: $c}] | $a + $b + $c' |
---|---|
输入 | [2, 3, {"c": 4, "d": 5}] |
输出 | 9 |
运行 |
命令 | jq '.[] as [$a, $b] | {a: $a, b: $b}' |
---|---|
输入 | [[0], [0, 1], [2, 1, 0]] |
输出 | {"a":0,"b":null} |
{"a":0,"b":1} | |
{"a":2,"b":1} | |
运行 |
解构替代运算符:?//
解构替代运算符提供了一种简洁的机制来解构可以采取几种形式的输入。
假设我们有一个返回与它们关联的资源列表和事件的 API,我们想要为每个资源获取第一个事件的 user_id 和 timestamp。API(已经从 XML 拼凑起来)只有在资源有多个事件时才会将事件包装在数组中:
{"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}},
{"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]}
我们可以使用解构替代运算符来简单地处理这种结构变化:
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts}
或者,如果我们不确定输入是值的数组还是对象:
.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ...
每个替代不必定义所有相同的变量,但所有命名的变量都将可用于后续表达式。在替代中未匹配的变量将被null
:
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts}
此外,如果后续表达式返回错误,则替代运算符将尝试尝试下一个绑定。在最后替代期间发生的错误将传递通过。
[[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end
命令 | jq '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' |
---|---|
输入 | [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] |
输出 | {"a":1,"b":2,"d":3,"e":4} |
{"a":1,"b":2,"d":3,"e":4} | |
运行 |
命令 | jq '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' |
---|---|
输入 | [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] |
输出 | {"a":1,"b":2,"d":3,"e":null} |
{"a":1,"b":2,"d":null,"e":4} | |
运行 |
命令 | jq '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' |
---|---|
输入 | [[3]] |
输出 | {"a":null,"b":3} |
运行 |
递归
You can give a filter a name using "def" syntax:
def increment: . + 1;
From then on, increment
is usable as a filter just like a
builtin function (in fact, this is how many of the builtins
are defined). A function may take arguments:
def map(f): [.[] | f];
Arguments are passed as filters (functions with no
arguments), not as values. The same argument may be
referenced multiple times with different inputs (here f
is
run for each element of the input array). Arguments to a
function work more like callbacks than like value arguments.
This is important to understand. Consider:
def foo(f): f|f;
5|foo(.*2)
The result will be 20 because f
is .*2
, and during the
first invocation of f
.
will be 5, and the second time it
will be 10 (5 * 2), so the result will be 20. Function
arguments are filters, and filters expect an input when
invoked.
If you want the value-argument behaviour for defining simple functions, you can just use a variable:
def addvalue(f): f as $f | map(. + $f);
Or use the short-hand:
def addvalue($f): ...;
With either definition, addvalue(.foo)
will add the current
input's .foo
field to each element of the array. Do note
that calling addvalue(.[])
will cause the map(. + $f)
part
to be evaluated once per value in the value of .
at the call
site.
Multiple definitions using the same function name are allowed. Each re-definition replaces the previous one for the same number of function arguments, but only for references from functions (or main program) subsequent to the re-definition. See also the section below on scoping.
Scoping
There are two types of symbols in jq: value bindings (a.k.a., "variables"), and functions. Both are scoped lexically, with expressions being able to refer only to symbols that have been defined "to the left" of them. The only exception to this rule is that functions can refer to themselves so as to be able to create recursive functions.
For example, in the following expression there is a binding
which is visible "to the right" of it, ... | .*3 as
$times_three | [. + $times_three] | ...
, but not "to the
left". Consider this expression now, ... | (.*3 as
$times_three | [. + $times_three]) | ...
: here the binding
$times_three
is not visible past the closing parenthesis.
isempty(exp)
Returns true if exp
produces no outputs, false otherwise.
limit(n; exp)
元数据中的limit
function extracts up to n
outputs from exp
.
命令 | jq '[limit(3;.[])]' |
---|---|
输入 | [0,1,2,3,4,5,6,7,8,9] |
输出 | [0,1,2] |
运行 |
first(expr)
, last(expr)
, nth(n; expr)
元数据中的first(expr)
和last(expr)
functions extract the first
and last values from expr
, respectively.
元数据中的nth(n; expr)
function extracts the nth value output by expr
.
Note that nth(n; expr)
doesn't support negative values of n
.
命令 | jq '[first(range(.)), last(range(.)), nth(./2; range(.))]' |
---|---|
输入 | 10 |
输出 | [0,9,5] |
运行 |
first
, last
, nth(n)
元数据中的first
和last
functions extract the first
and last values from any array at .
.
元数据中的nth(n)
function extracts the nth value of any array at .
.
命令 | jq '[range(.)]|[first, last, nth(5)]' |
---|---|
输入 | 10 |
输出 | [0,9,5] |
运行 |
reduce
元数据中的reduce
syntax allows you to combine all of the results of
an expression by accumulating them into a single answer.
The form is reduce EXP as $var (INIT; UPDATE)
.
As an example, we'll pass [1,2,3]
to this expression:
reduce .[] as $item (0; . + $item)
For each result that .[]
produces, . + $item
is run to
accumulate a running total, starting from 0 as the input value.
In this example, .[]
produces the results 1
, 2
,和3
,
so the effect is similar to running something like this:
0 | 1 as $item | . + $item |
2 as $item | . + $item |
3 as $item | . + $item
foreach
元数据中的foreach
syntax is similar to reduce
, but intended to
allow the construction of limit
and reducers that produce
intermediate results.
The form is foreach EXP as $var (INIT; UPDATE; EXTRACT)
.
As an example, we'll pass [1,2,3]
to this expression:
foreach .[] as $item (0; . + $item; [$item, . * 2])
Like the reduce
syntax, . + $item
is run for each result
that .[]
produces, but [$item, . * 2]
is run for each
intermediate values. In this example, since the intermediate
values are 1
, 3
,和6
, the foreach
expression produces
[1,2]
, [2,6]
,和[3,12]
. So the effect is similar
to running something like this:
0 | 1 as $item | . + $item | [$item, . * 2],
2 as $item | . + $item | [$item, . * 2],
3 as $item | . + $item | [$item, . * 2]
When EXTRACT
is omitted, the identity filter is used.
That is, it outputs the intermediate values as they are.
命令 | jq 'foreach .[] as $item (0; . + $item)' |
---|---|
输入 | [1,2,3,4,5] |
输出 | 1 |
3 | |
6 | |
10 | |
15 | |
运行 |
命令 | jq 'foreach .[] as $item (0; . + $item; [$item, . * 2])' |
---|---|
输入 | [1,2,3,4,5] |
输出 | [1,2] |
[2,6] | |
[3,12] | |
[4,20] | |
[5,30] | |
运行 |
命令 | jq 'foreach .[] as $item (0; . + 1; {index: ., $item})' |
---|---|
输入 | ["foo", "bar", "baz"] |
输出 | {"index":1,"item":"foo"} |
{"index":2,"item":"bar"} | |
{"index":3,"item":"baz"} | |
运行 |
Recursion
如上所述,recurse
使用递归,任何 jq 函数都可以是递归的。内置的while
也是用递归实现的。
当递归调用左侧的表达式输出其最后一个值时,会优化尾调用。在实践中,这意味着递归调用左侧的表达式不应为每个输入产生超过一个输出。
例如:
def recurse(f): def r: ., (f | select(. != null) | r); r;
def while(cond; update):
def _while:
if cond then ., (update | _while) else empty end;
_while;
def repeat(exp):
def _repeat:
exp, _repeat;
_repeat;
生成器和迭代器
一些 jq 运算符和函数实际上是生成器,因为它们可以为每个输入产生零个、一个或多个值,就像在其他有生成器的编程语言中可以预期的那样。例如,.[]
生成其输入中的所有值(输入必须是数组或对象),range(0; 10)
生成 0 到 10 之间的整数,等等。
即使逗号运算符也是一个生成器,它首先生成逗号左侧表达式生成的值,然后生成逗号右侧表达式生成的值。
元数据中的empty
生成器产生零个输出。内置的empty
生成器回溯到前面的生成器表达式。
所有 jq 函数都可以通过使用内置生成器来成为生成器。使用递归和逗号运算符也可以构造新的生成器。如果递归调用位于“尾位置”,则生成器将是高效的。在下面的示例中,_range
对自身的递归调用位于尾位置。示例展示了三个高级主题:尾递归、生成器构造和子函数。
命令 | jq 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 16 and . > upto)); range(0; 10; 3)' |
---|---|
输入 | null |
输出 | 0 |
3 | |
6 | |
9 | |
运行 |
命令 | jq 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' |
---|---|
输入 | 1 |
输出 | [1,2,4,8,16,32,64] |
运行 |
数学
jq 目前只支持 IEEE754 双精度(64 位)浮点数。
除了简单的算术运算符,如+
,jq 还具有来自 C 数学库的大多数标准数学函数。接受单个输入参数的 C 数学函数(例如,sin()
)作为零参数 jq 函数可用。接受两个输入参数的 C 数学函数(例如,pow()
)作为两个参数的 jq 函数,忽略.
。接受三个输入参数的 C 数学函数作为三个参数的 jq 函数,忽略.
.
标准数学函数的可用性取决于您的操作系统和 C 数学库中相应数学函数的可用性。不可用的数学函数将被定义,但会引发错误。
单输入 C 数学函数:acos
acosh
asin
asinh
atan
atanh
cbrt
ceil
cos
cosh
erf
erfc
exp
exp10
exp2
expm1
fabs
floor
gamma
j0
j1
lgamma
log
log10
log1p
log2
logb
nearbyint
pow10
rint
round
significand
sin
sinh
sqrt
tan
tanh
tgamma
trunc
y0
y1
.
双输入 C 数学函数:atan2
copysign
drem
fdim
fmax
fmin
fmod
frexp
hypot
jn
ldexp
modf
nextafter
nexttoward
pow
remainder
scalb
scalbln
yn
.
三输入 C 数学函数:fma
.
请参考您的系统手册以获取有关这些的更多信息。
I/O
目前 jq 对 I/O 的支持是最小的,主要是在读取输入时控制何时读取。提供了两个内置函数用于此,input
和inputs
,它们从与 jq 本身相同的来源(例如,stdin
,命令行上指定的文件)读取。这两个内置函数和 jq 自己的读取操作可以相互交错使用。它们通常与空输入选项-n
结合使用,以防止隐式读取一个输入。
两个内置函数提供最小的输出功能,debug
,和stderr
。(回想一下,jq 程序的输出值始终作为 JSON 文本输出在stdout
。)内置的debug
可以具有特定于应用程序的行为,例如对于使用 libjq C API 但不是 jq 可执行文件的执行文件。内置的stderr
将其输入以原始模式输出到 stder,没有任何额外的装饰,甚至没有换行符。
大多数 jq 内置函数是参考透明的,并且在应用于常量输入时产生常量和可重复的值流。这不是 I/O 内置函数的情况。
input
输出一个新输入。
注意,当使用input
时,通常需要使用命令行选项-n
调用 jq,否则第一个实体将被丢失。
echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4]
inputs
输出所有剩余输入,一次一个。
这主要用于对程序的输入进行归约。注意,当使用inputs
时,通常需要使用命令行选项-n
调用 jq,否则第一个实体将被丢失。
echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6
debug
, debug(msgs)
这两个过滤器类似于.
,但副作用是生成一个或多个消息到 stderr。
由debug
过滤器产生消息的形式
["DEBUG:",<input-value>]
其中<input-value>
是输入值的紧凑表示。这种格式将来可能会改变。
元数据中的debug(msgs)
过滤器定义为(msgs | debug | empty), .
,从而允许消息内容的高度灵活性,同时允许创建多行调试语句。
例如,表达式:
1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1)
会产生值 3,但以下两行将被写入 stderr:
["DEBUG:","Entering function foo with $x == 1"]
["DEBUG:",2]
stderr
打印其输入以原始和紧凑模式到 stderr,没有任何额外的装饰,甚至没有换行符。
input_filename
返回当前正在过滤的输入的文件名。注意,除非 jq 在 UTF-8 地区运行,否则这不会很好地工作。
input_line_number
返回当前正在过滤的输入的行号。
流式传输
使用--stream
选项 jq 可以流式解析输入文本,允许 jq 程序立即开始处理大型 JSON 文本,而不是解析完成后。如果你有一个单个 JSON 文本,大小为 1GB,流式传输它将允许你更快地处理它。
但是,流式处理并不容易处理,因为 jq 程序将具有[<path>, <leaf-value>]
(和其他几种形式)作为输入。
提供了几个内置函数来简化流处理。
以下示例使用["a",["b"]]
的流式形式,它是[[0],"a"],[[1,0],"b"],[[1,0]],[[1]]
.
流式形式包括[<path>, <leaf-value>]
(表示任何标量值、空数组或空对象),和[<path>]
(表示数组或对象的结束)。未来版本的 jq 运行时使用--stream
和--seq
可能会输出额外的形式["error message"]
当输入文本无法解析时。
truncate_stream(stream_expression)
消耗一个数字作为输入,并从给定流式表达式的输出的左侧截断相应数量的路径元素。
命令 | jq 'truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]])' |
---|---|
输入 | 1 |
输出 | [[0],"b"] |
[[0]] | |
运行 |
fromstream(stream_expression)
输出与流表达式输出的值对应的值。
命令 | jq 'fromstream(1|truncate_stream([[0],"a"],[[1,0],"b"],[[1,0]],[[1]]))' |
---|---|
输入 | null |
输出 | ["b"] |
运行 |
tostream
元数据中的tostream
输出其输入的流式形式。
命令 | jq '. as $dot|fromstream($dot|tostream)|.==$dot' |
---|---|
输入 | [0,[1,{"a":1},{"b":2}]] |
输出 | true |
运行 |
赋值
赋值在jq中的工作方式与大多数编程语言略有不同。jq不区分对某个对象的引用和副本——两个对象或数组要么相等,要么不相等,没有进一步的概念来判断它们是否是“同一个对象”或“不是同一个对象”。
如果一个对象有两个字段,它们都是数组,.foo
和.bar
,并且你向.foo
,然后.bar
不会变大,即使你之前设置了.bar = .foo
。如果你熟悉Python、Java、Ruby、JavaScript等语言的编程,那么你可以认为在jq执行赋值之前,它会复制每个对象(为了性能,它实际上并没有这样做,但这只是一个大致的概念)。
这意味着在jq中不可能构建循环值(例如,一个其第一个元素是它自己的数组)。这非常有意,并确保jq程序可以生成的任何内容都可以用JSON表示。
jq中的所有赋值运算符都在左侧(LHS)有路径表达式。右侧(RHS)提供要设置为LHS路径表达式命名的路径的值。
jq中的值总是不可变的。内部,赋值通过使用归约来计算已对所有所需赋值应用过的.
的新替换值,然后输出修改后的值。这个例子可以清楚地说明这一点:.
, then
outputting the modified value. This might be made clear by this
example: {a:{b:{c:1}}} | (.a.b|=3), .
. 这将输出{"a":{"b":3}}
和{"a":{"b":{"c":1}}}
,因为最后一个子表达式,.
,看到的是原始值,而不是修改后的值。
大多数用户希望使用修改赋值运算符,例如|=
或+=
,而不是=
.
注意,赋值运算符的左侧引用的是.
中的值。因此$var.foo = 1
不会按预期工作($var.foo
在.
中不是一个有效或有用的路径表达式);使用$var | .foo =
1
代替。
注意,e08c57: 不会设置.a,.b=0
does not set .a
和.b
,但(.a,.b)=0
会设置这两个。
更新赋值:|=
这是“更新”运算符|=
。它接受右侧的过滤器,并通过运行旧值通过这个表达式来计算被赋值给.
的属性的新值。例如,(.foo, .bar) |= .+1
将构建一个foo
字段设置为输入的foo
加1,以及bar
字段设置为输入的bar
加1的对象。
左侧可以是任何一般的路径表达式;参见path()
.
注意,b64df5: 的左侧引用的是|=
refers to a value in .
中的值。因此$var.foo |= . + 1
不会按预期工作($var.foo
在.
中不是一个有效或有用的路径表达式);使用$var |
.foo |= . + 1
代替。
如果右侧输出没有值(即,empty
),那么左侧路径将被删除,就像del(path)
.
如果右侧输出多个值,则只使用第一个(兼容性说明:在jq 1.5及更早版本中,它曾经是使用最后一个)。
命令 | jq '(..|select(type=="boolean")) |= if . then 1 else 0 end' |
---|---|
输入 | [true,false,[5,true,[true,[false]],false]] |
输出 | [1,0,[5,1,[1,[0]],0]] |
运行 |
算术更新赋值:+=
, -=
, *=
, /=
, %=
, //=
jq有几个形式的运算符a op= b
,它们都等效于a |= . op b
。所以,+= 1
可以用来增加值,与|= . + 1
.
命令 | jq '.foo += 1' |
---|---|
输入 | {"foo": 42} |
输出 | {"foo": 43} |
运行 |
简单赋值:=
这是简单的赋值运算符。与其他运算符不同,右侧(RHS)的输入与左侧(LHS)的输入相同,而不是LHS路径处的值,并且RHS输出的所有值都将被使用(如下所示)。
如果=
的右侧产生多个值,那么对于每个这样的值,jq将把左侧的路径设置为该值,然后它会输出修改后的.
。例如,(.a,.b) = range(2)
输出{"a":0,"b":0}
,然后{"a":1,"b":1}
。更新赋值形式(见上文)不这样做。
这个示例应该显示=
和|=
:
之间的区别。向{"a": {"b": 10}, "b": 20}
前者将输入的
.a = .b
和
.a |= .b
提供输入a
字段设置为b
字段,并产生输出{"a": 20, "b": 20}
。后者将输入的a
字段设置为a
字段的b
字段,产生{"a": 10, "b": 20}
.
复杂赋值
jq赋值左侧允许比大多数语言更多的事情。我们已经看到了左侧的简单字段访问,并且数组访问也同样有效:
.posts[0].title = "JQ Manual"
可能令人惊讶的是,左侧的表达式可能产生多个结果,引用输入文档中的不同位置:
.posts[].comments |= . + ["this is great"]
该示例将字符串"this is great"附加到输入中每个帖子的"comments"数组(其中输入是一个具有"posts"字段的字段,该字段是一个帖子数组)。
当jq遇到像'a = b'这样的赋值时,它在执行a时记录选择输入文档部分所采取的"路径"。然后,这个路径用于在执行赋值时找到要更改的输入部分。任何过滤器都可以用于等于运算符的左侧;无论它从输入中选择哪些路径,都会在那里执行赋值。
这是一个非常强大的操作。假设我们想要向博客帖子添加评论,使用上面相同的"blog"输入。这次,我们只想评论"stedolan"写的帖子。我们可以使用前面描述的"select"函数来找到这些帖子:
.posts[] | select(.author == "stedolan")
该操作提供的路径指向"stedolan"写的每个帖子,我们可以像之前一样对它们进行评论:
(.posts[] | select(.author == "stedolan") | .comments) |=
. + ["terrible."]
jq有一个库/模块系统。模块是文件名以
jq has a library/module system. Modules are files whose names end
in .jq
.
结尾的文件。程序导入的模块在默认搜索路径中搜索(见下文)。"import
和include
directives allow the
importer to alter this path.
搜索路径中的路径会根据各种替换进行操作。
对于以~/
, the user's home directory is
substituted for ~
.
对于以$ORIGIN/
, the directory where the jq
executable is located is substituted for $ORIGIN
.
对于以./
or paths that are .
, the path of
the including file is substituted for .
. For top-level programs
given on the command-line, the current directory is used.
导入指令可以可选地指定要追加到默认路径的搜索路径。
默认搜索路径是传递给-L
command-line option, else ["~/.jq", "$ORIGIN/../lib/jq",
"$ORIGIN/../lib"]
.
Null and empty string path elements terminate search path processing.
具有相对路径的依赖项foo/bar
would be searched for in
foo/bar.jq
和foo/bar/bar.jq
in the given search path. This
is intended to allow modules to be placed in a directory along
with, for example, version control files, README files, and so on,
but also to allow for single-file modules.
具有相同名称的连续组件是不允许的,以避免歧义(例如,foo/foo
).
例如,使用-L$HOME/.jq
a module foo
can be found in
$HOME/.jq/foo.jq
和$HOME/.jq/foo/foo.jq
.
If $HOME/.jq
is a file, it is sourced into the main program.
import RelativePathString as NAME [<metadata>];
从搜索路径中的目录相对于给定路径导入模块。将.jq
suffix will be added to
the relative path string. The module's symbols are prefixed
with NAME::
.
可选的元数据必须是一个常量jq表达式。它应该是一个具有homepage
and so on. At
this time jq only uses the search
key/value of the metadata.
The metadata is also made available to users via the
modulemeta
builtin.
元数据中的search
key in the metadata, if present, should have a
string or array value (array of strings); this is the search
path to be prefixed to the top-level search path.
include RelativePathString [<metadata>];
从搜索路径中的目录相对于给定路径导入模块,就像它被直接包含一样。将.jq
suffix will be added to the relative path string. The
module's symbols are imported into the caller's namespace as
if the module's content had been included directly.
可选的元数据必须是一个常量jq表达式。它应该是一个具有homepage
and so on. At
this time jq only uses the search
key/value of the metadata.
The metadata is also made available to users via the
modulemeta
builtin.
import RelativePathString as $NAME [<metadata>];
从搜索路径中的目录相对于给定路径导入JSON文件。将.json
suffix will be added to
the relative path string. The file's data will be available
as $NAME::NAME
.
可选的元数据必须是一个常量jq表达式。它应该是一个具有homepage
and so on. At
this time jq only uses the search
key/value of the metadata.
The metadata is also made available to users via the
modulemeta
builtin.
元数据中的search
key in the metadata, if present, should have a
string or array value (array of strings); this is the search
path to be prefixed to the top-level search path.
module <metadata>;
此指令完全是可选的。它不是正常运行所必需的。它只用于提供可以通过modulemeta
builtin.
元数据必须是一个常量jq表达式。它应该是一个具有homepage
. At this time jq doesn't
use this metadata, but it is made available to users via the
modulemeta
builtin.
modulemeta
接收模块名称作为输入,并输出模块的元数据作为对象,模块的导入(包括元数据)作为deps
key and the module's defined
functions as an array value for the defs
key.
程序可以使用此功能查询模块的元数据,然后可以使用这些元数据来搜索、下载和安装缺失的依赖项。
颜色
要配置替代颜色,只需将JQ_COLORS
environment variable to colon-delimited list of partial terminal
escape sequences like "1;31"
, in this order:
- 数组颜色
null
- 数组颜色
false
- 数组颜色
true
- color for numbers
- color for strings
- color for arrays
- 对象颜色
- 对象键颜色
默认颜色方案与设置JQ_COLORS="0;90:0;37:0;37:0;37:0;32:1;37:1;37:1;34"
.
This is not a manual for VT100/ANSI escapes. However, each of these color specifications should consist of two numbers separated by a semi-colon, where the first number is one of these:
- 1(亮)
- 2(暗)
- 4(下划线)
- 5(闪烁)
- 7(反转)
- 8(隐藏)
以及第二个是这些中的一个:
- 30(黑色)
- 31(红色)
- 32(绿色)
- 33(黄色)
- 34(蓝色)
- 35(洋红色)
- 36(青色)
- 37(白色)