Jq 命令行 JSON 处理神器

jq 是一个轻量级且强大的命令行 JSON 处理器,类似于 sed 用于 JSON 数据。它允许你切片、过滤、映射和转换结构化数据,是处理 API 响应、配置文件和日志分析的必备工具。

安装

macOS

1brew install jq

Linux

1# Debian/Ubuntu
2sudo apt-get install jq
3
4# CentOS/RHEL
5sudo yum install jq
6
7# Alpine
8apk add jq

验证安装

1jq --version
2# jq 1.7

基本语法

jq 的基本用法:

1jq [options] 'filter' [file]

如果没有指定文件,jq 会从标准输入读取。

核心概念

1. 身份过滤器 (.)

最简单的过滤器,输出输入的内容不变:

1echo '{"name": "Alice", "age": 30}' | jq '.'
2# {
3#   "name": "Alice",
4#   "age": 30
5# }

2. 对象属性访问

使用 .key 访问对象属性:

1echo '{"name": "Alice", "age": 30}' | jq '.name'
2# "Alice"
3
4# 嵌套对象
5echo '{"user": {"name": "Alice", "age": 30}}' | jq '.user.name'
6# "Alice"

3. 数组操作

访问数组元素:

1echo '[1, 2, 3, 4, 5]' | jq '.[0]'      # 第一个元素: 1
2echo '[1, 2, 3, 4, 5]' | jq '.[-1]'     # 最后一个元素: 5
3echo '[1, 2, 3, 4, 5]' | jq '.[2:4]'    # 切片: [3, 4]
4echo '[1, 2, 3, 4, 5]' | jq '.[:3]'     # 前三个: [1, 2, 3]

4. 数组迭代 (.[])

遍历数组元素:

1echo '[{"name": "Alice"}, {"name": "Bob"}]' | jq '.[].name'
2# "Alice"
3# "Bob"

常用操作

过滤数据

使用 select() 条件过滤:

1echo '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]' | \
2  jq '.[] | select(.age > 28)'
3# {
4#   "name": "Alice",
5#   "age": 30
6# }

映射和转换

使用 map 转换数组:

1echo '[1, 2, 3]' | jq 'map(. * 2)'
2# [2, 4, 6]
3
4# 提取字段
5echo '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]' | \
6  jq 'map(.name)'
7# ["Alice", "Bob"]

创建新对象

使用 {} 构建新对象:

1echo '{"firstName": "Alice", "lastName": "Smith"}' | \
2  jq '{name: .firstName, full: "\(.firstName) \(.lastName)"}'
3# {
4#   "name": "Alice",
5#   "full": "Alice Smith"
6# }

数组操作

 1# 排序
 2echo '[3, 1, 4, 1, 5, 9]' | jq 'sort'
 3# [1, 1, 3, 4, 5, 9]
 4
 5# 反转
 6echo '[1, 2, 3]' | jq 'reverse'
 7# [3, 2, 1]
 8
 9# 去重
10echo '[1, 1, 2, 2, 3]' | jq 'unique'
11# [1, 2, 3]
12
13# 分组
14echo '[{"a": 1}, {"a": 1}, {"a": 2}]' | jq 'group_by(.a)'
15# [[{"a": 1}, {"a": 1}], [{"a": 2}]]
16
17# 统计
18echo '[1, 2, 2, 3, 3, 3]' | jq 'group_by(.) | map({value: .[0], count: length})'
19# [{"value": 1, "count": 1}, {"value": 2, "count": 2}, {"value": 3, "count": 3}]

高级技巧

管道操作符 (|)

链式处理数据:

1echo '{"users": [{"name": "Alice", "active": true}, {"name": "Bob", "active": false}]}' | \
2  jq '.users | map(select(.active)) | map(.name)'
3# ["Alice"]

条件表达式

使用 if-then-else

1echo '[1, 2, 3, 4, 5]' | jq 'map(if . % 2 == 0 then "even" else "odd" end)'
2# ["odd", "even", "odd", "even", "odd"]

字符串操作

 1# 分割字符串
 2echo '{"path": "/usr/local/bin"}' | jq '.path | split("/")'
 3# ["", "usr", "local", "bin"]
 4
 5# 连接字符串
 6echo '["a", "b", "c"]' | jq 'join("-")'
 7# "a-b-c"
 8
 9# 大小写转换
10echo '{"name": "Alice"}' | jq '.name | ascii_downcase'
11# "alice"

数学运算

1echo '[1, 2, 3, 4, 5]' | jq 'add'        # 求和: 15
2echo '[1, 2, 3, 4, 5]' | jq 'min'        # 最小值: 1
3echo '[1, 2, 3, 4, 5]' | jq 'max'        # 最大值: 5
4echo '[1, 2, 3, 4, 5]' | jq 'length'     # 长度: 5
5echo '[1, 2, 3, 4, 5]' | jq 'unique | length'  # 唯一值数量

处理 JSON 文件

 1# 格式化 JSON
 2jq '.' data.json
 3
 4# 压缩 JSON
 5jq -c '.' data.json
 6
 7# 提取特定字段
 8jq '.users[].name' data.json
 9
