1. 为什么需要 jq

想象一下你用 curl 请求一个 API,返回了 500 行的 JSON 数据,但你只想要其中一个字段的值。jq 就是用来解决这个问题的。

核心功能:


2. 安装


3. 基础使用与示例数据

jq 通过“过滤器”(filter)表达式来工作。它从 stdin(标准输入)读取 JSON 数据,应用过滤器,然后将结果输出到 stdout(标准输出)。

基本语法:

示例数据 (users.json)在本教程中,我们将使用以下 users.json 文件:


4. 级别一:基础访问与过滤

4.1. 美化与查看 (Identity Filter: .)

'.' 过滤器表示“整个输入”。这是 jq 最简单的用途:格式化 JSON。

(输出会是上面那个格式化好的 users.json)

4.2. 访问对象键 (.key)

使用 .key 来访问对象的字段。

4.3. 访问数组元素 (.[index])

使用 .[index] 访问数组元素(索引从 0 开始)。

4.4. 数组/对象迭代器 (.[]) ⭐

这是 jq 最核心的概念之一。当在一个数组上使用 .[] 时,它会将数组“解包”(unpack)成一个数据流 (stream),即将数组中的每个元素作为独立的 JSON 输出。

输出: (注意,这不是一个数组了,而是三个独立的对象)


5. 级别二:管道 (|) 与数据流

jq 内部的 | 管道符,和 Shell 的管道符 | 概念一致:将左侧表达式的输出,作为右侧表达式的输入。

这允许你将简单的过滤器链接起来,构建复杂的查询。

5.1. 结合 .[].key

目标:获取所有用户的名字。

  1. .users:获取 users 数组。
  2. | .[]:将数组解包成 3 个用户对象流。
  3. | .name:对流中的每一个对象应用 .name 过滤器。

输出:

5.2. 逗号 (,)

逗号 (,) 用于将两个过滤器应用于同一个输入,并把它们的结果合并到一个流中。

输出:


6. 级别三:条件过滤 (select)

select(expression)jqgrep。它只保留那些使 expression 结果为 true 的输入。

目标:只获取所有“活跃”(isActive) 的用户。

  1. .users[]:获取用户流。
  2. | select(.isActive == true):对流中的每个对象进行检查,只保留 isActivetrue 的对象。

输出: (只返回 Alice 和 Charlie 的对象)

目标:获取所有“活跃”用户的“名字”。我们只需在上面的基础上,再加一个管道:

输出:

目标:获取年龄大于 30 且会用 "docker" 的用户。(注意:select 内部可以使用 and, or。检查数组包含使用 any)

输出:


7. 级别四:转换数据(构建新 JSON)

jq 不仅能过滤,还能创建新的 JSON 对象 {} 和数组 []

目标:获取所有用户的列表,但只包含他们的名字和技能数量。

  1. .users[]:获取用户流。

  2. | { ... }:对流中的每个对象,构建一个新对象

    • username: .name:在新对象中创建 username 键,值为原对象name 键。
    • skill_count: (.skills | length):在新对象中创建 skill_count 键,值为原对象 skills 数组的长度 (length 是一个内置函数)。

输出: (三个新构造的对象流)

目标:将上述结果重新包装成一个数组。只需在整个过滤器表达式两边加上 []

输出: (一个包含三个新对象的数组)


8. 级别五:与 Shell 脚本集成(极其重要)

jq 是为 Shell 脚本而生的。有两个关键标志:-r--arg

8.1. -r (--raw-output):移除引号

默认情况下,jq 输出的字符串会带引号 ("Alice")。这在 Shell 中非常不便。-r 标志会移除字符串两边的引号。

在 Shell 脚本中使用:

8.2. --arg:将 Shell 变量传入 jq

千万不要试图用 $ 拼接 Shell 变量来构建 jq 过滤器,这很脆弱且不安全。正确的方法是使用 --arg

语法: --arg <jq内部变量名> <Shell变量的值>

目标:在 Shell 脚本中查找指定 ID 的用户。

输出:


jq 快速备忘录

过滤器/标志示例描述
.jq '.' data.json完整输入 (用于美化)
.keyjq '.users' data.json访问对象键
.[N]jq '.users[0]' data.json访问数组索引
.[]jq '.users[]' data.json将数组解包为数据流
|jq '.users[] | .name'管道:将左侧输出传给右侧
select(...)jq '... | select(.age > 30)'过滤:只保留满足条件的
{}jq '... | {n: .name, a: .age}'构造新对象
[]jq '[ .users[] | .name ]'构造新数组 (收集流)
lengthjq '.users | length'返回数组或字符串的长度
keysjq '.users[0] | keys'返回对象的所有键 (作为数组)
-rjq -r '.users[0].name'Raw Output:移除字符串的引号
--arg name valjq --arg u "Bob" '... | select(.name == $u)'传入 Shell 变量 (作为字符串)
--argjson n vjq --argjson id 2 '... | select(.id == $id)'传入 Shell 变量 (保留 JSON 类型)