はじめに
AWS CLIでリソースを探すとき、--filtersと--queryを何となく使っていないでしょうか。
どちらも結果を絞るために使えますが、処理する場所と役割が違います。さらに、AWSサービスによっては--filter、--prefix、--filter-expressionなど、似た名前のオプションが登場します。
この記事では、AWS CLI v2を使うときに迷いやすい次の内容を、EC2の実例を中心に整理します。
-
--filtersと--queryの違い - JMESPathを使った抽出、整形、並べ替え
-
--outputの選び方 - ページネーションと画面ページャーの違い
- サービスごとに異なるフィルターの調べ方
- 空の結果や
nullになったときの確認方法
先に結論
AWS CLIの検索コマンドは、次の順番で組み立てると理解しやすくなります。
| 役割 | 代表的なオプション | 処理する場所 | 覚え方 |
|---|---|---|---|
| 取得対象を減らす |
--filters、--filter、--prefixなど |
AWSサービス側 | 何を取得するか |
| 返却結果を加工する | --query |
AWS CLI側 | 何を取り出して並べるか |
| 表示方法を決める | --output |
AWS CLI側 | どう表示するか |
基本方針は、AWS側で指定できる条件を先に使い、その結果を--queryで整えることです。
「filter」という名前でも、必ず処理量や料金が減るとは限りません。例えばDynamoDBのFilterExpressionは、読み取り後に結果を絞ります。各コマンドの公式リファレンスで処理順序を確認してください。
前提
この記事のコマンド例は、次の環境を前提にしています。
- AWS CLI v2
- macOSまたはLinuxのbash・zsh
- AWS CLIの認証設定が完了している
- 読み取り系の
describe、list、scan操作が中心
最初に、CLIのバージョン、認証先、リージョンの設定元を確認します。
# AWS CLIのバージョンを確認する。
aws --version
# 現在の認証情報が指しているAWSアカウントとIAM主体を確認する。
aws sts get-caller-identity --output table
# プロファイル、アクセスキー、リージョンがどこから設定されたか確認する。
aws configure list
実際のアカウントID、リソースID、タグ値は、所属組織の情報管理ルールに従って扱ってください。
AWS CLIコマンドの基本構造
AWS CLIは、基本的に次の形です。
aws <サービス名> <操作名> [操作固有のオプション] [共通オプション]
東京リージョンにある本番用の起動中EC2を表示する例です。
# prodプロファイルを使い、Environment=prodかつ起動中のEC2を取得する。
aws ec2 describe-instances \
--profile prod \
--region ap-northeast-1 \
--filters \
"Name=instance-state-name,Values=running" \
"Name=tag:Environment,Values=prod" \
--query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`].Value | [0],InstanceId:InstanceId,Type:InstanceType,State:State.Name,PrivateIp:PrivateIpAddress}' \
--output table \
--no-cli-pager
長く見えますが、役割を分けると単純です。
| 部分 | 役割 |
|---|---|
aws ec2 describe-instances |
EC2のインスタンス情報を取得する |
--profile・--region
|
接続先の認証プロファイルとリージョンを指定する |
--filters |
AWS側で対象を絞る |
--query |
返されたJSONから必要な列を作る |
--output table |
人が確認しやすい表にする |
--no-cli-pager |
lessなどの画面ページャーを開かない |
--filtersはAWS側で取得対象を絞る
EC2のdescribe-instancesでは、次の形式でフィルターを指定します。
--filters "Name=<フィルター名>,Values=<値>"
ここにあるName=は、EC2のNameタグという意味ではありません。「どのフィルターを使うか」を指定する項目です。
1つの条件で絞る
起動中のEC2だけを取得します。
# instance-state-nameフィルターへrunningを指定する。
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--output json \
--no-cli-pager
同じフィルターの複数値はOR
EC2では、同じフィルターに複数の値を指定するとOR条件になります。
# runningまたはstoppedのEC2を取得する。
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running,stopped" \
--output json \
--no-cli-pager
異なるフィルターはAND
異なるフィルターを複数指定するとAND条件になります。
# 起動中かつEnvironment=prodのEC2を取得する。
aws ec2 describe-instances \
--filters \
"Name=instance-state-name,Values=running" \
"Name=tag:Environment,Values=prod" \
--output json \
--no-cli-pager
条件を式で表すと、次のようになります。
(状態がrunning)
AND
(Environmentタグがprod)
同じフィルター内に複数値を入れると、ANDとORを組み合わせられます。
# 状態はrunningまたはstopped、環境はprodまたはstgを対象にする。
aws ec2 describe-instances \
--filters \
"Name=instance-state-name,Values=running,stopped" \
"Name=tag:Environment,Values=prod,stg" \
--output json \
--no-cli-pager
これは次の条件です。
(running OR stopped)
AND
(prod OR stg)
タグで絞る
タグのキーと値を指定する場合は、tag:<タグキー>を使います。
# Nameタグがweb-server-01のEC2を取得する。
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=web-server-01" \
--output json \
--no-cli-pager
# Ownerタグが存在するEC2を取得する。タグ値は問わない。
aws ec2 describe-instances \
--filters "Name=tag-key,Values=Owner" \
--output json \
--no-cli-pager
EC2のAPIフィルターは大文字・小文字を区別します。タグキーやタグ値も実際の表記と合わせます。
ワイルドカードは引用符で囲む
EC2のAPIフィルターでは、*を0文字以上の任意文字として利用できます。
# Nameタグがweb-で始まるEC2を取得する。
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=web-*" \
--output json \
--no-cli-pager
zshでは、引用符のない*をファイル名展開として解釈します。"Name=tag:Name,Values=web-*"のように、フィルター全体を引用符で囲むと安全です。
フィルター名、AND・ORの扱い、ワイルドカード対応はサービスや操作ごとに確認してください。EC2で使える構文が、そのままRDSやS3でも使えるとは限りません。
--queryは返却されたJSONを加工する
--queryはAWS CLIの共通オプションです。AWSサービスから返されたJSONに対して、JMESPath式を実行します。
describe-instancesのレスポンスは、概略として次の構造です。
{
"Reservations": [
{
"Instances": [
{
"InstanceId": "i-0123456789abcdef0",
"InstanceType": "t3.micro",
"State": {
"Name": "running"
}
}
]
}
]
}
JSONの階層をたどる
インスタンスIDだけを取り出します。
# ReservationsとInstancesの配列を展開し、InstanceIdを抽出する。
aws ec2 describe-instances \
--query 'Reservations[].Instances[].InstanceId' \
--output json \
--no-cli-pager
[]は配列を展開します。EC2のような入れ子のレスポンスでは、Reservations[].Instances[]のように階層ごとに展開します。
表示する列に名前を付ける
実務では、名前付きオブジェクトへ整形すると表が読みやすくなります。
# {表示名:JSON項目}の形式で、表に必要な列を作る。
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{InstanceId:InstanceId,Type:InstanceType,State:State.Name}' \
--output table \
--no-cli-pager
JMESPathでは、{表示名:JSONの項目}で任意の表示名を付けられます。
Nameタグを取り出す
EC2のタグは配列です。KeyがNameの要素を探し、そのValueの先頭を取得します。
# Tags配列からKey=NameのValueを1件取り出す。
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`].Value | [0],InstanceId:InstanceId}' \
--output table \
--no-cli-pager
| 式の部分 | 意味 |
|---|---|
Tags |
タグの配列 |
[?Key==\Name`]` |
KeyがNameの要素だけ残す |
.Value |
Valueを取り出す |
| ` | [0]` |
バッククォートはJMESPathのリテラルです。bash・zshでは、--query式全体をシングルクォートで囲むと、シェルのコマンド置換を防げます。
数値で絞る
100GiB以上のEBSボリュームを表示します。
# Sizeが100以上のボリュームを抽出し、必要な列だけ表示する。
aws ec2 describe-volumes \
--query 'Volumes[?Size >= `100`].{VolumeId:VolumeId,SizeGiB:Size,AZ:AvailabilityZone}' \
--output table \
--no-cli-pager
AWS側で指定できる条件は、先に--filtersへ入れます。次は「未使用かつ100GiB以上」のEBSを探す例です。
# AWS側でavailableに絞り、CLI側で100GiB以上を抽出する。
aws ec2 describe-volumes \
--filters "Name=status,Values=available" \
--query 'Volumes[?Size >= `100`].{VolumeId:VolumeId,SizeGiB:Size,AZ:AvailabilityZone}' \
--output table \
--no-cli-pager
並べ替えと件数を使う
# EBSをサイズの大きい順に並べる。
aws ec2 describe-volumes \
--query 'reverse(sort_by(Volumes,&Size))[].{VolumeId:VolumeId,SizeGiB:Size}' \
--output table \
--no-cli-pager
# 起動中EC2の総数を数える。
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'length(Reservations[].Instances[])' \
--output json \
--no-cli-pager
--outputは用途で使い分ける
AWS CLI v2の主な出力形式は次のとおりです。
| 出力形式 | 向いている用途 | 注意点 |
|---|---|---|
json |
構造確認、スクリプト、全体へのquery | 最初の確認に向いている |
yaml |
人が階層構造を読む | JSON前提の既存ツールとは分ける |
yaml-stream |
大きなデータをストリーム表示する | 複数ドキュメントになる |
table |
端末で一覧を確認する | スクリプトの入力には向かない |
text |
タブ区切り値をシェルで扱う | ページごとにqueryが適用される |
まずjsonでレスポンス構造を見て、コマンドが完成したら用途に合う形式へ変えるのがおすすめです。
--output textでは、ページ分割後に--queryが各ページへ適用されます。[0]、[:5]、sort_by、lengthなど、全体を対象に判断したい処理では、jsonまたはyamlを使う方が安全です。
ページネーションと画面ページャーは別物
名前が似ていますが、取得処理と画面表示の違いがあります。
| オプション | 変えるもの | 結果への影響 |
|---|---|---|
--page-size |
1回のAWS API呼び出しで取得する量 | 通常、最終的な総件数は変えない |
--max-items |
AWS CLIが返す最大件数 | 続きがあればトークンが返る |
--starting-token |
前回の続きを取得する位置 | AWS CLIが返したトークンを使う |
--no-paginate |
APIの自動ページ取得 | 最初のサービスページだけになる |
--no-cli-pager |
lessなどへの画面表示 |
APIの取得件数は変えない |
大量のリソースがある環境で--no-paginateを付けると、一部しか取得できない可能性があります。単にlessを開きたくない場合は、--no-cli-pagerを使います。
フィルター名はサービスごとに違う
サーバー側フィルターはAWSサービスAPIが提供するため、名前も動作も統一されていません。
| サービス・操作 | 主な絞り込み | 例 |
|---|---|---|
EC2 describe-instances
|
--filters |
状態、タイプ、タグ |
RDS describe-db-instances
|
--filters |
エンジン、DB識別子など |
S3 list-objects-v2
|
--prefix |
オブジェクトキーの先頭文字列 |
CloudWatch Logs filter-log-events
|
--filter-pattern |
ログイベントの内容 |
DynamoDB scan
|
--filter-expression |
読み取り後に返却結果を絞る |
RDSをエンジンで絞る
# PostgreSQLエンジンのDBインスタンスを取得する。
aws rds describe-db-instances \
--filters "Name=engine,Values=postgres" \
--query 'DBInstances[].{Identifier:DBInstanceIdentifier,Version:EngineVersion,Class:DBInstanceClass,Status:DBInstanceStatus}' \
--output table \
--no-cli-pager
S3をプレフィックスで絞る
# logs/2026/で始まるオブジェクトキーを取得する。
aws s3api list-objects-v2 \
--bucket example-bucket \
--prefix 'logs/2026/' \
--query 'Contents[].{Key:Key,Size:Size,LastModified:LastModified}' \
--output table \
--no-cli-pager
CloudWatch Logsをパターンで絞る
# 指定ロググループからERRORを含むイベントを検索する。
aws logs filter-log-events \
--log-group-name '/aws/lambda/example-function' \
--filter-pattern 'ERROR' \
--query 'events[].{Time:timestamp,Stream:logStreamName,Message:message}' \
--output table \
--no-cli-pager
DynamoDBのFilterExpressionは読み取り後に適用される
# LastPostedBy属性がUser Aの項目だけを返却結果に残す。
aws dynamodb scan \
--table-name Thread \
--filter-expression 'LastPostedBy = :name' \
--expression-attribute-values '{":name":{"S":"User A"}}' \
--output json \
--no-cli-pager
DynamoDBのScanでは、最大1MBのデータを読み取った後にFilterExpressionが適用されます。そのため、条件に合わない項目が多くても、消費する読み取りキャパシティは減りません。大量データでは、Query、キー設計、GSIの利用を先に検討します。
利用できるオプションを調べる
フィルター名を推測するより、対象コマンドのヘルプを確認する方が確実です。
# AWS CLI全体のヘルプを開く。
aws help
# EC2サービスの操作一覧を確認する。
aws ec2 help
# describe-instances固有のオプションとフィルターを確認する。
aws ec2 describe-instances help
lessでヘルプが開いた場合は、/filtersと入力すると該当箇所を検索でき、qで終了できます。
入力項目が多い操作では、JSONのひな型も生成できます。
# 実行せず、入力パラメーターのJSONひな型を表示する。
aws ec2 run-instances \
--generate-cli-skeleton input
AWS公式リファレンスでは、--generate-cli-skeletonの生成内容はAWS CLIのバージョン間で安定性が保証されないと説明されています。生成物はそのまま固定せず、利用中のCLIバージョンと公式リファレンスを確認します。
よくあるエラーと確認順序
Unknown options: --filter
その操作が--filterを受け付けていない可能性があります。--filters、--filter-patternなどを推測で置き換えず、コマンド固有のヘルプを確認します。
aws <service> <operation> help
結果が空になる
次の順番で確認します。
-
--profileは正しいか -
--regionは正しいか - フィルターを外すとデータが返るか
- フィルター名と値の大文字・小文字は正しいか
- 複数フィルターのAND条件が厳しすぎないか
- タグキーとタグ値に誤字がないか
いきなり条件を増やさず、まず生のJSONを確認します。
# 接続先を明示し、加工前のレスポンスを確認する。
aws ec2 describe-instances \
--profile prod \
--region ap-northeast-1 \
--output json \
--no-cli-pager
--queryの結果がnullになる
JSONの階層や大文字・小文字が違う可能性があります。
誤: reservations[].instances[].instanceId
正: Reservations[].Instances[].InstanceId
まず--queryを外してJSONを表示し、実際のキー名と配列構造を確認します。
zsh: no matches foundになる
引用符のない*や?をzshが展開しようとしています。
避ける: --filters Name=tag:Name,Values=web-*
推奨: --filters "Name=tag:Name,Values=web-*"
デバッグログを共有するときは内容を確認する
--debugを使うと、HTTPリクエストや認証処理を含む詳細なログが出ます。
# 問題調査用の詳細ログを表示する。
aws ec2 describe-instances --debug
リクエストパラメーター、アカウントや環境を推測できる情報が含まれる可能性があります。外部へ共有する前に、所属組織のルールとログ内容を確認します。
失敗しにくいコマンドの組み立て方
最初から長いコマンドを書かず、次の4段階で確認します。
1. 生のJSONを見る
aws ec2 describe-instances \
--output json \
--no-cli-pager
2. AWS側のフィルターを追加する
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--output json \
--no-cli-pager
3. queryで必要な項目だけ取り出す
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'Reservations[].Instances[].{InstanceId:InstanceId,Type:InstanceType,State:State.Name}' \
--output json \
--no-cli-pager
4. 最後に表示形式を変える
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'Reservations[].Instances[].{InstanceId:InstanceId,Type:InstanceType,State:State.Name}' \
--output table \
--no-cli-pager
この順番なら、結果が空になったときも、フィルター、query、表示形式のどこで問題が起きたか切り分けやすくなります。
チートシート
# EC2の状態で絞る。
--filters "Name=instance-state-name,Values=running"
# 同じフィルターへ複数値を指定する。
--filters "Name=instance-state-name,Values=running,stopped"
# Nameタグで絞る。
--filters "Name=tag:Name,Values=web-*"
# インスタンスIDだけ抽出する。
--query 'Reservations[].Instances[].InstanceId'
# 名前付きの列を作る。
--query 'Reservations[].Instances[].{Id:InstanceId,Type:InstanceType,State:State.Name}'
# JSONで表示する。
--output json
# 表形式で表示する。
--output table
# 画面ページャーを開かない。
--no-cli-pager
# 接続先を明示する。
--profile prod --region ap-northeast-1
関連記事
- AWS EC2サイジング入門 CPU・メモリ・EBS・Compute Optimizerを見る
- CloudFormation後編|本番更新が怖い人向け(ドリフト・DeletionPolicy・cfn-lint・50KB・インポート救出)
参考・確認先
- AWS CLI: Filtering output in the AWS CLI
- AWS CLI: describe-instances
- AWS CLI: describe-db-instances
- AWS CLI: list-objects-v2
- AWS CLI: filter-log-events
- AWS CLI: scan
- AWS CLI: Using pagination in the AWS CLI
- AWS CLI: Setting the output format
- AWS CLI: Using quotation marks and literals
- AWS CLI: Using AWS CLI help
- AWS CLI: Generate a skeleton and input file
- Amazon EC2: Find resources using filters
- DynamoDB: Scanning tables
- 筆者独自に追加した内容: AWS CLIを4段階で組み立てる手順、トラブル時の確認順序、実務向けチートシート
- 事実確認日: 2026年8月28日
まとめ
- AWS側で指定できる条件は、
--filtersなどの操作固有オプションで先に絞る - AWS CLIが受け取ったJSONは、
--queryとJMESPathで抽出・整形する -
--output textでは、ページごとにqueryが適用される点に注意する -
--no-paginateはAPI取得、--no-cli-pagerは画面表示を変える - フィルター名や動作はサービスごとに公式ヘルプで確認する
- 結果が空なら、生のJSONから一段ずつ条件を足して切り分ける
おわりに
最初は、よく使うdescribeコマンドを一つ選び、生のJSON、filters、query、outputの順に追加してみてください。コマンドの役割を分けて考えられると、別のAWSサービスにも応用しやすくなります。
Wealthy Designでは、AWS・Google Cloud・Azureの設計、実装、運用で得た知見を、現場で再利用できる形に整理して発信しています。

