- AWS
AWS CLI –queryの使い方|JMESPath絞り込みと出力形式
AWS CLI の --query とは、コマンドが返す JSON から必要な部分だけを取り出すオプションで、JMESPath(ジェイムズパス)という問い合わせ言語で式を書きます。 aws ec2 describe-instances のように出力が長いコマンドでも、--query を付ければ「インスタンスタイプと名前だけ」「サイズが大きい順に2件だけ」といった形に絞り込めます。別のツールを入れなくても AWS CLI だけで完結するのが利点です。
この記事では、同じ入力 JSON に対して式を変えたときの出力を一覧にし、すべて実際に実行した結果を載せています。あわせて、--filters との違い、--output の json・text・table・yaml を同じデータで比べた結果、text 形式で None が出る場合や行の並び方、そして引用符(シングルクォートとバッククォート)の書き分けと、bash・PowerShell でエラーになる書き方と直し方を扱います。
確認環境:Ubuntu 24.04 / AWS CLI 2.37.9 / bash 5.2.21 / PowerShell 7.6.6(Linux 版)。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しました。掲載するコマンドは、実際の AWS でそのまま使える形にしています。
--query(JMESPath)の早見表
次の5つのオブジェクトが入ったバケットに aws s3api list-objects-v2 --bucket demo-bucket-query を実行した結果を入力にします(入力 JSON は次の章に載せています)。
| やりたいこと | 式 | 出力 |
|---|---|---|
| 全要素から1項目を取り出す | Contents[].Key |
5つのキーの配列 |
| 先頭の1件 | Contents[0].Key |
"config.json" |
| 末尾の1件 | Contents[-1].Key |
"logs/error.log" |
| 先頭から2件 | Contents[0:2].Key |
["config.json", "docs/readme.txt"] |
| 文字列が一致するもの | Contents[?StorageClass == 'STANDARD_IA'].Key |
["images/photo.png"] |
| 数値で比べる | 数値をバッククォートで囲む(下のコード例の6番) | 1000 より大きい3件 |
| 複数項目を配列で | Contents[].[Key, Size] |
[["config.json", 512], ...] |
| 別名を付ける | Contents[].{Name: Key, Bytes: Size} |
[{"Name": "config.json", "Bytes": 512}, ...] |
| 絞り込んでから先頭1件 | Contents[?contains(Key, 'log')] | [0].Key |
"logs/app.log" |
| 並べ替え(昇順) | sort_by(Contents, &Size)[].Key |
サイズの小さい順 |
| 並べ替え(降順) | reverse(sort_by(Contents, &Size))[].Key |
サイズの大きい順 |
| 文字列を含む | Contents[?contains(Key, 'log')].Key |
["logs/app.log", "logs/error.log"] |
| 前方一致 | Contents[?starts_with(Key, 'logs/')].Key |
["logs/app.log", "logs/error.log"] |
| 後方一致 | Contents[?ends_with(Key, '.log')].Key |
["logs/app.log", "logs/error.log"] |
| 件数 | length(Contents) |
5 |
| 最大の1件 | max_by(Contents, &Size).Key |
"images/photo.png" |
| 最小の1件 | min_by(Contents, &Size).[Key, Size] |
["docs/readme.txt", 120] |
| 合計 | sum(Contents[].Size) |
62072 |
| 1つの文字列に連結 | join(', ', Contents[].Key) |
"config.json, docs/readme.txt, ..." |
| 出力形式 | 指定 | 向いている用途 |
|---|---|---|
| JSON | --output json |
そのまま保存する/ほかのプログラムに渡す |
| テキスト | --output text |
シェルの変数やループで使う |
| 表 | --output table |
画面で目で確認する |
| YAML | --output yaml |
階層を保ったまま読みやすく |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWS CLI --queryの使い方|JMESPath絞り込みと出力形式」
例に使う入力 JSON
--query を付けずに実行した出力です。以降の式は、すべてこの JSON に対して実行しています。
aws s3api list-objects-v2 --bucket demo-bucket-query
{
"Contents": [
{
"Key": "config.json",
"LastModified": "2026-10-03T09:51:07+00:00",
"ETag": "\"bf619eac0cdf3f68d496ea9344137e8b\"",
"ChecksumAlgorithm": [
"CRC64NVME"
],
"Size": 512,
"StorageClass": "STANDARD"
},
{
"Key": "docs/readme.txt",
"LastModified": "2026-10-03T09:51:03+00:00",
"ETag": "\"222f7d881ded1871724a1b9a1cb94247\"",
"ChecksumAlgorithm": [
"CRC64NVME"
],
"Size": 120,
"StorageClass": "STANDARD"
},
{
"Key": "images/photo.png",
"LastModified": "2026-10-03T09:51:06+00:00",
"ETag": "\"bf235f22df3e004ede21041978c24f2e\"",
"ChecksumAlgorithm": [
"CRC64NVME"
],
"Size": 51200,
"StorageClass": "STANDARD_IA"
},
{
"Key": "logs/app.log",
"LastModified": "2026-10-03T09:51:04+00:00",
"ETag": "\"c99a74c555371a433d121f551d6c6398\"",
"ChecksumAlgorithm": [
"CRC64NVME"
],
"Size": 2048,
"StorageClass": "STANDARD"
},
{
"Key": "logs/error.log",
"LastModified": "2026-10-03T09:51:05+00:00",
"ETag": "\"0829f71740aab1ab98b33eae21dee122\"",
"ChecksumAlgorithm": [
"CRC64NVME"
],
"Size": 8192,
"StorageClass": "STANDARD"
}
],
"RequestCharged": null,
"Prefix": ""
}
| キー | サイズ | ストレージクラス |
|---|---|---|
| config.json | 512 | STANDARD |
| docs/readme.txt | 120 | STANDARD |
| images/photo.png | 51200 | STANDARD_IA |
| logs/app.log | 2048 | STANDARD |
| logs/error.log | 8192 | STANDARD |
式と出力の一覧(すべて実行結果)
コマンドの形は共通で、--query の中身だけを差し替えています。
aws s3api list-objects-v2 --bucket demo-bucket-query --output json --query '式'
以下は「式」と、その下に => で出力(1行にまとめたもの)を並べた一覧です。
取り出す:射影・添字・スライス
1. Contents[].Key
=> ["config.json", "docs/readme.txt", "images/photo.png", "logs/app.log", "logs/error.log"]
2. Contents[*].Key
=> ["config.json", "docs/readme.txt", "images/photo.png", "logs/app.log", "logs/error.log"]
3. Contents[0].Key
=> "config.json"
4. Contents[-1].Key
=> "logs/error.log"
5. Contents[0:2].Key
=> ["config.json", "docs/readme.txt"]
[] と [*] は、この入力では同じ結果になります。違いが出るのは配列が入れ子になっているときで、後半の EC2 の例で比べます。
絞り込む:フィルタ
6. Contents[?Size > `1000`].Key
=> ["images/photo.png", "logs/app.log", "logs/error.log"]
7. Contents[?Size >= `512` && Size < `10000`].Key
=> ["config.json", "logs/app.log", "logs/error.log"]
8. Contents[?StorageClass == 'STANDARD_IA'].Key
=> ["images/photo.png"]
9. Contents[?StorageClass != 'STANDARD'].Key
=> ["images/photo.png"]
10. Contents[?contains(Key, 'log') || Size > `50000`].Key
=> ["images/photo.png", "logs/app.log", "logs/error.log"]
11. Contents[?!contains(Key, '/')].Key
=> ["config.json"]
[?条件] がフィルタです。文字列はシングルクォート、数値はバッククォートで囲むのが基本の書き分けです。&&(かつ)、||(または)、!(否定)で条件を組み合わせられます。
形を整える:マルチセレクトと別名
12. Contents[].[Key, Size]
=> [["config.json", 512], ["docs/readme.txt", 120], ["images/photo.png", 51200], ["logs/app.log", 2048], ["logs/error.log", 8192]]
13. Contents[].{Name: Key, Bytes: Size}
=> [{"Name": "config.json", "Bytes": 512}, {"Name": "docs/readme.txt", "Bytes": 120}, {"Name": "images/photo.png", "Bytes": 51200}, {"Name": "logs/app.log", "Bytes": 2048}, {"Name": "logs/error.log", "Bytes": 8192}]
14. Contents[0].[Key, Size]
=> ["config.json", 512]
15. {Count: length(Contents), Total: sum(Contents[].Size)}
=> {"Count": 5, "Total": 62072}
16. Contents[].{Key: Key, Class: StorageClass, Big: Size > `5000`}
=> [{"Key": "config.json", "Class": "STANDARD", "Big": false}, {"Key": "docs/readme.txt", "Class": "STANDARD", "Big": false}, {"Key": "images/photo.png", "Class": "STANDARD_IA", "Big": true}, {"Key": "logs/app.log", "Class": "STANDARD", "Big": false}, {"Key": "logs/error.log", "Class": "STANDARD", "Big": true}]
| 書き方 | 名前 | 結果の形 | 使いどころ |
|---|---|---|---|
[Key, Size] |
マルチセレクト(リスト) | 配列 | text・table で列の順番を自分で決めたい |
{Name: Key, Bytes: Size} |
マルチセレクト(ハッシュ) | オブジェクト | 見出し(別名)を付けたい |
つなぐ:パイプ
17. Contents[?Size > `1000`] | [0].Key
=> "images/photo.png"
18. Contents[?Size > `1000`][0].Key
=> []
19. Contents[?Size > `1000`].Key | [0]
=> "images/photo.png"
17番と18番の違いがパイプの役割です。 フィルタ [?...] の直後に [0] を続けると、「絞り込んだ結果の先頭」ではなく「各要素に対する [0]」として扱われ、空の配列になりました。| を挟むと、左側の結果をいったん確定させてから右側の式を適用するので、「絞り込んだ結果の先頭1件」が取り出せます。JMESPath の仕様書でも、パイプは左側の射影を止めて右側に渡すものと説明されています。
並べ替える:sort_by と reverse
20. sort_by(Contents, &Size)[].Key
=> ["docs/readme.txt", "config.json", "logs/app.log", "logs/error.log", "images/photo.png"]
21. reverse(sort_by(Contents, &Size))[0:2].[Key, Size]
=> [["images/photo.png", 51200], ["logs/error.log", 8192]]
22. sort_by(Contents, &LastModified)[-1].Key
=> "config.json"
23. sort(Contents[].Key)[0]
=> "config.json"
sort_by の2つめの引数には、& を付けて「どの項目で並べるか」を渡します。& を忘れると次のエラーになります。
24. sort_by(Contents, Size)[].Key
=> aws: [ERROR]: In function sort_by(), invalid type for value: None, expected one of: ['expref'], received: "null"
22番は「最後に更新されたものを1件」の形です。降順にしたいときは reverse() で包みます。
文字列で探す:contains・starts_with・ends_with
25. Contents[?contains(Key, 'log')].Key
=> ["logs/app.log", "logs/error.log"]
26. Contents[?starts_with(Key, 'logs/')].Key
=> ["logs/app.log", "logs/error.log"]
27. Contents[?ends_with(Key, '.log')].Key
=> ["logs/app.log", "logs/error.log"]
数える・集計する:length・max_by・sum・join
28. length(Contents)
=> 5
29. length(Contents[?Size > `1000`])
=> 3
30. max_by(Contents, &Size).Key
=> "images/photo.png"
31. min_by(Contents, &Size).[Key, Size]
=> ["docs/readme.txt", 120]
32. sum(Contents[].Size)
=> 62072
33. max(Contents[].Size)
=> 51200
34. avg(Contents[].Size)
=> 12414.4
35. join(', ', Contents[].Key)
=> "config.json, docs/readme.txt, images/photo.png, logs/app.log, logs/error.log"
36. keys(Contents[0])
=> ["Key", "LastModified", "ETag", "ChecksumAlgorithm", "Size", "StorageClass"]
37. Contents[].to_string(Size)
=> ["512", "120", "51200", "2048", "8192"]
max_by は「最大の要素そのもの」を返すので、続けて .Key と書けます。max は値の配列から最大値だけを返します。36番の keys() は、どんな項目名があるかを調べたいときに便利です。
関数の早見表
| 関数 | 役割 | 引数の例 |
|---|---|---|
length(x) |
配列・文字列・オブジェクトの長さ | length(Contents) |
sort_by(配列, &項目) |
項目で昇順に並べ替え | sort_by(Contents, &Size) |
reverse(配列) |
逆順にする | reverse(sort_by(...)) |
max_by(配列, &項目) / min_by |
最大・最小の要素 | max_by(Contents, &Size) |
max(配列) / min / sum / avg |
値の配列の最大・最小・合計・平均 | sum(Contents[].Size) |
contains(対象, 探す値) |
文字列や配列に含まれるか | contains(Key, 'log') |
starts_with(文字列, 前) / ends_with |
前方一致・後方一致 | starts_with(Key, 'logs/') |
join(区切り, 文字列の配列) |
1つの文字列に連結 | join(', ', Contents[].Key) |
keys(オブジェクト) / values |
項目名・値の一覧 | keys(Contents[0]) |
not_null(a, b, ...) |
最初の null でない値 | not_null(Name, '-') |
to_string(x) / to_number(x) |
型を変える | to_string(Size) |
関数の一覧と引数の型は JMESPath の仕様書(jmespath.org)に載っています。型が合わないと、次のように実行時のエラーになります。
38. length(Contents[0].Size)
=> aws: [ERROR]: In function length(), invalid type for value: 512, expected one of: ['string', 'array', 'object'], received: "number"
入れ子の配列を扱う:EC2 の例
aws ec2 describe-instances の出力は Reservations の中に Instances が入った二重の配列です。4台(Name タグが web-1・web-2・batch-1 の3台と、タグなしの1台)で確かめます。
フラット化で入れ子をならす
aws ec2 describe-instances --query "Reservations[*].Instances[*].InstanceType"
aws ec2 describe-instances --query "Reservations[].Instances[].InstanceType"
[["t3.micro"],["t3.small"],["t3.large"],["t3.micro"]]
["t3.micro","t3.small","t3.large","t3.micro"]
[*] は入れ子の形を保ち、[] は1段ならして平らな配列にします(フラット化)。一覧にしたいときは [] が扱いやすい形です。
タグの値を取り出す
タグは [{"Key": "Name", "Value": "web-1"}, ...] という配列なので、フィルタで Key を選び、パイプで先頭の Value を取り出します。
aws ec2 describe-instances \
--query "Reservations[].Instances[].{Name: Tags[?Key=='Name'] | [0].Value, Type: InstanceType, State: State.Name}" \
--output table
------------------------------------
| DescribeInstances |
+---------+-----------+------------+
| Name | State | Type |
+---------+-----------+------------+
| web-1 | running | t3.micro |
| web-2 | running | t3.small |
| batch-1| stopped | t3.large |
| None | running | t3.micro |
+---------+-----------+------------+
パイプを使わずに Tags[?Key=='Name'].Value と書くと、値が配列に包まれた形になります。
Reservations[].Instances[].Tags[?Key=='Name'].Value
=> [["web-1"],["web-2"],["batch-1"]]
Reservations[].Instances[].Tags[?Key=='Name'].Value[]
=> ["web-1","web-2","batch-1"]
末尾に [] を足すと平らになります。この書き方ではタグのないインスタンスは結果に現れません(3件になっています)。インスタンスごとに1行ずつ出したいときは、上の表の例のように | [0].Value を使うと、行数がそろいます。
状態やタグで絞り込む
aws ec2 describe-instances \
--query "Reservations[].Instances[?State.Name=='running'][].[InstanceType, State.Name]" \
--output text
t3.micro running
t3.small running
t3.micro running
aws ec2 describe-instances \
--query "Reservations[].Instances[?Tags[?Key=='Env' && Value=='prod']][].InstanceType"
["t3.micro","t3.large"]
aws ec2 describe-instances --query "length(Reservations[].Instances[?State.Name=='running'][])"
3
Instances[?...] のあとの [] は、Reservations ごとに分かれた結果を1つの配列にまとめるためのものです。
--filters と --query の違い
絞り込みには、サービス側で行う --filters と、手元で行う --query の2種類があります。
| 比べる点 | --filters(サーバー側) |
--query(クライアント側) |
|---|---|---|
| 絞り込む場所 | AWS のサービス | 手元の AWS CLI |
| 使えるコマンド | 対応しているコマンドだけ(EC2 の describe 系など) | すべてのコマンド |
| 書き方 | Name=項目名,Values=値 |
JMESPath |
| 通信で返ってくる量 | 条件に合うものだけ | 全件(そのあと手元で絞る) |
| 得意なこと | 件数が多いときに応答を小さくする | 項目の選択、別名、並べ替え、集計 |
AWS CLI ユーザーガイド「Filtering output in the AWS CLI」には、サーバー側のフィルタは一致した結果だけを返すので大きなデータで応答が速くなること、クライアント側の --query はサーバー側にない機能を持つこと、が書かれています。
同じ4台に対して、running かつ Env タグが prod のものを --filters で絞ります。
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" "Name=tag:Env,Values=prod" \
--query "Reservations[].Instances[].[InstanceType, State.Name]" \
--output text
t3.micro running
おすすめは組み合わせです。--filters で対象を減らし、--query で必要な項目だけを取り出して並べ替えます。
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=web-*" \
--query "sort_by(Reservations[].Instances[], &InstanceType)[].{Name: Tags[?Key=='Name'] | [0].Value, Type: InstanceType}" \
--output table
-----------------------
| DescribeInstances |
+--------+------------+
| Name | Type |
+--------+------------+
| web-1 | t3.micro |
| web-2 | t3.small |
+--------+------------+
--output の4形式を同じデータで比べる
同じ式 Contents[].{Key: Key, Size: Size, Class: StorageClass} を、出力形式だけ変えて実行します。
json
aws s3api list-objects-v2 --bucket demo-bucket-query \
--query 'Contents[].{Key: Key, Size: Size, Class: StorageClass}' --output json
[
{
"Key": "config.json",
"Size": 512,
"Class": "STANDARD"
},
{
"Key": "docs/readme.txt",
"Size": 120,
"Class": "STANDARD"
},
(先頭の2件を抜粋。残り3件も同じ形で続きます)
text
STANDARD config.json 512
STANDARD docs/readme.txt 120
STANDARD_IA images/photo.png 51200
STANDARD logs/app.log 2048
STANDARD logs/error.log 8192
table
----------------------------------------------
| ListObjectsV2 |
+--------------+--------------------+--------+
| Class | Key | Size |
+--------------+--------------------+--------+
| STANDARD | config.json | 512 |
| STANDARD | docs/readme.txt | 120 |
| STANDARD_IA | images/photo.png | 51200 |
| STANDARD | logs/app.log | 2048 |
| STANDARD | logs/error.log | 8192 |
+--------------+--------------------+--------+
yaml
- Class: STANDARD
Key: config.json
Size: 512
- Class: STANDARD
Key: docs/readme.txt
Size: 120
- Class: STANDARD_IA
Key: images/photo.png
Size: 51200
- Class: STANDARD
Key: logs/app.log
Size: 2048
- Class: STANDARD
Key: logs/error.log
Size: 8192
列の順番を決めたいときはリスト形式にする
式では Key・Size・Class の順に書きましたが、text・table・yaml では Class・Key・Size と、項目名のアルファベット順に並びました。公式ドキュメントにも、ハッシュ形式({})は項目名のアルファベット順、リスト形式([])は書いた順に並ぶと説明されています。順番を自分で決めたいときはリスト形式を使います。
aws s3api list-objects-v2 --bucket demo-bucket-query \
--query 'Contents[].[Key, Size, StorageClass]' --output table
----------------------------------------------
| ListObjectsV2 |
+-------------------+--------+---------------+
| config.json | 512 | STANDARD |
| docs/readme.txt | 120 | STANDARD |
| images/photo.png | 51200 | STANDARD_IA |
| logs/app.log | 2048 | STANDARD |
| logs/error.log | 8192 | STANDARD |
+-------------------+--------+---------------+
| 形式 | 列の順番 | 見出し | 向いている用途 |
|---|---|---|---|
{別名: 項目} と table |
別名のアルファベット順 | 付く | 画面で確認する |
[項目, 項目] と table |
書いた順 | 付かない | 順番を優先する |
[項目, 項目] と text |
書いた順(タブ区切り) | 付かない | シェルで読み取る |
{別名: 項目} と json |
書いた順 | キーとして付く | ほかのプログラムに渡す |
公式ドキュメントでは、このほかに大きなデータを順に出力する yaml-stream と、標準出力への表示をやめる off も紹介されています。--output off を今回の環境で実行すると、何も表示されず終了コードは 0 でした。出力形式は --output のほか、環境変数 AWS_DEFAULT_OUTPUT や設定ファイルの output でも指定できます。
text 形式の扱い方:None・1行と複数行・ページ分割
シェルスクリプトで使うことが多い text 形式には、知っておくと安心な挙動がいくつかあります。
値がないと None と表示される
Name タグのないインスタンスを含めて一覧を出すと、その行には None という文字列が入ります。
aws ec2 describe-instances \
--query "Reservations[].Instances[].[InstanceType, State.Name, Tags[?Key=='Name'] | [0].Value]" \
--output text
t3.micro running web-1
t3.small running web-2
t3.large stopped batch-1
t3.micro running None
json 形式では同じ箇所が null です。text の None は「値がない」ことを表す文字列なので、スクリプトで名前として扱わないよう、not_null() で代わりの値を決めておくと安全です。
aws ec2 describe-instances \
--query "Reservations[].Instances[].[InstanceType, not_null(Tags[?Key=='Name'] | [0].Value, '-')]" \
--output text
t3.micro web-1
t3.small web-2
t3.large batch-1
t3.micro -
該当がないときの結果も、式の形によって変わります。
| 式の結果 | json での表示 | text での表示 |
|---|---|---|
該当なしの配列([?条件].Key) |
[] |
何も表示されない(空) |
該当なしから1件取り出す(... | [0]) |
null |
None |
項目名のつづり違い(contents[].Key) |
null |
None |
変数に受け取るときは、空文字と None の両方を「該当なし」として判定すると取りこぼしがありません。
1行にまとまる場合と、1件1行になる場合
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[].Key' --output text
config.json docs/readme.txt images/photo.png logs/app.log logs/error.log
文字列の配列は、タブ区切りの1行で出力されます。1件ずつ改行したいときは、各要素を [Key] のように配列で包みます。
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[].[Key]' --output text
config.json
docs/readme.txt
images/photo.png
logs/app.log
logs/error.log
シェルのループで使う
aws s3api list-objects-v2 --bucket demo-bucket-query \
--query 'Contents[?Size > `1000`].[Key, Size]' --output text |
while read -r key size; do
echo "key=${key} size=${size}"
done
COUNT=$(aws s3api list-objects-v2 --bucket demo-bucket-query --query 'length(Contents)' --output text)
echo "count=${COUNT}"
key=images/photo.png size=51200
key=logs/app.log size=2048
key=logs/error.log size=8192
count=5
ページ分割と text の組み合わせ
公式ドキュメントには、--output text のときはページに分けてから --query が適用され、ページごとに式が1回ずつ実行されると書かれています。--page-size 2 で5件を3ページに分けて確かめます。
aws s3api list-objects-v2 --bucket demo-bucket-query --page-size 2 --query 'Contents[0].Key' --output text
config.json
images/photo.png
logs/error.log
「先頭の1件」のつもりが、各ページの先頭が1件ずつ、合計3行出力されました。同じ式を json で実行すると、全体をまとめてから式が適用されるので1件です。
aws s3api list-objects-v2 --bucket demo-bucket-query --page-size 2 --query 'Contents[0].Key' --output json
"config.json"
length(Contents) も、text では 2・2・1 と3行に分かれました。
| 状況 | 起きること | 対応 |
|---|---|---|
text で [0] や length() を使い、結果が複数ページにまたがる |
ページごとに結果が出る | json で受け取る/head -n 1 で先頭だけ使う |
text で一覧(Contents[].[Key])を出す |
全ページ分が順に並ぶ | そのまま使える |
| json・yaml | 全体をまとめてから式を1回適用 | 集計はこちらが確実 |
件数や先頭1件のように「全体に対する結果」が欲しいときは json で受け取る、と覚えておくと迷いません。
引用符の書き分けと、シェルごとの注意点
--query でいちばんつまずきやすいのが引用符です。JMESPath の中の役割と、シェルの中の役割を分けて考えると整理できます。
JMESPath の中での役割
| 記号 | JMESPath での意味 | 例 |
|---|---|---|
| シングルクォート | 文字列(そのままの文字) | 'STANDARD_IA' |
| バッククォート | JSON の値(数値・true・false・null など) | 数値の 1000 をバッククォートで囲む |
| ダブルクォート | 項目名(ハイフンなどを含む名前を囲む) | "group-name" |
この書き分けを取り違えると、エラーにならないまま結果が空になることがあります。
39. Contents[?StorageClass == "STANDARD_IA"].Key
=> []
40. Contents[?Size == '512'].Key
=> []
41. Contents[?Size == `512`].Key
=> ["config.json"]
42. Contents[?Size > 1000].Key
=> aws: [ERROR]: An error occurred (ParamValidation): Bad value for --query Contents[?Size > 1000].Key: invalid token: Parse error at column 17, token "1000" (NUMBER), for expression:
"Contents[?Size > 1000].Key"
^
43. Contents[?Size > '1000'].Key
=> aws: [ERROR]: '>' not supported between instances of 'int' and 'str'
| 書いた式 | 起きたこと | 理由 | 直し方 |
|---|---|---|---|
| 39番:文字列をダブルクォートで囲んだ | 空の配列 | ダブルクォートは項目名として読まれる | シングルクォートにする |
| 40番:数値をシングルクォートで囲んだ | 空の配列 | 数値の 512 と文字列の 512 は別の値 | バッククォートにする |
| 42番:数値を何も囲まなかった | Parse error | 数値はそのままでは書けない | バッククォートで囲む |
| 43番:数値と文字列を大小比較した | 型のエラー | 数値と文字列は比べられない | バッククォートにする |
項目名のつづりや大文字・小文字が違う場合も、エラーではなく null や空の配列になります。
44. contents[].Key
=> null
45. Contents[].key
=> []
結果が空のときは、まず keys() で項目名を確かめ、次に引用符の種類を見直す、という順で調べると早く原因にたどり着けます。
bash での書き方
bash では、式全体をシングルクォートで囲むのが基本です。シングルクォートの中では、バッククォートもそのままの文字として渡ります。
| 外側 | 内側に書けるもの | 例 |
|---|---|---|
| シングルクォート | バッククォート(数値) | 6番の式をそのまま |
| ダブルクォート | シングルクォート(文字列) | "Contents[?StorageClass == 'STANDARD_IA'].Key" |
| ダブルクォート | バッククォートは \ を前に付ける |
下のコード例 |
うまくいかない書き方と、その結果です。
# 1. ダブルクォートの中にバッククォートをそのまま書く
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > `1000`].Key"
b.sh: line 3: 1000: command not found
aws: [ERROR]: An error occurred (ParamValidation): Bad value for --query Contents[?Size > ].Key: invalid token: Parse error at column 17, token "]" (RBRACKET), for expression:
"Contents[?Size > ].Key"
^
bash がバッククォートを「コマンドの実行」として解釈し、1000 というコマンドを探しています。その結果が空文字に置き換わり、式が壊れました。
# 2. 引用符なしで書く
aws s3api list-objects-v2 --bucket demo-bucket-query --query Contents[?Size > `1000`].Key
b.sh: line 7: 1000: command not found
こちらは > が出力の書き出し先(リダイレクト)として解釈され、].Key という名前のファイルが作られて、そこにエラー文が書き込まれました。
# 3. シングルクォートの中にシングルクォートを書く
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[?StorageClass == 'STANDARD_IA'].Key'
[]
内側のシングルクォートが外側を閉じてしまい、STANDARD_IA が引用符なしの項目名として渡ったため、空の結果になりました。
直した書き方はこちらです。
# 数値:外側をシングルクォートに
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[?Size > `1000`].Key'
# 数値:ダブルクォートを使うなら \ を付ける
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > \`1000\`].Key"
# 文字列:外側をダブルクォートに
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?StorageClass == 'STANDARD_IA'].Key"
# シェル変数を使う:外側をダブルクォートに
CLS=STANDARD_IA; MIN=1000
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?StorageClass == '${CLS}'].Key"
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > \`${MIN}\`].Key"
5つとも、想定どおりの結果(数値の条件は3件、文字列の条件は images/photo.png の1件)が返りました。シェル変数を式に入れるときは、シングルクォートの中では変数が展開されないため、外側をダブルクォートにします。
PowerShell での書き方
PowerShell 7.6.6(Linux 版)で確かめた結果です。PowerShell ではバッククォートがエスケープ文字なので、ダブルクォートの中に書くと消えてしまいます。
# 1. シングルクォートで囲む(そのまま渡る)
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[?Size > `1000`].Key'
# 2. ダブルクォートの中にバッククォートをそのまま書く
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > `1000`].Key"
# 3. ダブルクォートの中ではバッククォートを2つ重ねる
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > ``1000``].Key"
1番と3番は3件が返り、2番は次のエラーになりました。バッククォートが取り除かれて、数値がそのまま式に入っています。
aws: [ERROR]: An error occurred (ParamValidation): Bad value for --query Contents[?Size > 1000].Key: invalid token: Parse error at column 17, token "1000" (NUMBER), for expression:
"Contents[?Size > 1000].Key"
^
文字列の条件では、シングルクォートの中にシングルクォートを書くと式が途中で切れます。
# 4. シングルクォートの中にシングルクォート
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[?StorageClass == 'STANDARD_IA'].Key'
aws: [ERROR]: An error occurred (ParamValidation): Bad value for --query Contents[?StorageClass == : Invalid jmespath expression: Incomplete expression:
"Contents[?StorageClass == "
^
# 5. 外側をダブルクォートにする
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?StorageClass == 'STANDARD_IA'].Key"
# 6. シングルクォートを2つ重ねる
aws s3api list-objects-v2 --bucket demo-bucket-query --query 'Contents[?StorageClass == ''STANDARD_IA''].Key'
# 7. 変数を使う
$cls = 'STANDARD_IA'; $min = 1000
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?StorageClass == '$cls'].Key"
aws s3api list-objects-v2 --bucket demo-bucket-query --query "Contents[?Size > ``$min``].Key"
5〜7番はいずれも想定どおりの結果でした。
シェル別の書き方まとめ
| 条件の種類 | bash | PowerShell |
|---|---|---|
| 数値の比較 | 外側をシングルクォート | 外側をシングルクォート |
| 数値の比較(変数を使う) | 外側をダブルクォート、バッククォートの前に \ |
外側をダブルクォート、バッククォートを2つ重ねる |
| 文字列の比較 | 外側をダブルクォート、内側をシングルクォート | 外側をダブルクォート、内側をシングルクォート |
| 文字列の比較(変数を使う) | '${CLS}' を内側に |
'$cls' を内側に |
「外側をダブルクォート、内側の文字列をシングルクォート」にした書き方は、bash と PowerShell のどちらでも同じ結果でした。Windows のコマンドプロンプトについては、AWS CLI ユーザーガイド「Using quotation marks and literals with strings in the AWS CLI」で、文字列をダブルクォートで囲むと案内されています。同ガイドでは、Linux・macOS はシングルクォート、PowerShell はシングルクォート(そのままの文字として渡す)かダブルクォート(変数を展開する)を使うと説明されています。
エラー文から原因を探す表
| エラー文・症状 | 主な原因 | 直し方 |
|---|---|---|
| 1000: command not found(bash) | ダブルクォートの中、または引用符なしでバッククォートを書いた | 外側をシングルクォートにする/\ を付ける |
| invalid token: Parse error ... token "1000" (NUMBER) | 数値がバッククォートなしで式に入った(PowerShell でバッククォートが消えた場合を含む) | バッククォートで囲む/PowerShell では2つ重ねる |
| Invalid jmespath expression: Incomplete expression | 引用符が途中で閉じて式が切れた/かっこの閉じ忘れ | 外側と内側の引用符を別の種類にする |
| '>' not supported between instances of 'int' and 'str' | 数値と文字列を大小比較した | 数値をバッククォートで囲む |
| invalid type for value ... expected one of: ['expref'] | sort_by や max_by の & を忘れた |
&Size のように & を付ける |
結果が [] や null になる |
項目名のつづり・大文字小文字の違い/引用符の種類の違い | keys() で項目名を確かめる/文字列はシングルクォート |
| 見慣れない名前のファイルができる(bash) | 引用符なしで > を書き、リダイレクトとして扱われた |
式全体を引用符で囲む |
式を組み立てる手順
長い式は、一度に書かず、段階を踏んで確かめながら伸ばしていくと確実です。
| 手順 | すること | 例 |
|---|---|---|
| 1 | --query なしで全体の形を見る |
aws s3api list-objects-v2 --bucket 名前 |
| 2 | 1件だけ取り出して項目名を確かめる | --query 'Contents[0]' や keys(Contents[0]) |
| 3 | 絞り込みの条件を足す | フィルタ [?条件] |
| 4 | 出力する項目を選ぶ | .[Key, Size] や .{Name: Key} |
| 5 | 並べ替え・件数の指定を足す | sort_by(...)、パイプと [0] |
| 6 | 出力形式を決める | --output table や --output text |
よくある質問
Q. --query で絞り込むと、通信量や処理時間は減りますか?
A. --query は手元で結果を絞り込む仕組みなので、サービスから返ってくるデータ量は変わりません。対象が多いときは、対応しているコマンドで --filters を併用し、サービス側で件数を減らしてから --query で整形します。
Q. 結果が空の配列になります。どこを見ればよいですか?
A. 項目名の大文字・小文字、文字列をシングルクォートで囲んでいるか、数値をバッククォートで囲んでいるか、の3点を順に確かめます。--query 'keys(Contents[0])' のように keys() を使うと、実際の項目名を一覧できます。
Q. text 形式で None と表示されるのはなぜですか?
A. 式の結果が null のとき、text 形式では None という文字列で表示されます。not_null(式, '-') のように代わりの値を指定しておくと、スクリプトで扱いやすくなります。
まとめ
--queryは JMESPath で書き、[]で全要素、[0]で1件、[?条件]で絞り込み、{別名: 項目}で形を整える- 文字列はシングルクォート、数値はバッククォート、項目名はダブルクォート。取り違えるとエラーにならず空の結果になることがある
- 絞り込んだ結果から1件取り出すときはパイプ(
[?条件] | [0])を使う sort_by・max_byには&項目名を渡す。件数はlength()、連結はjoin()--filtersはサーバー側、--queryはクライアント側。件数を減らすのは--filters、整形は--query- 列の順番を決めたいときはリスト形式
[Key, Size]。ハッシュ形式は text・table で項目名のアルファベット順になる - text 形式は null が None になり、ページごとに式が適用される。全体の件数や先頭1件は json で受け取る
- bash は式全体をシングルクォート、PowerShell のダブルクォート内ではバッククォートを2つ重ねる
参考・出典
- AWS CLI ユーザーガイド「Filtering output in the AWS CLI」 https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html
- AWS CLI ユーザーガイド「Setting the output format in the AWS CLI」 https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-output-format.html
- AWS CLI ユーザーガイド「Using quotation marks and literals with strings in the AWS CLI」 https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-quoting-strings.html
- JMESPath Specification https://jmespath.org/specification.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWS CLI --queryの使い方|JMESPath絞り込みと出力形式」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。