やりたいこと
jq で以下のような JSON を入力として、
{"id":5}
{"id":2}
{"id":1}
{"id":4}
{"id":3}
特定のキーの値 (この場合は id
) でソートして出力したい。
{"id":1}
{"id":2}
{"id":3}
{"id":4}
{"id":5}
結論
$ jq 'sort_by(.id) | .[]' --slurp input.json
以下、やっていることの詳細を説明します。
sort_by
ソートについて jq のマニュアルを調べると、 sort_by
という関数が見つかります。
sort, sort_by(path_expression)
しかしこれは、今回やりたいことと微妙に異なるものです。
sort
や sort_by
は Array
を入出力にするもので、たとえば以下のようにしてもエラーになります。
$ jq 'sort_by(.id)' input.json
jq: error: Cannot index number with string
jq: error: object and array cannot be sorted, as they are not both arrays
...
jq
では連続する JSON をストリームのように受け取れますが、これはあくまでストリームであって Array
ではありません。
とはいえ、これを Array
に変換することができれば sort_by
が使えそうです。
--slurp
コマンドラインオプションの --slurp
がまさに連続する JSON を Array
にするためのものです。
つまり、通常以下のようになる入力であれば、
$ jq '.' input.json
{"id":5}
{"id":2}
{"id":1}
{"id":4}
{"id":3}
--slurp
をつけると以下のようになります。
$ jq '.' --slurp input.json
[
{"id":5},
{"id":2},
{"id":1},
{"id":4},
{"id":3}
]
※一部インデントを調整しています。
というわけで連続する JSON を Array
にすることができたので、あとはこれを sort_by
すればよいことになります。
出力が Array
にくるまれてほしくないのであれば、さらに | .[]
にパイプして Array
の皮をむいて完成です。
おまけ: jr ならもっと直感的にできるよ
拙作の jr
であれば、より直感的に書くことが可能です。
$ jr 'sort_by(&:id)' input.json
--slurp
オプション無しでできました。
(そもそも --slurp
オプション自体ないんですが)
jr
では連続する JSON を Enumerable
として受け取るので、Enumerable
が持つメソッドなら何でも適用することができます。
普段から Ruby を書いているかたであればオススメです。