jq コマンドの ‘.[0]’ を理解 する
Looks like an Object Oriented Language.
前回の投稿で jq
コマンドのフィルターにおける制御構造( if ~ then ~ else ~ end
)を紹介いたしました。
# 前回の投稿のテクニック(8)で紹介したサンプル
> cat sample2.json \
| jq -r '.[]
| [ .id,
([(.attrs[] | select(.key == "middlename").value)]
| if length == 0 then
null
else
.[0]
end)
]'
制御構造が入ることによって、jq
コマンドがプログラミング言語処理系にみえてきますね。
そういえば、配列やオブジェクトを取り出す方法も、オブジェクト指向のプログラミング言語に似ています。前回の投稿でも、オブジェクトメンバーの値を取り出すのに、 .id
と記述していますし、 配列の要素を取り出すのに .[0]
と記述します。
一見すんなり理解出来そうなのですが、 .[0]
はよくよく見るとおかしいですよね。普通のプログラミング言語のように [0]
( .
無し)で取り出したいです。
事実、 jq
コマンドでも .attr[0]
の様に、配列を値に持つメンバー名( attr
)とつなげて書く場合は、メンバー名と [
の間に .
は不要です。逆にある場合はエラーになります。
> cat sample3.json
{ "attr" : ["foo", "bar", "baz"] }# . 無しの場合(エラー無し)
> cat sample3.json | jq '.attr[0]'
"foo"# . 有りの場合(エラー発生)
> cat sample3.json | jq '.attr.[0]'
jq: error: syntax error, unexpected '[', expecting FORMAT or QQSTRING_START (Unix shell quoting issues?) at <top-level>, line 1:
.attr.[0]
jq: 1 compile error
結局配列の要素を取り出すときに .
はいるのでしょうか?いらないのでしょうか?
どうやら配列を操作するときには、以下のように理解すれば良さそうです。
メンバー名に連続して配列操作の記載をする場合には、 [
の前に .
は不要
> cat sample3.json
{ "attr" : ["foo", "bar", "baz"] }#既出
> cat sample3.json | jq '.attr[0]'
"foo"
その他の場合(フィルターの最初、もしくはフィルター内の pipe ( |
) の直後)に配列操作の記載をする場合には、 [
の前に .
が必要
# フィルターの最初
> cat sample4.json
["foo", "bar", "baz"]> cat sample4.json | jq '.[0]'
"foo"# フィルター内の pipe (|) の直後
> cat sample3.json
{ "attr" : ["foo", "bar", "baz"] }> cat sample3.json | jq '.attr | .[0]'
"foo"
ちょっと違和感があるのですが、私は []
を使って配列を生成する文法(前回の投稿のテクニック(6))との衝突を避けるためだと理解しています。
# sample3.json の内容に関係なく 0 を要素に持つ配列を生成
> cat sample3.json | jq '[0]'
[
0
]
さて、もともと前回の投稿にコラムとして挟む予定だったのですが、そこそこボリュームがあったので、分けて投稿させていただきました。
jq
コマンドは関数も定義できますし、 length
などの組み込み機能もまだまだあります。今後も折を見て紹介していこうと思います。