とほほのjq入門

トップ > jq

目次

jqとは

JSON を整形して出力することができます。

$ echo '{"a":123, "b":456}' | jq
{
  "a": 123,
  "b": 456
}

JSON の中から指定したキーや配列の情報を取り出すことができます。

$ echo '{"a":123, "b":456}' | jq '.b'
456

JSON の中から、age が 40 以下などの条件を指定して取り出すこともできます。

$ cat sample.json | jq -c '.users[] | select(.age <= 40)'
{"name":"Yamada","age":26}
{"name":"Tanaka","age":32}

下記の様に JSON データを整形することもできます。

$ cat sample.json | jq -rc '.users[] | "\(.name)(\(.age))"'
Yamada(26)
Tanaka(32)
Suzuki(45)

合計値などを求めることもできます。

$ cat sample.json | jq '[.users[].age] | add'
103

簡単な計算ツールとして使用することもできます。

$ jq -n '60 * 60 * 24'
86400

簡単なコンバートツールとして使用することもできます。

$ echo '"x > y"' | jq -r '@html'
x &gt; y

インストール

# RHEL8系
# yum -y install jq

# RHEL7系
# yum -y install epel-release
# yum -y install jq

# Ubuntu 22.04
# apt -y install jq

サンプルJSON

本書では、サンプルとして下記の JSON を使用します。

sample.json
{
  "status": "OK",
  "count": 3,
  "users": [
    { "name": "Yamada", "age": 26 },
    { "name": "Tanaka", "age": 32 },
    { "name": "Suzuki", "age": 45 }
  ]
}

コマンドライン

jq [options]
jq [options] filter [file...]
jq [options] --args filter [arguments...]
jq [options] --jsonargs filter [json_texts...]

例えば下記の様に使用します。

$ cat sample.json | jq
$ cat sample.json | jq '.users'
$ jq '.users' sample.json

オプション

出力に関するオプション
インデント数 (--indent n)

インデント文字数を指定します。

$ echo '{"name": "Yamada"}' | jq --indent 4
{
    "name": "Yamada"
}
タブインデント (--tab)

インデントにタブ文字を使用します。

$ echo '{"name": "Yamada"}' | jq --tab
{
	"name": "Yamada"
}
コンパクト出力 (-c | --compact-output)

改行やインデント無しのコンパクト形式で出力します。

$ echo '{"name": "Yamada"}' | jq -c
{"name": "Yamada"}
キーソート出力 (-S | --sort-keys)

キーをソートして出力します。

$ echo '{"b":"B", "c":"C", "a":"A"}' | jq -S
{
  "a": "A",
  "b": "B",
  "c": "C"
}
色つき出力 (-C | --color-output)

色つきで出力します。色は JQ_COLORS でカスタマイズできます。

$ echo '{"name": "Yamada"}' | jq -C
{
  "name": "Yamada"
}
色無し出力 (-M | --monochrome-output)

色無しで出力します。

$ echo '{"name": "Yamada"}' | jq -M
{
  "name": "Yamada"
}
RAW出力 (-r | --raw-output)

出力データの文字列のダブルクォーテーションを取り除きます。

$ echo '{"name":"Yamada"}' | jq '.name'
"Yamada"
$ echo '{"name":"Yamada"}' | jq -r '.name'
Yamada
連結出力 (-j | --join-output)

-r と似ていますが、個々の出力の末尾に改行を出力しません。

$ echo '{"name":"Yamada"}{"name":"Tanaka"}' | jq -j '.name'
YamadaTanaka
ASCII出力 (-a | --ascii-output)

非ASCII文字を ASCII文字で出力します。

$ echo '{"name":"山田"}' | jq -c
{"name":"山田"}
$ echo '{"name":"山田"}' | jq -c -a
{"name":"\u5c71\u7530"}
バイナリ出力 (-b | --binary)

Windows 利用者がこのオプションを使用すると、jq.exe が LF を CR LF に変換するのを抑制することができます。

C:\Temp> jq.exe -b ...
バッファリング無し出力 (--unbuffered)

出力をバッファリングしないようにします。

$ tail -f xxx.log | jq --unbuffered > xxx.json
入力に関するオプション
啜り入力 (-S | --slurp)

複数の JSON が連続するデータを読み取り、配列に変換して出力します。

$ echo '{"name":"Yamada"}{"name":"Suzuki"}' | jq -c
{"name":"Yamada"}
{"name":"Suzuki"}
$ echo '{"name":"Yamada"}{"name":"Suzuki"}' | jq -c -s
[{"name":"Yamada"},{"name":"Suzuki"}]
RAW入力 (-R | --raw-input)

入力を JSON としてではなく、改行で区切られた文字列の集合として扱います。

$ cat xx.csv
Yamada,26
Tanaka,32
$ cat xx.csv | jq -c -R 'split(",")'
["Yamada","26"]
["Tanaka","32"]
入力無し (-n | --null-input)

入力を読み込まず、引数で指定した文字列を JSON として扱います。

$ jq -n '{"name":"Yamada"}'
{
  "name": "Yamada"
}
JSON-SEQ型 (--seq)

入力を application/json-seq 型のデータとして扱います。複数個の JSON データを、JSON データの先頭に RS(U+001E)、末尾に LF(U+000A) を付けて並べた形式です。あまり利用されていません。

$ cat json-seq.json | js --seq '...'
キーアサイン
引数指定 (--arg key value)

$keyvalue を割り当てます。

$ jq -nc --arg name Yamada '{"name": $name}'
{"name": "Yamada"}
引数指定(JSON) (--argjson key json)

$key に JSON値 value を割り当てます。

$ jq -cn --argjson foo '{"name":"Yamada"}' '{"foo":$foo}'
{"foo":{"name":"Yamada"}}
ファイル指定 (--slurpfile key filename)

$keyfilename で指定したファイルの中身を割り当てます。

