侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Linux 命令行下优雅的解析 JSON

zze
zze
2021-04-28 / 0 评论 / 0 点赞 / 553 阅读 / 8105 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

简介

JSON 是前后端交互经常用到的格式,对于常见后端语言来说(比如 Java、Python、Golang 等),解析 JSON 都不是什么大事,干的相当的漂亮。Linux 下也有处理处理 JSON 的神器:jq

要使用 jq 首先需要安装它,由于它是使用 C 语言编写的,所以它没有什么特殊依赖,它对应命令的名字也叫 jq,所以你可以直接在官网下载它的二进制包加个执行权限就可以使用了,官网地址:

可以看到其它安装方式在上述链接中也描述的很全面,我这里使用的 Linux 发行版是 Ubuntu,所以安装它我也可以使用 apt

$ apt install jq -y

jq 提供了类是于编程语言的表达式系统,包括逻辑判断、正则表达式、debug、try-catch、while、以及各种函数等等,可以作为一门语言来学,这里就不详细展开来,换言之就是它很牛批内容很多,所以本篇文章仅会介绍一些我觉得常用、有必要知道的知识点,所以你如果想要了解除本篇文章之外的内容,你可以参考官网:

使用

首先准备以下 json 数据用做测试,我这里将如下内容保存到名为 json-example.json 文件中 :

{"apiVersion": "extensions/v1beta1","kind": "Ingress","metadata": {"annotations": {"kubernetes.io/ingress.class": "nginx"},
"generation": 1,"name": "test-ing","namespace": "test"},"spec": {"rules": [{"host": "zze.xyz",
"http": {"paths": [
{"backend": {"serviceName": "zze-backend","servicePort": 80},"path": "/","pathType": "ImplementationSpecific"},{"backend": {"serviceName": "test-backend","servicePort": 80
},"path": "/test","pathType": "ImplementationSpecific"}]}}]}}

你可能会想我为啥要放一个乱糟糟的未排版的内容在这,因为这里要介绍的 jq 的第一个功能就是格式化排版。

它的使用类似 grep|awk|sed,既支持 jq <选项|表达式> <文件名> 的语法,也支持接收管道过来的数据,所以这里也可以使用 cat <文件名> | jq [选项|表达式] 的语法。

jq 的表达式中,开头的 . 有着特殊含义。可以把整个 Json 内容当做一个大的 Object,而 . 就代指这个 Object,其中的各个 Key 就是这个 Object 的属性,属性可以通过 .<属性名>[.属性名[.属性名]...] 的方式来访问。

格式化排版

  • 格式化显示 json-example.json 的内容。
# 也可使用 `cat json-example.json | jq`,后面的 `'.'` 可以省略,这里它的语法有点类似 Go Template 的语法,如果你常写 Helm Chart 就应该感到很亲切。
$ cat json-example.json | jq '.'
{
  "apiVersion": "extensions/v1beta1",
  "kind": "Ingress",
  "metadata": {
    "annotations": {
      "kubernetes.io/ingress.class": "nginx"
    },
    "generation": 1,
    "name": "test-ing",
    "namespace": "test"
  },
  "spec": {
    "rules": [
      {
        "host": "zze.xyz",
        "http": {
          "paths": [
            {
              "backend": {
                "serviceName": "zze-backend",
                "servicePort": 80
              },
              "path": "/",
              "pathType": "ImplementationSpecific"
            },
            {
              "backend": {
                "serviceName": "test-backend",
                "servicePort": 80
              },
              "path": "/test",
              "pathType": "ImplementationSpecific"
            }
          ]
        }
      }
    ]
  }
}

按 key 取值

  • 取出 metadata.namespace 值。
$ cat json-example.json | jq '.metadata.namespace'
"test"
  • 取出 spec.rules 列表下第一个元素的 host 值。
# [0] 表示取列表的第一个元素,0 是元素的索引
$ cat json-example.json | jq '.spec.rules[0].host'
"zze.xyz"
  • 取出 spec.rules[].http.paths 列表下所有元素的 path 值。
$ cat json-example.json | jq '.spec.rules[].http.paths[].path'
"/"
"/test"
  • 取一个不存在的 Key haha 会返回 null
$ cat json-example.json | jq '.haha'
null

修改指定 Key 的值

  • 修改 metadata.namespace 的值为 zze-test
{
...
  "metadata": {
    "annotations": {
      "kubernetes.io/ingress.class": "nginx"
    },
    "generation": 1,
    "name": "test-ing",
    "namespace": "zze-test"
  },
...

为文章简约明了,我这里只将改变后内容相关结果展示出来,... 表示内容没有发生变化。

  • 修改 spec.rules 列表下第一个元素的 host 值为 test.zze.xyz
$ cat json-example.json | jq '.spec.rules[0].host="test.zze.xyz"'
{
...
  "spec": {
    "rules": [
      {
        "host": "test.zze.xyz",
...

增加属性

  • 增加一个多级嵌套属性 status.loadBalancer.ingress,它是一个数组,该数组下还有一个嵌套对象 {"ip" : "10.0.1.100"}
$ cat json-example.json | jq '.status.loadBalancer.ingress[0]={"ip" : "10.0.1.100"}'
...
  },
  "status": {
    "loadBalancer": {
      "ingress": [
        {
          "ip": "10.0.1.100"
        }
      ]
    }
  }
}

取指定字段值生成新 Json

  • 修改 metadata.annos 的名字为 metadata.annos 并添加属性 n
$ cat json-example.json | jq '. | {"n": .metadata.name, ".annos": .metadata.annotations}'
{
  "n": "test-ing",
  ".annos": {
    "kubernetes.io/ingress.class": "nginx"
  }
}
  • 修改 spec.rules[].http.paths 下所有的名为 path 的 Key 为 p 值不变存入新数组。
$ cat json-example.json | jq '[.spec.rules[].http.paths[] | {"p": .path }]'
[
  {
    "p": "/"
  },
  {
    "p": "/test"
  }
]

查看列表长度

  • 查看 spec.rules 列表长度。
$ cat json-example.json | jq '.spec.rules | length'
1

删除指定 Key

  • 删除 metadata.generation 属性。
$ cat json-example.json | jq 'del(.metadata.generation)'
{
  "apiVersion": "extensions/v1beta1",
  "kind": "Ingress",
  "metadata": {
    "annotations": {
      "kubernetes.io/ingress.class": "nginx"
    },
    "name": "test-ing",
    "namespace": "test"
  },
...

获取所有的 Key

  • 获取最外层所有 Keys。
$ cat json-example.json | jq 'keys'
[
  "apiVersion",
  "kind",
  "metadata",
  "spec"
]
  • 获取 metadata 下的所有 Key
$ cat json-example.json | jq '.metadata | keys'
[
  "annotations",
  "generation",
  "name",
  "namespace"
]

判断是否存在某个 Key

  • 判断 metadata 下是否存在名为 generation 的 Key。
$ cat json-example.json | jq '.metadata | has("generation")'
true
0

评论区