このドキュメントはStephen Dolan氏が権利を有するコマンドラインプロセッサーjqのマニュアルおよびチュートリアルを、CC-BY-3.0の条件に基づき日本語へ翻訳したものです。
Stephen Dolan氏は日本語版の公開や翻訳について関与するものではありません。
翻訳により混入した誤りや誤字の責任はYuji Okazawaに帰属します。
リリース済みバージョンについては次のリンクを参照してください jq 1.6 jq 1.5 jq 1.4 jq 1.3
jqは「フィルター」プログラムです。入力を受け取り出力を生成します。 受け取ったオブジェクトから任意のフィールドを抽出する多数のフィルターを内蔵しているため、数値から文字列への変換など、さまざまな標準的なタスクを実行できます。
フィルターはさまざまな方法で組み合わせることができます。 フィルターの出力を他のフィルターの入力へパイプで連結することもできますし、フィルターの出力を配列へ集めることもできます。
中には複数の結果を生成するフィルターがあります。 例えば、入力に与えた配列のそれぞれの要素を出力するようなフィルターもあるのです。 そのようなフィルターと別のフィルターをパイプで連結すると、配列のそれぞれの要素を次のフィルターへ入力するようになります。 jqは一般的なプログラミング言語が繰り返しや反復で実現している処理を、フィルターを連結するだけで実現できるのです。
どんなフィルターにも入力と出力があるのは重要なので覚えておきましょう。
文字列リテラル"hello"や数値リテラル42は、どんな入力を受け取っても常に同じリテラルを出力するフィルターなのです。
2つのフィルターを組み合わせる演算子は、加算(addition)演算子のように、基本的に同じ入力をそれぞれのフィルターに渡して、それらの結果を統合します。
平均値フィルターはadd / length
のように実装できます。
この場合、入力された配列をadd
とlength
それぞれのフィルターに渡してから、最後に除算することになります。
説明が先走りすぎたので :) もう少し簡単な例を紹介していきます。
jqフィルターはJSONデータのストリームを処理します。 jqは空白文字列を区切り文字とする JSON 値の並びとして入力を評価します。 そして、それぞれのJSON値を指定したフィルターへ渡します。 フィルターの出力は、入力と同じ空白文字列を区切り文字とするJSON値として標準出力へ書き込みます。
注意:シェルのクォート規則には注意が必要です。
基本的にjqプログラムへ指定する値は常にシングルクォート(U+0027)で囲むのがベストです。
jqが特別扱いするさまざまな文字の中にはシェルのメタ文字も含まれるからです。
具体的にはjq "foo"
のように実行すると、ほとんどの Unix シェルではjq foo
を実行することになり、foo is not defined
というエラーになるでしょう。
Windowsのコマンドシェル(cmd.exe)で、-f 実行ファイル名
のように実行するのではなく、コマンドラインからjqを実行するときは、ダブルクォート(U+0022)でベストです。
ただし、jqプログラムへ指定する値にダブルクォートを含める場合、バックスラッシュ(U+005c)でエスケープしなければなりません。
jqがどのように入力を読み取り、出力へ書き込むかはコマンドラインオプションで指定できます。
--version
:jqのバージョンを出力し、終了ステータス0で終了します。
--seq
:jqへの入力と出力をMIMEタイプスキームapplication/json-seq
により分割します。
出力するときはオブジェクトのそれぞれのフィールドを出力する前にレコードセパレータ文字(ASCII RS)を挿入し、それぞれのオブジェクトの後に改行文字(ASCII LF)を挿入します。
入力されたJSON文字列について、解析に失敗したら警告を出力し、次のレコードセパレータ文字まで読み飛ばします。
このオプションを指定した場合、--seq
オプションを指定しなかったjqの出力も解析します。
--stream
:入力をストリームとして解釈し、パスとリーフ値(スカラー値や空配列、空オブジェクト)の配列を出力します。
例えば"a"
の出力は[[],"a"]
になります。
また[[],"a",["b"]]
の出力は[[0,[]],[[1],"a"],[[2,0],"b"],[[2,0]],[[2]]
になります。
巨大な入力を処理したいときは便利です。
フィルターにreduce
およびforeach
構文を組み合わせれば、大量の入力を逐次的に集約できます。
--slurp
/-s
:入力されたそれぞれのJSONオブジェクトへフィルターを適用する代わりに、全ての入力ストリームを大きな配列にして1度だけフィルターを適用します。
--raw-input
/-R
:入力をJSONとして解析しません。
代わりにそれぞれの入力行を文字列としてフィルターへ渡します。
--slurp
オプションと組み合わせると、全ての入力を単一の長い文字列としてフィルターへ渡すことができます。
--null-input
/-n
:入力を読み取りません!
代わりにnull
を入力としてフィルターを実行します。
簡単な計算機として使用する、あるいは、0からJSONデータを組み立てるためにjqを使うときは便利です。
--compact-output
/ -c
:jqのデフォルト出力はJSONを整形します。 このオプションを指定すると、それぞれのJSONオブジェクトを1行ずつ出力する代わりに、よりコンパクトに出力します。
--tab
:2文字の空白文字(U+0020)ではなくタブ(U+0009)でインデントします。
--indent n
:指定された数(ただし7未満)の空白文字(U+0020)でインデントします。
--color-output
/ -C
and --monochrome-output
/ -M
:疑似端末の標準出力へ出力する場合、jqのデフォルト出力はJSONを色付けします。
-C
オプションを指定した場合、パイプやファイルへ出力する場合でも強制的に色付けします。
-M
オプションを指定した場合は色付けを無効化します。
使用する色種類は環境変数JQ_COLORS
で制御できます(詳しくは後述します)。
--binary
/ -b
:WindowsユーザーがWSLやMSYS2やCygwinからネイティブ実行可能形式のjq.exeを実行するときはこのオプションを指定しなければなりません。 指定しなかった場合jqは改行文字(LF)を復帰文字と改行文字(CRLF)へ変換します。
--ascii-output
/ -a
:jqは非ASCIIのユニコードコードポイントをUTF-8として出力します。 "\u03bc"のようにエスケープシーケンスを入力した場合でも同様です。 このオプションを指定した場合、jqはASCII文字だけを出力するようになります。非ASCII文字は等価なエスケープシーケンスへ変換します。
--unbuffered
:JSONオブジェクトを出力するたびに出力バッファをフラッシュします。 (遅いデータソースの出力とjqをパイプで連結し、jqの出力を別の何かの入力へパイプで連結している場合は便利です)
--sort-keys
/ -S
:それぞれのオブジェクトのフィールドを文字列昇順にして出力します。
--raw-output
/ -r
:このオプションを指定した場合、結果をクォートされたJSON文字列として書式化せず文字列として標準出力へ書き込みます。 jqがJSONベースではないシステムと連携するときは便利です。
--join-output
/ -j
:-r
と同様ですが、それぞれの出力の後に改行文字を挿入しません。
--nul-output
/ -0
:-r
と同様ですが、それぞれの出力の後にNUL
を挿入します。
値として改行文字を含むような場合に便利です。
-f filename
/ --from-file filename
:コマンドラインではなくファイルからフィルターを読み込みます。
awkコマンドの-fオプションと同様です。
#
で始まる行はコメントとして無視します。
-Ldirectory
/ -L directory
:モジュールを探索するディレクトリをdirectory
に指定します。
このオプションを指定した場合、組み込みの検索リストは使いません。
後述のモジュールに関するセクションを参照してください。
-e
/ --exit-status
:このオプションを指定すると、最後に出力した値がfalse
やnull
でなければ、終了ステータスは0になります。
false
やnull
なら、終了ステータスは1になります。
正常に出力出来なかった場合、終了ステータスは4になります。
通常なら、オプション指定や入力に問題がある場合やシステムエラーの場合、終了ステータスは2になります。
コンパイルエラーの場合、終了ステータスは3になります。
正常終了した場合、終了ステータスは0になります。
組み込み関数のhalt_error
でも終了ステータスを設定できます。
--arg name value
:指定した値の変数をjqに渡します。
jqを実行するとき--arg foo bar
を渡すと、プログラムから$foo
という変数で"bar"
という値を参照できます。
value
は文字列になるので注意してください。つまり、--arg foo 123
を渡した場合$foo
の値は"123"
になります。
名前付き引数は$ARGS.named
のように参照することもできます。
--argjson name JSON-text
:JSONにエンコードした値の変数をjqに渡します。
jqを実行するとき--argjson foo 123
を渡すと、プログラムから$foo
という変数で123
という値を参照できます。
--slurpfile variable-name filename
:指定したファイルに含まれる全てのJSON文字列をJSON値の配列として解釈した結果を、指定した名前のグローバル変数で参照できるようにします。
jqを実行するとき--slurpfile foo bar
を渡すと、プログラムからは$foo
という変数で配列(bar
というファイルに含まれる文字列)を参照できます。
--rawfile variable-name filename
:指定したファイルに含まれる全ての文字列を、指定した名前のグローバル変数で参照できるようにします。
jqを実行するとき--rawfile foo bar
を渡すと、プログラムからは$foo
という変数で文字列(bar
というファイルに含まれる文字列)を参照できます。
--argfile variable-name filename
:このオプションは使わないでください。代わりに--slurpfile
を使いましょう。
(--slurpfile
と同じようなオプションですが、ファイルに含まれる文字列が1行だけの場合はこちらのオプションを使うようにしてください。複数行の文字列は--slurpfile
により文字列の配列として参照できます)
--args
:指定した値を文字列配列にします。
jqプログラムからは$ARGS.positional[]
で参照できます。
--jsonargs
:指定した値をJSON値の配列にします。
jqプログラムからは$ARGS.positional[]
で参照できます。
--run-tests [filename]
:指定したファイルあるいは標準入力から受け取ったテストを実行します。
このオプションは最後に指定しなければなりません。また、その前に指定していたオプションによる制御は無視されます。
入力はコメント行、空行、それから1行のプログラム行に対する複数行の出力(期待値)です。
空行が終端を表します。
コンパイルの失敗を確認するテストは"%%FAIL"
で開始して、失敗するプログラムを記述します。期待値には実際のエラーメッセージと比較するメッセージを記述します。
このオプションは後方互換性を損なう変更をする場合があるため注意してください。
.
.
は最も単純なフィルターです。
入力を変更せずそのまま出力するという性質から、アイデンティティ(同一性)演算子と呼ばれています。
jqのデフォルト出力は全ての出力を整形します。
このフィルターはcurl
などが出力するJSON文字列を整形するのに役立つ場合があります。
jq '.' | |
Input | "Hello, world!" |
Output | "Hello, world!" |
.foo
, .foo.bar
.foo
は最も単純で便利なフィルターです。
辞書や連想配列のようなJSONオブジェクトを入力すると、キーである"foo"
に対応する値を生成します。キーが存在しない場合はnullを生成します。
.foo.bar
という形式のフィルターは.foo|.bar
と等価です。
この記法はキーのように単純な識別子にだけ利用できます。 使用できるのは数字以外で始まる英数字とアンダースコア(U+005f)だけで構成された識別子です。
キーに特殊文字が含まれている場合や数字で開始する場合、ダブルクォート(U+0022)で囲まなければなりません。
例:."foo$"
や.["foo$"]
.["foo::bar"]
や.["foo.bar"]
は使用できますが.foo::bar
は使用できません。
.foo.bar
は.["foo"].["bar"]
という意味になります。
jq '.foo' | |
Input | {"foo": 42, "bar": "less interesting data"} |
Output | 42 |
jq '.foo' | |
Input | {"notfoo": true, "alsonotfoo": false} |
Output | null |
jq '.["foo"]' | |
Input | {"foo": 42} |
Output | 42 |
.foo?
.foo
と同様ですが、.
が配列やオブジェクトでなくてもエラーを出力しません。
jq '.foo?' | |
Input | {"foo": 42, "bar": "less interesting data"} |
Output | 42 |
jq '.foo?' | |
Input | {"notfoo": true, "alsonotfoo": false} |
Output | null |
jq '.["foo"]?' | |
Input | {"foo": 42} |
Output | 42 |
jq '[.foo?]' | |
Input | [1,2] |
Output | [] |
.[<string>]
オブジェクトのフィールドは.["foo"]
のような記法でも参照できます。
(前述の.foo
という記法は、識別子として利用可能な文字列にだけ使用できるこの記法の省略版です。)
.[2]
インデックスの値が整数の場合、.[<value>]
は配列を添え字で参照できます。
配列の添え字は0から始まるので、.[2]
は3番目の要素を参照することになります。
負の添え字も使用できます。-1は末尾の要素を、-2は末尾から1つ前の要素を参照します。
jq '.[0]' | |
Input | [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] |
Output | {"name":"JSON", "good":true} |
jq '.[2]' | |
Input | [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] |
Output | null |
jq '.[-2]' | |
Input | [1,2,3] |
Output | 2 |
.[10:15]
スライス記法を使用すると部分配列や部分文字列を取得できます。
.[10:15]
は元の配列の添え字10(以上)から15(未満)までの要素からなる長さ5の配列を返します。
負の添え字を指定した場合、配列の末尾から逆順に数えます。
添え字を指定しなかった場合、先頭あるいは末尾になります。
jq '.[2:4]' | |
Input | ["a","b","c","d","e"] |
Output | ["c", "d"] |
jq '.[2:4]' | |
Input | "abcdefghi" |
Output | "cd" |
jq '.[:3]' | |
Input | ["a","b","c","d","e"] |
Output | ["a", "b", "c"] |
jq '.[-2:]' | |
Input | ["a","b","c","d","e"] |
Output | ["d", "e"] |
.[]
配列インデックス記法.[index]
で添え字を指定しなかった場合、配列の要素を全て返します。
.[]
に[1,2,3]
を入力すると、単一の配列ではなく別々の3つの数字を生成します。
この記法をオブジェクトにも指定すると、オブジェクトの全ての値を返します。
jq '.[]' | |
Input | [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] |
Output | {"name":"JSON", "good":true} |
{"name":"XML", "good":false} |
jq '.[]' | |
Input | [] |
Output | none |
jq '.[]' | |
Input | {"a": 1, "b": 1} |
Output | 1 |
1 |
.[]?
.[]
と同様ですが、.
が配列やオブジェクトでなくてもエラーを出力しません。
,
2つのフィルターをカンマ(U+002c)で区切ると、プログラムの入力をそれぞれのフィルターに入力し、それぞれの出力を並び順通りに連結した値ストリームを出力します。
つまり、カンマの左側の式による結果を全て出力してから、右側の式による結果を出力します。
例えば、.foo,.bar
と記述すると"foo"
フィールドと"bar"
フィールドの値を順番に出力します。
jq '.foo, .bar' | |
Input | {"foo": 42, "bar": "something else", "baz": true} |
Output | 42 |
"something else" |
jq '.user, .projects[]' | |
Input | {"user":"stedolan", "projects": ["jq", "wikiflow"]} |
Output | "stedolan" |
"jq" | |
"wikiflow" |
jq '.[4,2]' | |
Input | ["a","b","c","d","e"] |
Output | "e" |
"c" |
|
パイプ演算子(|
)は2つのフィルターを連結します。
つまり、左側のフィルターの出力を右側のフィルターの入力に連結します。
Unixシェルのパイプとほとんど同じように使うことができます。
左側のフィルターが複数の結果を生成する場合、それぞれの結果に対して右側のフィルターを実行します。
従って.[] | .foo
と記述すると、入力した配列のそれぞれの要素について"foo"
フィールドの値を取得します。
.a.b.c
と記述するのは.a | .b | .c
と記述するのと同様です。
「パイプライン」のいずれかのステージに登場する.
は入力値そのものを指します。
従って.a | . | .b
と記述するのは.a.b
と記述するのと同様です。
中央の.
は.a
の生成した結果を表しているからです。
jq '.[] | .name' | |
Input | [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] |
Output | "JSON" |
"XML" |
開き括弧(U+0028)と閉じ括弧(U+0029)は他のプログラミング言語と同様にグループ化する演算子です。
jq '(. + 2) * 5' | |
Input | 1 |
Output | 15 |
jqはJSONと同じデータ型に対応しています。 すなわち数値、文字列、真偽値、配列、オブジェクト(JSONでは文字列のキーだけで構成された連想配列のこと)、"null"のことです。
JavaScriptでは真偽値、null、文字列、数値は同じように記述します。
jqでも同様に、単純な値を入力として受け取り、出力として生成します。
42
はjqプログラムとして正しい形式で、入力を無視して42という値を生成します。
[]
JSONと同様に配列を生成するときは[]
と記述します。具体的には[1,2,3]
のように記述します。
パイプラインを含む任意のjq式が配列の要素になります。
全てのjq式の生成した結果を集約した単一の巨大な配列を生成します。
[.foo, .bar, .baz]
のように既知の要素数の配列を生成できます。
また、[.items[].name]
のようにフィルターの結果を要素とする配列を生成することもできます。
カンマ演算子を理解できればjqの配列記法を別の視点で捉えることができます。
[1,2,3]
という記述は組み込み記法であるカンマ区切りの配列ではありません。
結果を集約する配列構築子[]
を1,2,3
という式に適用したことになります。
そして、3種類の異なる結果を生成するのです。
何らかのフィルターX
が4個の結果を生成するなら、[X]
という式は4要素の配列に対する単一の結果を生成します。
jq '[.user, .projects[]]' | |
Input | {"user":"stedolan", "projects": ["jq", "wikiflow"]} |
Output | ["stedolan", "jq", "wikiflow"] |
jq '[ .[] | . * 2]' | |
Input | [1, 2, 3] |
Output | [2, 4, 6] |
{}
JSONと同様にオブジェクト(辞書あるいは連想配列)を生成するときは{}
と記述します。具体的には{"a": 42, "b": 17}
のように記述します。
キーが「識別子として利用可能な文字列」ならクォートは省略できます。つまり{a:42, b:17}
のように記述できます。
キーの式表現で変数を参照すると、変数の値をキーにすることができます。
キーの式表現でリテラルや識別子や変数参照以外を使用する場合、括弧で囲まなければ鳴りません。具体的には{("a"+"b"):59}
のように記述します。
値には任意の式を記述できます。(ただしコロン(U+003a)を含むなど括弧で囲まなければならない場合もあります)。
それぞれの式は{}
式への入力に対して適用します。(全てのフィルターに入力と出力があることを思い出しましょう)。
{foo: .bar}
と記述し、{"bar":42, "baz":43}
を入力した場合、JSONオブジェクト{"foo": 42}
を生成します。
このフィルターを使うとオブジェクトの特定のフィールドを選択できます。
入力したオブジェクトに次のようなフィールド("user"、"title"、"id"、"content)があるとき、{user: .user, title: .title}
と記述すれば"user"と"title"を抽出できます。
ありふれた使い方のため、{user, title}
のように省略する記法が用意されています。
いずれかの式が複数の結果を生成する場合、複数の辞書を生成します。 次のようなオブジェクトを入力し
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
次のような式を評価すると
{user, title: .titles[]}
次のように2つの結果を生成します。
{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}
キーを括弧で囲むと式として評価することになります。 前の例と同じ入力に対して次のような式を評価すると
{(.user): .titles}
次のような結果を生成します。
{"stedolan": ["JQ Primer", "More JQ"]}
キーで変数を参照すると変数の値をキーとして使用します。 フィールドに値を指定しなければ変数の値を使用します。 次の式は
"f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo}
次のような結果を生成します。
{"f o o":"f o o","b a r":"f o o"}
jq '{user, title: .titles[]}' | |
Input | {"user":"stedolan","titles":["JQ Primer", "More JQ"]} |
Output | {"user":"stedolan", "title": "JQ Primer"} |
{"user":"stedolan", "title": "More JQ"} |
jq '{(.user): .titles}' | |
Input | {"user":"stedolan","titles":["JQ Primer", "More JQ"]} |
Output | {"stedolan": ["JQ Primer", "More JQ"]} |
..
再帰下降型のアイデンティティ演算子.
は全ての値を生成します。
組み込み関数reduce
(後で説明します)を引数無しで呼び出す場合と同様です。
XPathの//
演算子とよく似ています。
ただし..a
という記述は動作しません。代わりに..|.a
と記述してください。
また、..|.a?
と記述すれば.
の前に発見したすべてのオブジェクトについてキーa
の値を取得します。
path(EXP)
関数(後で説明します)と?
演算子を組み合わせて使用するときは特に役立ちます。
jq '..|.a?' | |
Input | [[{"a":1}]] |
Output | 1 |
jqの演算子の中には受け取った型に応じて異なる振る舞いをするものがあります(例えば+
)。
ですが、jqは暗黙的な型変換をしません。
文字列をオブジェクトに加算しようとすればエラーになるだけで結果を生成することはありません。
+
加算演算子+
は2つのフィルターを引数に取り、それぞれに同じ入力を提供してその結果を加算します。
データ型によって「加算」の意味は異なります。
数値 の場合、通常の算術演算をします。
配列 の場合、連結してより大きな配列を生成します。
文字列 の場合、連結してより大きな文字列を生成します。
オブジェクト の場合加算とはマージのことです。
両方のオブジェクトの全てのキーと値を持つ1つのオブジェクトを生成します。
同じキーを持つ場合、+
演算子の右辺に指定したオブジェクトの値で上書きします。(再帰的にマージするときは*
演算子を使います)
null
はあらゆる値に加算できます。そして元の値を変更しません。
jq '.a + 1' | |
Input | {"a": 7} |
Output | 8 |
jq '.a + .b' | |
Input | {"a": [1,2], "b": [3,4]} |
Output | [1,2,3,4] |
jq '.a + null' | |
Input | {"a": 1} |
Output | 1 |
jq '.a + 1' | |
Input | {} |
Output | 1 |
jq '{a: 1} + {b: 2} + {c: 3} + {a: 42}' | |
Input | null |
Output | {"a": 42, "b": 2, "c": 3} |
-
通常の数値に対する算術演算と同じように、左辺の配列から右辺の配列に一致する要素を全て取り除くことができます。
jq '4 - .a' | |
Input | {"a":3} |
Output | 1 |
jq '. - ["xml", "yaml"]' | |
Input | ["xml", "yaml", "json"] |
Output | ["json"] |
*
, /
, and %
これらの中置演算子は両側に数値を指定した場合は意図した通りに機能します。
ゼロ除算はエラーになります。また、x % y
はxのyによる剰余を算出します。
文字列と数値の乗算は、数値と同じ数だけ連結した文字列を生成します。
ただし"x" * 0
はnullを生成します。
文字列を別の文字列で除算すると、前者の文字列を後者の文字列で分割します。
オブジェクト同士を乗算すると再帰的にマージします。 それぞれのオブジェクトに同じキーがある場合はオブジェクト同士の加算と同様に処理します。 値がオブジェクトだった場合も同じ戦略でマージします。
jq '10 / . * 3' | |
Input | 5 |
Output | 6 |
jq '. / ", "' | |
Input | "a, b,c,d, e" |
Output | ["a","b,c,d","e"] |
jq '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' | |
Input | null |
Output | {"k": {"a": 0, "b": 2, "c": 3}} |
jq '.[] | (1 / .)?' | |
Input | [1,0,-1] |
Output | 1 |
-1 |
length
組み込み関数length
は様々なデータ型に応じた長さを出力します。
文字列の長さはユニコードコードポイント数です。 (ASCII文字だけで構成したJSONをバイト列にエンコードしたときのバイト長と同じです)
配列の長さは要素数です。
オブジェクトの長さはキー・値ペア数です。
nullの長さは0です。
jq '.[] | length' | |
Input | [[1,2], "string", {"a":2}, null] |
Output | 2 |
6 | |
1 | |
0 |
utf8bytelength
組み込み関数utf8bytelength
はUTF-8にエンコードした文字列のバイト長を出力します。
jq 'utf8bytelength' | |
Input | "\u03bc" |
Output | 2 |
keys
, keys_unsorted
組み込み関数keys
は指定したオブジェクトのキーを配列で出力します。
キーはユニコードコードポイントの順番に基づいて「アルファベット順」に並び替えます。 あらゆる言語に対する適切な順序になるとは限りません。 しかし、ロケール設定に関わらず同じキー集合を持つオブジェクトなら同じ結果を出力します。
配列を指定すると有効な添え字の配列を返します。 添え字の範囲は0から長さ-1までです。
keys_unsorted
関数はkeys
と同様ですが、オブジェクトを入力した場合キーを並び替えません。
おそらく登場した順序になるでしょう。
jq 'keys' | |
Input | {"abc": 1, "abcd": 2, "Foo": 3} |
Output | ["Foo", "abc", "abcd"] |
jq 'keys' | |
Input | [42,3,35] |
Output | [0,1,2] |
has(key)
組み込み関数has
は入力したオブジェクトに指定したキーがあるかどうか、または、入力した配列に指定した添え字の要素が存在するかどうかの真偽値を出力します。
$key
が配列の場合、has($key)
は$key
がkeys
関数の出力した配列の部分配列であるかどうかを確かめるのと同じ結果にあります。
ただし、has
関数のほうが高速です。
jq 'map(has("foo"))' | |
Input | [{"foo": 42}, {}] |
Output | [true, false] |
jq 'map(has(2))' | |
Input | [[0,1], ["a","b","c"]] |
Output | [false, true] |
in
組み込み関数in
は入力したキー(配列)が引数のオブジェクトに存在するかどうか、または、入力した添え字(配列)が引数の配列に存在するかどうかの真偽値を出力します。
基本的にはhas
と逆の処理をする関数です。
jq '.[] | in({"foo": 42})' | |
Input | ["foo", "bar"] |
Output | true |
false |
jq 'map(in([0,1]))' | |
Input | [2, 0] |
Output | [false, true] |
map(x)
, map_values(x)
map(x)
は入力した配列それぞれの要素に任意のフィルターx
を適用し、それぞれのフィルターの生成した結果を要素とする新しい配列を生成します。
例えば、map(.+1)
は数値の配列それぞれの要素をインクリメントします。
同様に、map_values(x)
は入力がオブジェクトならそれぞれのフィールドの値にフィルターを適用し、元の値と置き換えたオブジェクトを生成します。
map(x)
という記述は[.[] | x]
と等価です。実際にそのように定義されています。
また、map_values(x)
も同様に.[] |= x
と等価です。
jq 'map(.+1)' | |
Input | [1,2,3] |
Output | [2,3,4] |
jq 'map_values(.+1)' | |
Input | {"a": 1, "b": 2, "c": 3} |
Output | {"a": 2, "b": 3, "c": 4} |
path(path_expression)
入力.
に適用したパス式の配列表現を生成します。
出力は文字列配列(オブジェクトのキー)あるいは数値配列(配列の添え字)です。
jqにおけるパス式とは.a
や.[]
という記法のことです。
パス式には単一の要素と正確にマッチする式と、複数要素にマッチする式があります。
例えば.a.b.c
は単一の要素と正確にマッチする式で、.a[].b
は複数要素にマッチする式です。
path(exact_path_expression)
は入力.
に対応する要素が存在しなくても指定したパス式の配列表現を生成します。
入力.
はnull
や配列やオブジェクトです。
path(pattern)
は入力.
にマッチしたpattern
の配列表現を生成します。
パス式は通常の式と区別されないので注意してください。
例えばpath(..|select(type=="boolean"))
と記述した場合、入力.
に存在する全ての真偽値型の値に対するパスだけを出力します。
jq 'path(.a[0].b)' | |
Input | null |
Output | ["a",0,"b"] |
jq '[path(..)]' | |
Input | {"a":[{"b":1}]} |
Output | [[],["a"],["a",0],["a",0,"b"]] |
del(path_expression)
組み込み関数del
は指定したパス式に対応するキーと値を入力したオブジェクトから削除します。
jq 'del(.foo)' | |
Input | {"foo": 42, "bar": 9001, "baz": 42} |
Output | {"bar": 9001, "baz": 42} |
jq 'del(.[1, 2])' | |
Input | ["foo", "bar", "baz"] |
Output | ["foo"] |
getpath(PATHS)
組み込み関数getpath
は入力したオブジェクトについてPATHS
のそれぞれの要素にマッチした値の配列を生成します。
jq 'getpath(["a","b"])' | |
Input | null |
Output | null |
jq '[getpath(["a","b"], ["a","c"])]' | |
Input | {"a":{"b":0, "c":1}} |
Output | [0, 1] |
setpath(PATHS; VALUE)
組み込み関数setpath
は入力したオブジェクトについてPATHS
のそれぞれの要素にマッチした値をVALUE
にしたオブジェクトを生成します。
jq 'setpath(["a","b"]; 1)' | |
Input | null |
Output | {"a": {"b": 1}} |
jq 'setpath(["a","b"]; 1)' | |
Input | {"a":{"b":0}} |
Output | {"a": {"b": 1}} |
jq 'setpath([0,"a"]; 1)' | |
Input | null |
Output | [{"a":1}] |
delpaths(PATHS)
組み込み関数delpaths
は入力したオブジェクトについてPATHS
のそれぞれの要素にマッチしたフィールドを削除したオブジェクトを生成します。
PATHS
はパス式(文字列配列あるいは数値配列)の配列です。
jq 'delpaths([["a","b"]])' | |
Input | {"a":{"b":1},"x":{"y":2}} |
Output | {"a":{},"x":{"y":2}} |
to_entries
, from_entries
, with_entries
これらの組み込み関数はオブジェクトとキーと値からなる配列を相互に変換します。
to_entries
にオブジェクトを入力すると、キーと値k: v
のオブジェクトを要素とする配列[{"key": k, "value": v}]
を生成します。
from_entries
はto_entries
と逆の変換をします。
with_entries(foo)
はto_entries | map(foo) | from_entries
の省略記法です。
オブジェクトの全てのキーと値に何らかの処理をしたい場合に便利です。
from_entries
はキーのキー名として key Key name Name を受け付けます。
また、値のキー名として value Value を受け付けます。
jq 'to_entries' | |
Input | {"a": 1, "b": 2} |
Output | [{"key":"a", "value":1}, {"key":"b", "value":2}] |
jq 'from_entries' | |
Input | [{"key":"a", "value":1}, {"key":"b", "value":2}] |
Output | {"a": 1, "b": 2} |
jq 'with_entries(.key |= "KEY_" + .)' | |
Input | {"a": 1, "b": 2} |
Output | {"KEY_a": 1, "KEY_b": 2} |
select(boolean_expression)
組み込み関数select(foo)
は式foo
が入力に対して真を返したら、入力を変更せずに出力します。それ以外の場合は何も出力しません。
リストからいずれかの要素を抽出するのに便利です。
例えば[1,2,3] | map(select(. >= 2))
と記述すると[2,3]
を出力します。
jq 'map(select(. >= 2))' | |
Input | [1,5,3,0,7] |
Output | [5,3,7] |
jq '.[] | select(.id == "second")' | |
Input | [{"id": "first", "val": 1}, {"id": "second", "val": 2}] |
Output | {"id": "second", "val": 2} |
arrays
, objects
, iterables
, booleans
, numbers
, normals
, finites
, strings
, nulls
, values
, scalars
これらの組み込み関数は、関数名に対応するデータ型のオブジェクトを抽出します。
jq '.[]|numbers' | |
Input | [[],{},1,"foo",null,true,false] |
Output | 1 |
empty
組み込み関数empty
は何も結果を生成しません。null
ですらありません。
時には役に立つ場合があります。必要な時になれば分かるはずです :)
jq '1, empty, 2' | |
Input | null |
Output | 1 |
2 |
jq '[1,2,empty,3]' | |
Input | null |
Output | [1,2,3] |
error(message)
組み込み関数error
はエラーを生成します。
nullやオブジェクト以外の入力に.a
のような式を適用した場合とは違って、指定した文字列が値になります。
エラーは後述するtry/catch
で処理できます。
halt
それ以上何も出力せずにjqプログラムを停止します。
終了ステータスは0
になります。
halt_error
, halt_error(exit_code)
それ以上何も出力せずにjqプログラムを停止します。
入力は素の文字列として修飾せずに標準エラーstderr
へ出力します(文字列をダブルクォートで囲んだりしません)。
改行文字もそのままです。
引数のexit_code
はjqの終了ステータスになります。未指定の場合5
です。
具体的には"Error: somthing went wrong\n"|halt_error(1)
のように記述します。
$__loc__
キー"file"
に対してファイル名を、キー"line"
に対して$__loc__
が登場した位置の行番号を値として持つオブジェクトを生成します。
jq 'try error("\($__loc__)") catch .' | |
Input | null |
Output | "{\"file\":\"<top-level>\",\"line\":1}" |
paths
, paths(node_filter)
, leaf_paths
組み込み関数paths
は入力されたオブジェクトあるいは配列の全ての要素に対応するパスを出力します。
(ただし空の配列や入力.
自体は除外します)
paths(f)
はフィルターf
が真になる全ての値に対応するパスを出力します。
つまり、paths(numbers)
と記述すると全ての数値に対応するパスを出力します。
leaf_paths
はpaths(scalars)
の省略記法ですが、廃止予定であり、将来のメジャーリリースで削除される予定です。
jq '[paths]' | |
Input | [1,[[],{"a":2}]] |
Output | [[0],[1],[1,0],[1,1],[1,1,"a"]] |
jq '[paths(scalars)]' | |
Input | [1,[[],{"a":2}]] |
Output | [[0],[1,1,"a"]] |
add
入力した配列の全ての要素を加算した値を出力します。
要素のデータ型に応じて数値の総和や連結した文字列やマージしたオブジェクトを生成します。
データ型と処理の関係は前述した+
演算子と同様です。
入力が空配列だった場合null
を出力します。
jq 'add' | |
Input | ["a","b","c"] |
Output | "abc" |
jq 'add' | |
Input | [1, 2, 3] |
Output | 6 |
jq 'add' | |
Input | [] |
Output | null |
any
, any(condition)
, any(generator; condition)
入力した真偽値の配列について1つでもtrue
があればtrue
を出力します。
入力が空配列だった場合false
を出力します。
any(condition)
と記述すると、入力した配列の全ての要素を評価します。
any(generator; condition)
と記述すると、指定したジェネレータの生成した全ての値を評価します。
jq 'any' | |
Input | [true, false] |
Output | true |
jq 'any' | |
Input | [false, false] |
Output | false |
jq 'any' | |
Input | [] |
Output | false |
all
, all(condition)
, all(generator; condition)
入力した真偽値の配列について全ての要素がtrue
だったらtrue
を出力します。
all(condition)
と記述すると、入力した配列の全ての要素を評価します。
all(generator; condition)
と記述すると、指定したジェネレータの生成した全ての値を評価します。
入力が空配列だった場合true
を出力します。
jq 'all' | |
Input | [true, false] |
Output | false |
jq 'all' | |
Input | [true, true] |
Output | true |
jq 'all' | |
Input | [] |
Output | true |
flatten
, flatten(depth)
入力した配列を要素とする配列について、それぞれの要素を再帰的に展開した全ての要素で置換した平坦な配列を生成します。 引数にネストの深さを指定できます。
例えば、flatten(2)
と記述すると2段階のネストまで再帰します。
jq 'flatten' | |
Input | [1, [2], [[3]]] |
Output | [1, 2, 3] |
jq 'flatten(1)' | |
Input | [1, [2], [[3]]] |
Output | [1, 2, [3]] |
jq 'flatten' | |
Input | [[]] |
Output | [] |
jq 'flatten' | |
Input | [{"foo": "bar"}, [{"foo": "baz"}]] |
Output | [{"foo": "bar"}, {"foo": "baz"}] |
range(upto)
, range(from;upto)
range(from;upto;by)
組み込み関数range
は数値の区間を生成します。
range(4;10)
と記述すると4以上10未満の6つの数値を生成します。
出力する数値は別々ですが[range(4;10)]
とすれば区間の配列を生成できます。
1引数で呼び出した場合、0から指定した数値まで1ずつ増分した区間を生成します。
2引数で呼び出した場合、from
からupto
まで1ずつ増分した区間を生成します。
3引数で呼び出した場合、from
からupto
までby
ずつ増分した区間を生成します。
jq 'range(2;4)' | |
Input | null |
Output | 2 |
3 |
jq '[range(2;4)]' | |
Input | null |
Output | [2,3] |
jq '[range(4)]' | |
Input | null |
Output | [0,1,2,3] |
jq '[range(0;10;3)]' | |
Input | null |
Output | [0,3,6,9] |
jq '[range(0;10;-1)]' | |
Input | null |
Output | [] |
jq '[range(0;-5;-1)]' | |
Input | null |
Output | [0,-1,-2,-3,-4] |
floor
入力した数値に最も近いより小さい整数を出力します。
jq 'floor' | |
Input | 3.14159 |
Output | 3 |
sqrt
入力した数値の平方根を出力します。
jq 'sqrt' | |
Input | 9 |
Output | 3 |
tonumber
入力を数値として解釈します。 正確な書式で記述した文字列を対応する数値へ変換します。 入力に数値以外の文字がある場合エラーを生成します。
jq '.[] | tonumber' | |
Input | [1, "1"] |
Output | 1 |
1 |
tostring
入力を文字列として解釈します。 入力が文字列ならそのまま出力します。 それ以外の場合はJSONエンコードします。
jq '.[] | tostring' | |
Input | [1, "1", [1]] |
Output | "1" |
"1" | |
"[1]" |
type
引数のデータ型を文字列で出力します。
null、真偽値boolean
、数値number
、文字列string
、配列array
、オブジェクトobject
のいずれかになります。
jq 'map(type)' | |
Input | [0, false, [], {}, null, "hello"] |
Output | ["number", "boolean", "array", "object", "null", "string"] |
infinite
, nan
, isinfinite
, isnan
, isfinite
, isnormal
算術演算には無限大やNaN(非数値、"not a number")を受け付けるものがあります。
組み込み関数isinfinite
は入力が無限大のとき真を返します。
組み込み関数isnan
は入力がNaNのとき真を返します。
組み込み関数infinite
は正の無限大を返します。
組み込み関数nan
はNaNを返します。
組み込み関数isnormal
は入力が通常の数値なら真を返します。
0除算はエラーになるため注意してください。
今のところほとんどの算術演算は無限大やNaN、通常の数値の部分集合に対してエラーを生成しません。
jq '.[] | (infinite * .) < 0' | |
Input | [-1, 1] |
Output | true |
false |
jq 'infinite, nan | type' | |
Input | null |
Output | "number" |
"number" |
sort, sort_by(path_expression)
入力した配列の要素を並び替えた配列を生成します。 値は次の順番で並び替えます。
null
false
true
オブジェクトの並び替え規則は少し複雑です。 まずキーの配列を並び替えた状態で比較します。 それから一致するキーについて値を比較します。
オブジェクトの特定のフィールドだけを並び替えることもできますし、任意のフィルターを適用した結果で並び替えることもできます。
sort_by(foo)
と記述すると、比較しているそれぞれの要素にフィルターfoo
を適用した結果を比較します。
jq 'sort' | |
Input | [8,3,null,6] |
Output | [null,3,6,8] |
jq 'sort_by(.foo)' | |
Input | [{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}] |
Output | [{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}] |
group_by(path_expression)
group_by(.foo)
と記述すると、入力した配列についてフィールド.foo
が同じ値を持つ要素の配列を要素とする配列を生成します。
要素の並び順はフィールド.foo
の値になります。
.foo
のようなフィールドアクセスだけでなく、任意のjq式を指定できます。
並び順はsort
と同じ規則です。
jq 'group_by(.foo)' | |
Input | [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}] |
Output | [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]] |
min
, max
, min_by(path_exp)
, max_by(path_exp)
入力した配列から最小値あるいは最大値を探索します。
min_by(path_exp)
やmax_by(path_exp)
と記述すると、パス式path_exp
で指定したフィールドあるいはプロパティを探索します。
例えばmin_by(.foo)
と記述するとフィールドfoo
が最小値のオブジェクトを探索します。
jq 'min' | |
Input | [5,4,2,7] |
Output | 2 |
jq 'max_by(.foo)' | |
Input | [{"foo":1, "bar":14}, {"foo":2, "bar":3}] |
Output | {"foo":2, "bar":3} |
unique
, unique_by(path_exp)
入力した配列の重複を除去して並び替えた配列を生成します。
unique_by(path_exp)
と記述すると、それぞれの要素について引数のパス式path_exp
で指定したフィールドの値だけを参照します。
group_by
の生成した配列から1要素だけ取り出して配列を生成することもできます。
jq 'unique' | |
Input | [1,2,5,3,5,3,1,3] |
Output | [1,2,3,5] |
jq 'unique_by(.foo)' | |
Input | [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}] |
Output | [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}] |
jq 'unique_by(length)' | |
Input | ["chunky", "bacon", "kitten", "cicada", "asparagus"] |
Output | ["bacon", "chunky", "asparagus"] |
reverse
入力した配列を逆順にした配列を生成します。
jq 'reverse' | |
Input | [1,2,3,4] |
Output | [4,3,2,1] |
contains(element)
contains(b)
と記述すると、入力に値b
と完全に一致する要素があれば真を返します。
文字列Bが文字列Aの部分文字列であるとき、文字列Aは文字列Bを含むことになります。
配列Bが配列Aの部分配列であるとき、配列Aは配列Bを含むことになります。
オブジェクトBのフィールドがオブジェクトAのフィールドの部分集合であるとき、オブジェクトAはオブジェクトBを含むことになります。
他のデータ型については値が等しければお互いを含むことになります。
jq 'contains("bar")' | |
Input | "foobar" |
Output | true |
jq 'contains(["baz", "bar"])' | |
Input | ["foobar", "foobaz", "blarp"] |
Output | true |
jq 'contains(["bazzzzz", "bar"])' | |
Input | ["foobar", "foobaz", "blarp"] |
Output | false |
jq 'contains({foo: 12, bar: [{barp: 12}]})' | |
Input | {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} |
Output | true |
jq 'contains({foo: 12, bar: [{barp: 15}]})' | |
Input | {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} |
Output | false |
indices(s)
入力.
に存在する引数s
の位置からなる配列を生成します。
入力が配列でs
も配列なら、配列としてs
に一致する全ての部分配列の位置からなる配列を生成します。
jq 'indices(", ")' | |
Input | "a,b, cd, efg, hijk" |
Output | [3,7,12] |
jq 'indices(1)' | |
Input | [0,1,2,1,3,1,4] |
Output | [1,3,5] |
jq 'indices([1,2])' | |
Input | [0,1,2,3,1,4,2,5,1,2,6,7] |
Output | [1,8] |
index(s)
, rindex(s)
index(s)
と記述した場合、入力.
に存在する引数s
の最初の位置を生成します。
rindex(s)
と記述した場合、入力.
に存在する引数s
の最後の位置を生成します。
jq 'index(", ")' | |
Input | "a,b, cd, efg, hijk" |
Output | 3 |
jq 'rindex(", ")' | |
Input | "a,b, cd, efg, hijk" |
Output | 12 |
inside
組み込みフィルターinside(b)
は、入力がb
に内包されるなら真を返します。
本質的にはcontains
の逆バージョンです。
jq 'inside("foobar")' | |
Input | "bar" |
Output | true |
jq 'inside(["foobar", "foobaz", "blarp"])' | |
Input | ["baz", "bar"] |
Output | true |
jq 'inside(["foobar", "foobaz", "blarp"])' | |
Input | ["bazzzzz", "bar"] |
Output | false |
jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' | |
Input | {"foo": 12, "bar": [{"barp": 12}]} |
Output | true |
jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})' | |
Input | {"foo": 12, "bar": [{"barp": 15}]} |
Output | false |
startswith(str)
入力.
が指定された文字列で開始するなら真を返します。
jq '[.[]|startswith("foo")]' | |
Input | ["fo", "foo", "barfoo", "foobar", "barfoob"] |
Output | [false, true, false, true, false] |
endswith(str)
入力.
が指定された文字列で終了するなら真を返します。
jq '[.[]|endswith("foo")]' | |
Input | ["foobar", "barfoo"] |
Output | [false, true] |
combinations
, combinations(n)
入力した配列について、全ての要素の組み合わせからなる配列を生成します。
引数n
は、入力した配列の要素が出力する配列に登場する回数です。
jq 'combinations' | |
Input | [[1,2], [3, 4]] |
Output | [1, 3] |
[1, 4] | |
[2, 3] | |
[2, 4] |
jq 'combinations(2)' | |
Input | [0, 1] |
Output | [0, 0] |
[0, 1] | |
[1, 0] | |
[1, 1] |
ltrimstr(str)
入力.
が指定された文字列で開始するなら、引数の文字列を除去した文字列を生成します。
jq '[.[]|ltrimstr("foo")]' | |
Input | ["fo", "foo", "barfoo", "foobar", "afoo"] |
Output | ["fo","","barfoo","bar","afoo"] |
rtrimstr(str)
入力.
が指定された文字列で終了するなら、引数の文字列を除去した文字列を生成します。
jq '[.[]|rtrimstr("foo")]' | |
Input | ["fo", "foo", "barfoo", "foobar", "foob"] |
Output | ["fo","","bar","foobar","foob"] |
explode
入力した文字列を、それぞれの文字に対応するユニコードコードポイントの数値にした配列を生成します。
jq 'explode' | |
Input | "foobar" |
Output | [102,111,111,98,97,114] |
implode
explode
と逆に、入力した配列の要素であるユニコードコードポイントに対応する文字を連結した文字列を生成します。
jq 'implode' | |
Input | [65, 66, 67] |
Output | "ABC" |
split(str)
入力した文字列を、引数の文字列で分割した配列を生成します。
jq 'split(", ")' | |
Input | "a, b,c,d, e, " |
Output | ["a","b,c,d","e",""] |
join(str)
引数の文字列を区切り文字として、入力した配列の要素を連結した文字列を生成します。
組み込み関数split
の逆バージョンです。
つまり、split("foo") | join("foo")
と記述すると、入力した文字列と同じ文字列を出力します。
入力した数値や真偽値は文字列へ変換します。 nullは空文字列として扱います。 配列やオブジェクトには対応していません。
jq 'join(", ")' | |
Input | ["a","b,c,d","e"] |
Output | "a, b,c,d, e" |
jq 'join(" ")' | |
Input | ["a",1,2.3,true,null,false] |
Output | "a 1 2.3 true false" |
ascii_downcase
, ascii_upcase
組み込み関数ascii_downcase
は、入力した文字列のアルファベット(aからzあるいはA-Z)を小文字に変換した文字列を生成します。
組み込み関数ascii_upcase
は、入力した文字列のアルファベット(aからzあるいはA-Z)を大文字に変換した文字列を生成します。
while(cond; update)
組み込み関数while(cond; update)
は条件cond
が偽になる間、入力.
に繰り返しupdate
を適用します。
jqの内部では再帰関数として定義されているので注意してください。
while
の再帰的な呼び出しは、update
が入力に対して多くても1つだけ出力を生成するなら追加のメモリを消費しません。
詳しくは高度な使い方のセクションで説明します。
jq '[while(.<100; .*2)]' | |
Input | 1 |
Output | [1,2,4,8,16,32,64] |
until(cond; next)
組み込み関数until(cond; next)
は条件cond
が真になる間、入力.
に繰り返しnext
を適用します。
jqの内部では再帰関数として定義されているので注意してください。
until
の再帰的な呼び出しは、next
が入力に対して多くても1つだけ出力を生成するなら追加のメモリを消費しません。
詳しくは高度な使い方のセクションで説明します。
jq '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]' | |
Input | 4 |
Output | 24 |
recurse(f)
, recurse
, recurse(f; condition)
, recurse_down
組み込み関数recurse(f)
を使うと再帰的なデータ構造を探索し、あらゆる段階のデータを抽出できます。
次のようにファイルシステムの情報を入力した場合を考えてみましょう。
{"name": "/", "children": [
{"name": "/bin", "children": [
{"name": "/bin/ls", "children": []},
{"name": "/bin/sh", "children": []}]},
{"name": "/home", "children": [
{"name": "/home/stephen", "children": [
{"name": "/home/stephen/jq", "children": []}]}]}]}
ここでは全てのファイル名を抽出することにします。
つまり.name
と.children[].name
だけでなく、.children[].children[].name
のようにどんどん繰り返さなければいけません。
次のように記述すると実現できます。
recurse(.children[]) | .name
引数を指定しない場合、recurse(.[]?)
と同じ意味になります。
recurse(f)
はrecurse(f; . != null)
と同一です。
再帰の深さを気にせず実行できます。
recurse(f; condition)
はジェネレーターです。
condition
が真になるまで入力.
を繰り返しf
に適用します。
つまり.|f, .|f|f, .|f|f|f
のような繰り返しになります。
例えば、理屈ではrecurse(.+1; true)
のように記述すれば全ての整数を出力できます。
recurse_down
は互換性を保つために残っている引数無しのrecurse
の別名です。
廃止予定であり、将来のメジャーリリースで削除される予定です。
recurse(f)
による再帰呼び出しは、f
が入力に対して多くても1つだけ出力を生成するなら追加のメモリを消費しません。
jq 'recurse(.foo[])' | |
Input | {"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]} |
Output | {"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]} |
{"foo":[]} | |
{"foo":[{"foo":[]}]} | |
{"foo":[]} |
jq 'recurse' | |
Input | {"a":0,"b":[1]} |
Output | {"a":0,"b":[1]} |
0 | |
[1] | |
1 |
jq 'recurse(. * .; . < 20)' | |
Input | 2 |
Output | 2 |
4 | |
16 |
walk(f)
組み込み関数walk(f)
は入力されたエンティティの全ての要素へ再帰的にフィルターf
を適用します。
要素が配列だったら、最初に全ての配列要素へf
を適用してから、配列全体を対象にf
を適用します。
要素がオブジェクトだったら、最初に全てのフィールドへf
を適用してから、オブジェクト全体を対象にf
を適用します。
実際には、具体例のように入力をテストするフィルターを指定することになるでしょう。
1つ目の例は、配列の前に配列の要素である配列を処理することの利点を示しています。
2つ目の例は、入力に含まれる全てのオブジェクトの全てのキーについて変更できるかどうかを確かめています。
jq 'walk(if type == "array" then sort else . end)' | |
Input | [[4, 1, 7], [8, 5, 2], [3, 6, 9]] |
Output | [[1,4,7],[2,5,8],[3,6,9]] |
jq 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )' | |
Input | [ { "_a": { "__b": 2 } } ] |
Output | [{"a":{"b":2}}] |
$ENV
, env
組み込み変数$ENV
はjqコマンドを実行した時点の環境変数を表すオブジェクトです。
組み込み関数env
は実行中のjqプロセスの環境変数を出力します。
現時点で環境変数を設定する機能はありません。
jq '$ENV.PAGER' | |
Input | null |
Output | "less" |
jq 'env.PAGER' | |
Input | null |
Output | "less" |
transpose
配列の配列のようにでこぼこした表を転置します。 不足している行の値にはnullを追加するため、結果は常に正方行列になります。
jq 'transpose' | |
Input | [[1], [2,3]] |
Output | [[1,2],[null,3]] |
bsearch(x)
組み込み関数bsearch(x)
は入力された配列についてx
を軸とする2分探索を実行します。
入力の配列が並び替えた状態でx
を含むなら、配列中に登場したx
の添え字を返します。
並び替えた状態だけどx
を含まないなら、(-1 - ix)
を返します。
ix
はx
を挿入する位置なので、(-1 - ix)
は配列の並び順を保ちつつx
を挿入した後のx
の添え字になります。
配列が並び替えた状態でないとしてもbsearch(x)
は整数を返しますが、おそらく意味の無い値です。
jq 'bsearch(0)' | |
Input | [0,1] |
Output | 0 |
jq 'bsearch(0)' | |
Input | [1,2,3] |
Output | -1 |
jq 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end' | |
Input | [1,2,3] |
Output | [1,2,3,4] |
\(foo)
文字列の中にバックスラッシュ(U+005c)と括弧で式を埋め込むことができます。 式の結果は文字列として挿入されます。
jq '"The input was \(.), which is one less than \(.+1)"' | |
Input | 42 |
Output | "The input was 42, which is one less than 43" |
tojson
, fromjson
組み込み関数tojson
は入力された値をJSON文字列として出力します。
逆に、組み込み関数fromjson
は入力された値をJSON文字列として解釈します。
組み込み関数tostring
は文字列を変更せずに出力しますが、tojson
は文字列をJSON文字列へエンコードして出力します。
jq '[.[]|tostring]' | |
Input | [1, "foo", ["foo"]] |
Output | ["1","foo","[\"foo\"]"] |
jq '[.[]|tojson]' | |
Input | [1, "foo", ["foo"]] |
Output | ["1","\"foo\"","[\"foo\"]"] |
jq '[.[]|tojson|fromjson]' | |
Input | [1, "foo", ["foo"]] |
Output | [1,"foo",["foo"]] |
文字列の書式化やエスケープには@foo
という記法を利用します。
URLを組み立てたり、HTMLやXMLなどのドキュメントを生成したりする場合に役立ちます。
@foo
はフィルターとしても利用できます。
エスケープのために利用できる記法は次のとおりです。
@text
:組み込み関数tostring
を呼び出します。詳しくは関数の説明を参照してください。
@json
:入力をJSONにシリアライズします。
@html
:HTML/XMLエスケープを行います。
つまり、<>%'"
という文字列はそれぞれ<
、>
、&
、'
、"
へエスケープします。
@uri
:パーセントエンコーディングします。
つまり、URIの予約文字を%XX
へエスケープします。
@csv
:入力は配列でなければなりません。 出力はCSVです。 文字列はダブルクォートで囲みますし、文字列中のダブルクォートは二重のダブルクォートへエスケープします。
@tsv
:入力は配列でなければなりません。
出力はTSV(タブ区切り)です。
入力した配列の要素は単一の行として出力します。
フィールドの区切り文字はタブ文字(U+0009)です。
入力に含まれる改行文字(U+000a)や復帰文字(U+000d)、タブ文字(U+0009)やバックスラッシュ(U+005c)は、それぞれ対応するエスケープ文字の\n
、\r
、\t
、\\
へエスケープします。
@sh
:入力をPOSIXシェルのコマンドラインで利用できる形式へエスケープします。 配列を入力した場合、空白文字で区切られた文字列の系列を出力します。
@base64
:入力をRFC4648で定義されたBASE64符号へ変換します。
@base64d
:@base64
とは反対に、入力をRFC4648で定義されたBASE64符号として復号します。
(注意点:復号した文字列の文字エンコーディングがUTF-8でない場合の結果は未定義です)
これらの記法は文字列の内挿と組み合わせて便利に使うことができます。
トークン@foo
に続けてリテラル文字列を記述できるということです。
リテラル文字列はエスケープしません。
ただし、リテラル文字列に内挿された式の結果はエスケープされます。
例えば次のように記述して
@uri "https://www.google.com/search?q=\(.search)"
{"search":"what is jq?"}
を入力すると、次のように出力します。
"https://www.google.com/search?q=what%20is%20jq%3F"
スラッシュ(U+002f)やクエスチョン(U+003f)など、リテラル文字列のURLに含まれる文字はエスケープされないことに注意してください。
jq '@html' | |
Input | "This works if x < y" |
Output | "This works if x < y" |
jq '@sh "echo \(.)"' | |
Input | "O'Hara's Ale" |
Output | "echo 'O'\\''Hara'\\''s Ale'" |
jq '@base64' | |
Input | "This is a message" |
Output | "VGhpcyBpcyBhIG1lc3NhZ2U=" |
jq '@base64d' | |
Input | "VGhpcyBpcyBhIG1lc3NhZ2U=" |
Output | "This is a message" |
jqは日時を扱う基本的な機能を高水準関数と低水準関数の組み込み関数として提供します。 どの関数もたいてい時刻はUTCとして扱います。
組み込み関数fromdateiso8601
はISO 8601形式の日時を解析して、UNIXエポック(1970-01-01T00:00:00Z)からの秒数(数値)を出力します。
組み込み関数todateiso8601
はその逆の変換をします。
組み込み関数fromdate
は日時文字列を解析します。
現時点ではISO 8601形式にのみ対応していますが、将来的には他の形式にも対応する予定です。
組み込み関数todate
はtodateiso8601
の別名です。
組み込み関数now
は現在日時のUNIXエポック秒を出力します。
jqはCライブラリの時刻関数(strptime
、strftime
、strflocaltime
、mktime
、gmtime
、localtime
)を呼び出す低水準インターフェイスも提供しています。
strptime
やstrftime
の書式文字についてはホストOSのドキュメントを参照してください。
(注意点:特に地域化の機能など、jqとして安定したインターフェイスを提供する必然性はありません)
組み込み関数gmtime
はUNIXエポック秒を入力すると、グリニッジ標準時へ換算した要素別の日時からなる配列を出力します(順番は年、月(0から数えます)、月の日、時、分、秒、週の日、年の日)。
月以外は1から数えた数値になります。
システムによっては1900年3月1日より以前の日時を入力すると、間違った週の日が出力される場合があります。
2099年12月31日以降の日時についても同様です。
組み込み関数localtime
はgmtime
と同様の機能ですが、タイムゾーンの設定に従います。
組み込み関数mktime
には、gmtime
やstrptime
の生成する要素別の日時を入力します。
組み込み関数strptime(fmt)
は引数の書式文字列fmt
にマッチする文字列を解釈します。
出力はgmtime
と同様に要素別の日時からなる配列で、mktime
の入力に利用できます。
組み込み関数strftime(fmt)
は入力された日時(GMT)を引数の書式文字列fmt
で書式化します。
組み込み関数strflocaltime
も同様の機能ですが、タイムゾーンの設定に従います。
strptime
およびstrftime
の書式文字列は、ほとんどのCライブラリドキュメントで説明されています。
ISO 8601形式の日時は"%Y-%m-%dT%H:%M:%SZ"
と記述します。
jqはシステムの提供する全ての日時機能に対応しているわけではありません。
特にmacOSではstrptime(fmt)
へ指定できる書式文字列の%u
や%j
は未対応です。
jq 'fromdate' | |
Input | "2015-03-05T23:51:47Z" |
Output | 1425599507 |
jq 'strptime("%Y-%m-%dT%H:%M:%SZ")' | |
Input | "2015-03-05T23:51:47Z" |
Output | [2015,2,5,23,51,47,4,63] |
jq 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime' | |
Input | "2015-03-05T23:51:47Z" |
Output | 1425599507 |
jqはいくつかSQLスタイルの演算子を提供します。
組み込み演算子INDEX(stream; expr)
はオブジェクトを生成します。
キーはstream
に式expr
を適用した結果、値はstream
です。
組み込み演算子JOIN($idx; stream; idx_expr; join_expr)
はstream
の値を$idx
に結合します。
インデックスのキーはstream
に式idx_expr
を適用した結果、値はstream
です。
ストリームの要素が配列ならインデックスの対応する値と共に式join_expr
を評価し、結果を生成します。
JOIN($idx; stream; idx_expr; .)
と同様です。
JOIN($idx; .; idx_expr; .)
と同様です。
結合演算について詳しくは後述します。
組み込み演算子IN(s)
は入力.
のいずれかの要素がストリームs
に存在するときtrue
を出力します。
それ以外ではfalse
を出力します。
組み込み演算子IN(s)
はストリームsource
のいずれかの要素がストリームs
に存在するときtrue
を出力します。
それ以外ではfalse
を出力します。
builtins
全ての組み込み関数の一覧を関数名/アリティ
という書式で出力します。
同じ名前でもアリティの異なる関数は別の関数です。
従ってall/0
、all/1
、all/2
のように出力されます。
==
, !=
a == b
という式はa
とb
が等しければtrue
を生成します(JSONドキュメントとして等しい場合です)。
それ以外の場合はfalse
を生成します。
なお、文字列は決して数値と等しくなりません。
jqにおける==
はJavascriptの===
のように考えることができます。
つまり、同じデータ型で同じ値の場合等しいことになるのです。
!=
は「等しい」の否定です。
従ってa != b
はa == b
の反対の値になります。
jq '.[] == 1' | |
Input | [1, 1.0, "1", "banana"] |
Output | true |
true | |
false | |
false |
if A then B else C end
と記述すると、A
がfalse
あるいはnull
以外を生成した場合はB
になります。それ以外の場合はC
になります。
if A then B end
と記述した場合はif A then B else . end
と記述した場合と同じ意味になります。
else
節は必須ではなく、存在しない場合は.
を指定した場合と同じになります。
false
やnull
を確かめたいというのは「真であって欲しい」という希望の表れであり、JavascriptやPythonよりもそのように考える場合が多いと思います。
ですが、そのためには希望する条件をより明示的に記述しなければならないのです。
したがってif .name then A else B end
と記述しても文字列が空かどうか確かめることはできません。
他の方法が必要です。
条件A
が複数の結果を生成する場合、false
やnull
でないそれぞれの要素についてB
を評価し、false
やnull
のそれぞれの要素についてC
を評価します。
if
をたくさん記述しなければならない場合はelif A then B
のように記述することもできます。
jq 'if . == 0 then "zero" elif . == 1 then "one" else "many" end' | |
Input | 2 |
Output | "many" |
>, >=, <=, <
比較演算子>
は左辺値が右辺値を超えるかどうか、>=
は左辺値が右辺値以上かどうか、<=
は左辺値が右辺値以下かどうか、<
は左辺値が右辺値未満かどうかを返します。
大小の基準はsort
と同様です。
jq '. < 5' | |
Input | 2 |
Output | true |
jqは論理演算子and/or/not
に対応しています。
標準的な解釈と同様に、式の結果がfalse
やnull
なら「偽」、それ以外は「真」になります。
いずれかのオペランドが複数の結果を生成するなら、論理演算子はオペランドをそれそれの値に置き換えた場合の結果を生成します。
組み込み関数not
は演算子ではありません。
特殊構文ではなく、フィルターとしてパイプのさまざまな場面で呼び出すことができます。
例えば.foo and .bar | not
のように記述できるのです。
論理演算子は「真」あるいは「偽」だけを生成します。
従って、PerlやPythonやRubyで一般的なイディオムvalue_that_may_be_null or default
のような記述はできないため、純粋に論理式として使用することになります。
or
を条件として評価するのではなくイディオム風に使いたければ代わりに//
演算子を使うといいでしょう。
jq '42 and "a string"' | |
Input | null |
Output | true |
jq '(true, false) or false' | |
Input | null |
Output | true |
false |
jq '(true, true) and (true, false)' | |
Input | null |
Output | true |
false | |
true | |
false |
jq '[true, false | not]' | |
Input | null |
Output | [false, true] |
//
フィルターをa // b
と記述すると、a
がfalse
やnull
以外を生成する場合はa
と同じ結果を、それ以外の場合はb
と同じ結果を生成します。
この演算子を使うと簡単に初期値を提供できるようになります。
.foo // 1
と記述すると、.foo
という要素がなければ1
になるのです。
Pythonなどのプログラミング言語でor
を使うイディオムと同じような効果があります。
(jqはor
演算子を厳密な論理演算子として扱います)
jq '.foo // 42' | |
Input | {"foo": 19} |
Output | 19 |
jq '.foo // 42' | |
Input | {} |
Output | 42 |
try exp1 catch exp2
と記述すると、exp1
を評価したときに発生するエラーを捕捉できます。
exp1
が失敗したらそのエラーメッセージを入力としてexp2
を実行するのです。
exp1
が何らかの結果を生成した場合でも、例外ハンドラexp2
を実行した場合はその結果も出力します。
try EXP
と記述した場合の例外ハンドラはempty
です。
jq 'try .a catch ". is not an object"' | |
Input | true |
Output | ". is not an object" |
jq '[.[]|try .a]' | |
Input | [{}, true, {"a":1}] |
Output | [null, 1] |
jq 'try error("some exception") catch .' | |
Input | true |
Output | "some exception" |
try/catch
記法はreduce
やforeach
やwhile
などの制御構造から脱出するために利用できます。
例えば次のように記述できます。
# 式`exp`が`"break"`をレイズするまで繰り返し評価します。
# `"break"`をレイズしたら、それ以上エラーをレイズしないで繰り返しを終了します。
# ただし、レイズしたエラーが`"break"`でなければ再びレイズします。
try repeat(exp) catch .=="break" then empty else error;
jqは"break"
や"go (back) to"
の宛先に指定できる名前付きラベル記法に対応しています。
label $out | ... break $out ...
break $label_name
と記述すると、式の左側を見て最も近いlabel $label_name
へ移動し、empty
を生成します。
break
とlabel
の関係はレキシカルスコープで決定されます。
つまり、label
はbreak
から「見える」ところに定義しなければなりません。
reduce
から脱出するには次のように記述します。
label $out | reduce .[] as $item (null; if .==false then break $out else ... end)
次の記述は構文エラーになります。
break $out
$out
というラベルを参照できないからです。
?
?
演算子はEXP?
のように記述します。
この場合はtry EXP
の省略形になります。
jq '[.[]|(.a)?]' | |
Input | [{}, true, {"a":1}] |
Output | [null, 1] |
jqはPHPやRubyやTextMateやSublime Textなどいろいろなソフトウェアが利用しているOniguruma正規表現ライブラリを利用しています。 このセクションではjqに関連する内容を説明します。
jqの正規表現フィルターは次のいずれかの記法で定義できます。
STRING | FILTER( REGEX )
STRING | FILTER( REGEX; FLAGS )
STRING | FILTER( [REGEX] )
STRING | FILTER( [REGEX, FLAGS] )
登場する要素の意味は次のとおりです。
STRING,REGEX,FLAGS
はjqにおける文字列あるいは文字列の内挿に使用できるオブジェクトですREGEX
はPCREに即した正規表現でなければなりませんFILTER
は後述するtest
やmatch
やcapture
のいずれかですFLAGS
はOnigurumaが対応している次のいずれかの制御文字で構成された文字列です。
g
- 全体検索(最初にマッチした文字列だけでなく、全ての文字列を検索します)i
- 大文字と小文字を区別しない検索m
- 複数行モード(.
が改行文字にもマッチします)n
- 空のマッチを除外しますp
- s
とm
を両方とも有効化しますs
- 単一行モード(^
は\A
に、$
は\Z
に相当します)l
- 最長マッチを探索しますx
- 拡張正規表現を有効にします(空白やコメントを無視します)例えば、x
を指定した状態で空白文字をマッチするには次のように\s
をエスケープします。
正規表現REGEX
の中で指定できる制御文字もあるので注意してください。
次のように記述すると、true, true, false, false
のように評価されます。
test(val)
, test(regex; flags)
match
と同様ですが、正規表現がマッチした結果からマッチオブジェクトを生成せずtrue
かfalse
を生成します。
jq 'test("foo")' | |
Input | "foo" |
Output | true |
jq '.[] | test("a b c # spaces are ignored"; "ix")' | |
Input | ["xabcd", "ABC"] |
Output | true |
true |
match(val)
, match(regex; flags)
matchはマッチした内容を含むオブジェクトを生成します。 マッチオブジェクトは次のようなフィールドを持っています。
offset
- UTF-8のコードポイントで数えた、入力の先頭からマッチした位置の先頭まで距離(オフセット)length
- UTF-8のコードポイントで数えた、マッチした文字列の長さstring
- マッチした文字列そのものcaptures
- キャプチャグループそれぞれを要素とする配列キャプチャグループのオブジェクトは次のようなフィールドを持っています。
offset
- UTF-8のコードポイントで数えた、入力の先頭からマッチした位置の先頭まで距離(オフセット)length
- UTF-8のコードポイントで数えた、グループの文字列の長さstring
- キャプチャした文字列そのものname
- キャプチャグループの名前(無ければnull
)何もマッチしなかったキャプチャグループのoffset
は-1
です。
jq 'match("(abc)+"; "g")' | |
Input | "abc abc" |
Output | {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]} |
{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]} |
jq 'match("foo")' | |
Input | "foo bar foo" |
Output | {"offset": 0, "length": 3, "string": "foo", "captures": []} |
jq 'match(["foo", "ig"])' | |
Input | "foo bar FOO" |
Output | {"offset": 0, "length": 3, "string": "foo", "captures": []} |
{"offset": 8, "length": 3, "string": "FOO", "captures": []} |
jq 'match("foo (?<bar123>bar)? foo"; "ig")' | |
Input | "foo bar foo foo foo" |
Output | {"offset": 0, "length": 11, "string": "foo bar foo", "captures": [{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]} |
{"offset": 12, "length": 8, "string": "foo foo", "captures": [{"offset": -1, "length": 0, "string": null, "name": "bar123"}]} |
jq '[ match("."; "g")] | length' | |
Input | "abc" |
Output | 3 |
capture(val)
, capture(regex; flags)
入力のJSONオブジェクトについて名前付きキャプチャグループを集めます。 グループの名前をキー、マッチした文字列を値とするオブジェクトを生成します。
jq 'capture("(?<a>[a-z]+)-(?<n>[0-9]+)")' | |
Input | "xyzzy-14" |
Output | { "a": "xyzzy", "n": "14" } |
scan(regex)
, scan(regex; flags)
入力の文字列について、正規表現regex
と制御文字列flags
にマッチした重複しない部分文字列を要素とするストリームを生成します。
マッチしなければストリームは空になります。
入力の文字列それぞれを全てキャプチャするには[ scan(regex) ]
のようなイディオムで記述します。
split(regex; flags)
後方互換性を保つため、正規表現ではなく文字列で分割します。
splits(regex)
, splits(regex; flags)
対応するsplit
と同じ結果になりますが、配列ではなくストリームを生成します。
sub(regex; tostring)
sub(regex; string; flags)
入力の文字列について、正規表現regex
にマッチした最初の部分文字列を内挿してからtostring
した結果で置換します。
tostring
はjq文字列でなければなりません。名前付きキャプチャグループの名前を含む場合もありmす。
実際のところ、tostring
の入力はcapture
で生成した名前付きキャプチャグループのJSONオブジェクトです。
従って、参照するキャプチャグループの名前が"x"
なら"\(.x)"
のように記述しなければなりません。
gsub(regex; string)
, gsub(regex; string; flags)
sub
と同様ですが、マッチした重複しない部分文字列全てを内挿した結果で置換します。
変数はほとんどのプログラミング言語に必要不可欠な要素ですが、jqでは「高度な使い方」という扱いになります。
ほとんどのプログラミング言語において変数はデータの入れ物にすぎません。 計算した値を繰り返し使いたければ変数に記憶しなければならないのです。 値を他のプログラム部品へ渡すには、値を記録する場所である変数もプログラム部品の一部として定義しなければなりません(関数の引数やオブジェクトのメンバーなど)。
jqは関数を定義できるのですが、主な用途はjqの標準ライブラリを定義することです(map
やfind
など多くの関数は実際にjqが定義しています)。
jqには還元処理のための演算子があります。 とても強力ですが少し分かりにくい機能です。 繰り返しになりますが、基本的には標準ライブラリとして提供するいくつかの便利な機能を定義するために内部で使用するものです。
初めて見るときは分かりにくいかもしれませんが本来jqはジェネレーターです(他のプログラミング言語によくある機能です)。 いくつかの便利機能はジェネレーターを作りやすくするためにあるのです。
最小限の入出力(標準入力からJSONを読み取ったり、標準出力へJSONを書き込んだり)に対応しています。
最後になりますが、jqはモジュールおよびライブラリで構成されたシステムです。
... as $identifier | ...
jqでは全てのフィルターが入力と出力を持っているので、隣のプログラム部品に値を渡すため手作業であれこれする必要はありません。
a + b
のような大部分の式で、入力を部分式へ分配するようになっています(a
とb
は同じ入力を受け取るということです)。
ですから、たいていの場合値を繰り返し使うために変数が必要になることはないのです。
例えば、数値の配列について平均値を計算する場合、たいていのプログラミング言語ならいくつか変数が必要になるでしょう。
少なくとも配列を保持するための変数が1つ、場合によってはそれぞれの要素を保持したりループ回数を数えるためにもう1つ必要になるでしょう。
jqではadd / length
と記述するだけです。
式add
は入力した配列の総和を生成し、式length
は入力した配列の長さを生成するからです。
従って、基本的にjqではほとんどの問題を変数を使うことなくきれいに解決できます。
それでも変数を使うほうが分かりやすくなる場合もあるので、expression as $variable
という記法で変数を定義できるようになっています。
変数名は$
から始めます。
次の例は配列の平均値を計算する不細工なバージョンです。
length as $array_length | add / $array_length
実際に変数を導入したほうが簡単になる、もっと複雑な問題が必要ですね。
ブログの投稿を要素とする配列があることにします。 それぞれの要素は"author"、"title"、"realnames"をフィールドに持っています。 "realnames"は投稿者のユーザー名と本名からなる連想配列です。 具体的には次のようになります。
{"posts": [{"title": "Frist psot", "author": "anon"},
{"title": "A well-written article", "author": "person1"}],
"realnames": {"anon": "Anonymous Coward",
"person1": "Person McPherson"}}
ここで、それぞれのブログの投稿に投稿者の本名を持たせることを考えます。 具体的には次のようになります。
{"title": "Frist psot", "author": "Anonymous Coward"}
{"title": "A well-written article", "author": "Person McPherson"}
そこで本名を含むオブジェクトrealnames
を変数$names
へ格納します。
そうすれば残りの式でユーザー名から本名を参照できるようになります。
.realnames as $names | .posts[] | {title, author: $names[.author]}
exp as $x | ...
と記述すると、全ての入力についてexp
の値を格納した変数$x
と共にパイプラインの後続部分を実行できます。
as
はforeachによる繰り返しのように働くのです。
{foo: .foo}
という記述の省略形が{foo}
であるのと同様に、{$foo}
という記述は{foo: $foo}
という記述の省略形です。
式as
は入力のデータ構造に合わせることで複数の変数を宣言できます("オブジェクトの解体"と呼ばれています)。
. as {realnames: $names, posts: [$first, $second]} | ...
. as [$first, $second]
のように配列で変数を宣言することもできます。
入力した配列の先頭からそれぞれの要素を変数に束縛していきます。
入力した配列へ配列パターンに対応する要素がなければ変数にはnull
が設定されます。
変数の有効範囲は宣言した位置から後ろ全てです。 次のような記述は意図したように機能します。
.realnames as $names | (.posts[] | {title, author: $names[.author]})
しかし、次のような記述は意図したように機能しません。
(.realnames as $names | .posts[]) | {title, author: $names[.author]}
プログラミング言語理論の専門家には、jqの変数がレキシカルスコープに束縛されると説明するほうが正確でしょう。 一度値を束縛した変数に別の値を束縛する方法はありません。 新たに同じ名前の変数を生成するだけで、元の値に束縛した変数は参照できなくなります。
jq '.bar as $x | .foo | . + $x' | |
Input | {"foo":10, "bar":200} |
Output | 210 |
jq '. as $i|[(.*2|. as $i| $i), $i]' | |
Input | 5 |
Output | [10,5] |
jq '. as [$a, $b, {c: $c}] | $a + $b + $c' | |
Input | [2, 3, {"c": 4, "d": 5}] |
Output | 9 |
jq '.[] as [$a, $b] | {a: $a, b: $b}' | |
Input | [[0], [0, 1], [2, 1, 0]] |
Output | {"a":0,"b":null} |
{"a":0,"b":1} | |
{"a":2,"b":1} |
?//
解体(代替)演算子はさまざまな形式の入力を解体するための簡潔な仕組みを提供します。
リソースとリソースに結びつくイベントの一覧を返すAPIがあるとします。 そして、それぞれのリソースについてユーザーIDと最初に登場するイベントのタイムスタンプを取得したいことにします。 このAPIの応答は、リソースに複数のイベントが結びつく場合だけイベントを配列にするようです(XMLから変更したようであまりいい構造ではありません)。
{"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}},
{"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]}
解体(代替)演算子を使うとそういう構造のデータを簡潔に処理できます。
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts}
入力が値の配列なのかオブジェクトなのかわからない場合は次のように記述できます。
.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ...
演算子の両側で同じ変数を定義する必要はありません。
しかし、後続の式では全ての変数が有効になります。
演算子の入力にマッチしなかった側で定義した変数の値はnull
になります。
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts}
Additionally, if the subsequent expression returns an error, the alternative operator will attempt to try the next binding. Errors that occur during the final alternative are passed through. 加えて、後続の式がエラーを返す場合、演算子はもう一方の代替パターンで変数の束縛を試みます。 最後の代替パターンまで全てエラーを返す場合、その処理はエラーで終了します。
[[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end
jq '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}' | |
Input | [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] |
Output | {"a":1,"b":2,"d":3,"e":4} |
{"a":1,"b":2,"d":3,"e":4} |
jq '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}' | |
Input | [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] |
Output | {"a":1,"b":2,"d":3,"e":null} |
{"a":1,"b":2,"d":null,"e":4} |
jq '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end' | |
Input | [[3]] |
Output | {"a":null,"b":3} |
"def"記法によりフィルターに名前を付けられます。
def increment: . + 1;
そうするとincrement
は他の組み込みフィルターと同じように使えるようになります(実際にたくさんの組み込みフィルターはそうやって定義されています)。
関数は引数を取ることができます。
def map(f): [.[] | f];
引数は_フィルター_として(引数無しの関数として)渡されます。値では_ありません_。
同じ引数が異なる入力に対して複数回参照される場合があります(次の例では入力した配列のそれぞれの要素にf
を適用します)。
関数の引数は値というよりコールバック関数のように機能します。
これは重要なので理解しておかなければなりません。
次の例で考えてみましょう。
def foo(f): f|f;
5|foo(.*2)
f
は.*2
なので、結果は20になるはずです。
最初にf
を評価したときは.
が5で、2回目にf
を評価した結果は10(5*2)になるので、全体の結果は20になるのです。
関数の引数もフィルターです。
フィルターは入力を受け取った時点で評価されるのです。
単純な関数として引数には値のように振る舞って欲しい場合、次のように変数を使うことができます。
def addvalue(f): f as $f | map(. + $f);
あるいは単純に次のように記述できます。
def addvalue($f): ...;
どちらの記法でもaddvalue(.foo)
と記述した場合、入力したオブジェクトのフィールド.foo
を配列のそれぞれの要素に加算します。
addvalue(.[])
のように記述してはいけません。
そうするとmap(. + $f)
の部分が.
のそれぞれの値ごとに評価されてしまうからです。
同じ名前の関数を複数定義することができます。 引数の数が同じなら後で定義した関数が前の定義を置換します。 つまり後続の指揮で参照できるのは最後に定義した関数になるのです。 詳しくは後述するスコープの説明を参照してください。
jq 'def addvalue(f): . + [f]; map(addvalue(.[0]))' | |
Input | [[1,2],[10,20]] |
Output | [[1,2,1], [10,20,10]] |
jq 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])' | |
Input | [[1,2],[10,20]] |
Output | [[1,2,1,2], [10,20,1,2]] |
jqには2種類の記号があります。 値を束縛する記号と関数です。 どちらもレキシカルスコープで定義します。 「自分より左側」で定義した変数や関数しか参照できません。 この規則の例外は、関数の定義から自分自身を名前で参照できることです。 つまり再帰関数を定義できるのです。
例えば、式... | .*3 as $times_three | [. + $times_three] | ...
では「変数定義より右側」の式からは変数を参照できますが、「変数定義より左側」の式からは変数を参照できません。
式`... | (.*3 as $times_three | [. + $times_three]) | ...``では閉じ括弧より右側の式から変数を参照_できません_。
reduce
記法を使うと全ての要素に何らかの式を適用した結果を累積し、単一の結果を生成できます。
例えば次の式に[3,2,1]
を入力してみましょう。
reduce .[] as $item (0; . + $item)
.[]
の生成するそれぞれの結果について0から初めて. + $item
を実行し、合計を算出します。
この例では.[]
は3、2、1を生成するので、次のような計算をするのと同じ意味になります。
0 | (3 as $item | . + $item) |
(2 as $item | . + $item) |
(1 as $item | . + $item)
jq 'reduce .[] as $item (0; . + $item)' | |
Input | [10,2,5,3] |
Output | 20 |
isempty(exp)
式exp
が何も出力しなければ真を返します。それ以外では偽を返します。
jq 'isempty(empty)' | |
Input | null |
Output | true |
limit(n; exp)
組み込み関数limit
は式exp
の出力から最大n
個の要素を取り出します。
jq '[limit(3;.[])]' | |
Input | [0,1,2,3,4,5,6,7,8,9] |
Output | [0,1,2] |
first(expr)
, last(expr)
, nth(n; expr)
組み込み関数first(expr)
は式expr
の出力から先頭の要素を取り出します。
組み込み関数last(expr)
は式expr
の出力から最後の要素を取り出します。
組み込み関数nth(n; expr)
は式expr
の出力からn
番目の要素を取り出します。
次のように定義しても同じように機能します。
def nth(n; expr): last(limit(n + 1; expr));
なお、組み込み関数nth
は負の値に対応していません。
jq '[first(range(.)), last(range(.)), nth(./2; range(.))]' | |
Input | 10 |
Output | [0,9,5] |
first
, last
, nth(n)
組み込み関数first
は入力した配列から先頭の要素を取り出します。
組み込み関数last
は入力した配列から最後の要素を取り出します。
組み込み関数nth(n)
は入力した配列からn
番目の要素を取り出します。
jq '[range(.)]|[first, last, nth(5)]' | |
Input | 10 |
Output | [0,9,5] |
foreach
foreach
記法はreduce
と似ていますが、limit
の作成や還元処理の途中で中間結果を生成するために用意されています(具体例を参照してください)。
次のように記述します。
foreach EXP as $var (INIT; UPDATE; EXTRACT)
reduce
と同様に、INIT
は最初に1度だけ評価され状態値を生成します。
そして式EXP
の出力するそれぞれの要素を変数$var
へ束縛し、$var
と現在の状態値の元で式UPDATE
を評価します。
式UPDATE
の結果により状態値を更新します。
最後に、生成されたそれぞれの状態値について式EXTRACT
を評価し、foreach
の出力を生成します。
基本的にはreduce
やlimit
のような関数を作成する場合に便利な機能です。
しかし、それよりも部分的な還元処理をする場合のほうが一般的でしょう(具体例を参照してください)。
jq '[foreach .[] as $item ([[],[]]; if $item == null then [[],.[0]] else [(.[0] + [$item]),[]] end; if $item == null then .[1] else empty end)]' | |
Input | [1,2,3,4,null,"a","b",null] |
Output | [[1,2,3,4],["a","b"]] |
前述のとおりrecurse
は再帰を利用します。
そして全てのjq関数は再帰呼び出し可能です。
組み込みのwhile
記法も再帰で実装されています。
再帰呼び出しの左側の式の値が最後に出力する値なら、その再帰呼び出しは末尾最適化できます。 実際のところ、再帰呼び出しの左側の式は入力のそれぞれの値に対して1つ以上の値を出力するべきではありません。
具体的には次のようにします。
def recurse(f): def r: ., (f | select(. != null) | r); r;
def while(cond; update):
def _while:
if cond then ., (update | _while) else empty end;
_while;
def repeat(exp):
def _repeat:
exp, _repeat;
_repeat;
jqの提供する演算子や関数には、入力のそれぞれの値に対して0個、1個、あるいはそれ以上の値を出力するまさにジェネレータと呼ぶものがあります。
他のプログラミング言語ではちょうど1個だけ出力するものをジェネレータと呼んでいます。
例えば.[]
は入力された全ての値を生成します(入力は配列やオブジェクトでなければなりません)。
またrange(0; 10)
は0から10までの数値列を生成します。
カンマ演算子もジェネレータです。 カンマの左側の式が値を生成してから、右側の式が値を生成するからです。
組み込み関数empty
は0個の出力を生成するジェネレータです。
先行する式(ジェネレータ)の生成する値を無効化するのです。
全てのjq関数は組み込みのジェネレータと同じようにジェネレータとして利用できます。
再帰記法とカンマ演算子だけで新しいジェネレータを定義することもできます。
再帰呼び出しが「末尾」にあるならより効率的に動作するジェネレータになります。
次の具体例の関数_range
は末尾で自分自身を再帰呼び出ししています。
この例は末尾再帰、ジェネレータコンストラクタ、部分関数という3種類の高度な要素を示しています。
jq 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)' | |
Input | null |
Output | 0 |
3 | |
6 | |
9 |
jq 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]' | |
Input | 1 |
Output | [1,2,4,8,16,32,64] |
現在のjqはIEEE754で規定された64ビットの倍精度浮動小数点にのみ対応しています。
jqは+
のように単純な算術演算子だけでなく、C言語の数学ライブラリが提供する標準的な数学関数を提供しています。
C言語の数学関数の中でsin()
のように1引数の関数を、jqでは引数無しの関数として提供しています。
pow()
のように2引数の関数は、入力.
を無視する2引数の関数として提供しています。
3引数の関数は、入力.
を無視する3引数の関数として提供しています。
標準的な数学関数の中でどれが利用できるかは、OSとC言語の数学ライブラリの提供する数学関数に依存しています。 利用できない関数を呼び出した場合、エラーをレイズするでしょう。
C言語の数学関数(1引数): acos
acosh
asin
asinh
atan
atanh
cbrt
ceil
cos
cosh
erf
erfc
exp
exp10
exp2
expm1
fabs
floor
gamma
j0
j1
lgamma
log
log10
log1p
log2
logb
nearbyint
pow10
rint
round
significand
sin
sinh
sqrt
tan
tanh
tgamma
trunc
y0
y1
.
C言語の数学関数(2引数): atan2
copysign
drem
fdim
fmax
fmin
fmod
frexp
hypot
jn
ldexp
modf
nextafter
nexttoward
pow
remainder
scalb
scalbln
yn
.
C言語の数学関数(3引数): fma
.
それぞれの関数に関するより詳しい情報はシステムのマニュアルを参照してください。
今のところjqの提供する入出力機能は大半が入力の読み取りを制御するための最小限ものだけです。
組み込み関数input
とinputs
が対応します。
標準入力やコマンドラインに指定したファイルなど、jqの読み取り機能と同じ入力源から読み取ります。
jqの読み取り機能とこれらの関数は交互に動作します。
最小限の出力機能を提供するのが組み込み関数debug
とstderr
です。
(jqプログラムは常に標準出力へJSON文字列を出力することを思い出しましょう)。
debug
はjqを直接実行するのではなく、libjqのC言語APIを利用するアプリケーションに固有の振る舞いをもたらします。
stderr
は入力を改行文字も含めて一切加工せずに文字列として標準エラー出力へ出力します。
jqのほとんどの組み込み機能には参照等価性があります。 同じ入力を与えるとまったく同じ値のストリームを繰り返し生成できるのです。 ただし、入出力機能についてはそうなりません。
input
入力から受け取った1つの値を出力します。
inputs
入力から受け取った全ての値を1つずつ出力します。
主にjqへの入力を集計するのに便利です。
debug
入力した値に応じたデバッグメッセージを生成します。
jqコマンドでは入力した値を["DEBUG":, <input-value>]
という形式にして改行と共に標準エラー出力へ出力します。
将来変更するかもしれません。
stderr
改行を含めて入力を変更せず標準エラー出力へ出力します。
input_filename
フィルター処理している入力を読み取ったファイル名を返します。 jqを実行しているときのロケールがUTF-8でない場合は機能しません。
input_line_number
フィルター処理している入力の行番号を返します。
jqを--stream
オプションと共に実行すると、入力の文字列をストリームとして解釈します。
巨大なJSON文字列を全て解析することなくフィルター処理を始められるようになります。
もし1GBのJSON文字列があるとしたら、ストリームにすればより早く処理できるようになります。
しかし、入力が[<path>, <leaf-value>]
のような形式の場合(他にもいくつかそういう形式があります)、
それほど簡単にストリームとして扱えるわけではありません。
ストリームの処理を簡単にするためのさまざまな組み込み機能を提供しています。
例えば[0,[1]]
を入力したときのストリーム形式は[[0],0],[[1,0],1],[[1,0]],[[1]]
のようになります。
ストリーム形式に含まれるのは[<path>, <leaf-value>]
(任意のスカラー値や空の配列、空のオブジェクトを表します)と
[<path>]
(配列やオブジェクトの終端)です。
jqの将来のバージョンでは--stream
と-seq
を指定すると、入力した文字列の解釈に失敗したことを示す["error message"]
のような形式も出力できるようになる予定です。
truncate_stream(stream_expression)
式straem_expression
の生成するストリームについて、左側から数えて入力した数値に対応する位置より後ろを切り捨てた結果を生成します。
jq '[1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])]' | |
Input | 1 |
Output | [[[0],2],[[0]]] |
fromstream(stream_expression)
式stream_expression
の生成するストリームに対応する値を生成します。
jq 'fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))' | |
Input | null |
Output | [2] |
tostream
組み込み関数tostream
は入力した値を対応するストリーム形式へ変換した結果を生成します。
jq '. as $dot|fromstream($dot|tostream)|.==$dot' | |
Input | [0,[1,{"a":1},{"b":2}]] |
Output | true |
jqの代入は他のプログラミング言語と比べて少し異なる機能になっています。 jqでは参照とコピーを区別しません。 つまり、2つのオブジェクトあるいは配列があるとして、それらは等しいか等しくないかというだけで、「同じオブジェクトである」とか「同じオブジェクトではない」とかそういうことを判断しないのです。
あるオブジェクトに2つのフィールド.foo
と.bar
があるとしましょう。いずれも値は配列です。
そして、.bar = .foo
のように代入してから.foo
に何らかの値を追加しても、.bar
の値は変化しません。
PythonやJava、RubyやJavaScriptなどのプログラミング言語を使ったことがあるなら、
jqは代入するときにオブジェクト全体をディープコピーしているものと考えることができます。
(性能の都合もあるので完全にそういう処理をしているわけではありませんが基本的な考え方としては合っています)
つまりjqでは値を循環させられないということです(例えば配列の先頭要素が配列自身を参照するような構造)。 これは完全に意図的な設計で、jqがどのような出力を生成しても必ずJSONで表現できることを保証します。
jqにおける代入演算子は左辺(LHS、left-hand side)にパス式を指定します。 右辺(RHS、right-hand side)には、左辺のパス式から導かれたパスに設定する値を指定します。
jqでは値は常に変更不能(イミュータブル)です。
内部的には、代入する値に必要な情報を全て保持する入力.
から新しい値を還元的に計算し、出力しています。
具体的には次のような例を読めばはっきりします。
{a:{b:{c:1}}} | (.a.b|=3), .
この式は{"a":{"b":3}}
と{"a":{"b":{"c":1}}}
を出力します。
最後の式は.
なので入力した値を変更せずそのまま出力するからです。
ほとんどの利用者は=
ではなく|=
や+=
のような変化形を使うでしょう。
代入演算子のLHSも入力.
を参照するので注意してください。
つまり、$var.foo = 1
と記述しても意図したように動作しません($var.foo
という記述は入力.
のパス式としては便利ですが不正な記法です)。
$var | .foo = 1
のように記述しましょう。
.a,.b=0
という記述は.a
にも.b
にも値を代入しません。
(.a,.b)=0
のように記述すれば両方に値を代入します。
|=
右辺のフィルター式が入力.
から生成した新しい値を代入します。
例えば(.foo, .bar) |= .+1
と記述すると、フィールドfoo
には入力したオブジェクトのフィールドfoo
に1を加算した値、フィールドbar
には入力したオブジェクトのフィールドbar
に1を加算した値を代入します。
左辺には任意のパス式を指定できます。詳しくはpath()
の説明を参照してください。
左辺で入力.
の値を参照している場合は注意が必要です。
つまり$var.foo |= . + 1
と記述しても意図したように動作しません($var.foo
という記述は入力.
のパス式としては便利ですが不正な記法です)。
$var | .foo |= . + 1
のように記述しましょう。
右辺が何も値を出力しなければ(empty
など)左辺のパスに対応する要素は削除します(del(path)
と同様です)。
右辺が複数の値を出力する場合、最初の値だけを使用します。 (互換性の注意点:jq1.5以前のバージョンでは最後の値だけを使うようになっていました)
jq '(..|select(type=="boolean")) |= if . then 1 else 0 end' | |
Input | [true,false,[5,true,[true,[false]],false]] |
Output | [1,0,[5,1,[1,[0]],0]] |
+=
, -=
, *=
, /=
, %=
, //=
jqにはa op= b
という形式の代入演算子を複数提供しています。
いずれもa |= . op b
と記述したのと同じ意味になります。
つまり値をインクリメントする+= 1
は|= . + 1
と記述するのと同じ結果になります。
jq '.foo += 1' | |
Input | {"foo": 42} |
Output | {"foo": 43} |
=
基本的な代入演算子です。 他の代入演算子と違って右辺と左辺に同じ入力が渡されます。 左辺にどんなパス式を指定しても、右辺の生成する全ての出力が使われます(詳しくは後述します)。
右辺が複数の値を生成する場合、それぞれの値を左辺値のパスに対応する名前に設定し、変更された.
を出力します。
例えば(.a,.b)=range(2)
と記述すると{"a":0,"b":0}
と{"a":1,"b":1}
を出力します。
前に説明した自己代入演算子ならそうはなりません。
次の例は間違いなく=
と|=
の違いを説明してくれます。
'{"a": {"b": 10}, "b": 20}'を次のような式に入力してみましょう。
.a = .b
.a |= .b
前の式は入力したオブジェクトのフィールド"a"にフィールド"b"の値を代入し、{"a": 20, "b": 20}
を出力します。
後の式は入力したオブジェクトのフィールド"a"にフィールド"a"の値であるオブジェクトのフィールドb"の値を代入し、{"a": 10, "b": 20}
を出力します。
他にも=
と|=
の違いを示す例があります。
null|(.a,.b)=range(3)
この式は'{"a":0,"b":0}, {"a":1,"b":1}, {"a":2,"b":2}'を出力します。 ですが次の式は'{"a":0,"b":0}'を出力します。
null|(.a,.b)|=range(3)
他のプログラミング言語と違ってjqの代入演算子の左辺ではいろいろなことが許可されています。 これまで説明してきたのは単純なフィールドアクセスでしたが、配列アクセスができるとしても驚くことではありません。
.posts[0].title = "JQ Manual"
左辺の式が入力ドキュメントを別の視点から参照する複数の結果を生成するとしたら驚かされることになります。
.posts[].comments |= . + ["this is great"]
この例は入力に含まれるそれぞれのブログ投稿が持つフィールド"comments"の配列値へ文字列"this is great"を追加します(入力はオブジェクトでフィールド"posts"の値はブログ投稿の配列です)。
jqはa = b
のような代入を発見すると、a
に渡された入力ドキュメントの部分を選択するため"path"を記録します。
記録したパスで入力オブジェクトから代入する部分を探索します。
左辺では任意のフィルターを使用できるので、結果として代入するときは入力から任意のパスを選択できることになるのです。
これはとても強力な操作です。
ブログの投稿にコメントを追加したければ、同じように"blog"を入力に与えればいいからです。
仮に"stedolan"の投稿にだけコメントを追加したければ、組み込み関数select
で対象のブログ投稿を探索できるからです。
.posts[] | select(.author == "stedolan")
この操作により得られるパスは"stedolan"のブログ投稿だけを指定することになるので、前の例と同じようにコメントを追加できます。
(.posts[] | select(.author == "stedolan") | .comments) |=
. + ["terrible."]
jqにはライブラリ(モジュール)システムがあります。
モジュールファイルの拡張子は.jq
です。
プログラムの取り込むモジュールは初期探索パス(後述します)から探索します。
import
命令とinclude
命令は探索パスを変更できます。
探索パスから発見したパスはさまざまな置換の対象になります。
パスが"~/"から開始するときは、"~"をユーザーのホームディレクトリへ置換します。
パスが"$ORIGIN/"から開始するときは、"$ORIGIN"はjqコマンドの配置されたパスへ置換します。
パスが"./"から開始するときは、"."はそのモジュールを取り込んでいるファイルの配置されたパスへ置換します。 プログラムをコマンドラインで指定したときは、jqコマンドを実行したディレクトリへ置換します。
import
命令には初期探索パスに追加する探索パスを指定できます。
初期探索パスはコマンドラインオプションの-L
で指定できます。
指定しなかったときは["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]
になります。
探索パスについてモジュールを探索しているとき、nullや空文字列に到達したら探索は中止します。
"foo/bar"のように相対パスで記述された依存モジュールは、探索パスから"foo/bar.jq"および"foo/bar/bar.jq"を探索します。 これは、バージョン管理システムのファイルやREADMEファイルと共にディレクトリとしてモジュールを配置したり、単独のファイルとして配置するための機能です。
曖昧さを回避するため、"foo/foo"のように同じ名前が繰り返し登場するコンポーネント名は利用できません。
つまり探索パスを-L$HOME/.jq
としたとき、モジュールfoo
は$HOME/.jq/foo.jq
か$HOME/.jq/foo/foo.jq
のいずれかになります。
"$HOME/.jq"がファイルならメインプログラムへ取り込みます。
import RelativePathString as NAME [<metadata>];
相対パスで指定したモジュールを探索パスから探索し、発見したモジュールを取り込みます。 探索中に相対パスへ拡張子".jq"を追加する場合もあります。 モジュールのシンボルには接頭辞"NAME::"がつきます。
任意指定可能なメタデータは定数のjq式でなければなりません。
"homepage"などのキーからなるオブジェクトにするべきです。
現在のjqはメタデータの含むキー"search"の値だけを利用します。
モジュールの利用者は組み込み関数modulemeta
でメタデータへアクセスできます。
メタデータにキー"search"があるとして、その値は文字列あるいは文字列の配列でなければなりません。 指定された探索パスは、探索時にトップレベル探索パスからの相対パスとして解決します。
include RelativePathString [<metadata>];
相対パスで指定したモジュールを探索パスから探索し、発見したモジュールを今のコンテキストへ取り込みます。 探索中に相対パスへ拡張子".jq"を追加する場合もあります。 モジュールのシンボルは呼び出し側の名前空間に取り込まれます。
任意指定可能なメタデータは定数のjq式でなければなりません。
"homepage"などのキーからなるオブジェクトにするべきです。
現在のjqはメタデータの含むキー"search"の値だけを利用します。
モジュールの利用者は組み込み関数modulemeta
でメタデータへアクセスできます。
import RelativePathString as $NAME [<metadata>];
相対パスで指定したJSONファイルを探索パスから探索し、発見したJSONファイルを取り込みます。
探索中に相対パスへ拡張子".json"を追加する場合もあります。
ファイルの内容は$NAME::NAME
のように参照できるようになります。
任意指定可能なメタデータは定数のjq式でなければなりません。
"homepage"などのキーからなるオブジェクトにするべきです。
現在のjqはメタデータの含むキー"search"の値だけを利用します。
モジュールの利用者は組み込み関数modulemeta
でメタデータへアクセスできます。
メタデータにキー"search"があるとして、その値は文字列あるいは文字列の配列でなければなりません。 指定された探索パスは、探索時にトップレベル探索パスからの相対パスとして解決します。
module <metadata>;
完全に任意な命令です。
正常な操作に必要な命令ではありません。
組み込み関数modulemeta
が読み取るメタデータを提供するのが目的です。
メタデータは定数のjq式でなければなりません。
"homepage"などのキーからなるオブジェクトにするべきです。
現在のjqはメタデータの含むキー"search"の値だけを利用します。
モジュールの利用者は組み込み関数modulemeta
でメタデータへアクセスできます。
modulemeta
入力したモジュール名に対するモジュールのメタデータをオブジェクトとして出力します。 キー"deps"には、指定したモジュールが取り込んでいるモジュールをメタデータと共に配列で出力します。
プログラムはこの組み込み関数でモジュールのメタデータを取得できます。 取得したメタデータから存在しない依存モジュールを検索したり、ダウンロードしたり、インストールすることができるでしょう。
別の設定で色付けするには、環境変数JQ_COLORS
にコロン(U+003a)を区切り文字として端末制御文字を記述します。
指定する順序は次のとおりです。
null
false
true
デフォルトのカラースキーマと同じ設定は"JQ_COLORS=1;30:0;37:0;37:0;37:0;32:1;37:1;37"
です。
ここではVT100/ANSIエスケープについて解説しません。 とはいえそれぞれの色定義はセミコロン(U+003b)で区切られた2つの数値で構成されています。 最初の数値は次のいずれかになります。
2番目の数値は次のいずれかになります。