それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

jq で 条件にマッチするオブジェクトを取り出す where 句的なこと

jq 便利ですよね。

jq 使ってます。みんなあれ整形程度にしか使ってなかったり、絞込にしか使ってない気と思うんですよね

jq である条件を満たすオブジェクトを取り出したい

SQLselect where みたいに select {} where [].name = 'takuya' みたいな jq がかけたら最高なんですよ。

条件マッチしたノードを取り出す例
$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq ' .[] | select(.x) '
{
  "x": 1
}

出来るんです。マニュアルに有りました。ああ。これは最高だ。

単純なところから、見ていく

いきなり select 見ても何のことかわからないので、単純なところから見ていくことにする。

単純な整形

jq を使って整形をするよくある例です。これは jq . と書いてます。つまりカレントノードを出力しろって意味です。

単純な整形の例
$ echo '[{},{}]' | jq .
[
  {},
  {}
]

配列の中身を出す

配列の中を自動で走査して中身を取り出してくれるのが、こちらにになります。 jq .[] は jq の最上位のノードのひとつ下の配列をIterationして中身をくれって事になります。

配列の中身を出力取り出す例
$ echo '[1,2,3]' | jq '.[]'
1
2
3

配列の指定したINDEXを取り出す。

配列のなかに、インデックスを指定すると、指定した番号のものが取り出せる。

配列の指定したINDEXを取り出す例
$ echo '[1,2,3]' | jq '.[1]'
2

さらにこれは、一つだけじゃなくさらに突っ込んだ書き方ができる。

配列の中身の順番を複数指定してしまう例
$ echo '[1,2,3]' | jq '.[0,2,1]' # 順序も
1
3
2
$ echo '[1,2,3]' | jq '.[0,2]' # 選択も
1
3

要素がオブジェクトで ハッシュキーから取り出す

選択対象となる要素がハッシュ(オブジェクト)でその中をStringをキーに取り出していきたいとき。

オブジェクトの中身だけを取り出したい。
$ echo '{ "a":1 , "b":2 }'  | jq '.a'
1
$ echo '{ "a":1 , "b":2 }'  | jq '.b'
2
ネストしたオブジェクトでも大丈夫。
# ネスト 1段 ・ネスト2
$ echo '{ "a": { "x": 1 }, "b":2 }'  | jq '.a'
{
  "x": 1
}
$ echo '{ "a": { "x": 1 }, "b":2 }'  | jq '.a.x' #ネスト 2段
1

配列とオブジェクトの選択の組み合わせ。

ここまで見た配列とオブジェクトの指定をjq で行う場合を組み合わせると次のようになる。

配列とオブジェクトを同時に使う。
$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq '.' # まずは単純に整形
[
  {
    "a": 1
  },
  {
    "x": 1
  }
]
$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq '.[]' # 配列要素ごとにprint 
{
  "a": 1
}
{
  "x": 1
}
$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq '.[].a' # 配列の要素内で検索
1

true/falseに変形(検索条件を書く

ここで、更に検索条件を足して、書き換え処理を行う。map 処理です。

配列の各要素をその値によって書き換えていきます。

jq で要素のオブジェクトを書き換え true/falseにする
$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq '(.[].a==1)'
true
false

最後にselect と組み合わせる。

true / false に変形することが出来たらそれをフィルタする。 map /reduce / filter の概念が理解できてればかんたんです。

$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq '.[] | select (.a==1)' # a == 1 のものだけ
{
  "a": 1
}

$ echo '[ { "a":1 },  { "x": 1 } ]'  | jq ' .[] | select(.x) ' # 'x': object が存在するものだけ
{
  "x": 1
}

個人的感想

jq 便利すぎてやばい。STDIOとパイプをJSONと組み合わせたxargs にかわる新しい概念かもしれない。

参考資料

まにゅあるにあったわ。。

https://stedolan.github.io/jq/manual/#Assignment