$ echo '{"name":"Yamada"}{"name":"Tanaka"}' > sample.json
$ jq -nc --slurpfile foo sample.json '{"foo":$foo}'
{"foo":[{"name":"Yamada"},{"name":"Tanaka"}]}
ファイル指定 (--argfile key filename)

--slurpfile と同様ですが、ファイルの内容が1行の場合のみ利用できます。

$ echo -n '"Yamada"' > sample.raw
$ jq -nc --argfile foo sample.raw '{"foo":$foo}'
{"foo":"Yamada"}
ファイル指定 (--rawfile key filename)

$keyfilename で指定したファイルの中身(RAWデータ)を割り当てます。

$ echo -n Yamada > sample.raw
$ jq -nc --rawfile foo sample.raw '{"foo":$foo}'
{"foo":"Yamada"}
引数指定 (--args)

パラメータを引数で指定します。パラメータは $ARG.positional で参照することができます。

$ jq -nc --args '$ARGS' AAA BBB
{"positional":["AAA","BBB"],"named":{}}
JSON指定 (--jsonargs)

パラメータを JSON 形式で指定します。パラメータは $ARG.positional で参照することができます。

$ jq -nc --jsonargs '$ARGS' '{"arg1":"AAA","arg2":"BBB"}'
{"positional":[{"arg1":"AAA","arg2":"BBB"}],"named":{}}
その他
バージョン (--version)

バージョンを表示します。

$ jq --version
jq-1.6
ヘルプ (--help)

ヘルプを表示します。

$ jq --help
フィルタファイル指定 (-f | --from-file file)

フィルタ情報をコマンドラインからではなくファイルで指定します。

$ cat sample.jq
.name
$ echo '{"name":"Yamada"}' | jq -f sample.jq
"Yamada"
ストリーム処理 (--stream)

入力をストリーム的に読込み、ひとつの値を、[[値のパス配列],値] の列に変換しながら処理します。JSON が完了していなくても値毎に逐次処理できるため、巨大な JSON ファイルを逐次処理する際に利用されます。

$ cat sample.json | jq -c --stream
[["status"],"OK"]
[["count"],3]
[["users",0,"name"],"Yamada"]
[["users",0,"age"],26]
[["users",0,"age"]]
[["users",1,"name"],"Tanaka"]
[["users",1,"age"],32]
[["users",1,"age"]]
[["users",2,"name"],"Suzuki"]
[["users",2,"age"],45]
[["users",2,"age"]]
[["users",2]]
[["users"]]
ライブラリパス (-L directory)

include や import で読み込むライブラリファイルのパス名を指定します。

$ cat sample.json | jq -L /usr/local/lib/jq -f sample.jq
終了コード制御 (-e | --exit-status)

jq コマンド通常の終了コードは、0(正常終了)、2(利用方法エラーやシステムエラー)、3(コンパイルエラー) となりますが、-e を指定すると最後に処理したデータが false や null でなければ 0、false や null であれば 1、有効な結果が得られなければ 4 を返します。

$ echo 'null' | jq -e ; echo $?
null
1

フィルタ

JSON からキーを指定して値を取り出すことができます。

キーによる抽出
キー (.key)

.key は該当するキーの値を取り出します。

$ cat sample.json | jq '.status'
"OK"
列挙 (,)

カンマ(,)で複数の値を取り出すこともできます。

$ cat sample.json | jq '.status, .count'
"OK"
3
配列の抽出
配列 ([])

配列要素を抽出します。

$ cat sample.json | jq -c '.users'
[{"name":"Yamada","age":26},{"name":"Tanaka","age":32},{"name":"Suzuki","age":45}]
$ cat sample.json | jq -c '.users[]'
{"name":"Yamada","age":26}
{"name":"Tanaka","age":32}
{"name":"Suzuki","age":45}
配列 ([n])

0から数えて n番目の要素を取り出します。

$ cat sample.json | jq -c '.users[1]'
{"name":"Tanaka","age":32}
配列 ([-n])

最後から n番目の要素を取り出します。

$ cat sample.json | jq -c '.users[-1]'
{"name":"Suzuki","age":45}
配列 ([n:m])

nm番目の要素を配列形式で取り出します。

$ cat sample.json | jq -c '.users[0:2]'
[{"name":"Yamada","age":26},{"name":"Tanaka","age":32}]
抽出結果からの再抽出
再抽出 (filter1 | filter2)

結果の JSON に対してさらに jq で抽出を行うことができます。複数の jq コマンドを連結することもできますが、パイプ(|)で連結することにより、一つ目のフィルタで抽出した結果を入力として再度抽出を行うこともできます。

$ cat sample.json | jq '.users[]' | jq '.name'
"Yamada"
"Tanaka"
"Suzuki"
$ cat sample.json | jq '.users[] | .name'
"Yamada"
"Tanaka"
"Suzuki"
再抽出 (filter1.filter2)

ドット(.)で連結することにより、一つ目のフィルタで抽出した結果を入力として再度抽出を行うこともできます。

$ cat sample.json | jq '.users[].name'
"Yamada"
"Tanaka"
"Suzuki"
抽出結果の整形
配列への整形 ([filter])

抽出した列を配列として整形するには全体を [...] で囲みます。

$ cat sample.json | jq -c '[.users[].name]'
["Yamada","Tanaka","Suzuki"]

JSON列を下記の様に名前をキーとした配列に変換することもできます。

$ cat sample.json | jq -c '.users[] | [.name, .age]'
["Yamada",26]
["Tanaka",32]
["Suzuki",45]
オブジェクトへの整形 ({filter})

オブジェクトとして整形したい場合は全体を {key:...} で囲みます。

$ cat sample.json | jq -c '{name:.users[].name}'
{"name":"Yamada"}
{"name":"Tanaka"}
{"name":"Suzuki"}

下記の様にオブジェクト列にすることもできます。

