jq —— JSON 的命令行处理器

运维工具手册 04-文本处理 6.0 KB 原文

jq —— JSON 的命令行处理器

分类:04 文本处理 适用:全平台(jq 1.6 / 1.7) 一句话:解析接口返回、K8s 配置、云厂商 API 输出,把 JSON 变成可读、可筛、可统计的文本。

1. 它解决什么问题

  • curl 回来的 JSON 挤成一行,看不清结构。
  • 从嵌套 JSON 里取出某个字段做统计。
  • 把 JSON 数组转成 CSV/表格。
  • 批量改 JSON 配置(改镜像、改副本数)。

2. 基础

echo '{"a":{"b":1}}' | jq .            # 格式化输出
jq . file.json                         # 同上
jq -c . file.json                      # 紧凑输出(一行)
jq -r .name file.json                  # 原始字符串(去掉引号)
jq '.a.b' file.json                    # 取嵌套字段
jq '.items[0]' file.json               # 数组第一个
jq '.items[-1]' file.json              # 最后一个
jq '.items[1:3]' file.json             # 切片
jq '.items[]' file.json                # 展开数组
jq '.items[].name' file.json           # 取每项字段
jq '.a, .b' file.json                  # 多个输出
jq '.a | .b' file.json                 # 管道
jq 'keys' file.json                    # 键列表
jq 'length' file.json                  # 长度(数组/字符串/对象)
jq 'type' file.json                    # 类型
jq 'has("name")' file.json             # 是否有键

字段名含特殊字符:

jq '."my-key"' file.json
jq '.data["user name"]' file.json

字段不存在不会报错,返回 null;对 null 取子字段会报错,用 ? 抑制:

jq '.a.b?' file.json
jq '.items[]?.name' file.json

3. 过滤与转换

# select 过滤
jq '.items[] | select(.status == "Running")' pods.json
jq '.items[] | select(.status == "Running") | .metadata.name' pods.json
jq '.[] | select(.age > 30)' users.json
jq '.[] | select(.name | test("^web"))' hosts.json
jq '.[] | select(.tags | index("prod"))' hosts.json

# map 对数组逐项处理
jq 'map(.name)' file.json
jq 'map(select(.enabled))' file.json
jq 'map({name: .name, port: .port})' file.json

# 构造新对象
jq '{name: .metadata.name, ns: .metadata.namespace}' pod.json
jq '[.items[] | {n: .metadata.name}]' pods.json

# 删除字段
jq 'del(.password)' file.json
jq 'del(.items[].secret)' file.json

# 合并
jq '.a + .b' f1.json f2.json           # 浅合并
jq -s '.[0] * .[1]' a.json b.json      # 深合并(* 递归)
jq -s 'add' a.json b.json              # 数组合并成一个

4. 统计与分组

jq 'length'                                  # 元素个数
jq '[.[] | .age] | add'                      # 求和
jq '[.[] | .age] | add / length'             # 平均
jq '[.[] | .age] | max'                      # 最大
jq '[.[] | .age] | min'
jq 'group_by(.status) | map({status: .[0].status, count: length})'
jq '[.[] | .status] | group_by(.) | map({(.[0]): length}) | add'
jq 'sort_by(.time)'                          # 排序
jq 'sort_by(.time) | reverse'
jq 'unique_by(.name)'                        # 按字段去重
jq 'unique'                                  # 完全去重
jq 'to_entries'                              # {a:1} → [{key,value}]
jq 'with_entries(select(.value != null))'    # 过滤空值
jq 'reduce .[] as $x (0; . + $x)'            # reduce

5. 输出格式

jq -r '.[] | "\(.name)\t\(.port)"' file.json          # 制表符分隔
jq -r '.[] | [.name, .port] | @tsv' file.json         # TSV
jq -r '.[] | [.name, .port] | @csv' file.json         # CSV
jq -r '.[] | @base64' file.json                       # base64
jq -r '.token' file.json                              # 取裸值(脚本用)
jq -j '.name' file.json                               # 不换行
jq '.items | length' file.json                        # 直接算长度
jq '.[] | keys' file.json

