シェルスクリプトで、JSONからデータを取り出すのにjqコマンドを使っています。
使い方をよく忘れるので、自分用使い方メモです。
基本
- 基本動作「標準入力から入力を受け取り、フィルターをかけて、標準出力に出力する」
.
は入力値を表す- フィルターはパイプ(
|
)でつなげていく - フィルターはシングルクォーテーションでくくる
- フィルターにダブルクォーテーションを使う場合は、バックスラッシュでエスケープして入力する
その他
- 単にJSON整形ツールとしても使える(
jq '.'
) - JSON文字列を生成できる
- テストサイト
配列
.[インデックス]
でインデックスを指定して取り出す- インデックスはマイナス値も使える
- インデックスは複数指定できる
[]
は配列全体を展開する- 展開した配列を配列に戻すには、全体を
[]
で囲む- 展開した配列からパイプを介して配列に戻すことはできない
# 入力 (input) [ "a", 123, "b" ] ########## # 配列の要素をインデックスで指定する # (Specify array elements by index) jq '.[0]' # 結果 (result) "a" ########## # インデックスにマイナス値を使う # (Use negative values for indexes) jq '.[-1]' # 結果 (result) "b" ########## # インデックスを複数指定する # (Specify multiple indexes) jq '.[1, 2]' # 結果 (result) 123 "b" ########## # 配列を展開する # (Expand the array) jq '.[]' # 結果 (result) "a" 123 "b" ########## # 展開した配列を配列に戻す # (Returns the expanded array to an array.) jq '[.[]]' # 結果 (result) [ "a", 123, "b" ] ########## # 一度配列を展開すると、後から配列に戻せない # (Once an array is expanded, it cannot be returned to an array later.) jq '.[] | [.]' # 結果 (result) [ "a" ] [ 123 ] [ "b" ]
オブジェクト
.key
でオブジェクトのキーの値を取り出す- JavaScriptのように
object["key"]
で指定することもできる- 特に、キー名が特殊文字を含んだり数字で始まっていて、
.key
で指定できない場合に有効
- 特に、キー名が特殊文字を含んだり数字で始まっていて、
- オブジェクトに
[]
を使うと、全キーの値が取り出される - 取り出した値を、次のオブジェクトのキーにするには、値を
()
でくくる
# 入力 (input) { "a": "A", "b": 123, "123c": "TEST" } ########## # オブジェクトのキーの値を取り出す # (Retrieve the value of an object's key) jq '.b' # 結果 (result) 123 ########## # []でキーを指定 # (Specify key in [].) jq '.["123c"]' # 結果 (result) "TEST" ########## # []はオブジェクトの全てのキーの値を取得 # ([] gets the value of all keys of the object) jq '.[]' # 結果 (result) "A" 123 "TEST" ########## # 取得した値をキー名として、オブジェクトを生成する # (Create an object with the obtained value as the key name) jq '{(.b):.a}' # 結果 (result) { "123": "A" }
配列・オブジェクト生成
[]
で新たに配列を生成できる{}
で新たにオブジェクトを生成できる
# 入力 (input) { "a": "A", "b": 123 } ########## # 配列を生成する # (Generate array) jq '[.a, .b]' # 結果 (result) [ "A", 123 ] ########## # オブジェクトを生成する # (Generating Objects) jq '{aa:.a, bb:.b}' # 結果 (result) { "aa": "A", "bb": 123 }
パイプ
.
でkey
をつなげて書くことができる|
で処理をつなげていくことができる
# 入力 (input) { "a": { "b":["test1", "test2", "test3"] } } ########## # キーは「.」で連結できる # (Keys can be concatenated with "." can be concatenated with) jq '.a.b[1]' # 結果 (result) "test2" ########## # 「|」でパイプ処理 # (Piping with "|".) jq '.a|.b|.[1]' # 結果 (result) "test2" ########## # 「|」はjqをパイプでつなぐのと同等 # ("|" is equivalent to piping jq) jq '.a' | jq '.b' | jq '.[1]' # 結果 (result) "test2"
関数・代入
|=
|
はパイプ- 左側のフィルターをかけて
|
でパイプして右側に移る。そして、右側の演算をし、その結果を左側のフィルターに戻して値を更新する
# 入力 (input) [1, 2, 3] ########## # インデックス0の値を演算して更新する # (Update the value of index 0 by computing) jq '.[0]|=.*100' # 結果 (result) [ 100, 2, 3 ] ########## # 配列の各値を演算して更新する # (Operate and update each value in the array) jq '.[]|=.*100' # 結果 (result) [ 100, 200, 300 ]
# 入力 (input) { "a":1, "b":2, "c":3 } ########## # .aだけ演算して更新 # (Only .a is calculated and updated) jq '.a|=.*100' # 結果 (result) { "a":100, "b":2, "c":3 } ########## # オブジェクトの値を演算して更新 # (Operate and update object values) jq '.[]|=.*100' # 結果 (result) { "a":100, "b":200, "c":300 }
=
- 代入
# 入力 (input) {"a": {"b": 10}, "b": 20} ########## # .a,.bは同じ階層を指す # (.a,.b refer to the same hierarchy) jq '.a = .b' # 結果 (result) { "a": 20, "b": 20 } ########## # .a.bは.aの子 # (.a.b is a child of .a) jq '.a = .a.b' # 結果 (result) { "a": 10, "b": 20 } ########## # exp # 「|」はパイプなので右の「.」は左フィルター(.a)の中 # (Since "|" is a pipe, the right ". is in the left filter (.a)) jq '.a |= .b' # 結果 (result) { "a": 10, "b": 20 }
keys
- オブジェクトのキーを配列で返す
- 配列の場合はインデックスが返る
# 入力 (input) { "a": "TEST", "b": 123 } ########## # keysでオブジェクトのキーを配列で返す # (Returns an array of object keys with keys) jq 'keys' # 結果 (result) [ "a", "b" ]
# 入力 (input) [ "a", "b", "c" ] ########## # keysで配列のインデックスを返す # (Returns the index of an array with keys) jq 'keys' # 結果 (result) [ 0, 1, 2 ]
map(x)
[.[]|x]
と同じ- 配列を展開して、各値を使って演算し、結果を配列にして返す
- これを1つの関数にまとめたもの
- 最終結果は配列になる
# 入力 (input) [ 1, 2, 3 ] ########## # 配列の各要素を使って演算する # (Arithmetic operations with each element of an array) jq 'map(.*100)' # 結果 (result) [ 100, 200, 300 ]
# 入力 (input) { "a":1, "b":2, "c":3 } ########## # オブジェクトの各要素を使って演算する # (Operate with each element of an object) jq 'map(.*100)' # 結果 (result) [ 100, 200, 300 ]
map_values(x)
.[]|=x
と同じ- オブジェクトの各値を使って演算し、結果で更新する
- 最終結果は、入力がオブジェクトならオブジェクト、配列なら配列になる
# 入力 (input) [ 1, 2, 3 ] ########## # 配列の各要素を使って演算する # (Arithmetic operations with each element of an array) jq 'map_values(.*100)' # 結果 (result) [ 100, 200, 300 ]
# 入力 (input) { "a":1, "b":2, "c":3 } ########## # オブジェクトの各要素を使って演算する # (Operate with each element of an object) jq 'map_values(.*100)' # 結果 (result) { "a":100, "b":200, "c":300 }
select(x)
- 条件を満たすものを残す
map(select(x))
や.[]|select(x)
など、配列から条件に合う項目を取り出すのによく使われる
# 入力 (input) [1,5,3,0,7] ########## # 配列をフィルターする # (Filtering Arrays) jq 'map(select(. >= 2))' # 結果 (result) [ 5, 3, 7 ] ########## # 配列を展開して、各要素から条件に合うものを残す # (Expand the array and keep the ones that match the criteria from each element.) jq '.[]|select(. >= 2)' # 結果 (result) 5 3 7
# 入力 (input) [ {"a":1, "b":100}, {"a":5, "b":500}, {"a":3, "b":300}, {"a":0, "b":0}, {"a":7, "b":700} ] ########## # 配列をフィルターする # (Filtering Arrays) jq 'map(select(.a >= 2))' # 結果 (result) [ {"a":5, "b":500}, {"a":3, "b":300}, {"a":7, "b":700} ] ########## # 配列を展開して、各要素から条件に合うものを残す # (Expand the array and keep the ones that match the criteria from each element.) jq '.[]|select(.a >= 2)' # 結果 (result) {"a":5, "b":500}, {"a":3, "b":300}, {"a":7, "b":700}
to_entries
- オブジェクトを
key/value
ペアの配列にする - 配列を渡すと
key
は配列のインデックスになる
# 入力 (input) {"a":1, "b":"TEST"} ########## # オブジェクトを``key/value``ペアの配列にする # (turn an object into an array of ``key/value`` pairs) jq 'to_entries' # 結果 (result) [ { "key": "a", "value": 1 }, { "key": "b", "value": "TEST" } ]
# 入力 (input) [{"a":1, "b":"TEST"}] ########## # 配列を``index/value``ペアの配列にする # (Make an array of ``index/value`` pairs) jq 'to_entries' # 結果 (result) [ { "key": 0, "value": { "a": 1, "b": "TEST" } } ]
tojson
- JSONをJSON文字列にする
# 入力 (input) [ {"a":1, "b":"TEST1"}, {"a":2, "b":"TEST2"} ] ########## # JSONをJSON文字列にする # (JSON to JSON string) jq '.[]|tojson' # 結果 (result) "{\"a\":1,\"b\":\"TEST1\"}" "{\"a\":2,\"b\":\"TEST2\"}"
@csv
- csv出力する
- csv出力する行を配列で記述する
-r
オプションでダブルクォーテーションを除外しておく- ヘッダーの出力はできない
# 入力 (input) [ { "a": "A", "b": 1, "c": "TEST1"}, { "a": "B", "b": 2, "c": "TEST2"}, { "a": "C", "b": 3, "c": "TEST3"} ] ########## # CSV出力する # (CSV output) jq -r '.[]|[.a, .b, .c]|@csv' # 結果 (result) "A",1,"TEST1" "B",2,"TEST2" "C",3,"TEST3"
変数
as $var
で値を変数に覚えさせることができる
# 入力 (input) { "userID":123, "userInfo":{ "name":"TEST" }, "data":[ {"a":"A", "b":1}, {"a":"B", "b":2}, {"a":"C", "b":3} ] } ########## # 変数を使って値を別の場所で使う # (Use variables to use values elsewhere) jq '.userID as $userID|.userInfo.name as $name|.data[]|{userID:$userID, name:$name, a:.a, b:.b}' # 結果 (result) { "userID": 123, "name": "TEST", "a": "A", "b": 1 } { "userID": 123, "name": "TEST", "a": "B", "b": 2 } { "userID": 123, "name": "TEST", "a": "C", "b": 3 }
変数外部代入
- 外部から変数に代入できる
- 数値を代入
--argjson var_name value
- 文字を代入
--arg var_name value
# 入力 (input) { "aa":12, "bb":"AB" } ########## # 外部から変数に値を代入して内部で使う # (Assign values to variables from the outside and use them internally) jq --argjson cc 34 --arg dd "CD" '{a:.aa, b:.bb, c:$cc, d:$dd"}' # 結果 (result) { "a": 12, "b": "AB", "c": 34, "d": "CD" }
オプション
-c
- 1つのJSONを1行で出力
-r
- 文字列のダブルクォーテーションを表示しない
-n
- 入力を取らない。JSONを自作する時に使う
シェルスクリプトでJSONデータ作成
a=12 b=AB json=$(cat <<__JSON__ { "a": $a, "b": "$b" } __JSON__ ) echo $json | jq . # 結果 (result) # { # "a": 12, # "b": "AB" # }
感想など
.
は例えるなら、プログラム言語のthis
みたいなものでしょうか。
「配列」と「配列を展開したもの」は、似ていて混乱しやすいのですが別物です。
「配列」は配列として1つで出力されるのに対し、「配列を展開したもの」は出力が要素毎に分かれてしまいます。