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

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

jqの使い方メモ

シェルスクリプトで、JSONからデータを取り出すのにjqコマンドを使っています。

使い方をよく忘れるので、自分用使い方メモです。

基本

  • 基本動作「標準入力から入力を受け取り、フィルターをかけて、標準出力に出力する」
  • .は入力値を表す
  • フィルターはパイプ(|)でつなげていく
  • フィルターはシングルクォーテーションでくくる
  • フィルターにダブルクォーテーションを使う場合は、バックスラッシュでエスケープして入力する

その他

  • 単にJSON整形ツールとしても使える(jq '.'
  • JSON文字列を生成できる
  • A playground for jq

配列

  • .[インデックス]でインデックスを指定して取り出す
  • インデックスはマイナス値も使える
  • インデックスは複数指定できる
  • []は配列全体を展開する
  • 展開した配列を配列に戻すには、全体を[]で囲む
    • 展開した配列からパイプを介して配列に戻すことはできない
# 入力
[ "a", 123, "b" ]

##########
# 配列の要素をインデックスで指定する
jq '.[0]'
# 結果
"a"

##########
# インデックスにマイナス値を使う
jq '.[-1]'
# 結果
"b"

##########
# インデックスを複数指定する
jq '.[1, 2]'
# 結果
123
"b"

##########
# 配列を展開する
jq '.[]'
# 結果
"a"
123
"b"

##########
# 展開した配列を配列に戻す
jq '[.[]]'
# 結果
[
  "a",
  123,
  "b"
]

##########
# 一度配列を展開すると、後から配列に戻せない
jq '.[] | [.]'
# 結果
[ "a" ]
[ 123 ]
[ "b" ]

オブジェクト

  • .keyでオブジェクトのキーの値を取り出す
  • JavaScriptのようにobject["key"]で指定することもできる
    • 特に、キー名が特殊文字を含んだり数字で始まっていて、.keyで指定できない場合に有効
  • オブジェクトに[]を使うと、全キーの値が取り出される
  • 取り出した値を、次のオブジェクトのキーにするには、値を()でくくる
# 入力
{
    "a": "A",
    "b": 123,
    "123c": "TEST"
}

##########
# オブジェクトのキーの値を取り出す
jq '.b'
# 結果
123

##########
# []でキーを指定
jq '.["123c"]'
# 結果
"TEST"

##########
# []はオブジェクトの全てのキーの値を取得
jq '.[]'
# 結果
"A"
123
"TEST"

##########
# 取得した値をキー名として、オブジェクトを生成する
jq '{(.b):.a}'
# 結果
{
    "123": "A"
}

パイプ

  • .keyをつなげて書くことができる
  • |で処理をつなげていくことができる
# 入力
{
    "a": {
        "b":["test1", "test2", "test3"]
    }
}

##########
# キーは「.」で連結できる
jq '.a.b[1]'
# 結果
"test2"

##########
# 「|」でパイプ処理
jq '.a|.b|.[1]'
# 結果
"test2"

##########
# 「|」はjqをパイプでつなぐのと同等
jq '.a' | jq '.b' | jq '.[1]'
# 結果
"test2"

フィルター記載箇所

  • フィルターは複数回書ける
  • ,でフィルターを区切ると、都度フィルターが評価される
# 入力
{
    "a": "TEST",
    "b": 123
}

##########
# フィルターを複数箇所で使用する
jq '{testA:.a, testB:.b}'
# 結果
{
    "testA": "TEST",
    "testB": 123
}

##########
# 「,」で区切ると、フィルターの数だけ取得が行われる
jq '.a, .b, .b, .a'
# 結果
"TEST"
123
123
"TEST"

関数・代入

|=

  • |はパイプ
  • 左側のフィルターをかけて|でパイプして右側に移る。そして、右側の演算をし、その結果を左側のフィルターに戻して値を更新する
# 入力
[1, 2, 3]

##########
# インデックス0の値を演算して更新する
jq '.[0]|=.*100'
# 結果
[
    100,
    2,
    3
]

##########
# 配列の各値を演算して更新する
jq '.[]|=.*100'
# 結果
[
    100,
    200,
    300
]
# 入力
{
    "a":1,
    "b":2,
    "c":3
}

##########
# .aだけ演算して更新
jq '.a|=.*100'
# 結果
{
    "a":100,
    "b":2,
    "c":3
}

##########
# オブジェクトの値を演算して更新
jq '.[]|=.*100'
# 結果
{
    "a":100,
    "b":200,
    "c":300
}

=

  • 代入
# 入力
{"a": {"b": 10}, "b": 20}

##########
# .a,.bは同じ階層を指す
jq '.a = .b'
# 結果
{
  "a": 20,
  "b": 20
}

##########
# .a.bは.aの子
jq '.a = .a.b'
# 結果
{
  "a": 10,
  "b": 20
}

##########
# exp
# 「|」はパイプなので右の「.」は左フィルターの中
jq '.a |= .b'
# 結果
{
  "a": 10,
  "b": 20
}

keys

  • オブジェクトのキーを配列で返す
  • 配列の場合はインデックスが返る
# 入力
{
    "a": "TEST",
    "b": 123
}

##########
# keysでオブジェクトのキーを配列で返す
jq 'keys'
# 結果
[
    "a",
    "b"
]
# 入力
[ "a", "b", "c" ]

##########
# keysで配列のインデックスを返す
jq 'keys'
# 結果
[
    0,
    1
]

map(x)

  • [.[]|x]と同じ
  • 配列を展開して、各値を使って演算し、結果を配列にして返す
    • これを1つの関数にまとめたもの
  • 最終結果は配列になる
# 入力
[ 1, 2, 3 ]

##########
# 配列の各要素を使って演算する
jq 'map(.*100)'
# 結果
[
    100,
    200,
    300
]
# 入力
{
    "a":1,
    "b":2,
    "c":3
}

##########
# オブジェクトの各要素を使って演算する
jq 'map(.*100)'
# 結果
[
    100,
    200,
    300
]

map_values(x)

  • .[]|=xと同じ
  • オブジェクトの各値を使って演算し、結果で更新する
  • 最終結果は、入力がオブジェクトならオブジェクト、配列なら配列になる
# 入力
[ 1, 2, 3 ]

##########
# 配列の各要素を使って演算する
jq 'map_values(.*100)'
# 結果
[
    100,
    200,
    300
]
# 入力
{
    "a":1,
    "b":2,
    "c":3
}

##########
# オブジェクトの各要素を使って演算する
jq 'map_values(.*100)'
# 結果
{
    "a":100,
    "b":200,
    "c":300
}

select(x)

  • 条件を満たすものを残す
  • map(select(x)).[]|select(x)など、配列から条件に合う項目を取り出すのによく使われる
# 入力
[1,5,3,0,7]

##########
# 配列をフィルターする
jq 'map(select(. >= 2))'
# 結果
[
    5,
    3,
    7
]

##########
# 配列を展開して、各要素から条件に合うものを残す
jq '.[]|select(. >= 2)'
# 結果
5
3
7
# 入力
[
    {"a":1, "b":100},
    {"a":5, "b":500},
    {"a":3, "b":300},
    {"a":0, "b":0},
    {"a":7, "b":700}
]

##########
# 配列をフィルターする
jq 'map(select(.a >= 2))'
# 結果
[
    {"a":5, "b":500},
    {"a":3, "b":300},
    {"a":7, "b":700}
]

##########
# 配列を展開して、各要素から条件に合うものを残す
jq '.[]|select(.a >= 2)'
# 結果
{"a":5, "b":500},
{"a":3, "b":300},
{"a":7, "b":700}

to_entries

  • オブジェクトをkey/valueペアの配列にする
  • 配列を渡すとkeyは配列のインデックスになる
# 入力
{"a":1, "b":"TEST"}

##########
# オブジェクトを``key/value``ペアの配列にする
jq 'select'
# 結果
[
  {
    "key": "a",
    "value": 1
  },
  {
    "key": "b",
    "value": "TEST"
  }
]
# 入力
[{"a":1, "b":"TEST"}]

##########
# 配列を``index/value``ペアの配列にする
jq 'select'
# 結果
[
  {
    "key": 0,
    "value": {
      "a": 1,
      "b": "TEST"
    }
  }
]

tojson

  • JSONをJSON文字列にする
# 入力
[
  {"a":1, "b":"TEST1"},
  {"a":2, "b":"TEST2"}
]

##########
# JSONをJSON文字列にする
jq '.[]|tojson'
# 結果
"{\"a\":1,\"b\":\"TEST1\"}"
"{\"a\":2,\"b\":\"TEST2\"}"

オプション

  • -c
    • 1つのJSONを1行で出力
  • -r
    • 文字列のダブルクォーテーションを表示しない

感想など

.は例えるなら、プログラム言語のthisみたいなものでしょうか。

「配列」と「配列を展開したもの」は、似ていて混乱しやすいのですが別物です。

「配列」は配列として1つで出力されるのに対し、「配列を展開したもの」は出力が要素毎に分かれてしまいます。