jq:JSON 界的 sed/awk,一个 13 年历史的 CLI 工具如何成为现代基础设施的隐形基石
jq:JSON 界的 sed/awk,一个 13 年历史的 CLI 工具如何成为现代基础设施的隐形基石
如果你在终端里处理过 JSON,大概率用过或见过这个命令:
curl https://api.example.com/data | jq '.items[].name'一行代码,从 API 响应中提取所有 item 的 name 字段。没有 import,没有 package.json,没有 venv,没有 compile step。
这就是 jq——一个用 C 编写的命令行 JSON 处理器,零运行时依赖,单二进制文件。2013 年发布 1.3 版本,2025 年 6 月发布 1.8.0,7 月发布 1.8.1。13 年了,它依然是 JSON 数据处理的事实标准。
项目地址:https://github.com/jqlang/jq
本文大纲
- 为什么 JSON 需要专用处理器
- 核心设计哲学:管道 + 过滤器
- 从基础到进阶:jq 的能力光谱
- Streaming:处理多 GB 大文件
- 现代工作流中的隐形基石
- 1.7 到 1.8:五年沉寂后的回归
- 为什么 jq 不可替代
为什么 JSON 需要专用处理器
Linux 有三驾马车——sed、awk、grep——处理文本数据极其强大。但 JSON 不是普通文本,它是结构化数据。
你可以用 grep 从 JSON 里提取某一行,但 grep 不理解 JSON 的嵌套结构。你可以用 sed 替换某个值,但 sed 不知道那个值在对象树的哪一层。你可以用 awk 做计算,但 awk 需要先自己解析 JSON。
jq 的定位非常精准:它是 sed/awk/grep 的 JSON 等价物。 理解 JSON 的对象、数组、嵌套、类型,在此基础上提供切片、过滤、映射、变换的能力。
核心设计哲学:管道 + 过滤器
jq 的核心模型和 Unix 管道一脉相承:数据从左到右流经一系列过滤器,每个过滤器做一件事,组合起来完成复杂变换。
# 基础:提取字段
jq '.name' package.json
# 管道:提取 + 过滤
jq '.dependencies | to_entries[] | select(.value | startswith("^"))' package.json
# 变换:构建新对象
jq '{name, version, deps: (.dependencies | keys)}' package.json. 是恒等过滤器(identity),原样输出。.name 提取 name 字段。| 是管道操作符,把左边的输出传给右边。[] 展开数组。这些基础元素组合起来,表达能力远超你的直觉。
从基础到进阶:jq 的能力光谱
基础操作
# 提取数组中所有元素
jq '.[]' data.json
# 提取特定字段
jq '.[].name' data.json
# 过滤数组
jq '.[] | select(.type == "dolphin")' data.json对象构建
jq 可以用 {} 和 [] 从零构建新的 JSON 结构:
# 从平铺数据构建新对象
jq '{total: (.[] | .clams) | add, count: length}' data.json
# 映射成新的数组
jq '[.[] | {name: .name, isDolphin: (.type == "dolphin")}]' data.json字符串插值
jq '.[] | "\(.name) is a \(.type)"' data.jsonreduce:有状态的累积计算
reduce 是 jq 中最强大的操作符之一,类似函数式编程中的 fold:
# 计算所有 clams 的总和
jq 'reduce .[] as $item (0; . + $item.clams)' data.json
# 构建频率统计
jq 'reduce .[] as $item ({}; .[$item.type] += 1)' data.json递归遍历
.. 操作符递归遍历整个 JSON 树,配合 select 可以在任意深度查找数据:
# 在整个 JSON 树中查找所有包含 "error" 的键
jq '.. | objects | select(has("error"))' response.json
# 提取所有字符串值
jq '.. | strings' nested.json条件与错误处理
# 条件分支
jq '.[] | if .clams > 3 then "rich" else "poor" end' data.json
# try-catch
jq 'try .invalid.path catch "not found"' data.json模式匹配与解构
# 数组解构
jq '.[] | . as {name: $n, type: $t} | "\($n): \($t)"' data.json
# 可选字段
jq '.[] | .optional_field // "default"' data.jsonStreaming:处理多 GB 大文件
jq 默认会将整个 JSON 文档加载到内存。对于多 GB 的大文件,这不可行。
--stream 标志启用流式解析器,逐 token 处理,内存占用极低:
# 流式处理大文件
jq --stream '.[0] | .[0]' huge-file.json
# 配合 --slurpfile 使用
jq --stream 'fromstream(1|truncate_stream(inputs))' huge-file.json | head -100流式模式的 trade-off 是用速度换内存——解析更慢,但可以处理远超内存容量的文件。对于 ETL 管道中的大数据集处理,这是唯一可行的方式。
现代工作流中的隐形基石
jq 的应用场景早已超越了"美化 JSON 输出":
DevOps 与 Kubernetes
# 提取 Pod 状态
kubectl get pods -o json | jq '.items[] | {name: .metadata.name, status: .status.phase}'
# 检查 Deployment 副本数
kubectl get deployment my-app -o json | jq '.status.availableReplicas'CI/CD 管道
# 从 package.json 提取版本号
VERSION=$(jq -r '.version' package.json)
# 检查 API 响应状态
curl -s https://api.healthcheck.io | jq -e '.status == "healthy"'API 数据处理
# 从 GitHub API 提取 PR 信息
curl -s https://api.github.com/repos/org/repo/pulls | \
jq '.[] | {number, title, user: .user.login, created: .created_at}'
# 批量提取和格式化
curl -s https://api.example.com/users | \
jq '[.[] | {id, email}] | sort_by(.id)'AI/ML 数据预处理
# 清洗训练数据
jq '[.[] | select(.label != null) | {text: .content, label}]' raw-data.json > clean-data.json
# 转换格式适配模型输入
jq -c '.[] | {prompt: .question, completion: .answer}' dataset.jsonShell 脚本中的 JSON 操作
# 合并两个 JSON 文件
jq -s '.[0] * .[1]' file1.json file2.json
# JSON 转 CSV
jq -r '.[] | [.name, .type, .clams] | @csv' data.json
# 环境变量注入
jq --arg env "$ENVIRONMENT" '. + {environment: $env}' config.json1.7 到 1.8:五年沉寂后的回归
jq 的版本历史本身就是一段故事:
| 版本 | 时间 | 说明 |
|---|---|---|
| 1.3 | 2013 年 5 月 | 早期版本 |
| 1.4 | 2014 年 6 月 | 稳定性改进 |
| 1.5 | 2015 年 8 月 | 大版本:datetime、math、regexp、try/catch、streaming parser、模块系统 |
| 1.6 | 2018 年 11 月 | 最后一个由原作者维护的版本 |
| 五年沉寂 | 2018-2023 | 项目几乎停滞 |
| 1.7 | 2023 年 9 月 | 新管理团队回归,重组 GitHub 组织 |
| 1.7.1 | 2023 年 12 月 | 安全修复(CVE-2023-50246, CVE-2023-50268) |
| 1.8.0 | 2025 年 6 月 | 大量改进 |
| 1.8.1 | 2025 年 7 月 | 最新稳定版 |
1.5 版本引入的 streaming parser 和模块系统是 jq 走向生产级工具的转折点。1.7 版本的回归标志着项目治理的成熟——新的管理员和维护者团队接手,修复了安全漏洞,恢复了发布节奏。
1.8 系列则带来了更多改进,确保 jq 在现代环境中持续保持竞争力。
为什么 jq 不可替代
在 AI 时代,为什么一个 13 年前的 CLI 工具依然不可替代?
零依赖 + 单二进制 = 到处可用。 scp 一个二进制到远程服务器,立即可用。没有 Python 环境、没有 Node.js、没有 pip install 的网络问题。在 Docker 镜像中加一行 RUN apk add jq,在 CI/CD 中零配置。
C 语言写的 = 快。 对于 JSON 处理,jq 的性能接近原生速度。Python 的 json 模块需要解释器开销,Node.js 需要 V8 启动时间,jq 直接读取、解析、输出。
表达能力不成比例地高。 一行 jq 等价于几十行 Python 或 JavaScript。jq '[.[] | select(.x > 0) | {a: .y}]' 这一行做的事,用其他语言需要循环、条件判断、对象构建、数组收集。
管道模型的组合性。 jq 的过滤器可以无限组合,就像 Unix 管道一样。这种组合性是命令式脚本无法提供的。
确定性。 给定相同的输入和相同的过滤器,jq 的输出是确定的。没有随机性,没有 LLM 的不确定性,没有版本间行为差异。在 CI/CD 管道中,这种确定性至关重要。
jq 的存在证明了一件事:好的 CLI 工具不会过时。 它们解决的问题是永恒的——把数据从一种形式变成另一种形式,快速、可靠、可组合。sed 和 awk 诞生于 1970 年代,jq 诞生于 2013 年,它们的生命力来自同一个来源:对问题域的深刻理解和极简的设计哲学。
项目地址:jq 在线试用:play.jqlang.org
作者: itech001 来源: 公众号:AI人工智能时代 网站: https://www.theaiera.cn/ 每日分享最前沿的AI新闻资讯和技术研究。
本文首发于 AI人工智能时代,转载请注明出处。