この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
前回の記事でAWS CLIコマンドのJSONデータをjqコマンドで操作したら大変便利だったので紹介します。
jqコマンドとは
JSONデータをsedやgrep、awkのようにデータ抽出、変換、集計してくれるツールです。
AWS CLIのの出力形式は、複数の出力形式がサポートされていますが、デフォルトではJSONで出力されます。
AWS CLIでも--filters
や--query
を使えば抽出や変換できますが、AWS CLI以外のJSONデータ(公開されている様々なAPIが、ほぼJSONで出力)を操作するとき、jqコマンドのようなツールを覚えておくと便利かなと考えました。
公開API(例)
使い方
jqは各種OSにインストールして利用できます。今回はmacOS Catalinaにインストールした環境で操作していきます。
バージョン確認コマンドが出力されればOKです。
% jq --version
jq-1.6
jqで操作するJSONデータは、aws ec2 describe-vpcs
で出力されたデータをローカルに保存しておきます。AWS CLIコマンドをパイプで渡して操作もできるので都度ローカルに保存する必要はありません。
describe-instances.json
{
"Vpcs": [
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
},
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
]
}
シンプルな出力
まずはシンプルにjqコマンドを実行してみます。
% cat ./describe-vpcs.json | \
jq '.'
{
"Vpcs": [
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
},
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
]
}
catコマンドと出力結果は変わりませんが、厳密には標準出力された内容をJSONで標準出力しています。引数'.'
が、JSONオブジェクト(ブレース{
で始まりブレース}
で終わる)を表しています。
配列を指定した出力
インデックス(0から始まる)を指定して抽出できます。describe-vpcs.jsonには、VPcsに2つの配列(0,1)があるので、ブラケット[]
に[0]
を指定して抽出してみます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[0]'
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
指定したインデックスにデータが存在しない場合は、Nullが返されます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[2]'
null
範囲を指定した出力
範囲を指定して配列を抽出できます。
ブラケット[]
を[0:2]
では、0以上2未満で抽出されます。範囲の開始を指定しない[:2]
の場合は、0から開始されるので先程とおなじく0以上2未満で抽出されます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[0:2]'
[
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
},
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
]
% cat ./describe-vpcs.json | \
jq '.Vpcs[:2]'
[
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
},
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
]
後方から範囲指定する場合は[-1:]
として抽出することもできます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[-1:]'
[
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
]
なお、範囲指定でインデックスにデータがない場合は何も表示されず、nullが返されません。
最後尾から出力
配列のインデックスをreverseして抽出できます。範囲を指定した出力と一緒でreverse[]
のブラケットにインデックスや範囲を指定して抽出できます。
% cat ./describe-vpcs.json | \
jq '.[] | reverse[]'
{
"CidrBlock": "10.0.0.0/16",
"DhcpOptionsId": "dopt-87e9dxxx",
"State": "available",
"VpcId": "vpc-354f2873de5162xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e99eaeae46622xxx",
"CidrBlock": "10.0.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
{
"CidrBlock": "10.255.0.0/16",
"DhcpOptionsId": "dopt-77e9dxxx",
"State": "available",
"VpcId": "vpc-029f2873de5756xxx",
"OwnerId": "xxxxxxxxxxxx",
"InstanceTenancy": "default",
"CidrBlockAssociationSet": [
{
"AssociationId": "vpc-cidr-assoc-0e18eaeae48822xxx",
"CidrBlock": "10.255.0.0/16",
"CidrBlockState": {
"State": "associated"
}
}
],
"IsDefault": false
}
値の出力
各配列にある値を抽出する場合は、JSONデータ構造を意識して抽出します。VpcsのCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[].CidrBlock'
"10.255.0.0/16"
"10.0.0.0/16"
インデックスを指定しなければ、すべての配列からCidrBlock値のValueが抽出されます。
また、ネストされた配列からも抽出できます。CidrBlockAssociationSetのCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[].CidrBlockAssociationSet[].CidrBlock'
"10.255.0.0/16"
"10.0.0.0/16"
値の出力(フィルタリング)
select
jqには、様々な組み込み演算子や関数が用意されています。先程の値の抽出で特定の値だけ抽出する場合は、selectを使ってフィルタリングできます。
CidrBlock値が10.255.0.0/16
と一致する配列からCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock == "10.255.0.0/16") | .CidrBlock '
"10.255.0.0/16"
contains
CidrBlock値に16
を含む配列からCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| contains ("16")) | .CidrBlock '
"10.255.0.0/16"
"10.0.0.0/16"
startswith
10.255
から始まるCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| startswith ("10.255")) | .CidrBlock '
endswith
16
で終わるCidrBlock値を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| endswith ("16")) | .CidrBlock '
AND OR
ANDやOR条件も使えます。10.255
から始まる且つ、16
で終わる配列を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| startswith ("10.255") and endswith ("16")) | .CidrBlock '
"10.255.0.0/16"
10.255
から始まるまたは16
で終わる配列を抽出します。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| startswith ("10.255") or endswith ("16")) | .CidrBlock '
"10.255.0.0/16"
"10.0.0.0/16"
出力結果を整形
フィルタリングした内容を整形することができます。先程の出力だと値だけ出力されるので{ 任意キー(String): .CidrBlock }
を追加して出力できます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| startswith ("10.255") or endswith ("16")) | { CidrBlock: .CidrBlock } '
{
"CidrBlock": "10.255.0.0/16"
}
{
"CidrBlock": "10.0.0.0/16"
}
VpcIdも一緒に出力してみます。カンマ,
で区切ればいくつも追加して出力できます。
% cat ./describe-vpcs.json | \
jq '.Vpcs[] | select( .CidrBlock| startswith ("10.255") or endswith ("16")) | { CidrBlock: .CidrBlock, VpcId: .VpcId} '
{
"CidrBlock": "10.255.0.0/16",
"VpcId": "vpc-029f2873de5756xxx"
}
{
"CidrBlock": "10.0.0.0/16",
"VpcId": "vpc-354f2873de5162xxx"
}
RAWデータで出力
jqはJSON形式で出力するので抽出された最小の値でもダブルクォーテーションで括られたデータで出力されます。jqコマンドにオプション-r
を追加するとRAWデータで出力されます。
% cat ./describe-vpcs.json | \
jq -r '.Vpcs[] | select( .CidrBlock| startswith ("10.255") and endswith ("16")) | .CidrBlock '
10.255.0.0/16
さいごに
JSONデータを良い感じに操作できるjqコマンドの紹介でした。基本的な一部の出力方法をご案内しましたが、まだまだいろんな機能があります。詳しくは公式のManualを参照してください。
jqをインストールする前にどんな感じで抽出されるか確認したい場合は、以下のページでも確認できます。ただ、入力したデータの取り扱いに関する記載が見つけられなかったので、データをマスキングしてお試しください。