@tsv / @csv 会自动处理转义,比手拼字符串可靠。

6. 变量与参数

jq --arg name "web01" '.[] | select(.name == $name)' hosts.json
jq --argjson port 8080 '.[] | select(.port == $port)' svc.json
jq --slurpfile cfg cfg.json '. + $cfg[0]' main.json
jq -n --arg a 1 --arg b 2 '{sum: ($a|tonumber) + ($b|tonumber)}'
jq --argjson arr '[1,2,3]' -n '$arr | add'

-n 不读输入,用于构造 JSON;-s(--slurp)把多个输入合成一个数组。

7. 实战场景

7.1 格式化 API 返回

curl -s https://api.example.com/users | jq .
curl -s -H 'Authorization: Bearer x' https://api.example.com/users | jq '.[] | {id, name}'

7.2 从 K8s 输出里取容器镜像

kubectl get pods -A -o json \
  | jq -r '.items[] | .spec.containers[] | "\(.image)"' \
  | sort | uniq -c | sort -nr

7.3 找出状态异常的 Pod

kubectl get pods -A -o json \
  | jq -r '.items[] | select(.status.phase != "Running") | "\(.metadata.namespace)/\(.metadata.name) \(.status.phase)"'

7.4 JSON 转 CSV 给 Excel

jq -r '["name","cpu","mem"], (.[] | [.name, .cpu, .mem]) | @csv' nodes.json > nodes.csv

7.5 批量改 JSON 配置

jq '.spec.replicas = 3' deploy.json > /tmp/new.json && mv /tmp/new.json deploy.json
jq '.image = "app:1.2.3"' deploy.json > tmp && mv tmp deploy.json
jq 'del(.spec.template.spec.containers[].resources.limits)' deploy.json > tmp && mv tmp deploy.json

7.6 处理 JSON Lines(每行一个 JSON)

jq -c 'select(.level == "ERROR") | {t: .time, msg: .msg}' app.jsonl
jq -s 'group_by(.service) | map({service: .[0].service, n: length})' app.jsonl

7.7 默认值处理

jq '.config.timeout // 30' file.json          # null/false 时用默认
jq '.items // [] | length' file.json
jq 'if .enabled then "on" else "off" end' file.json

8. 常见坑

  1. 字段名带 - 或空格必须引号:.my-key 会被解析成减法。
  2. .[] 对 null 报错:用 .[]?。
  3. -r 只对字符串生效:对象仍会输出 JSON。
  4. 浮点精度:jq 用 IEEE754,金额统计会失真,重要计算用 Python。
  5. 大文件内存:jq 默认全量读入,几百 MB 会吃满内存,改用 --stream 或 jq -c 逐行。
  6. sort_by 对混合类型报错:先统一类型(tostring)。
  7. group_by 必须先排序(jq 内部会排,但语义上要保证字段存在)。
  8. --argjson 与 --arg 混用:前者传 JSON,后者传字符串,类型错会报错。
  9. 中文输出乱码:jq 输出 UTF-8,终端 locale 不对时乱码。
  10. // 也会把 false 当空值:false // 30 得到 30,注意业务语义。
  11. -e 用于脚本判断:输出为 false/null 时退出码 1,可做断言。
  12. Windows 下引号麻烦:PowerShell 里用单引号包 jq 表达式,双引号包外层。

9. 速查表

jq .                             # 格式化
jq -c .                          # 紧凑
jq -r '.a'                       # 裸字符串
jq '.a.b'                        # 嵌套
jq '.items[]'                    # 展开
jq '.items[].name'               # 批量取字段
jq 'keys' / 'length' / 'type'
jq '.[] | select(.x == "y")'
jq 'map(.name)'
jq 'group_by(.k) | map({k: .[0].k, n: length})'
jq 'sort_by(.t)'
jq 'del(.p)'
jq '.a = 1'                      # 赋值
jq --arg v x '.[] | select(.n == $v)'
jq -r '.[] | [.a,.b] | @tsv'
jq -n '{a:1}'                    # 构造
jq -s 'add'                      # 合并数组
jq '.x // "default"'             # 默认值