新しいことにはウェルカム

技術 | 電子工作 | ガジェット | ゲーム のメモ書き

jqの使い方メモ

シェルスクリプトで、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つで出力されるのに対し、「配列を展開したもの」は出力が要素毎に分かれてしまいます。

関連カテゴリー記事

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com