jq命令简易教程——Linux中处理JSON数据的利器

在shell脚本中,当我们需要对JSON数据(例如ceph、kubernetes等一些命令的输出,或是调用API获得的响应)进行处理和提取时,如果使用传统的文本三剑客sed、awk和grep,命令将会非常臃肿不可读。虽然这三个命令在处理松散结构的数据时很有用,但当面对JSON这类数据时,却显得不够优雅。

jq就是这样一个命令行工具,专门用于处理JSON数据,特别适用于shell脚本。

jq命令的使用

首先我们需要安装jq命令:yum install jq -y

创建如下的示例文件(一张学生成绩表):

json 复制代码
# cat test.json
[
    { "name": "zhangsan", "gender": "male", "score": 80 },
    { "name": "lisi", "gender": "male", "score": 90 },
    { "name": "wangerma", "gender": "female", "score": 100 }
]

jq命令的标准语法为jq [options] <jq filter> [file...],最简单的过滤器为.,它将输入原封不动地转换为输出(会做格式化、高亮),例如:

json 复制代码
#  jq '.' test.json 
[
  {
    "name": "zhangsan",
    "gender": "male",
    "score": 80
  },
  {
    "name": "lisi",
    "gender": "male",
    "score": 90
  },
  {
    "name": "wangerma",
    "gender": "female",
    "score": 100
  }
]

这个命令可以用于检测输入是否为合格的json,例如将test.json修改为:

json 复制代码
# cat test.json
[
    { "name": "zhangsan", "gender": "male", "score": 80 },
    { "name": "lisi", "gender": "male", "score": 90 },
    { "name": "wangerma", "gender": "female", "score": 100 }

则命令会报错:

shell 复制代码
#  jq '.' test.json 
parse error: Unfinished JSON term at EOF at line 6, column 0

所以我们可以写如下shell作判断:

shell 复制代码
#!/bin/bash
if jq '.' test.json >/dev/null 2>&1
then
    echo "valid json"
else 
    echo "invalid json"
fi

检索键值

如果我们将需要获取所有学生的姓名列表,如下:

json 复制代码
[
  "zhangsan",
  "lisi",
  "wangerma"
]

该怎么做?为此我们需要先使用数组迭代器.[]来获取列表中每一项值:

json 复制代码
#  jq '.[]' test.json 
{
  "name": "zhangsan",
  "gender": "male",
  "score": 80
}
{
  "name": "lisi",
  "gender": "male",
  "score": 90
}
{
  "name": "wangerma",
  "gender": "female",
  "score": 100
}

然后获取每一项输出的name键值,这里使用我们熟悉的管道符|

json 复制代码
#  jq '.[] | .name' test.json 
"zhangsan"
"lisi"
"wangerma"

如果想要去掉输出中的双引号,可以使用-r参数输出原始字符串:

json 复制代码
#  jq -r '.[] | .name' test.json 
zhangsan
lisi
wangerma

接下来我们可以在过滤器的最外层加上[]来讲结果转换为列表:

json 复制代码
#  jq '[.[] | .name]' test.json 
[
  "zhangsan",
  "lisi",
  "wangerma"
]

以上过滤器的表达式看起来似乎有些臃肿了,好在jq提供了map函数,因此我们可以将上述表达式替换为:

json 复制代码
#  jq 'map(.name)' test.json 
[
  "zhangsan",
  "lisi",
  "wangerma"
]

使用add函数对键值进行求和

仿照上述语法,我们可以可以获得所有学生的成绩列表:

json 复制代码
#  jq 'map(.score)' test.json 
[
  80,
  90,
  100
]

同样。使用管道符|add函数,即可轻松获取所有学生的成绩总和:

json 复制代码
#  jq 'map(.score) | add' test.json 
270

使用select获取部分键值

如果我们想要对所有男生的成绩进行求和,就需要使用select(condition)函数了,所有conditiontrue的输入会被保留,false则会被丢弃,如我们获取所有性别为男的数据gender == "male"

json 复制代码
#  jq 'map(select(.gender == "male"))' test.json 
[
  {
    "name": "zhangsan",
    "gender": "male",
    "score": 80
  },
  {
    "name": "lisi",
    "gender": "male",
    "score": 90
  }
]

进一步获取所有男生的分数:

json 复制代码
#  jq 'map(select(.gender == "male").score)' test.json 
[
  80,
  90
]

最后求和:

json 复制代码
#  jq 'map(select(.gender == "male").score) | add' test.json 
170

将输入转换为新的格式输出

如果我们想将上述步骤中的输出合并为一个新的json数据并输出,则可以使用如下方式进行格式化输出:

json 复制代码
#  jq '{ students: map(.name), totalscore: map(.score) | add, totalmalescore: map(select(.gender == "male").score) | add }' test.json 
{
  "students": [
    "zhangsan",
    "lisi",
    "wangerma"
  ],
  "totalscore": 270,
  "totalmalescore": 170
}

总结

在shell脚本中处理json数据,jq命令是个很好的选择。

本教程将对这个命令的用法只进行了简单入门介绍,如需了解详细语法,可以参看官方文档:https://jqlang.github.io/jq/manual/

相关推荐
cellurw40 分钟前
Day69 SQLite3动态库移植 + BMP图像解析显示 + 进度条控件设计与动态文本管理
linux
nono牛1 小时前
Linux基础指令大全(快速上手)
linux·服务器·windows·智能手机
<但凡.1 小时前
Linux修炼:库制作与原理(一)
linux·运维·服务器
Maple_land3 小时前
编译器的“隐形约定”与本地变量:解锁Linux变量体系的关键密码
linux·运维·服务器·c++·centos
深思慎考3 小时前
微服务即时通讯系统(服务端)——Speech 语音模块开发(2)
linux·c++·微服务·云原生·架构·语音识别·聊天室项目
小蜜蜂爱编程4 小时前
Ubuntu无法开机Failed to activate swap /swapfile
linux·运维·ubuntu
阿巴~阿巴~4 小时前
CPU 指令集、权限与用户态内核态机制
linux·运维·服务器·指令集·权限·用户态内核态
小涵4 小时前
企业SRE/DevOps向的精通Linux课程培训课程
linux·运维·devops·1024程序员节
航Hang*4 小时前
第1章:初识Linux系统——第8节:查看/修改权限控制和ACL
linux·运维·服务器·笔记·操作系统
我爱钱因此会努力5 小时前
初始化服务器
linux·运维·服务器·tcp/ip·centos