■ はじめに
AWS CLI からのレスポンスがJSONなので そこから値を取得する必要がある。 そこで調べてみたら jqコマンド ってのがみつかったのでメモ。
目次
【1】参考にできるサイト 1)ドキュメント 2)動画 【2】環境設定 1)Linux の場合 2)Windows の場合 【3】コマンドオプション 1)-r オプション 2)-f オプション 3)-c オプション 【4】使用上の注意 1)jq -f <file>で行う場合、改行コードはLFにしておくこと 【5】基本的な文法 1)「.」 2)SELECT 3)map 4)sort, sort_by 5)unique, unique_by 6)if-then-else-end 7)変数定義(as) 8)代替演算子(//) 【6】サンプル 例1:Windows環境下での実行 例2:Linux環境下での実行 例3:JSON の扱い 例4:複雑なJSON
【1】参考にできるサイト
1)ドキュメント
https://jqlang.github.io/jq/manual/
2)動画
https://dotinstall.com/lessons/basic_jq
【2】環境設定
1)Linux の場合
yumコマンド
sudo yum -y install epel-release sudo yum -y install jq
2)Windows の場合
[1] 以下のサイトから、「jq-win64.exe」をダウンロードし、 任意の場所に置く
https://stedolan.github.io/jq/
[2] コマンドプロンプトを立ち上げて、[1]の場所まで移動 [3] 「jq-win64.exe --version」を入力 => 今回は「jq-1.6」が出力される
補足:任意設定
* 以下のようにしておくと、Linuxライクに使える [1] 「jq-win64.exe」を「jq.exe」にリネーム [2] 環境変数 Path にjq.exeまでのパスを追加(例:Path=C:\soft\) [3] コマンドプロンプトを立ち上げて、「jq --version」を入力 => 今回は「jq-1.6」が出力される
【3】コマンドオプション
1)-r オプション
囲み文字であるダブルクォートが除去
2)-f オプション
* フィルタ情報をファイルで指定 (-f | --from-file <file>) => JSONファイルから別形式のJSONが出力した時などに使える
https://www.tohoho-web.com/ex/jq.html#opt-from-file
* 以下のサイトで行われていることを「-f」オプションを使ってみる
https://www.digitalocean.com/community/tutorials/how-to-transform-json-data-with-jq
[1] まずは、データの確認
less seaCreatures.json ~~~~ [ { "name": "Sammy", "type": "shark", "clams": 5 }, { "name": "Bubbles", "type": "orca", "clams": 3 }, { "name": "Splish", "type": "dolphin", "clams": 2 }, { "name": "Splash", "type": "dolphin", "clams": 2 } ] ~~~~
[2] 同じことをやってみる(JSONファイルから別形式のJSONが出力された)
jq '{ creatures: map(.name), totalClams: map(.clams) | add, totalDolphinClams: map(select(.type == "dolphin").clams) | add }' seaCreatures.json
~[出力結果]~~~
{
"creatures": [
"Sammy",
"Bubbles",
"Splish",
"Splash"
],
"totalClams": 12,
"totalDolphinClams": 4
}
~~~~
[3] 「{ creatures: ... add }'」部分をファイル化する
vi template.jq ~~~~ { creatures: map(.name), totalClams: map(.clams) | add, totalDolphinClams: map(select(.type == "dolphin").clams) | add } ~~~~
[4] [2] と同じ結果になることを確認する
jq -f template.jq seaCreatures.json ~[出力結果]~~~ { "creatures": [ "Sammy", "Bubbles", "Splish", "Splash" ], "totalClams": 12, "totalDolphinClams": 4 } ~~~~~~
3)-c オプション
* 改行やインデント無しのコンパクト形式で出力
【4】使用上の注意
1)jq -f で行う場合、改行コードはLFにしておくこと
https://dk521123.hatenablog.com/entry/2024/04/19/121312
でやらかしたのだが、jq -f <file>を使う場合、ファイル(<file>)の改行コードは、 CRLFではなくLFにしておくこと => Windows環境下だけなら、気にしなくていいが、LFで統一した方が無難 => 以下「エラーメッセージ」のようになってしまう可能性がある
エラーメッセージ
jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
at <top-level>, line1:
{
【5】基本的な文法
1)「.」
* 「現在の入力」を表す
2)SELECT
* 値の抽出
例
$ echo '[{"name": "_Hello", "value": 25},{"name": "World", "value": 30}]' | jq '.[] | select(.name | startswith("_"))' { "name": "_Hello", "value": 25 } # 逆 $ echo '[{"name": "_Hello", "value": 25},{"name": "World", "value": 30}]' | jq '.[] | select(.name | startswith("_") | not)' { "name": "World", "value": 30 }
3)map
* 配列やオブジェクトを受け取り、配列を返却
例
$ echo '[1,2,3]' | jq -c 'map(. * 2)' [2,4,6]
4)sort, sort_by
* 配列をソート
例
... | jq -c '[.] | sort_by(.database,.schema,.name)'
5)unique, unique_by
* 重複した値をひとつにまとめる
例
... | jq -c '[.] | unique_by(.database,.schema,.name)' [{"database":"dbt_db","schema":"public","name":"my_first_dbt_model"}] [{"database":"dbt_db","schema":"public","name":"my_second_dbt_model"}] [{"database":"dbt_db","schema":"public_dbt_test__audit","name":"not_null_my_first_dbt_model_id"}] [{"database":"dbt_db","schema":"public_dbt_test__audit","name":"not_null_my_second_dbt_model_id"}] [{"database":"dbt_db","schema":"public_dbt_test__audit","name":"unique_my_first_dbt_model_id"}] [{"database":"dbt_db","schema":"public_dbt_test__audit","name":"unique_my_second_dbt_model_id"}]
6)if-then-else-end
* If 文で制御できる
https://jqlang.org/manual/#if-then-else-end
例
jq -c 'if .schema == "public" then "sample_schema" else .schema end | [.]' ["sample_schema"] ["sample_schema"] ["public_dbt_test__audit"] ["public_dbt_test__audit"] ["public_dbt_test__audit"] ["public_dbt_test__audit"]
7)変数定義(as)
* 変数を定義する
例
. as $file $file.violations[] as $violation
8)代替演算子(//)
* 値がない時の代替えするための演算子
例
# x が false や null でなければ x、さもなくば y x // y . // {}
【6】サンプル
例1:Windows環境下での実行
aws ssm get-parameters のレスポンスをパースする
https://docs.aws.amazon.com/cli/latest/reference/ssm/get-parameters.html
のレスポンスを使う
コマンド例
$ type sample.json | jq-win64.exe .Parameters[].Value "good day sunshine"
sample.json
{ "Parameters": [ { "Name": "helloWorld", "Type": "String", "Value": "good day sunshine", "Version": 1, "LastModifiedDate": 1542308384.49, "ARN": "arn:aws:ssm:us-east-1:123456789012:parameter/helloWorld" } ], "InvalidParameters": [] }
例2:Linux環境下での実行
https://dk521123.hatenablog.com/entry/2020/04/16/113816
にあるような開発環境下によって取得する値を変える
コマンド例
$ cat s3-setting.json | jq '.dev[]' "s3-bucket-dv001" "s3-bucket-dv002" "s3-bucket-dv003" $ cat s3-setting.json | jq -r '.prod.s3_bucket2' s3-bucket-pd002
s3-setting.json
{ "prod": { "s3_bucket1":"s3-bucket-pd001", "s3_bucket2":"s3-bucket-pd002", "s3_bucket3":"s3-bucket-pd003" }, "stage": { "s3_bucket1":"s3-bucket-sg001", "s3_bucket2":"s3-bucket-sg002", "s3_bucket3":"s3-bucket-pd003" }, "dev": { "s3_bucket1":"s3-bucket-dv001", "s3_bucket2":"s3-bucket-dv002", "s3_bucket3":"s3-bucket-dv003" } }
例3:JSON の扱い
* 最終的には、以下「input.json」の 「CRITICAL」又は「HIGH」の合算値を集計。 「CRITICAL」、「HIGH」がなかったら、「0」を返す
input.json
{
"CRITICAL": 1,
"HIGH": 2,
"MEDIUM": 3,
"LOW": 4,
"UNTRIGED": 5
}
コマンド例
$ cat input.json | jq 'keys'
[
"CRITICAL",
"HIGH",
"LOW",
"MEDIUM",
"UNTRIGED"
]
$ cat input.json | jq '. | to_entries'
[
{
"key": "CRITICAL",
"value": 1
},
{
"key": "HIGH",
"value": 2
},
{
"key": "MEDIUM",
"value": 3
},
{
"key": "LOW",
"value": 4
},
{
"key": "UNTRIGED",
"value": 5
}
]
$ cat input.json | jq '. | to_entries[] | select(.key=="CRITICAL" or .key=="HIGH")'
{
"key": "CRITICAL",
"value": 1
}
{
"key": "HIGH",
"value": 2
}
$ cat input.json | jq -c '[. | to_entries[] | select(.key=="CRITICAL" or .key=="HIGH") | .value] | add'
3
# データを変更
$ vi input2.json
~~~~
{
"MEDIUM": 3,
"LOW": 4,
"UNTRIGED": 5
}
~~~~
$ cat input2.json | jq -e '[. | to_entries[] | select(.key=="CRITICAL" or .key=="HIGH") | .value] | add'
null
# 代替演算子(//)
$ cat input.json | jq -e '[. | to_entries[] | select(.key=="CRITICAL" or .key=="HIGH") | .value] | add | . // 0'
3
# null の時は、0に置き換える
$ cat input2.json | jq -e '[. | to_entries[] | select(.key=="CRITICAL" or .key=="HIGH") | .value] | add | . // 0'
0
https://orebibou.com/ja/home/201605/20160509_001/
代替演算子(//)
https://www.tohoho-web.com/ex/jq.html
x // y # x が false や null でなければ x、さもなくば y
例4:複雑なJSON
https://dk521123.hatenablog.com/entry/2023/06/12/000000
で扱ったJSONをパースする
コマンド例 (Windows)
# ex1 $ type sql.json | jq .[] | jq .CreateTable.name [ { "value": "new_table", "quote_style": null } ] # ex2 $ type sql.json | jq .[] | jq .CreateTable.name[].value "new_table" # ex3 $ type sql.json | jq .[] | jq -r .CreateTable.name[].value new_table
[ { "CreateTable": { "or_replace": false, "temporary": false, "external": false, "global": null, "if_not_exists": false, "transient": false, "name": [ { "value": "new_table", "quote_style": null } ], "columns": [], "constraints": [], "hive_distribution": "NONE", "hive_formats": { "row_format": null, "storage": null, "location": null }, "table_properties": [], "with_options": [], "file_format": null, "location": null, "query": { "with": null, "body": { "Select": { "distinct": null, "top": null, "projection": [ { "UnnamedExpr": { "CompoundIdentifier": [ { "value": "t1", "quote_style": null }, { "value": "id", "quote_style": null } ] } }, { "UnnamedExpr": { "CompoundIdentifier": [ { "value": "t1", "quote_style": null }, { "value": "code", "quote_style": null } ] } }, { "UnnamedExpr": { "CompoundIdentifier": [ { "value": "t2", "quote_style": null }, { "value": "name", "quote_style": null } ] } } ], "into": null, "from": [ { "relation": { "Table": { "name": [ { "value": "table_1", "quote_style": null } ], "alias": { "name": { "value": "t1", "quote_style": null }, "columns": [] }, "args": null, "with_hints": [] } }, "joins": [ { "relation": { "Table": { "name": [ { "value": "table_2", "quote_style": null } ], "alias": { "name": { "value": "t2", "quote_style": null }, "columns": [] }, "args": null, "with_hints": [] } }, "join_operator": { "LeftOuter": { "On": { "BinaryOp": { "left": { "CompoundIdentifier": [ { "value": "t2", "quote_style": null }, { "value": "id", "quote_style": null } ] }, "op": "Eq", "right": { "CompoundIdentifier": [ { "value": "t1", "quote_style": null }, { "value": "id", "quote_style": null } ] } } } } } } ] } ], "lateral_views": [], "selection": { "BinaryOp": { "left": { "CompoundIdentifier": [ { "value": "t1", "quote_style": null }, { "value": "code", "quote_style": null } ] }, "op": "Eq", "right": { "Value": { "SingleQuotedString": "x0001" } } } }, "group_by": [], "cluster_by": [], "distribute_by": [], "sort_by": [], "having": null, "named_window": [], "qualify": null } }, "order_by": [], "limit": null, "offset": null, "fetch": null, "locks": [] }, "without_rowid": false, "like": null, "clone": null, "engine": null, "default_charset": null, "collation": null, "on_commit": null, "on_cluster": null, "order_by": null } } ]
参考文献
https://qiita.com/Nakau/items/272bfd00b7a83d162e3a
https://www.setouchino.cloud/blogs/19
https://www.wakuwakubank.com/posts/676-linux-jq/
https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af
関連記事
CodeBuild で パラメータストア / Secrets Manager を使う
https://dk521123.hatenablog.com/entry/2020/02/18/230358
機密データの管理 ~ Secrets Manager 編 ~
https://dk521123.hatenablog.com/entry/2020/03/12/220717
AWS CLI ~ --query / JMESPath ~
https://dk521123.hatenablog.com/entry/2024/01/07/000000