こちらの記事は ケーシーエスキャロット 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 のようなことは可能です。
うまく組み合わせれば、各々の絞り込みが簡潔になりそうですね。