首先要聲明,這里的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\nparagraph breaks\n",
"content": "Or we\ncan auto\nconvert line breaks\nto 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"
}
]
現在我想要過濾type
為Ready
的對象,可以使用以下命令
[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"
}
這樣使用正則表達式我們就可以不區分大小寫匹配了.
以上只列出了工作中可能常用的功能,詳細功能可以查看官方文檔