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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?