こちらの記事は ケーシーエスキャロット Advent Calendar 2020 の20日目の記事です。
昨日は aooki
さんの WMS の地図画像を Google Map 上に表示する でした、クロスブラウザ問題まだまだあるんですね…。
さて皆さん、aws cli
は使用していますか?
AWSコンソールで見れば手軽に状況や結果は確認できますが、複数の確認を行う時はポチポチを複数行わないといけませんよね。
そんな時、aws cli
を使用すれば、複数の結果を json
でひとまとめで確認できます。
…が、結果が多数あると確認作業が大変なことは変わりません。
例えば、aws ec2 describe-instances
のコマンドを使用すればインスタンス情報が取得出来ますが、色々な情報を出力されすぎて対象のデータを目視で探し出すのも大変です。
そんな時、jq
コマンドを使用すれば特定の情報を抜き出すことが出来ます。
jq
json
データの加工・フィルターが行えるコマンド。
オフィシャルのマニュアルはこちらを参照。
準備
まずはインストールから始めましょう。
Windows10
の WSL(ubuntu18.04)
環境下へインストールしてみます。
$ sudo apt -y install jq
$ jq --version
jq-1.5-1-a5b5cbe
基本編
jq
での基本的なコマンドは、
-
.
(ルート) -
[]
(リスト)
の2つです。
また、|
(パイプ)を繋げることによって、下階層のデータに対して操作が行えます。
{
"schema": "value",
"list": [
{
"param_a": 111
},
{
"param_a": 222
}
]
}
例えば、上記のような json
があったとして schema
キーの値を取得したい場合は以下のようにします。
$ cat test1.json | jq '.schema'
"value"
また、代わりに list
キーを指定すると以下になります。
$ cat test1.json | jq '.list'
[
{
"param_a": 111
},
{
"param_a": 222
}
]
さらに |
で繋げて .[]
を指定すると以下の結果になります。
$ cat test1.json | jq '.list | .[]'
{
"param_a": 111
}
{
"param_a": 222
}
※ 一見、違いが分かりにくいですが、最上位の []
が外れています。
さらにさらに param_a
を |
で繋げると以下の結果となります。
$ cat test1.json | jq '.list | .[] | .param_a'
111
222
応用編
前述した aws ec2 describe-instances
コマンドで取得できる json
データから一部抜粋した以下の内容を例に進めます。
{
"Reservations": [
{
"Instances": [
{
"InstanceId": "i-111",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xvda1",
"Ebs": {
"VolumeId": "vol-111aaa"
}
},
{
"DeviceName": "/dev/xvda2",
"Ebs": {
"VolumeId": "vol-111bbb"
}
}
]
},
{
"InstanceId": "i-222",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xvda1",
"Ebs": {
"VolumeId": "vol-222ccc"
}
},
{
"DeviceName": "/dev/xvda2",
"Ebs": {
"VolumeId": "vol-222ddd"
}
}
]
}
]
}
]
}
例えば、VolumeId
の値を列挙しようとした場合、基本編で記載した通り |
で繋げていけば取得出来ます。
$ cat test2.json | jq '.Reservations | .[] | .Instances | .[] | .BlockDeviceMappings | .[] | .Ebs | .VolumeId'
"vol-111aaa"
"vol-111bbb"
"vol-222ccc"
"vol-222ddd"
因みに .xxx | .[]
は .xxx[]
と記載できるので、以下でも同じ結果が得られます。
$ cat test2.json | jq '.Reservations[] | .Instances[] | .BlockDeviceMappings[] | .Ebs | .VolumeId'
"vol-111aaa"
"vol-111bbb"
"vol-222ccc"
"vol-222ddd"
もっと言えば、|
で繋げて記載しなくても実現出来たりますが、|
で区切った方が階層が分かりやすいようにも思います。(この辺りは好みの問題ですね)
$ cat test2.json | jq '.Reservations[].Instances[].BlockDeviceMappings[].Ebs.VolumeId'
"vol-111aaa"
"vol-111bbb"
"vol-222ccc"
"vol-222ddd"
もう少し発展させて、DeviceName
キーの値が /dev/xvda1
の VolumeId
値のみを取得したい場合はどうすれば良いでしょう?
答えは、select
を使用すれば実現できます。
$ cat test2.json | jq '.Reservations[] | .Instances[] | .BlockDeviceMappings[] | select(.DeviceName == "/dev/xvda1") | .Ebs.VolumeId'
"vol-111aaa"
"vol-222ccc"
※ select
で DeviceName
が /dev/xvda1
のもののみ抽出しています。
さらに発展させて一緒に InstanceId
も取得する場合は以下となります。
$ cat test2.json | jq '.Reservations[] | .Instances[] | .InstanceId, (.BlockDeviceMappings[] | select(.Devi
ceName == "/dev/xvda1") | .Ebs.VolumeId)'
"i-111"
"vol-111aaa"
"i-222"
"vol-222ccc"
※ InstanceId
と ,
で繋げた上で VolumeId
は ()
で括りました。
でも、この出力結果だと分かりづらいですね。
InstanceId,VolumeId
のように csv 形式で出力してみたいと思います、最後に @csv
を付けると実現できます。
$ cat test2.json | jq '.Reservations[] | .Instances[] | [.InstanceId, (.BlockDeviceMappings[] | select(.Dev
iceName == "/dev/xvda1") | .Ebs.VolumeId)] | @csv'
"\"i-111\",\"vol-111aaa\""
"\"i-222\",\"vol-222ccc\""
※ 取得する項目は []
で括っていますが、@csv
で出力するには array
形式でないといけないからです。
一応、csv 形式で出力されましたが、"
が邪魔ですね…。
そんな場合は、-r
を指定すると取り除けます。
$ cat test2.json | jq -r '.Reservations[] | .Instances[] | [.InstanceId, (.BlockDeviceMappings[] | select(.
DeviceName == "/dev/xvda1") | .Ebs.VolumeId)] | @csv'
"i-111","vol-111aaa"
"i-222","vol-222ccc"
まとめ
いかがでしたでょうか?
aws cli
からデータを取得後、jq
でフィルターする一連の処理をシェルスクリプトで記載しておけば、叩くだけで取得が行えるので便利です。
なお、例題に挙げた aws ec2 describe-instances
でも --filters
--query
を使用することにより jq
のようなことは可能です。
うまく組み合わせれば、各々の絞り込みが簡潔になりそうですね。