10# 原地编辑(需要 -i 标志,但 jq 不支持,需用临时文件)
11tmp=$(mktemp)
12jq '.version = "2.0"' config.json > "$tmp" && mv "$tmp" config.json

实战案例

案例 1:处理 API 响应

 1# 获取 GitHub 用户信息
 2curl -s 'https://api.github.com/users/github' | \
 3  jq '{login, name, public_repos, followers}'
 4
 5# {
 6#   "login": "github",
 7#   "name": "GitHub",
 8#   "public_repos": 158,
 9#   "followers": 28456
10# }

案例 2:分析日志文件

1# 统计各状态码出现次数
2cat access.log | jq -r '.status' | sort | uniq -c | sort -rn
3
4# 提取慢请求
5cat access.log | jq 'select(.duration > 1000) | {path: .request.path, duration}'
6
7# 提取错误日志
8cat app.log | jq 'select(.level == "error") | {timestamp, message}'

案例 3:转换数据格式

 1# JSON 转 CSV
 2echo '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]' | \
 3  jq -r '(["name", "age"] | @csv), (.[] | [.name, .age] | @csv)'
 4# "name","age"
 5# "Alice",30
 6# "Bob",25
 7
 8# CSV 转 JSON(需要配合其他工具)
 9echo 'name,age
10Alice,30
11Bob,25' | python3 -c "import csv, json, sys; print(json.dumps([dict(r) for r in csv.DictReader(sys.stdin)]))" | jq '.'
12# [{"name": "Alice", "age": "30"}, {"name": "Bob", "age": "25"}]

案例 4:批量修改配置

1# 更新嵌套配置值
2jq '.database.connection.timeout = 30 | .database.connection.pool_size = 10' config.json
3
4# 合并配置
5jq -s '.[0] * .[1]' default.json override.json
6
7# 删除字段
8jq 'del(.unused_field)' config.json

案例 5:复杂过滤

 1# 多条件过滤
 2echo '[{"name": "Alice", "age": 30, "active": true},
 3       {"name": "Bob", "age": 25, "active": false},
 4       {"name": "Charlie", "age": 35, "active": true}]' | \
 5  jq '[.[] | select(.active == true and .age >= 30)]'
 6# [{"name": "Alice", "age": 30, "active": true}, {"name": "Charlie", "age": 35, "active": true}]
 7
 8# 按条件分组统计
 9echo '[{"category": "A", "value": 10},
10       {"category": "A", "value": 20},
11       {"category": "B", "value": 15}]' | \
12  jq 'group_by(.category) | map({category: .[0].category, total: map(.value) | add})'
13# [{"category": "A", "total": 30}, {"category": "B", "total": 15}]

常用命令行选项

选项说明
-c紧凑输出(单行)
-r原始字符串输出(不带引号)
-n使用 null 作为输入
-e如果结果为 false 或 null,退出码为 1
-f FILE从文件读取过滤器
-s读取所有输入到一个数组
--tab使用 tab 缩进
-S对象键排序输出
--color-output强制彩色输出
--monochrome-output禁用彩色输出

调试技巧

使用 debug 输出中间结果

1echo '[1, 2, 3]' | jq 'map(. * 2) | debug | map(. + 1)'
2# ["DEBUG:",[2,4,6]]
3# [3, 5, 7]

查看类型

1echo '["hello", 123, true, null, {"a": 1}]' | jq '.[] | type'
2# "string"
3# "number"
4# "boolean"
5# "null"
6# "object"

错误处理

 1# 使用 ? 忽略错误
 2echo '[1, "two", 3]' | jq '.[] | . * 2?'
 3# 2
 4# 6
 5
 6# 使用 try-catch
 7echo '[1, "two", 3]' | jq '.[] | if type == "number" then . * 2 else "not a number" end'
 8# 2
 9# "not a number"
10# 6

性能优化

1# 使用 --stream 处理大文件
2jq --stream 'select(.[0][-1] == "id") | .[1]' large-file.json
3
4# 流式处理(逐行处理 JSON 数组)
5cat data.json | jq -c '.[]' | while read -r item; do
6  echo "$item" | jq '.name'
7done

快速参考

常用过滤器速查

 1.              # 输入本身
 2.key           # 对象属性
 3.[index]       # 数组索引
 4.[]            # 数组迭代
 5|              # 管道
 6,              # 多个输出
 7[]             # 数组构造器
 8{}             # 对象构造器
 9select(bool)   # 条件过滤
10map(f)         # 数组映射
11sort           # 排序
12unique         # 去重
13group_by(f)    # 分组
14add            # 求和
15length         # 长度
16keys           # 获取键名
17values         # 获取值
18to_entries     # 对象转键值对数组
19from_entries   # 键值对数组转对象

总结

jq 是处理 JSON 数据的瑞士军刀,掌握它可以大幅提升命令行数据处理效率。从简单的字段提取到复杂的数据转换,jq 都能优雅地处理。建议从基础命令开始练习,逐步掌握高级技巧,将其融入日常工作流程中。

参考资源