jq コマンドの ‘.[0]’ を理解 する

Goro Yanagi
VELTRA Engineering
Published in
4 min readJun 26, 2018

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 などの組み込み機能もまだまだあります。今後も折を見て紹介していこうと思います。

--

--