普段なんとなくjqを使うといったら.foo
くらいの単純なフィルタや整形用途くらいで、ガッツリ勉強したことはなかった。
ガッツリ勉強していないので、.[]
といった配列まわりの機能をゴリゴリ使えなかったのだが、基礎テクを学び直してある程度使えるようになっておこうと思った。そのメモ。
このメモは網羅的な物ではなく、基礎的でよく使いそうな項目だけ記載してある。
また、普段はScalaをメインに書いていて、一番理解しやすいのがScalaなので、Scalaでいうところのこれはこう書く、というふうにメモしてある。
Scalaのアレはこれ
Seq() / new
配列を作るにはそのまま[]
を使う。
Seq(1,2,3)
// jq [1, 2, 3]
同様に、{}
でオブジェクトを作ることができる。
// jq { foo: 42 }
JSONとは異なり、jqではキーのクオートを省略してもよい。
map
map操作を行うにはspread演算子.[]
を利用し、フィルタにつなぎ、それで配列を構築すればよい。
.[]
は公式にはIteratorと呼ばれているが、この記事では慣用的にspreadと呼ぶことがある。
arr.map(_.foo)
// jq
[.[].foo]
note: .[].ほげ
はperlのmap
に近い
// jq
[.[].foo, .[].bar]
こうすると1つの配列に押し込まれる。
ちなみにより簡便な方法として、配列からそのまま配列に変換するには、map
をそのまま使う(spreadの振る舞いを確認するためにあえて後から説明した)。
// jq map(.foo)
spread演算子を使う方法と同様に1つの配列に押し込めることができる。
// jq map(.foo, .bar)
note: map
演算子はspreadしてconstructすることと同等である。
一般に、[.[] | foo]
の形になった場合はmap
で書ける。
flaten
[[123, 456], [789, 012]]
を1つのArrayにつぶしたいとき。
mapとspread演算子について知っていればわかりやすい。
// jq map(.[])
merge
/ &&&
CatsのArrowのmerge
とjqの,
はおおむね同じ働きをする。同一の内容を複数のフィルタに投入して、それぞれの結果を返すのだ。
val f = (n: Int) => n * 2 val g = (n: Int) => Seq(n, n) val h = f &&& g h(42) // => (84, Seq(42, 42))
$ echo "42" | jq '[. * 2, [., .]]' [ 84, [ 42, 42 ] ]
filter
filterするにはselect
すればよい。ただし、select
自体は配列を受け取らないため、いちどspreadしてからpipeする。
$ echo '[1,2,3,4,5,6,7,8,9]' | jq '.[] | select(. % 2 == 0)' 2 4 6 8
また、最終的な結果が配列の場合はmapを組み合わせても書ける。
echo '[1,2,3,4,5,6,7,8,9]' | jq 'map(select(. % 2 == 0))' [2, 4, 6, 8]
string interpolation
\()
を使うとよい。
echo '[1,2,3]' | jq 'map("number is \(.)")' [ "number is 1", "number is 2", "number is 3" ]
|
: pipe
フィルタを結合する。.foo.bar
のように、自然と左右に並べられるフィルタもあるが、並べられないフィルタはpipeで結合する。
ポイントフリーならぬポイント有りのスタイルに書き換えられる。
最終的な出力の形をテンプレート的に一番後ろにもってきて、pipeで値をもらう、というのがよくあるイディオムらしい。
// jq foo | bar | {buzz: .piyo, hoge: .fuga}
..
-- 再帰抽出
ワイルドカード的に構造をスキップして子の値をすべて取出そうとする。
$ echo '{"foo": {"bar": {"buzz": {"piyo": 42}}}}' | jq '..|.piyo?|numbers' 42
グロブの**
に近いが、値に限らず配列やオブジェクトも取出そうとする。全走査といったほうがよい。
$ echo '[[1,2],[3,[4,5]]]' | jq '..' [ [ 1, 2 ], [ 3, [ 4, 5 ] ] ] [ 1, 2 ] 1 2 [ 3, [ 4, 5 ] ] 3 [ 4, 5 ] 4 5
CLI options
-r
: raw出力 -- ダブルクオートを忘却する
出力される文字列のダブルクオートを捨てる。
$ echo '["foo", "bar"]' | jq '.[]' -r foo bar
相補的な機能として-R
が存在する。
-R
: raw入力 -- ダブルクオートを追加する
入力されるJSONの前処理として、「各行を文字列とみなし、それらの配列を構成する」という処理を行う。
$ echo "foo\nbar" | jq -R "foo" "bar"
cf. -s
-s
: slurp入力 -- 入力全体を配列とみなす
入力\n入力2
の代わりに、[入力, 入力2]
が入力されたものとみなす。
echo '"foo"\n"bar"' | jq -s [ "foo", "bar" ]
ただし、-R
と-s
とは同時に複合できないため、二度jqを呼ぶ必要がある。
$ echo "foo\nbar" | jq -R | jq -s [ "foo", "bar" ]