jq JSON 命令行处理
一句话概述:jq 是命令行 JSON 处理工具,能解析、过滤、转换 JSON 数据,是处理 API 返回数据和配置文件的利器。
核心知识点
| 概念 | 白话解释 |
|---|
| jq | JSON 处理器 = 命令行版 JSON 编辑器 |
| Filter | 过滤器 = 提取/转换 JSON 的表达式 |
| Pipe | 管道 = 用 \| 串联多个过滤器 |
. | 当前对象 = 代表输入的整个 JSON |
.key | 取值 = 提取某个字段 |
.[] | 遍历 = 展开数组的每个元素 |
安装
# Linux
sudo apt install jq # Ubuntu/Debian
# macOS
brew install jq # Homebrew
# 验证
jq --version # 查看版本
基础用法
# 格式化(美化打印)
echo '{"name":"T2D","samples":50}' | jq . # 格式化输出
cat data.json | jq . # 格式化文件内容
# 提取字段
echo '{"name":"T2D","samples":50}' | jq '.name' # 输出: "T2D"
echo '{"name":"T2D","samples":50}' | jq '.samples' # 输出: 50
# 去掉引号(原始值)
echo '{"name":"T2D"}' | jq -r '.name' # 输出: T2D(无引号)
# 嵌套取值
echo '{"project":{"name":"T2D","year":2026}}' | jq '.project.name' # 输出: "T2D"
# 数组操作
echo '[1,2,3,4,5]' | jq '.[0]' # 第一个元素: 1
echo '[1,2,3,4,5]' | jq '.[-1]' # 最后一个: 5
echo '[1,2,3,4,5]' | jq '.[1:3]' # 切片: [2,3]
echo '[1,2,3,4,5]' | jq '.[]' # 展开所有元素
echo '[1,2,3,4,5]' | jq 'length' # 数组长度: 5
进阶用法
# === 过滤 ===
# 假设 samples.json 内容:
# [{"id":"S1","group":"T2D","shannon":3.2},
# {"id":"S2","group":"Control","shannon":4.1},
# {"id":"S3","group":"T2D","shannon":2.8}]
cat samples.json | jq '.[] | select(.group == "T2D")' # 筛选 T2D 组
cat samples.json | jq '.[] | select(.shannon > 3.0)' # Shannon > 3.0
cat samples.json | jq '[.[] | select(.group == "T2D")]' # 筛选后保持数组
# === 转换/构造 ===
cat samples.json | jq '.[] | {sample_id: .id, diversity: .shannon}' # 重命名字段
cat samples.json | jq '[.[] | .shannon]' # 提取所有 shannon 值为数组
cat samples.json | jq '[.[] | .shannon] | add/length' # 计算平均值
# === 排序 ===
cat samples.json | jq 'sort_by(.shannon)' # 按 shannon 升序
cat samples.json | jq 'sort_by(.shannon) | reverse' # 降序
# === Map/Reduce ===
cat samples.json | jq 'map(.shannon)' # 提取所有 shannon: [3.2, 4.1, 2.8]
cat samples.json | jq 'map(.shannon) | add' # 求和: 10.1
cat samples.json | jq 'map(.shannon) | min' # 最小值: 2.8
cat samples.json | jq 'map(.shannon) | max' # 最大值: 4.1
# === 条件表达式 ===
cat samples.json | jq '.[] | .id + ": " + (if .shannon > 3 then "高" else "低" end)'
# === 处理 API 返回 ===
curl -s https://api.github.com/repos/samtools/samtools/releases/latest \
| jq '{tag: .tag_name, date: .published_at, url: .html_url}' # 提取关键信息
# === 输出为 TSV/CSV ===
cat samples.json | jq -r '.[] | [.id, .group, .shannon] | @tsv' # 转 TSV
cat samples.json | jq -r '.[] | [.id, .group, .shannon] | @csv' # 转 CSV
# === 修改 JSON ===
cat config.json | jq '.threads = 8' # 修改字段值
cat config.json | jq '.threads = 8 | .memory = "16G"' # 修改多个字段
cat config.json | jq '. + {"new_field": "value"}' # 添加新字段
cat config.json | jq 'del(.old_field)' # 删除字段
实用场景
# 处理 Nextflow 流程日志
cat trace.json | jq '.[] | select(.status == "FAILED") | .name' # 查找失败任务
# 解析 conda 环境
conda list --json | jq '.[] | select(.name | contains("bio"))' # 查找 bio 相关包
# 处理 NCBI API
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=T2D+microbiome&retmode=json" \
| jq '.esearchresult.idlist' # 提取 PubMed ID 列表
常见报错
| 报错 | 原因 | 解决 |
|---|
parse error | 输入不是合法 JSON | 检查 JSON 格式(逗号/引号) |
null | 字段不存在 | 检查字段名,用 ? 避免报错:.key? |
Cannot iterate over null | 对 null 做遍历 | 加判空:(.field // []) | .[] |
| 中文乱码 | 编码问题 | 确保终端支持 UTF-8 |
速查表
# 基本语法
jq 'FILTER' file.json # 处理文件
echo 'JSON' | jq 'FILTER' # 处理管道输入
jq -r # 原始输出(无引号)
jq -c # 紧凑输出(单行)
jq -e # 结果为 false/null 时返回非0
# 核心过滤器
# . → 当前对象
# .key → 取字段
# .key1.key2 → 嵌套取值
# .[] → 遍历数组
# .[N] → 取第N个
# .[N:M] → 切片
# length → 长度
# keys → 所有键名
# values → 所有值
# type → 类型
# 常用函数
# select(cond) → 过滤
# map(expr) → 映射
# sort_by(.key) → 排序
# group_by(.key) → 分组
# unique_by(.key) → 去重
# add → 求和/合并
# min / max → 最值
# @tsv / @csv → 格式化输出