jq 处理 JSON 详解:从安装到高级应用
在日常工作中,JSON 格式的日志、配置文件或接口响应非常常见,jq
作为轻量级的命令行 JSON 处理器,能高效完成过滤、提取、分组、计数等操作,是处理 JSON 数据的必备工具。本文将从安装 jq
开始,围绕 JSON 数组和 “每行一个 JSON 对象”(JSON Lines)两种常见格式,详解 jq
的核心用法。
安装 jq
jq
不是系统默认安装的工具,需手动安装,以下是主流操作系统的安装方法:
Linux 系统
(1)Debian/Ubuntu 系列
1 | sudo apt-get update && sudo apt-get install -y jq |
(2)CentOS/RHEL 系列
1 | # CentOS 7 及以上(需启用 EPEL 源) |
(3)Fedora
1 | sudo dnf install -y jq |
(4)Arch Linux
1 | sudo pacman -S jq |
macOS 系统
(1)使用 Homebrew(推荐)
1 | brew install jq |
(2)使用 MacPorts
1 | sudo port install jq |
Windows 系统
(1)使用 Chocolatey 包管理器
1 | choco install jq -y |
(2)手动下载
从 jq 官方网站 下载 Windows 版本的可执行文件,添加到系统环境变量 PATH
中即可。
验证安装
安装完成后,执行以下命令验证:
1 | jq --version |
jq 基础:语法与核心概念
基本语法
1 | jq [选项] '过滤表达式' [输入文件] |
- 输入:可以是 JSON 文件(
.json
)、JSON Lines 文件(.jsonl
,每行一个 JSON 对象),或通过管道传递的 JSON 流。 - 过滤表达式:
jq
的核心,用于描述对 JSON 数据的处理逻辑(如筛选、提取、转换等)。 - 输出:处理后的 JSON 数据(默认格式化输出,便于阅读)。
核心概念
- JSON 结构:
jq
支持处理 JSON 对象({key: value}
)和数组([item1, item2]
)。 - 字段访问:通过
.字段名
访问对象字段(如.name
获取name
字段);通过.[索引]
访问数组元素(如.[0]
获取数组第一个元素)。 - 管道操作:用
|
连接多个处理步骤(如先筛选再分组:select(...) | group_by(...)
)。
处理 JSON 数组:完整数组结构
JSON 数组是最常见的格式(整个文件为一个数组,如 [{"a":1}, {"a":2}]
)。以下通过实例讲解筛选、分组、聚合等操作。
基础筛选:select()
select(条件)
用于筛选符合条件的元素,条件为布尔表达式(如字段相等、数值比较等)。
示例:假设有 data.json
,内容为:
1 | [ |
筛选 date
为 20241212
的记录:
1 | jq '.[] | select(.date == "20241212")' data.json |
.[]
:遍历数组中的每个元素(将数组 “展开” 为单个对象)。select(.date == "20241212")
:保留date
字段等于20241212
的对象。
输出:
1 | { |
分组与计数:group_by()
+ map()
group_by(字段)
按指定字段对数组元素分组(返回嵌套数组,每组为相同字段值的元素集合);map(表达式)
对分组后的数组进行转换(如计算每组长度即计数)。
示例:按 app
和 status
分组,统计 20241212
当天各组合的数量:
1 | jq ' |
解析:
map(select(...))
:对数组中每个元素应用筛选,返回筛选后的新数组(避免用.[]
展开,否则后续无法分组)。group_by(.app, .status)
:按app
和status
的组合分组,结果为嵌套数组(如[[user-success元素], [order-fail元素], ...]
)。map(...)
:遍历每个分组,用.[0].app
获取组内第一个元素的app
(因分组后组内元素该字段相同),length
为组内元素数量(计数)。
输出:
1 | [ |
处理 JSON Lines:每行一个 JSON 对象
日志文件常采用 “JSON Lines” 格式(.jsonl
),即每行一个独立的 JSON 对象(而非整个文件为一个数组)。此时需先用 jq
的 -s
选项将所有行合并为一个数组,再进行聚合操作。
-s
选项:合并多行为数组
-s
(--slurp
)选项会将所有输入行读入一个大数组(每行一个元素),从而支持跨行进分组、聚合。
示例:data.jsonl
内容(每行一个对象):
1 | {"app": "user", "status": "success", "date": "20241212"} |
合并为数组并查看:
1 | jq -s '.' data.jsonl # -s 将所有行合并为一个数组 |
输出:
1 | [ |
聚合操作:分组计数
对 JSON Lines 文件进行分组计数,步骤与 JSON 数组类似(先合并为数组,再筛选、分组)。
示例:统计 data.jsonl
中 20241212
当天各 app
和 status
的数量:
1 | jq -s ' |
说明:
-s
确保所有行被合并为一个数组,后续map
和group_by
可作用于整个数据集。group_by([.app, .status])
与group_by(.app, .status)
效果相同,均按两个字段组合分组。
输出:与 JSON 数组示例相同(按 app
和 status
分组的计数结果)。
进阶操作:提取、转换与条件逻辑
提取指定字段
用 {新字段名: .原字段名}
提取需要的字段,简化输出。
示例:从 data.json
中提取 app
和 date
字段:
1 | jq '.[] | {应用: .app, 日期: .date}' data.json |
输出:
1 | { "应用": "user", "日期": "20241212" } |
条件转换:if-else
根据字段值进行条件转换(如将 status
转换为中文)。
示例:将 status
为 success
转为 “成功”,fail
转为 “失败”:
1 | jq '.[] | { |
嵌套 JSON 处理
对于嵌套结构(如 {a: {b: 1}}
),用 .a.b
访问深层字段。
示例:处理嵌套 JSON:
1 | // nested.json |
提取 app
和 detail.code
:
1 | jq '.[] | {app: .app, code: .detail.code}' nested.json |
实用技巧与常见场景
1. 格式化输出
默认输出已格式化,若需紧凑格式(无缩进),用 -c
选项:
1 | jq -c '.[] | select(.date == "20241212")' data.json # 紧凑输出 |
2. 日志分析场景
结合管道处理实时日志流(如从 tail
输出中筛选特定日志):
1 | tail -f app.log | jq -c 'select(.level == "error")' # 实时打印错误级别日志 |
3. 计数去重
统计某个字段的去重值及出现次数:
1 | jq -s ' |
v1.3.10