美文网首页
关于使用jq 处理json格式的简单笔记

关于使用jq 处理json格式的简单笔记

作者: My熊猫眼 | 来源:发表于2021-08-07 13:02 被阅读0次

    json格式包含有如下的基本类型: 数字,字符串,false, true, null
    而由基本类型组成的复合类型有: 数组,对象;其中数组是以 [ ] 进行标记的,而对象是以 { } 进行标记;

    jq 这个命令用来处理json数据格式,非常方便,简单记录其常用的使用方法如下:
    A. 对于数组的处理:
    1). 如果 jq 要处理的json是 数组类型,那么用 “jq .[ ]” 可以将数组的最外层的[ ] 标记脱掉, 从而变成 对象 类型。
    2). 上述命令的 中括号里面可以带有参数,这个参数就是 数组的下标,这个下标从前向后最小是 0,最大值没有限制,如果超出,那么就会return null. 同时支持下标从后向前基数,最小为-1. 但是参数的值除了数字,不可以是空格. 同时数组的下表支持 切片,也就是 [2:7] 或者 [1,2,5,7] 这种格式都是支持的.
    B. 对于对象的处理:
    1). 因为对象里面的每个元素都是 key:value的形式存在,虽然value 也可以是一个复合类型,但是不影响 key:value 这种格式,所以对于对象,通常用 jq .key 这种方式来获取对应key的value. 其中key 在这里可以不用引号括起来,当然也可以用引号括起来,反正key都是字符串类型。
    2). 如果要获得对象所有元素的key值,那么要把 |keys 串接在对象后面,需要注意的是 这里不是利用的shell的管道,而是jq内置的管道,所以属于jq的参数的一部分. 例如:

    [root@localhost Desktop]# cat t | jq .[0]         #获得的结果是一个json 对象. 
    {   
      "cloudName": "ACl",
      "hom": "33ac8Xc",
      "id": "c2X8",
      "isDefault": true,
      "managedByms": [],
      "name": "Ation 1",
      "state": "Enabled",
      "DId": "3Xcd90ff72c2c",
      "user": {
        "name": "1Da",
        "type": "seDl"
      }
    }
    [root@localhost Desktop]# cat t | jq ".[0]|keys"   #获取所有的key值,如果value 依然是对象,那么这里不会列出value中对象的key值. 
    [
      "cloudName",
      "hom",
      "id",
      "isDefault",
      "managedByms",
      "name",
      "state",
      "DId",
      "user"
    ]
    

    其实 keys 属性不仅仅支持 对象,也支持json 数组,比如:

    [root@localhost Desktop]# echo '["china","chinese","CHINA"]' | jq '.|keys'
    [
      0,
      1,
      2
    ]
    

    3). 判断是否存在某个key.
    在上面利用jq内置的 keys 属性,可以获取所有的key, 其实还有jq内置的has 方法,这个方法可以判断对应的key是否存在. 例子如下:

    [root@localhost Desktop]# cat t | jq '.[0]|has("users")'
    false
    [root@localhost Desktop]# cat t | jq '.[0]|has("user")'
    true
    [root@localhost Desktop]# 
    

    4). jq 的查找结果避免输出 错误,转而输出null
    在查找条件的后面加上一个问号,那么如果找不到就不会输出任何的error, 相应的输出一个null来替代. 这个问号可以加在方法的后面(后面的例子中可以看到)。这在递归查找的时候非常有用;否则可能会出现报错的情形.
    5). jq 的查找结果为空,避免输出null ,而是什么都不输出
    目前不知道怎么实现,暂且用其他的linux 命令来过滤吧
    6). 根据指定的关键字查找有该关键字的key,也就是模糊查找
    jq 支持PCRE 正则表达式,所以支持模糊搜索, 这里主要展示用scan 方法输出模糊搜索的结果. 用法实例如下:

    [root@localhost Desktop]# cat t | jq '.[]|keys?|.[]|scan(".*ten.*",".*Ten.*",".*id.*")?'    #首先去掉 json 数组的 [ ] 符号, 然后调用keys 属性获得对应的keys 值,这时候的类型依然变成了数组,所以再次去掉数组的标志符号,从而变成了字符串,把这个字符串传递给scan 方法,从而输出模糊匹配的结果. 
    "homeTenantId"
    "id"
    "managedByTenants"
    "tenantId"
    "id"
    

    7). 根据指定的key, 查找嵌套对象中所有该key的value,输出该value
    使用 .. 或者 recurse 来表示递归查找,然后通过管道进行常规的查找就可以了,举例如下:

    [root@localhost Desktop]# cat t | jq 'recurse|.id?'
    "c22b1b54-fa25-4901-ad3f-d91836a747b8"
    null
    {
      "user": "multiple"
    }
    null
    [root@localhost Desktop]# cat t | jq 'recurse|.user?'   #使用 recurse 内置方法
    {
      "name": "1Da",
      "type": "sDl"
    }
    null
    null
    "multiple"
    [root@localhost Desktop]# cat t | jq '..|.user?'        #使用 .. 来表示递归,和recurse 一样;
    {
      "name": "1Da",
      "type": "sDl"
    }
    null
    null
    "multiple"
    

    8). 如何将匹配key 的 key 和value 一起进行输出?

    az vm get-instance-view -g rgtest -n rheltest |jq  '..|{name:.name?}'
    
    yan@Azure:~$ az vm get-instance-view  -g rgtest -n rheltest | jq '..|{name:.name?}|select(.name!=null)'       #通过select 方法实现非空输出,并且输出结果是key:value的方式
    {
      "name": "rheltest"
    }
    {
      "name": "rheltest_OsDisk_1_beee1fadb3de4ac0846a48c9df7c73b5"
    }
    {
      "name": "OmsAgentForLinux"
    }
    {
      "name": "rheltest_OsDisk_1_beee1fadb3de4ac0846a48c9df7c73b5"
    }
    
    yan@Azure:~$ az vm get-instance-view  -g rgtest -n rheltest | jq '..|.name?|select(.!=null)'      #通过select进行非空输出,并且输出结果是 value方式;
    "rheltest"
    "rheltest_OsDisk_1_beee1fadb3de4ac0846a48c9df7c73b5"
    "OmsAgentForLinux"
    "rheltest_OsDisk_1_beee1fadb3de4ac0846a48c9df7c73b5"
    

    以上的命令表示递归方式,获取Key为name的所有key:value对,并以key:value的方式进行输出,但是空的字典对象如何排除呢? 目前还没有发现好的解决方法

    9). 因为keys 属性支持对象的同时,也支持数组,所以如何来剔除数组而只是要对象的keys呢?
    有一个walk 方法可以实现,但是不常用,所以这里不做讨论.
    10).嵌套的模糊查找,上面描述了用scan进行模糊查找,以及用recurse来进行嵌套,如何两者结合呢?
    因为scan方法只能够作用于字符串,所以不可以简单的将recurse和scan 结合起来使用,这里需要通过keys来实现 嵌套的模糊查询. 举例如下:

    [root@localhost Desktop]# cat t | jq '.[]|keys?|.[]|scan(".*use.*")?'  #直接的模糊查询,只能找到一个key.
    "user"
    [root@localhost Desktop]# cat t | jq '.[]|..|keys?|.[]|scan(".*use.*")?' #先通过嵌套输出所有的key, 然后再模糊查询. 得到的是两个key. 
    "user"
    "user"
    [root@localhost Desktop]# 
    
    

    11). 其他使用小tips:
    在可以使用 .key1.key2 这种情况下,也可以使用 .key1|.key2 的格式,个人更倾向于使用 .key1|.key2 ,因为看起来更清晰明了. 比如下面的例子.

    [root@localhost Desktop]# cat t| jq .[0].user
    {
      "name": "1c56a18a-8458-486d-85a9-2e2ac4db47da",
      "type": "servicePrincipal"
    }
    [root@localhost Desktop]# cat t| jq .[0]|.user
    bash: .user: command not found...
    [root@localhost Desktop]# cat t| jq '.[0]|.user'
    {
      "name": "1c56a18a-8458-486d-85a9-2e2ac4db47da",
      "type": "servicePrincipal"
    }
    [root@localhost Desktop]# 
    

    在大多数情况下我们看到的json 复合格式最外层都是数组的形式,而不是对象的形式,这个是因为什么原因呢? 因为json的对象必须是 key:value 的格式,虽然value 也可以是一个复合格式,但是一定需要key:value 形式,而 数组的不同元素的类型之间没有任何的关联,同一个数组,既可以包含有字符串元素,也可以包含对象元素,还可以包含数字... ,因此一个复合类型的 json格式一般最外层都是数组的形式.

    最常使用的一种场景如下:

    首先用模糊查询,配合递归查找相应的key;-----简言之,就是找到key
    然后用特定的key, 配合递归查询找到所有的结果;------简言之,就是依据key遍历到所有的值
    最后对上述的结果做进一步的处理得到需要的结果. -----简言之,对得到的值做进一步的过滤获得真正需要的结果
    简单例子如下下:

    [root@localhost Desktop]# cat t | jq '.[]|..|keys?|.[]|match(".*use.*"; "ig")?|.string'        #这里使用 match 方法而不是使用 scan方法,因为scan方法不知道怎么忽略大小写. 其中flag 是 i, g ;分别表示忽略大小写,以及global match. 最终匹配到的key是如下的4个
    "UseAT"
    "user"
    "username"
    "username"
    [root@localhost Desktop]# cat t | jq '.[]|..|.username?' | grep -Evi null     #通过递归输出username 这个key的所有value.  
    "unknown"
    "multiple"
    #最后需要找到真正需求的值,这个根据具体情况来实现,这里不展示. 
    [root@localhost Desktop]# az account show | jq '..|keys?|.[]|match(".*tenant.*",".*home.*";"ig")|.string'      #其实match 可以实现多个条件写到一起,当这样做的时候,多个条件之间是 逻辑或的关系,并且是以 逗号进行分割的;而 flag 则是 分号进行分割的;
    "homeTenantId"
    "homeTenantId"
    "managedByTenants"
    "tenantId"
    [root@localhost Desktop]# 
    

    简单总结:

    1. 通过 模糊搜索,然后导出所有相关的key
    yan@Azure:~$ az vm get-instance-view -g rgtest -n rheltest | jq '..|keys?|.[]|scan(".*name.*")'
    "name"
    "name"
    "adminUsername"
    "name"
    "name"
    yan@Azure:~$
    
    1. 利用上一步的key, 然后输出对应的value或者key:value, 并且排除结果是null的值;
    yan@Azure:~$ for i in `az vm get-instance-view -g rgtest -n rheltest | jq '..|keys?|.[]|scan(".*name.*")' `;do az vm get-instance-view -g rgtest -n rheltest |jq "..|.$i?|select(.!=null)";done
    
    yan@Azure:~$for i in `az vm get-instance-view -g rgtest -n rheltest | jq '..|keys?|.[]|scan(".*name.*")' `;do az vm get-instance-view -g rgtest -n rheltest |jq "..|{$i:.$i?}|select(.$i!=null)"; done
    

    相关文章

      网友评论

          本文标题:关于使用jq 处理json格式的简单笔记

          本文链接:https://www.haomeiwen.com/subject/qlpbyltx.html