用 jq 在命令行里处理 JSON,能把一堆乱七八糟的数据立刻变得可读、可筛选、可合并。

说白了,jq 就像你在终端里用的那把小刀,专门对付 JSON 这种半结构化的东西。想查字段、取嵌套值、按条件过滤、重构对象、合并文件、做点数值运算、排序分组,这些活儿用几条命令就能干掉,省得写一堆小脚本。下面把常用的套路跟你唠唠清楚,能直接拿去用。
先来个最简单的:把文件美丽地打印出来,方便看结构。
$ jq '.' input.json
你会看到格式化的 JSON,比原始一行一堆符号好看多了,调试特别实用。
要是你想先按 age 排序,再按 country 分组,然后把每组做成一个数组输出,可以链式写法,像在流水线上一环接一环:
$ jq 'sort_by(.age) | group_by(.country) | map({country: .[0].country, people: .})' input.json
上面这句先把数组按年龄排好序,再把一样国家的条目打包成组,最后把每组变成包含国家名和人员数组的对象。运行后一看就知道每个 country 有几个人,结构也清清楚楚。
合并多个 JSON 文件也不难。常见情况是有两个文件都是数组,想合并成一个数组。用 -s(slurp)把所有输入一次性读进来,然后用 add:
$ jq -s 'add' file1.json file2.json > merged.json
如果文件里是对象而非数组,合并规则得按需求写,列如想把两个对象的键合并成一个对象,可以这样:
$ jq -s '.[0] + .[1]' a.json b.json
数值计算也行。列如每个人年龄加一:
$ jq '.[] | .age + 1' input.json
如果你想把整个对象的 age 字段改成加一后的值并输出修改后的对象:
$ jq '.[] | .age = (.age + 1)' input.json
筛选是最常用的。找出年龄大于 30 的记录:
$ jq '.[] | select(.age > 30)'
要只输出 name 和 age 两个字段,好端端地把结果提取出来:
$ jq '.[] | select(.age > 30) | {name: .name, age: .age}'
遍历数组、访问嵌套字段也很直观。数组迭代用 .[],嵌套字段用点号表明法。列如取每个人地址里 city 的值:
$ jq '.[] | .address.city' input.json
想同时取 name 和 city:
$ jq '.[] | {name: .name, city: .address.city}'
有时候只想把所有人的 name 列出来:
$ jq '.[] | .name'
比用 awk 或 grep 更靠谱,面向结构化数据,不容易被格式空格坑到。
数据转换(map/重构)也很顺手。要把每条记录变成只含 name 和 age 的新对象:
$ jq '.[] | {name: .name, age: .age}'
如果要把结果收回数组里,外面包一层:
$ jq '[.[] | {name: .name, age: .age}]' input.json
排序用 sort_by。按 age 从小到大:
$ jq 'sort_by(.age)' input.json
要逆序再加个 reverse:
$ jq 'sort_by(.age) | reverse' input.json
下面给个实用的示例数据,直接把这段保存为 input.json,就能照着上面的命令试:
[
{
“name”: “张三”,
“age”: 28,
“country”: “CN”,
“address”: {
“city”: “北京”,
“street”: “朝阳区某街道”
}
},
{
“name”: “李四”,
“age”: 35,
“country”: “CN”,
“address”: {
“city”: “上海”,
“street”: “浦东某路”
}
},
{
“name”: “Anna”,
“age”: 31,
“country”: “US”,
“address”: {
“city”: “San Francisco”,
“street”: “Market St”
}
}
]
如果你刚接触 jq,装一个先。大多数 Linux 发行版可以用包管理器直接装,像 apt、yum、brew 都有。装好之后在终端敲 jq,开干就行。
有几条经验别忽视:命令行里的表达式用单引号包起来,防止 shell 把点号和括号当成东西处理;处理中文时终端和文件编码都得是 UTF-8,否则可能看到乱码;如果数据量很大要注意内存,jq 是把输入读到内存里处理的,文件太大时要分片或分批处理。
输入的 JSON 结构不同,写法也会有差别。常见两类是“数组里套对象”和“对象里套对象”。许多示例默认第一种。如果你的输入不是数组,直接用 .[] 会报错,先用 jq '.' 看整体结构,确认键名和层级,再写表达式。
工具的链式处理特别好使。把读取、过滤、重构、排序、输出按步骤串起来,前一步的结果直接传给后一步,像流水线一样干活。输出紧凑格式用 -c,便于把结果传给别的命令或脚本:
$ jq -c '.[] | {name: .name, age: .age}' input.json
这玩意学会后,你会发现许多以前要写几十行脚本才能办的事,几条 jq 就能解决。调试快,上手也不难。平时做数据清洗、日志筛查、接口返回校验,拿 jq 在命令行里一转就干了。你可以把常用的几条命令收藏起来,遇到同类型的活儿直接套用,效率上来不少。


