はじめに
jsonをモニョモニョするのにjqというツールがありますが、使い始めるとAPI確認したり叩いたりするのにとても役に立ちます。
自分は大体以下のようなときに使います。
- jsonを見やすくする(本記事対象外)
- indentedなjsonを一行にする(
jq -c .) - jsonをパラメータに引き渡す/結果から取り出すための前処理をする
- jsonの中に文字列としてjsonフォーマットのデータを入れる(
jq '. | @json') - jsonの中からjsonを取り出す(
jq '. | fromjson)
- jsonの中に文字列としてjsonフォーマットのデータを入れる(
- jqコマンドの結果(の一部)を変数に格納する
対象文字列の用意
jsonのサンプルは以下から拝借。
https://www.ibm.com/support/knowledgecenter/ja/SS9H2Y_7.5.0/com.ibm.dp.doc/json_jsonexamples.html
以下の通り。
text_ship_to=$(cat << EOF
{ "name" : "Jane Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345"
}
EOF
)
text_bill_to=$(cat << EOF
{ "name" : "John Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345"
}
EOF
)
text_base=$(cat << EOF
{ "name" : "John Smith",
"sku" : "20223",
"price" : 23.95,
"shipTo" : ${text_ship_to},
"billTo" : ${text_bill_to}
}
EOF
)
echo $text_base した結果がこんなかんじ。
{ "name" : "John Smith",
"sku" : "20223",
"price" : 23.95,
"shipTo" : { "name" : "Jane Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345"
},
"billTo" : { "name" : "John Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345"
}
}
操作
indentedなjsonを一行にする(jq -c .)
$text_baseはインデントの入ったprettyなjsonなので、これをcomapctにしてみる。
json_text=$(echo $text_base| jq -c .)
ヒアドキュメントを直接渡す場合は、jqに << する。
json_text=$(jq -c . << EOF
{ "name" : "John Smith",
"sku" : "20223",
"price" : 23.95,
"shipTo" : { "name" : "Jane Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345" },
"billTo" : { "name" : "John Smith",
"address" : "123 Maple Street",
"city" : "Pretendville",
"state" : "NY",
"zip" : "12345" }
}
EOF
)
結果はこんなかんじ
$ json_text=$(echo $text_base| jq -c .)
$ echo $json_text
{"name":"John Smith","sku":"20223","price":23.95,"shipTo":{"name":"Jane Smith","address":"123 Maple Street","city":"Pretendville","state":"NY","zip":"12345"},"billTo":{"name":"John Smith","address":"123 Maple Street","city":"Pretendville","state":"NY","zip":"12345"}}
jsonをパラメータに引き渡す/結果から取り出すための前処理をする
自分はおもに、AWS CLIでIAM設定するときのPolicyDocumentなど、json形式の引数をjsonの中に埋めたり出したりするのに使います。
jsonの中に文字列としてjsonフォーマットのデータを入れる(jq '. | @json')
jsonの中に文字列としてjsonを入れるため、試しに以下をエスケープする。
# エスケープ
escaped_text_ship_to=$(echo $text_ship_to | jq '. | @json')
escaped_text_bill_to=$(echo $text_bill_to | jq '. | @json')
escaped_text_* をechoしてみると、@jsonな(jsonの中に入れられる)形式にエスケープされていることが分かる。
echo $escaped_text_ship_to
echo $escaped_text_bill_to
"{\"name\":\"Jane Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"
"{\"name\":\"John Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"
baseに入れてみる。
escaped_text_base=$(cat << EOF
{ "name" : "John Smith",
"sku" : "20223",
"price" : 23.95,
"shipTo" : ${escaped_text_ship_to},
"billTo" : ${escaped_text_bill_to}
}
EOF
)
echo $escaped_text_base | jq してみた結果。shipToとbillToがエスケープされたjsonになってる。
{
"name": "John Smith",
"sku": "20223",
"price": 23.95,
"shipTo": "{\"name\":\"Jane Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}",
"billTo": "{\"name\":\"John Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"
}
jsonの中に文字列として入っているjsonフォーマットのデータを取り出す(jq '. | fromjson')
$escaped_text_baseのjsonの中のshipToはエスケープされている。
# shipToを取り出してみる
echo $escaped_text_base | jq '.shipTo'
"{\"name\":\"Jane Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"
これを| fromjsonを使ってunescapeしてみる。
echo $escaped_text_base | jq '.shipTo | fromjson'
以下のように取れる。
{
"name": "Jane Smith",
"address": "123 Maple Street",
"city": "Pretendville",
"state": "NY",
"zip": "12345"
}
jqコマンドの結果(の一部)を変数に格納する
AWS CLIでコマンド叩いた結果からIdだけ引っ張ってくるのに使ったりします。
まずは対象データの準備。
input='"{\"name\":\"Jane Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"'
echo $input
"{\"name\":\"Jane Smith\",\"address\":\"123 Maple Street\",\"city\":\"Pretendville\",\"state\":\"NY\",\"zip\":\"12345\"}"
この $inputをjqにかけて結果を変数に入れます。たとえばstateをダブルクオートなしで取り出す。
state=$(echo $input| jq 'fromjson | .state' | sed -e 's/"//g')
echo $state
NY