2020/01/15

jq

JSON 格式的應用現在已經隨處可見了,目前使用的程式語言都有相關支援的套件,如果要在 Linux 底下操作的話有一個非常好用的工具叫 jq,下面來展示應用範例

應用網址:https://jsonplaceholder.typicode.com/users

curl -s https://jsonplaceholder.typicode.com/users | jq .

我們會得到格式漂亮的結果

[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
]

而 jq 可以做 node 的搜尋,以上面那个例子

curl -s https://jsonplaceholder.typicode.com/users | jq .[0].name # "Leanne Graham"
curl -s https://jsonplaceholder.typicode.com/users | jq .[0].address.street # "Kulas Light"

使用 jq 的一些參數也可以達成 json encode 的功能:

test

#!/bin/bash
NAME=$1
AGE=$2
JSON_STRING=$(jq -n \
--arg name "$NAME" \
--arg age "$AGE" \
'{name: $name, age: $age}')
echo $JSON_STRING

./test chan 40 # { "name": "chan", "age": "40" }

jq 沒有驗證 json format 的功能,但我們可以利用一些 shell script 的特性辦到這件事

#!/bin/bash
function json_validator() {
echo $1 | jq . &> /dev/null
if [[ $? == 0 ]]; then
echo "$1 is valid format"
else
echo "$1 is invalid format"
fi
}
JSON='{"name": "chan"}'
json_validator "$JSON"
# {"name": "chan"} is valid format
JSON='{"name":}'
json_validator "$JSON"
# {"name":} is invalid format

jq 也可以使用自定義模組,在 ~/.jq 裡面可以將一些複雜但常用的內容先寫好

def blurry($f):
($f | ascii_upcase) as $ucf
| to_entries[]
| select((.key|ascii_upcase) | startswith($ucf))
| .value;
def very_blurry($f):
($f | ascii_upcase) as $ucf
| to_entries[]
| select(.key | ascii_upcase | index($ucf))
| .value;

這樣的話像搜尋 docker 的 config 的話就非常好用,像是 docker inspect test | jq '.. | blurry("config")?' | objects

搜尋語法

$ jq 'map(select(.id=="1234"))'
$ jq 'map(select(.id|index("1234")))'
$ jq 'map(select(.id|contains("1234")))'
$ jq 'map(select(.id|test("1234";"i")))'
$ jq 'map(select(.id|match("1234";"i")))'

docker inspect 出來的結果是 json format,假設我們今天要找 LogPath,但不記得他的層級的話,有個語法可以針對該 key 找出資料。

docker inspect <container_id> | jq -r '.. | .LogPath? // empty'

-r 是輸出 raw data 好複製,// empty 部分會讓沒搜到的結構不輸出,因此最終只會跑出我們要的結果。