JQを使用したAWS CLI出力フィルタリングの習得:高度なテクニック

jqとAWS CLIのJSON出力を組み合わせて、クラウドデータをスクリプトやレポート向けにフィルタリング、再整形、エクスポートする方法。

AWS CLI出力フィルタリングをJQで極める:高度なテクニック

AWS CLIの出力フィルタリングは、コマンドが深くネストされたJSONを返すと煩雑になります。1つのインスタンスID、1つのタグ値、または短いCSVレポートだけが必要な場合でも、aws ec2 describe-instancesのようなコマンドはそれ以上のデータを返します。

AWS CLIには組み込みの--queryオプションがあり、JMESPathを使用します。これは単純な検索には適したツールです。jqは、よりリッチなJSON再整形、条件ロジック、CSV出力、シェルスクリプトで再利用可能なフィルタが必要な場合に役立ちます。

JSON出力から始める

jqはJSONを読み取るため、AWS CLIに明示的にJSONを返させる必要があります:

aws ec2 describe-instances --output json

aws configureでJSONをデフォルトとして設定することもできますが、例やスクリプトで--output jsonを使用すると依存関係が明確になります。

システムパッケージマネージャーでjqをインストールします(まだ利用できない場合):

sudo apt update && sudo apt install jq
sudo dnf install jq
brew install jq

AWS JSONの読み取りと検査

アイデンティティフィルタ.は入力JSONをそのまま返します。レスポンスの構造を学習しながら整形出力を確認するのに便利です:

aws ec2 describe-instances --output json | jq '.'

トップレベルのキーを選択するには、ドット記法を使用します:

aws ec2 describe-instances --output json | jq '.Reservations'

ほとんどのAWSコマンドは有用なデータを配列でラップします。EC2インスタンスの場合、構造はReservations[]の後にInstances[]が続くため、通常は両方のレベルが必要です。

配列の反復処理

.[]を使用して、配列から各アイテムを出力します。このコマンドは、すべての予約にわたるすべてのEC2インスタンスIDを出力します:

aws ec2 describe-instances --output json | jq '.Reservations[].Instances[].InstanceId'

デフォルトでは、文字列出力にはJSON引用符が含まれます。シェルループや別のコマンドで生のテキストが必要な場合は、-rを追加します:

aws ec2 describe-instances --output json | jq -r '.Reservations[].Instances[].InstanceId'

また、必要なフィールドのみを含む小さなオブジェクトを構築することもできます:

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {id: .InstanceId, state: .State.Name, type: .InstanceType}'

これにより、完全なEC2レスポンスではなく、コンパクトなJSONレコードが得られます。

select()でフィルタリング

条件に一致するレコードのみが必要な場合は、select()を使用します。この例では、実行中のインスタンスIDをリストします:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | select(.State.Name == "running") | .InstanceId'

jqフィルタ内の文字列リテラルは二重引用符("running"など)を使用します。jqプログラム全体を一重引用符で囲むと、シェルはそれらの二重引用符を安全に渡します。

より具体的なチェックとして、インスタンスタイプでフィルタリングします:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | select(.InstanceType == "t3.micro") | .InstanceId'

オプションフィールドを安全に処理

AWSリソースはフィールドを省略することがよくあります。タグは一般的な例です。インスタンスにTags配列がない場合、.Tags[]は失敗する可能性があります。オプションのイテレータ.Tags[]?を使用します:

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {id: .InstanceId, name: (.Tags[]? | select(.Key == "Name") | .Value)}'

これは機能しますが、タグがない場合にname値が生成されない可能性があります。スクリプトでは、デフォルト値がある方が通常は扱いやすいです:

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {
    id: .InstanceId,
    name: ((.Tags[]? | select(.Key == "Name") | .Value) // "unnamed")
  }'

ストリームではなく配列を返す

多くのjqフィルタは値のストリームを出力します。別のツールが1つの有効なJSON配列を期待する場合は、式を角括弧で囲みます:

aws ec2 describe-instances --output json |
  jq '[.Reservations[].Instances[].InstanceId]'

これは、別の自動化ステップ用にJSONファイルを書き込む場合に便利です。

CSVまたはTSVにエクスポート

スプレッドシート対応のレポートを作成するには、フィールドの配列を構築し、@csvまたは@tsvに渡します。-rを使用して、jqがJSON文字列ではなく生のCSV行を書き込むようにします:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | [.InstanceId, .InstanceType, .State.Name] | @csv'

ヘッダー行を含めるには、データ行の前に出力します:

aws ec2 describe-instances --output json |
  jq -r '["instance_id","instance_type","state"], (.Reservations[].Instances[] | [.InstanceId, .InstanceType, .State.Name]) | @csv'

実践例:未割り当てのElastic IPを検索

未割り当てのElastic IPアドレスは、回避可能なコストを生み出す可能性があります。このコマンドは、AWSがAssociationIdを返さなかったパブリックIPをリストします:

aws ec2 describe-addresses --output json |
  jq -r '.Addresses[] | select(.AssociationId == null) | .PublicIp'

アドレスが出力された場合は、解放前に確認します:

aws ec2 release-address --allocation-id eipalloc-0123456789abcdef0

結果を確認するまでは、検出クエリから直接解放コマンドをパイプしないでください。短い確認ステップは、誤ったリソースを削除した場合の復旧よりもコストが低くなります。

--queryを使用すべき場合

単純なプロジェクションにはAWS CLIの--queryを使用します。これは出力フォーマットの前に実行され、コマンドを自己完結型に保ちます:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].InstanceId' \
  --output text

結果により多くの変換(フォールバック値、CSVフォーマット、フィールドの結合、jq構文で読みやすい長いフィルタなど)が必要な場合は、jqを使用します。

まとめ

--output jsonをAWS CLIとjqの間の受け渡しポイントとして使用します。次に、.[]select()、オブジェクト構築、//デフォルト値、-r生出力を組み合わせて、大規模なAWSレスポンスをスクリプトやレポートに必要な正確なデータに変換します。