$ cat sample.json | jq -c '.users[] | {N:.name, A:.age}'
{"N":"Yamada","A":26}
{"N":"Tanaka","A":32}
{"N":"Suzuki","A":45}

下記の例では、名前をキー、年齢を値としたオブジェクトを生成します。キー名を (...) で囲む必要があります。

cat sample.json | jq -c '.users[] | {(.name):.age}'
{"Yamada":26}
{"Tanaka":32}
{"Suzuki":45}
再帰抽出
再帰抽出(..)

.filter1.filter2.filter3.filterx を途中のフィルタを省略して ..|.filterx と表現することができます。例えば、sample.json からデータ階層に関わらず name の値を抽出するには ..|.name と記述します。.name にマッチしない値もあるため、エラー無視の ? を付加して ..|.name? とし、さらに | strings で文字列のみを抽出します。

$ cat sample.json | jq '..|.name?|strings'
"Yamada"
"Tanaka"
"Suzuki"

演算子

算術演算子(+, -, *, /, %)
x + y		# xy の加算
x - y		# xy の減算
x * y		# xy の乗算
x / y		# xy の除算
x % y		# xy の剰余
比較演算子(==, !=, > >=, <, <=)
x == y		# xy が等しければ
x != y		# xy が等しくなければ
x > y		# xy より大きければ
x >= y		# xy 以上であれば
x <= y		# xy 以下であれば
x > y		# xy より小さければ
論理演算子(and, or, not)
x and y		# x かつ y が真であれば
x or y		# x または y が真であれば
not x 		# x が真でなければ
代替演算子(//)
x // y		# x が false や null でなければ x、さもなくば y
更新演算子(|=)

左辺のフィルタの値を左辺で更新します。

$ echo '{"flag":true}' | jq -c '.flag |= if . then 1 else 0 end'
{"flag":1}
代入演算子(=)

|= と = は似ていますが、下記などの例で差異が分かります。

$ echo '{"a": {"b": 10}, "b": 20}' | jq -c '.a = .b'
{"a":20,"b":20}
$ echo '{"a": {"b": 10}, "b": 20}' | jq -c '.a |= .b'
{"a":10,"b":20}
算術更新演算子(+=, -=, *=, /=, %=, //=)
$ echo '{"foo":42}' | jq -c '.foo += 1'
{"foo":43}

ビルトイン

セレクト
select(expression)

配列やJSON列を受け取り、条件にマッチした列のみを抽出します。

$ echo '[1,2,3,4,5]' | jq -c 'select(. > 2)'
[1,2,3,4,5]
$ echo '[{"k":"ABC","v":92},{"k":"DEF","v":76}]' | jq -c '.[] | select(.v > 80)'
{"k":"ABC","v":92}
マッピング
map(x)

配列やオブジェクトを受け取り、それぞれの値に対してマップ処理を行った結果の配列を返却します。

$ echo '[1,2,3]' | jq -c 'map(. + 1)'
[2,3,4]
map_values(x)

配列やオブジェクトを受け取り、それぞれの値を、値に対してマップ処理を行った結果で置換したものを返却します。

$ echo '{"a":1,"b":2,"c":3}' | jq -c 'map_values(. + 1)'
{"a":2,"b":3,"c":4}
合計
add

配列の値の合計を求めます。

$ echo '[1,2,3]' | jq -c 'add'
6
配列処理
sort, sort_by(path_expression)

配列をソートします。path_expression を指定した場合は指定したキーでソートします。

$ echo '[3,5,1,4,2]' | jq -c 'sort'
[1,2,3,4,5]
$ echo '[{"A":3,"B":2},{"A":1,"B":3},{"A":2,"B":1}]' | jq -c 'sort_by(.B)'
[{"A":2,"B":1},{"A":3,"B":2},{"A":1,"B":3}]
group_by(path_expression)

path_expression で指定したキーが同じ値を持つものをグルーピングします。

$ echo '[{"A":1,"B":3},{"A":3,"B":2},{"A":1,"B":1}]' | jq -c 'group_by(.A)'
[[{"A":1,"B":3},{"A":1,"B":1}],[{"A":3,"B":2}]]
unique, unique_by(path_exp)

重複した値をひとつにまとめます。

$ echo '[1,2,3,2,1]' | jq -c 'unique'
[1,2,3]
$ echo '[{"A":3,"B":1},{"A":1,"B":3},{"A":2,"B":1}]' | jq -c 'unique_by(.B)'
[{"A":3,"B":1},{"A":1,"B":3}]
reverse

配列の順序を逆順にします。

$ echo '[1,2,3]' | jq -c 'reverse'
[3,2,1]
any, any(condition), any(generator; condition)

配列を受け取り、配列要素の中に一つでも true または condition が true になるものがあれば true を返します。

$ echo '[false, true, false]' | jq 'any'
true
$ echo '["A","B","C"]' | jq 'any(.=="B")'
true
all, all(condition), all(generator; condition)

配列を受け取り、配列要素の中のすべての要素が true または condition が true であれば true を返します。

$ echo '[true, true, true]' | jq 'all'
true
$ echo '["A","A","A"]' | jq 'any(.=="A")'
true
flatten, flatten(depth)

配列の階層をフラットにします。depth を指定すると depth 階層までの配列をフラット化します。

$ echo '[1,[2,[3,4]]]' | jq -c 'flatten'
[1,2,3,4]
$ echo '[1,[2,[3,4]]]' | jq -c 'flatten(1)'
[1,2,[3,4]]
bsearch(x)

ソート済の配列を入力として値 x をバイナリサーチします。見つかれば見つかった位置のインデックスを、見つからなければ見つからないと判断した位置のインデックスの負数から1引いた値を返却します。

$ echo '[1,3,5,7,9]' | jq 'bsearch(5)'
2
$ echo '[1,3,5,7,9]' | jq 'bsearch(6)'
-4
長さ
length

配列の個数、オブジェクトの要素数、文字列の文字数を返します。

$ echo '["a","b","c"]' | jq 'length'
3
utf8bytelength

UTF-8 で表現した場合のバイト数を返します。

$ echo '"あ"' | jq 'utf8bytelength'
3
パス配列
path(path_expression)

パスとして参照されるキー名および配列インデックスの配列を返却します。

$ echo 'null' | jq -c 'path(.a[0].b)'
["a",0,"b"]
getpath(path)

パス配列を指定して値を抽出します。

$ echo '{"a":{"b":{"c":123}}}' | jq -c 'getpath(["a", "b", "c"])'
123
"Yamada"
setpath(path; value)

パス配列を指定して値を変更します。

$ echo '{"a":{"b":{"c":123}}}' | jq -c 'setpath(["a", "b", "c"]; 456)'
{"a":{"b":{"c":456}}}
delpaths(paths)

パス配列の配列を指定して値を削除します。

$ echo '{"a":{"b":{"c":123}}}' | jq -c 'delpaths([["a", "b", "c"]])'
{"a":{"b":{}}}
paths, paths(node_filter)

それぞれの値を得るためのパス配列の一覧を返却します。node_filter に型名を指定すると型にマッチする要素に関してのみ出力します。

$ echo '{"a":123, "b":456, "c":{"d":789}}' | jq -c '[paths]'
[["a"],["b"],["c"],["c","d"]]
$ echo '{"a":123, "b":456, "c":{"d":789}}' | jq -c '[paths(scalars)]'
[["a"],["b"],["c","d"]]
leaf_paths

paths(scalars) と同義です。

$ echo '{"a":123, "b":456, "c":{"d":789}}' | jq -c '[leaf_paths]'
[["a"],["b"],["c","d"]]
キー・バリュー
keys

キーのみの配列をソートして返します。

$ echo '{"b":"B", "c":"C", "a":"A"}' | jq -c 'keys'
["a","b","c"]
keys_unsorted

キーのみの配列をソートせずに返します。

$ echo '{"b":"B", "c":"C", "a":"A"}' | jq -c 'keys_unsorted'
["b","c","a"]
has(key)

オブジェクトを受け取り、オブジェクトが key キーを持っていれば true、さもなくば false を返します。

$ echo '{"foo":"FOO"}' | jq 'has("foo"), has("baa")'
true
false
in(value)

値の配列を受け取り、引数で指定したオブジェクトのキーとして存在すれば true、さもなくば false を返します。

$ echo '["foo","bar","baz"]' | jq '.[] | in({"foo":null})'
true
false
false
to_entries

{key: value} 形式を {"key":key, "value":value} 形式に変換します。

$ echo '{"a":123,"b":456}' | jq -c 'to_entries'
[{"key":"a","value":123},{"key":"b","value":456}]
from_entries

{"key":key, "value":value} 形式を {key: value} 形式に変換します。

$ echo '[{"key":"a","value":123},{"key":"b","value":456}]' | jq -c 'from_entries'
{"a":123,"b":456}
with_entries(x)

{key: value} の .key や .value に対して変換処理を行います。

$ echo '{"a":123,"b":456}' | jq -c 'with_entries(.key |= "KEY_" + .)'
{"KEY_a":123,"KEY_b":456}
型チェック
arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars

値の列を受け取り、型が合致するもののみを抽出します。

$ echo '["ABC",123,[4,5,6]]' | jq -c '.[] | strings'
"ABC"
$ echo '["ABC",123,[4,5,6]]' | jq -c '.[] | numbers'
123
$ echo '["ABC",123,[4,5,6]]' | jq -c '.[] | arrays'
[4,5,6]
type

値の型を返します。

$ echo '[true, "A", 123, [], {}, null]' | jq -c 'map(type)'
["boolean","string","number","array","object","null"]
エラー処理
error, error(message)

エラーメッセージを表示します。

# echo '120' | jq 'if . > 100 then error("TooBIG") else . end'
jq: error (at <stdin>:1): TooBIG
halt

プログラムを中断します。

$ echo '[88,92,123]' | jq '.[] | if . > 100 then halt else . end'
88
92
halt_error, halt_error(exit_code)

プログラムを中断し、終了コードを返します。

$ jq -n 'halt_error(99)'
$ echo $?
99
数学関数
floor, ceil, round, trunc, nearbyint, rint

floor は切り下げ、ceil は切り上げ、round は四捨五入を行います。trunc は切り下げを行いますが、負数の時は数値が小さくなる方向ではなく 0 に近づく方向に丸めます。nearbyintrint は銀行丸め (偶数+0.5の場合は切り下げ、奇数+0.5の場合は切り上げ)を行います。

$ echo '3.14159' | jq 'floor'
3
min, max, min_by(path_exp), max_by(path_exp)

最小値、最大値を返します。path_exp を指定すると、指定したキーの値が最小、最大のものを返します。

$ echo '[3,6,1]' | jq 'min'
1
$ echo '[3,6,1]' | jq 'max'
6
$ echo '[{"A":3,"B":2},{"A":1,"B":3},{"A":2,"B":1}]' | jq -c 'min_by(.B)'
{"A":2,"B":1}
$ echo '[{"A":3,"B":2},{"A":1,"B":3},{"A":2,"B":1}]' | jq -c 'max_by(.B)'
{"A":1,"B":3}
pow(x; y)

powxy乗を求めます。

$ jq -n 'pow(2;16)'
65536
sqrt, cbrt

数値の平方根、立方根を求めます。

$ echo '2' | jq 'sqrt'
1.4142135623730951
modf, frexp

modf は数値を整数部と小数部に分解し、[小数部, 整数部] を返します。frexp は入力を x とし、x = y(0.5~1.0) * 2 の z 乗が成り立つ [y, z] を返します。

$ echo '3.5' | jq -c 'modf'
[0.5,3]
$ echo '8.0' | jq -c 'frexp'
[0.5,4]
sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh

三角関数(sin, cos, tan)、逆三角関数(asin, acos, atan)、双曲線関数(sinh, cosh, tanh)、双曲線逆正弦(asinh, acosh, atanh)です。

$ echo '1.2' | jq 'sin'
0.9320390859672263
log, log10, log1p, log2, logb

対数に関連する数学関数です。

$ echo '2.0' | jq 'log'
0.6931471805599453
exp, exp2, exp10, expm1

オイラー定数 e に関連する数学関数です。

$ echo '1.0' | jq 'exp'
2.718281828459045
erf, erfc, fabs, gamma, lgamma, tgamma, j0, j1, y0, y1, significand

その他の数学関数として、誤差関数(erf)、相補誤差関数(erfc)、絶対値(fabs)、ガンマ関数関連(gamma, lgamma, tgamma)、ベッセル関数関連(j0, j1, y0, y1)、仮数(significand) があります。

$ echo '-2.3' | jq 'fabs'
2.3
atan2, copysign, drem, fdim, ...

上記の他、2個の引数をもつ数学関数として、atan2copysigndremfdimfmaxfminfmodhypotjnldexpnextafternexttowardremainderscalbscalblnyn があります。3個の引数をもつ数学関数として fma があります。詳細説明省略。

$ jq -n 'atan2(0.1;0.2)'
0.4636476090008061
文字列処理
startswith(str)

文字列が str で始まっていれば true を返します。

$ echo '"Japanese"' | jq 'startswith("Jap")'
true
ensswith(str)

文字列が str で終わっていれば true を返します。

$ echo '"Japanese"' | jq 'endswith("ese")'
true
ltrimstr(str), rtrimstr(str)

先頭から(末尾から) str を取り除いた文字列を返します。

$ echo '"Japanese"' | jq 'ltrimstr("Jap")'
"anese"
$ echo '"Japanese"' | jq 'rtrimstr("ese")'
"Japan"
explode

文字列を文字コードの配列に変換します。

$ echo '"ABC"' | jq -c 'explode'
[65,66,67]
implode

文字コードの配列を文字列に変換します。

$ echo '[65,66,67]' | jq 'implode'
"ABC"
ascii_downcase, ascii_upcase

小文字・大文字に変換します。

$ echo '"Japanese"' | jq 'ascii_downcase'
"japanese"
$ echo '"Japanese"' | jq 'ascii_upcase'
"JAPANESE"
文字列・配列
split(str), split(reg; flags)

文字列をデリミタで分割して配列にします。正規表現や、正規表現のフラグを指定することもできます。

$ echo '"foo,baa,baz"' | jq -c 'split(",")'
["foo","baa","baz"]
join(str)

配列をデリミタで連結して文字列にします。

$ echo '["foo","baa","baz"]' | jq 'join(",")'
"foo,baa,baz"
contains(element)

入力が文字列の場合、指定した文字列が含まれていれば true を返します。入力が配列の場合、指定した配列要素がすべて含まれていれば true を返します。入力がオブジェクトの場合、指定したパスの値が合致していれば true を返します。

$ echo '"ABCDEFGHIJ"' | jq 'contains("DEF")'
true
$ echo '["A","B","C"]' | jq 'contains(["A","C"])'
true
$ echo '{"A":12, "B":13, "D":{"E":14}}' | jq 'contains({"A":12, "D":{"E":14}})'
true
indices(s)

文字列や配列の中で s が出現する箇所のインデックスの配列を返します。

$ echo '"Japanese"' | jq -c 'indices("a")'
[1,3]
$ echo '[1,2,3,4,1,2,1,6]' | jq -c 'indices(1)'
[0,4,6]
$ echo '[1,2,3,4,1,2,1,6]' | jq -c 'indices([1,2])'
[0,4]
index(s), rindex(s)

文字列や配列の中で s が最初に(最後に)出現する箇所のインデックスを返します。

$ echo '"Japanese"' | jq -c '[index("a"), rindex("a")]'
[1,3]
$ echo '[1,2,3,4,1,2,1,6]' | jq -c '[index(1), rindex(1)]'
[0,6]
$ echo '[1,2,3,4,1,2,1,6]' | jq -c '[index(1), rindex([1,2])]'
[0,4]
limit(n; exp)

数値の列を引数として受け取り、最大値 n 以下の数値のみを返します。

$ echo '[1,2,3,4,5]' | jq -c '[limit(3;.[])]'
[1,2,3]
first, last, nth, first(list), last(list), nth(n; list)

配列を入力、または列を引数として受け取り、最初、最後、n番目(0開始)の要素を返します。

$ echo '["A","B","C","D","E"]' | jq 'first'
"A"
$ echo '["A","B","C","D","E"]' | jq 'last'
"E"
$ echo '["A","B","C","D","E"]' | jq 'nth(3)'
"D"
$ echo '["A","B","C","D","E"]' | jq 'first(.[])'
"A"
$ echo '["A","B","C","D","E"]' | jq 'last(.[])'
"E"
$ echo '["A","B","C","D","E"]' | jq 'nth(3; .[])'
"D"
正規表現
test(reg), test(reg, flags)

文字列を入力とし、正規表現 reg にマッチすれば true、さもなくば false を返します。

$ echo '"ABC"' | jq 'test("^[A-Z]+$")'
true

flags には 何度もマッチする(g)、大文字・小文字を無視する(i)、マルチラインモード(m)、シングルラインモード(s)、m と s 両方を有効化(p)、空マッチを無視(n)、最長マッチ(l)、拡張正規表現マッチ(x) の組み合わせを指定します。

$ echo '"abc"' | jq 'test("^[A-Z]+$"; "i")'
true
match(reg), match(reg; flags)

マッチした箇所のオフセット(offset)、長さ(length)、マッチ文字列(string)、キャプチャ情報(capture) を返します。

$ echo '"23:59:59"' | jq -c 'match("([0-9]+)"; "g")'
{"offset":0,"length":2,"string":"23","captures":[{"offset":0,"length":2,"string":"23","name":null}]}
{"offset":3,"length":2,"string":"59","captures":[{"offset":3,"length":2,"string":"59","name":null}]}
{"offset":6,"length":2,"string":"59","captures":[{"offset":6,"length":2,"string":"59","name":null}]}
capture(reg), capture(reg; flags)

キャプチャした文字列にキーを割り当てます。

$ echo '"23:59:59"' | jq -c 'capture("(?<hour>[0-9]+):(?<min>[0-9]+):(?<sec>[0-9]+)")'
{"hour":"23","min":"59","sec":"59"}
scan(reg), scan(reg; flags)

マッチした文字列を返します。

$ echo '"23:59:59"' | jq -c '[scan("[0-9]+")]'
["23","59","59"]
split(reg), split(reg; flags)

正規表現 reg で分割したものを配列として返します。

$ echo '"23:59:59"' | jq -c 'split(":") | .[]'
["23","59","59"]
splits(reg), splits(reg; flags)

正規表現 reg で分割したものを配列ではなく値の列として返します。

$ echo '"23:59:59"' | jq -c 'split(":") | .[]'
["23","59","59"]
sub(reg; str), sub(reg; str; flags)

文字列を受け取り、正規表現 reg にマッチする箇所を str に置換します。"g" フラグを指定しなければ最初の1回だけ置換します。

$ echo '"Japanese"' | jq 'sub("e"; "E")'
"JapanEse"
gsub(reg; str), gsub(reg; str; flags)

文字列を受け取り、正規表現 reg にマッチする箇所を str に置換します。"g" フラグを指定しなくてもすべて置換します。

$ echo '"Japanese"' | jq 'gsub("e"; "E")'
"JapanEsE"
型変換
tonumber

文字列を数値に変換します。

$ echo '"1.23"' | jq 'tonumber'
1.23
tostring

数値をに文字列変換します。

$ echo '1.23' | jq 'tostring'
"1.23"
特別値
infinite

扱える最大値を返します。

$ jq -n 'infinite'
1.7976931348623157e+308
nan

number 型ではあるけれども、数値ではない値 (Not a Number) を返します。

$ jq -nc '[nan, (nan | type)]'
[null,"number"]
empty

何も返却しません。

$ echo '{"a":123, "b":456}' | jq -c '[.a, empty, .b]'
[123,456]
$ENV, eng

環境変数を参照します。

$ jq -n 'env.PATH'
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
$__loc__

現在のファイル名と行数を返します。

$ echo '{"a":123}' | jq '$__loc__'
{
  "file": "<top-level>",
  "line": 1
}
isinfinite, isnan, isfinite, isnormal

無限数、NaN、有限数、正規数であるか否かを返します。

$ jq -nc 'infinite | isinfinite'
true
isempty(exp)

exp が empty であれば true、さもなくば false を返します。

$ jq -n 'isempty(empty)'
true
行列
combinations, combinations(n)

組み合わせを返します。n を指定すると n 個の要素を持つ組み合わせを生成します。

$ echo '[[1,2],[3,4]]' | jq -c 'combinations'
[1,3]
[1,4]
[2,3]
[2,4]
$ echo '[1,2]' | jq -c 'combinations(3)'
[1,1,1]
[1,1,2]
[1,2,1]
[1,2,2]
[2,1,1]
[2,1,2]
[2,2,1]
[2,2,2]
transpose

行列の転置を行います。(→ 転置行列)

$ echo '[[1,2],[3,4],[5,6]]' | jq -c 'transpose'
[[1,3,5],[2,4,6]]
inside(s)

入力した文字や要素が s の中に出現すれば true、さもなくば false を返します。

$ echo '"DEF"' | jq 'inside("ABCDEF")'
true
$ echo '["A"]' | jq 'inside(["A","B","C"])'
true
繰り返し処理
range(upto), range(from;upto), range(from;upto;by)

from から upto まで by 毎に加算した数値の列を返します。from を省略すると 0、by を省略すると 1 とみなされます。

$ echo 'null' | jq -c '[range(5)]'
[0,1,2,3,4]
$ echo 'null' | jq -c '[range(2;7)]'
[2,3,4,5,6]
$ echo 'null' | jq -c '[range(0;10;2)]'
[0,2,4,6,8]
while(cond; update)

条件式 cond が成り立つ間、update を繰り返して生成される値の配列を返します。

$ echo '1' | jq -c '[while(.<100; .*2)]'
[1,2,4,8,16,32,64]
until(cond; next)

cond が成り立つまで next を繰り返して最終的な値を返します。

$ echo '1' | jq 'until(.>100; .*2)'
128
recurse、recurse(f)、recurse(f; condition)、recurse_down

再帰構造のデータから特定のキーを取り出す際などに利用されます。例えば、下記のようなディレクトリツリーを表す再帰的な構造から name の一覧を取り出すには .name, .dirs[].name, .dirs[].dirs[].name, .dirs[].dirs[].dirs[].name などを取り出す必要がありますが、recurse(.dirs[]) | .name で何階層でもまとめて取り出すことができます。condition は再帰探索を継続する条件を指定します。recurse は recurse(.[]?) と同義です。recurse(f) は recurse(f; .!=null) と同義です。recurse_down は recurse と同義ですが過去互換性のために残されており非推奨です。

$ echo '
{"name": "/", "dirs": [
  {"name": "/bin", "dirs": [
    {"name": "/bin/ls", "dirs": []},
    {"name": "/bin/sh", "dirs": []}
  ]},
  {"name": "/usr", "dirs": [
    {"name": "/usr/sbin", "dirs": [
      {"name": "/usr/sbin/useradd", "dirs": []},
      {"name": "/usr/sbin/usermod", "dirs": []}
    ]}
  ]}
]}
' | jq 'recurse(.dirs[]) | .name'
"/"
"/bin"
"/bin/ls"
"/bin/sh"
"/usr"
"/usr/sbin"
"/usr/sbin/useradd"
"/usr/sbin/usermod"
walk(f)

子要素、孫要素などに対して再帰的に f を適用していきます。

$ echo '[[8,5,2], [4,1,7], [3,6,9]]' | jq -c 'walk(if type=="array" then sort else . end)'
[[1,4,7],[2,5,8],[3,6,9]]
foreach exp as $val (init; update; extract)

初期値を init とします。列 exp のひとつひとつを $val に代入し、update で初期値を変更しながら、extract を実行した結果の列を返却します。

$ echo '[10,20,30,40,50]' | jq -c '[foreach .[] as $n (300; . + $n; .)]'
[310,330,360,400,450]
削除
del(path_expression)

オブジェクトを受け取り指定したキーを削除します。また、配列を受け取り指定したインデックスの要素を削除します。

$ echo '{"foo":"FOO", "baa":"BAA", "baz":"BAZ"}' | jq -c 'del(.foo, .baz)'
{"baa":"BAA"}
$ echo '["foo", "baa", "baz"]' | jq -c 'del(.[0, 2])'
["baa"]
JSON
tojson

データを JSON 文字列に変換します。

$ echo '{"name":"Tanaka"}' | jq 'tojson'
"{\"name\":\"Tanaka\"}"
fromjson

JSON 文字列をデータに変換します。

echo '"{\"name\":\"Tanaka\"}"' | jq -c 'fromjson'
{"name": "Tanaka"}
日時関数
fromdate, fromdateiso8601

ISO 8601 形式の日時文字列を読み込み、1970年1月1日0時0分0秒UTC からの秒数に変換します。fromdate は今後は ISO 8601 以外にも対応するかもしれませんが、現時点では ISO 8601 形式のみに対応します。

$ echo '"2023-12-31T23:59:59Z"' | jq 'fromdate'
1704067199
$ echo '"2023-12-31T23:59:59Z"' | jq 'fromdateiso8601'
1704067199
todate, todateiso8601

1970年1月1日0時0分0秒UTC からの秒数を読み込み、ISO 8601 形式の時刻文字列に変換します。

$ echo '1704067199' | jq 'todate'
"2023-12-31T23:59:59Z"
$ echo '1704067199' | jq 'todateiso8601'
"2023-12-31T23:59:59Z"
now

現在の時刻を 1970年1月1日0時0分0秒UTC からの秒数で返します。

$ jq -n 'now'
1704067199.123456
gmtime, localtime, mktime

gmtime は 1970年1月1日0時0分0秒UTC からの秒数 を [年,月,日,時,分,秒,曜日,1年間の中の日数] の配列(UTC)に変換します。月は 0~11 で表すことに注意してください。localtime はローカルタイムに変換します。mktime は配列(UTC)を秒数に変換します。

$ echo '1704067199' | jq -c 'gmtime'
[2023,11,31,23,59,59,0,364]
$ echo '1704067199' | jq -c 'localtime'
[2024,0,1,8,59,59,1,0]
$ echo '[2023,11,31,23,59,59,0,364]' | jq -c 'mktime'
1704067199
strptime, strftime, strflocaltime

strptime は文字列をフォーマット指定で配列に変換します。strftime は配列をフォーマット指定で文字列に変換します。strflocaltime はローカルタイムとして変換します。

$ echo '"2023-12-31 23:59:59"' | jq -c 'strptime("%Y-%m-%d %H:%M:%S")'
[2023,11,31,23,59,59,0,364]
$ echo '[2023,11,31,23,59,59,0,364]' | jq -c 'strftime("%Y/%m/%d %H:%M:%S")'
"2023/12/31 23:59:59"
$ echo '[2023,11,31,23,59,59,0,364]' | jq -c 'strflocaltime("%Y-%m-%d %H:%M:%S")'
"2023-12-31 23:59:59"
入出力
stderr, debug

stderr は入力を標準エラー出力に出力します。debug は入力を ["DEBUG": 入力値] の形式で標準エラー出力に出力します。

$ echo '"ABC"' | jq 'debug' > /dev/null
["DEBUG:","ABC"]
input_filename

入力ファイル名を返します。

$ jq 'input_filename' sample.json
"sample.json"
input_line_number

入力中の行数を返します。

$ echo '{"foo":"FOO"}
{"baa":"BAA"}
{"baz":"BAZ"}
' | jq -c '[input_line_number, .]'
[1,{"foo":"FOO"}]
[2,{"baa":"BAA"}]
[3,{"baz":"BAZ"}]
ストリーム
tostream

--stream オプションと同様、入力値をストリーム形式に変換します。ストリーム形式は値のひとつひとつについて、[[path], value] の形式で与えられます。[path] はキーまたは配列インデックスの配列です。[[path]] はそのパスの処理が完了したことを示します。

$ echo '{"a":{"b":123,"c":["X","Y"]}}' | jq -c 'tostream'
[["a","b"],123]
[["a","c",0],"X"]
[["a","c",1],"Y"]
[["a","c",1]]
[["a","c"]]
[["a"]]
fromstream(stream_expression)

ストリーム形式に変換したJSON列を引数として受け取り、変換前の形式に逆変換します。

$ echo '{"a":{"b":123,"c":["X","Y"]}}' | jq -c '[tostream] | fromstream(.[])'
{"a":{"b":123,"c":["X","Y"]}}
truncate_stream(stream_expression)

数値を入力とし、stream_expression で与えられたストリーミング式の出力の左側から対応する数のパス要素を切り捨てます。(詳細不明...)

$ echo '["A",["B"]]' | jq -c '[tostream]'
[[[0],"A"],[[1,0],"B"],[[1,0]],[[1]]]
$ jq -nc '[1|truncate_stream([[0],"A"],[[1,0],"B"],[[1,0]],[[1]])]'
[[[0],"B"],[[0]]]
$ echo '[[[0],"B"],[[0]]]' | jq -c 'fromstream(.[])'
["B"]
その他
builtins

ビルトインの一覧を返します。

$ jq -n 'builtins'
[
  "input_line_number/0",
  "input_filename/0",
  "now/0",
  "localtime/0",
  "gmtime/0",
  "mktime/0",
     :

その他

関数(def)

def は関数を定義します。下記の例では半径を受け取って円の面積を求める関数 area_of_circle を定義し、それを呼び出しています。

$ echo '[10,20,30]' | jq -c '
def area_of_circle: . * . * 3.14;
map(area_of_circle)'
[314,1256,2826]

引数をもつ関数は下記の様に定義します。

$ echo '[10,20,30]' | jq -c '
def area_of_circle(x): x * x * 3.14;
map(area_of_circle(.))'
[314,1256,2826]
モジュール
include

モジュールファイルを読み込みます。

$ cat mymodule.jq
def times(n): . * n;
$ echo '[10,20,30]' | jq -c 'include "mymodule"; map(times(3))'
[30,60,90]
変数
変数定義(as)

as を用いて変数を定義することができます。下記の例では users オブジェクトを $users という名前の変数に覚えておき、.emails[] 処理の中でそれを参照しています。

$ echo '
{
    "users": {
        "U001": "Yamada",
        "U002": "Tanaka",
        "U003": "Suzuki"
    },
    "emails": [
        {"user_id": "U001", "email": "yamada@example.com"},
        {"user_id": "U002", "email": "tanaka@example.com"},
        {"user_id": "U003", "email": "suzuki@example.com"}
    ]
}
' | jq -c '.users as $users | .emails[] | {user: $users[.user_id], email}'
{"user":"Yamada","email":"yamada@example.com"}
{"user":"Tanaka","email":"tanaka@example.com"}
{"user":"Suzuki","email":"suzuki@example.com"}
分割代替演算子(?//)

変数代入する際に値の型がひとつに決まらない場合、分割代替演算子を用いることができます。下記の例では、baa の値はオブジェクトだったりオブジェクト配列だったりしますが、分割代替演算子 ?// を用いて、オブジェクトの場合の変数代入と、オブジェクト配列だった場合の変数代入を記述することができます。

$ echo '
[
    {"foo": {"baa": 123}},
    {"foo": [{"baa": 456}]}
]' | jq -c '.[] as {foo: {$baa}} ?// {foo: [{$baa}]} | {$baa}'
{"baa":123}
{"baa":456}
エスケープ・コンバート処理
@text, @json, @html, @uri, @csv, @tsv, @sh, @base64, @base64d

@foo は変換処理やエスケープ処理を行います。

$ echo '123' | jq '@text'
"123"
$ echo '{"foo":"FOO"}' | jq '@json'
"{\"foo\":\"FOO\"}"
$ echo '"x > y"' | jq '@html'
"x &gt; y"
$ echo '"foo?"' | jq '@uri'
"foo%3F"
$ echo '[123,"ABC"]' | jq '@csv'
"123,\"ABC\""
$ echo '[123,"ABC"]' | jq '@tsv'
"123\tABC"
$ echo '"x > y"' | jq '@sh'
"'x > y'"
$ echo '"This is Japan."' | jq '@base64'
"VGhpcyBpcyBKYXBhbi4="
$ echo '"VGhpcyBpcyBKYXBhbi4="' | jq '@base64d'
"This is Japan."
制御構文
if-then-else

最初の形式は、cond1 が真の時 exp1 を実行します。2番目の形式は、cond1 が真の時は exp1 を、さもなくば exp2 を実行します。3番目の形式は、cond1 が真であれば exp1 を、cond2 が真であれば exp2 を、さもなくば exp3 を実行します。

if cond1 then exp1 end
if cond1 then exp1 else exp2 end
if cond1 then exp1 elif cond2 then exp2 else exp3 end

使用例を下記に示します。

$ echo '[72,85,92]' | jq '.[] | if . > 80 then "Good!" else "Bad!" end'
"Bad!"
"Good!"
"Good!"
try-catch

exp1 実行中にエラーが発生すると処理を中断して exp2 を実行します。

try exp1 catch exp2

使用例を下記に示します。

$ echo '[1,2,3]' | jq 'try .foo catch "ERROR"'
"ERROR"
エラー無視
?

exp? は try exp の省略形です。エラーが発生してもエラーを無視します。

$ echo '123' | jq '.[]'
jq: error (at <stdin>:1): Cannot iterate over number (123)
$ echo '123' | jq '.[]?'
$
文字列
文字列の内挿(\(filter))

\(filter) を記述することで抽出した値を文字列の中に埋め込むことができます。

$ echo '{"name":"Tanaka"}' | jq '"My name is \(.name)."'
"My name is Tanaka."
色のカスタマイズ(JQ_COLORS)

環境変数 JQ_COLORS で色をカスタマイズすることができます。最初の x;y は null の色、次の x;y は false の色、その後、true の色、数字の色、文字列の色、[] の色、{} の色が続きます。x には 1(明るい)、2(暗い)、4(アンダースコア)、5(点滅)、7(反転)、8(非表示) のいずれかを指定します。y には 30(黒)、31(赤)、32(緑)、33(黄色)、34(青)、35(マゼンタ)、36(シアン)、37(白) のいずれかを指定します。

$ export JQ_COLORS="1;30:0;37:0;37:0;37:0;32:1;33:1;33"

Copyright (C) 2023 杜甫々
初版:2023年1月8日 最終更新:2023年1月8日
http://www.tohoho-web.com/ex/jq.html