← 全部文章

jq 教程:过滤与转换 JSON

jq 实用教程:安装、美化与压缩、选字段、用 select 过滤数组、用 map 转换,以及可直接复制粘贴的命令清单。

jq 是切片、过滤和转换 JSON 的标准命令行工具。它把一行命令变成处理 API 响应、日志文件和配置的强大查询语言。本教程涵盖安装、你每天会用到的核心 filter,以及一组针对最常见实际任务的可复制粘贴 recipe。

什么是 jq?

jq 从文件或标准输入读取 JSON,应用一个 filter,然后把 JSON(或纯文本)写到标准输出。默认会格式化输出,而且从不把你的数据发到任何地方 —— 它是个本地二进制,处理敏感 payload 也很合适。

安装 jq

# macOS
brew install jq

# Debian / Ubuntu
sudo apt-get install jq

# Windows (winget or choco)
winget install jqlang.jq

# 验证
jq --version

Identity Filter:随手格式化

最简单的 filter . 会原样返回输入 —— 这就让 jq 成了一个即时格式化工具:

# 格式化一个文件
jq . data.json

# 格式化 curl 的响应
curl -s https://api.example.com/users | jq .

# 反过来压缩(紧凑输出)
jq -c . data.json

选择字段

.key 钻进对象,用 [] 钻进数组:

echo '{"user":{"name":"Ada","age":36}}' | jq '.user.name'
# "Ada"

# 数组的全部元素
echo '[{"id":1},{"id":2}]' | jq '.[]'
# {"id":1}
# {"id":2}

# 从每个数组元素里取一个字段
echo '[{"id":1,"name":"Ada"},{"id":2,"name":"Bob"}]' | jq '.[].name'
# "Ada"
# "Bob"

# 用 -r 去掉 JSON 的引号(raw output)
jq -r '.[].name' users.json

用 select 过滤

# 只保留满足条件的对象
echo '[{"name":"Ada","active":true},{"name":"Bob","active":false}]' \
  | jq '.[] | select(.active == true)'
# {"name":"Ada","active":true}

# 数值比较
jq '.[] | select(.age > 30)' users.json

用 map 和对象构造来变形

# 把每个元素重新组合成新对象
echo '[{"id":1,"name":"Ada","email":"a@x.com"}]' \
  | jq 'map({ userId: .id, label: .name })'
# [{"userId":1,"label":"Ada"}]

# 抽出一个扁平的值列表
jq '[.[].email]' users.json     # ["a@x.com", ...]

# 用 | 把 filter 串起来
jq '.items | map(.price) | add' order.json   # 所有价格之和

常用 Recipe

任务命令
格式化jq . file.json
压缩jq -c . file.json
取一个字段jq '.data.token' resp.json
Raw 字符串(不带引号)jq -r '.token' resp.json
统计数组长度jq '. | length' list.json
对象的所有 keyjq 'keys' obj.json
过滤行jq '.[] | select(.active)'
按字段排序jq 'sort_by(.age)'
求和一个字段jq '[.[].amount] | add'
排序对象的 keyjq --sort-keys . file.json
校验(通过退出码)jq empty file.json

重塑对象:to_entries / from_entries

jq 里两个最有用的对象形状变换工具:

# 重命名每个 key(这里转小写)
echo '{"Name":"Ada","Active":true}' \
  | jq 'with_entries(.key |= ascii_downcase)'
# → {"name":"Ada","active":true}

# 丢掉值为 null 的 key
jq 'with_entries(select(.value != null))' file.json

# 对象 ⇄ 键值对数组
jq 'to_entries' file.json     # → [{"key":"name","value":"Ada"}, ...]
jq 'from_entries' pairs.json  # → {"name":"Ada", ...}

插值和输出格式:\(.x)@csv@json@base64

jq 内建字符串插值和 格式字符串,可以把 JSON 转成其他格式:

# 在引号字符串里做字符串插值
jq -r '"\(.user) bought \(.items|length) items"' order.json

# 每个对象一行 CSV
jq -r '.[] | [.id, .name, .total] | @csv' orders.json

# 内联 JSON 给 shell 用(转义过的字符串字面量)
jq -r '.user | @json' record.json

# Base64 编码一个值(处理 token / data URI 很方便)
jq -r '.payload | @base64' message.json
# 解码这边:较新版本 jq 支持 @base64d

用 jq 校验 JSON

因为 jq 遇到非法输入时退出码非零,jq empty file.json 是脚本和 CI 里干净利落的合法性检查 —— 更多校验方法见 如何校验 JSON

什么时候浏览器工具更快

jq 在脚本和 pipeline 里很出彩,但对于一次性的小事 —— 格式化粘贴过来的响应、查看一个陌生的结构、修复坏掉的 JSON —— 浏览器工具不用安装、也不用做 shell 转义:

常见问题

怎么用 jq 格式化 JSON?

运行 jq . file.json —— identity filter . 返回输入,而 jq 默认会格式化输出。想要紧凑输出就用 -c

怎么用 jq 抽出单个字段?

用路径 filter,比如 jq '.data.token',再加上 -r 就能拿到不带引号的 raw 值。

怎么用 jq 过滤 JSON 数组?

.[] 迭代,再用 select(),比如 jq '.[] | select(.active == true)'

jq 能校验 JSON 吗?

能 —— jq empty file.json 解析输入,如果非法就以非零退出码退出,在 CI 里很好用。详情见 如何校验 JSON

继续阅读