• kubernetes集群管理之通过jq来截取属性


    系列目录

    首先要声明,这里的jq并不是批前端框架里的jquery,而是一个处理json的命令行工具.

    jq工具相比yq,它更加成熟,功能也更加强大,主要表现在以下几个方面

    • 支持递归查找(我点对我们平时查看文件很方便)

    • 支持条件过滤

    • 支持控制语句

    • 支持数组范围索引

    这个工具在macos和windows都提供在线包安装服务,linux并没有官方包服务,需要下载后放到usr/bin目录下

    下载地址

    centos下也可以通过以下方式安装

    wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    rpm -ivh epel-release-latest-7.noarch.rpm
    yum repolist
    

    基本语法

    基本语法格式如下

    jq [options] <jq filter> [file...]
    

    需要把文件放在最后面,但是也无所谓,很多时候我们并不处理本地的json,而是通过标准输入来处理其它来源类型的json

    我本地存有一个叫作test.json的json文件,我们可以通过jq . test.json查看文件里的所有内容

    {
      "json": [
        "rigid",
        "better for data interchange"
      ],
      "yaml": [
        "slim and flexible",
        "better for configuration"
      ],
      "object": {
        "key": "value",
        "array": [
          {
            "name": null
          },
          {
            "name": true
          },
          {
            "name": 24
          }
        ]
      },
      "paragraph": "Blank lines denote
    paragraph breaks
    ",
      "content": "Or we
    can auto
    convert line breaks
    to save space"
    }
    

    jq输出的json文件默认都是格式化过的,方便我们查看

    我们仿照上一节,来获取json数组里的所有值.

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .json test.json
    [
      "rigid",
      "better for data interchange"
    ]
    

    通过以下命令获取array数组

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .object.array test.json
    [
      {
        "name": null
      },
      {
        "name": true
      },
      {
        "name": 24
      }
    ]
    

    通过与上节jq类似的命令获取array里面的值

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .object.array[].name test.json
    null
    true
    24
    

    数组也可以在中括号里面指定索引(跟绝大多数编程语言一样,从0开始)也与前面的yq类似,不同的是这里可以使用[start:end]的方式来索引范围

    上面的例子我们这次不取全部,只取第0个和第一个

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .object.array[0:2] test.json
    [
      {
        "name": null
      },
      {
        "name": true
      }
    ]
    

    除了索引范围以后,还可以索引不连续的对象,语法为[index1,index2,...]形式

    例如,以下操作获取第零个和第二个对象

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .object.array[0,2] test.json
    {
      "name": null
    }
    {
      "name": 24
    }
    

    以上操作并索引并不一定按照从小到大的顺序,比如以下也是可以的

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .object.array[1,0,2] test.json
    {
      "name": true
    }
    {
      "name": null
    }
    {
      "name": 24
    }
    

    可空对象

    有时候我们不确定一个对象是否存在,这时候我们可以在对象后面跟个问号?来表明不确定这个对象是否存在

    比如jq .yml? test.json表明你不确定yml这个属性在要查询的对象中是否存在,如果这个对象是不存在的,则返回的值为null

    实际上你会发现,上面不写问号返回的值也是null,并不会报错.在这里体现的不明显,但是对数组类型的如果一个对象不存在写为数组形式就会报错

    比如jq .yml[] test.json就会出现jq: error (at test.json:25): Cannot iterate over null (null)错误

    而使用jq .yml[]? test.json即便yml对象不存在也不会报错

    使用逗号,来取多个对象

    假如我们想要同时取json和yaml这两个对象,可以使用,把两个命令分开,把它们的结果合在一块

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq .json,.yaml test.json
    [
      "rigid",
      "better for data interchange"
    ]
    [
      "slim and flexible",
      "better for configuration"
    ]
    

    使用括号

    上面的使用都逗号的命令里我们已经使用两条命令了,实际工作中可能有更加复杂的命令组合,这时候可以使用()来组织.在jq里使用()和在其它编程语言里使用相同.

    使用管道符|

    在jq里管道符概念和linux上概念基本相同.可以把上一个命令的结果作为下一个命令的输出.前面的.object.array也可以写作管道模式.object|.array先用.object取object的所有对象,然后结果作为下级管道的输入值,.array从管道结果里取array数组

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq '.object|.array' test.json
    [
      {
        "name": null
      },
      {
        "name": true
      },
      {
        "name": 24
      }
    ]
    

    递归查找子对象

    在kubernetes 的jsonpath里,可以使用..来查找子对象,非常方便,惟一不好的是如果子对象包含数组类型则显示为Map[xxx]类型,并且展示的结果不再是json格式,可读性不是特别好.比较遗憾的是,在jq里并不支持..这种语法,而是更为复杂一些,需要使用管道符.

    命令的格式如下

    ..|.对象名?
    

    首先这里使用了..表示从根对象开始取,然后使用管道符,后面之所以使用可空对象(对象后面带问号)是因为它会在每一层都查找,不使用可空对象的话找不到就会报错.

    假如我们并不知道array对象的上一层是什么,但是知道这个对象存在.可以使用下面命令来获取.

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq '..|.array?' test.json
    null
    [
      {
        "name": null
      },
      {
        "name": true
      },
      {
        "name": 24
      }
    ]
    null
    null
    null
    

    这里之所以会出现好多的null,因为jq会进入每一层对象里面查找,找不到就返回null.为了展示美观,我们也可以做一些简的处理

    tylerzhou@DESKTOP-OE0CB8G:/mnt/d/test/jqjqtest$ jq '..|.array?' test.json|sed 's/null//g'
    
    [
      {
        "name":
      },
      {
        "name": true
      },
      {
        "name": 24
      }
    ]
    

    以上命令使用sed把null替换为空,这里不够优雅的地方在于把第一个name的值null也替换为空了.

    这里的命令外层加了引号,之所以要加引号是因为这个管道是jq管道,如果不加引号就会被shell识别为shell命令管道,从而导致错误.

    过滤对象

    我们使用示例来说明,使用以下命令获取kubernetes集群中的一个pod的conditions信息

    [centos@k8s-master ~]$ kubectl get pod consul-0 -ojson|jq '.status.conditions[]'
    [
      {
        "lastProbeTime": null,
        "lastTransitionTime": "2019-05-14T07:19:28Z",
        "status": "True",
        "type": "Initialized"
      },
      {
        "lastProbeTime": null,
        "lastTransitionTime": "2019-05-14T07:25:06Z",
        "status": "True",
        "type": "Ready"
      },
      {
        "lastProbeTime": null,
        "lastTransitionTime": "2019-05-14T07:25:06Z",
        "status": "True",
        "type": "ContainersReady"
      },
      {
        "lastProbeTime": null,
        "lastTransitionTime": "2019-05-14T07:19:28Z",
        "status": "True",
        "type": "PodScheduled"
      }
    ]
    

    现在我想要过滤typeReady的对象,可以使用以下命令

    [centos@k8s-master ~]$ kubectl get pod consul-0 -ojson|jq '.status.conditions[]|select(.type=="Ready")'
    {
      "lastProbeTime": null,
      "lastTransitionTime": "2019-05-14T07:25:06Z",
      "status": "True",
      "type": "Ready"
    }
    

    以上命令把status里的conditions数组对象做为输入传递给管道下一级,然后使用select函数里面传入条件.

    以上是完全匹配type属性值为Ready,如果想要模糊匹配,则可以通过管道使用contains函数

    [centos@k8s-master ~]$ kubectl get pod consul-0 -ojson|jq '.status.conditions[]|select(.type|contains("Ready"))'
    {
      "lastProbeTime": null,
      "lastTransitionTime": "2019-05-14T07:25:06Z",
      "status": "True",
      "type": "Ready"
    }
    {
      "lastProbeTime": null,
      "lastTransitionTime": "2019-05-14T07:25:06Z",
      "status": "True",
      "type": "ContainersReady"
    }
    

    这样,两个type值包含Ready的全部被选择出来了.

    正则匹配

    上面的过滤条件中,由于Ready是大写的,因此不论是相等比较还是包含比较,都必须使用大写,如果是小写则无法匹配到.但是很多时候我们可能对大小写是不清楚的,我们希望匹配的时候区分大小写,这在jq里也是可以做到的,我们使用match函数,match函数为正则匹配函数.接收一个数组形式的参数,数组的第一项为要匹配的内容,第二项为开关(比如g代表全局开关,i则代表不区分大小写)

    我们把上面的示例改造如下

    [centos@k8s-master ~]$ kubectl get pod consul-0 -ojson|jq '.status.conditions[]|select(.type|match(["ready","i"]))'
    {
      "lastProbeTime": null,
      "lastTransitionTime": "2019-05-14T07:25:06Z",
      "status": "True",
      "type": "Ready"
    }
    {
      "lastProbeTime": null,
      "lastTransitionTime": "2019-05-14T07:25:06Z",
      "status": "True",
      "type": "ContainersReady"
    }
    

    这样使用正则表达式我们就可以不区分大小写匹配了.

    以上只列出了工作中可能常用的功能,详细功能可以查看官方文档

  • 相关阅读:
    计算机硬件基础
    元类
    内置函数
    单例模式的三种实现方式
    字符编码
    odoo权限
    odoo api介绍
    odoo 二次开发小记不定时更新
    js与jQuery区别
    Cookie, LocalStorage 与 SessionStorage说明
  • 原文地址:https://www.cnblogs.com/tylerzhou/p/11054378.html
Copyright © 2020-2023  润新知