2018-11-13

jq -cとawkでndjsonを本来のJSONにする

[追記] 予想通り、このスクリプトは不要でした!

| jq <filter> | jq -s

でイケます! ポイントは jq と jq -s を分けること! jq -s はレコード指向ではなく全体をまるっと扱うオプションなんだけど、おかげで filter の指定方法が変わってしまう。しかし「抽出、加工」と「整形」を分けてしまうことでその問題も解決できちゃう。

さすがっす…。


改めてまとめると、jq の出力だけに注目すると

default謎の format
-cndjson
-sいわゆるJSON

ただし、-s オプションは filter の動作も変わってしまうので、

jq <filter> | jq -s

で出力するとよい。


以下は要らんドヤりでっす!

jq は JSON の中から欲しいデータを抽出したりできる便利なコマンドなんだけど、そのまま出力すると NDJSON ( Newline Delimitted JSON ) のようなものになる。

{
  "key": "value"
}
{
  "key2": 2
}
{
  "key": null
}

このように Array を意味する "[" "]" もその区切りの "," もない形になってしまう。

ndjson

正確には1行1レコードじゃないので NDJSON とも呼べなくて、こういう微妙なフォーマットをデフォルトにされると他のツールと互換性がなくなってしまうので嬉しくない。

そこでいわゆる本来の JSON にしたい場合はちょっと工夫が必要になる。

※ もしかしたら jq 自身にそういうオプションがあるかもしれないので、その場合は以下のコードは無駄です。

jq には -c オプションがあるので、これを使って出力すると余計な改行などがカットされて正しく NDJSON になる。そのうえで、こんな awk スクリプトを用意して、

#! /usr/bin/awk -f

BEGIN {
    print "["
}

{
    if ( last_line ) { print last_line  "," }
    last_line = $0
}

END {
    print last_line
    print "]"
}

以下のように

| jq -c <filter> | awk -f nd2purejson.awk

みたいなことをして各行のお尻に "," を付加して [ と ] で挟んでやれば ok.

awk はこんな風に面倒なロジックを考えずにちょっとした工夫で加工が済んじゃうのがいいんだよねぇ。

今回の工夫は今読み込んだ行を出力するのではなく、さっき読み込んだ行を出力するようにタイミングをずらしてやると、最後の END で自動的に最終行だけ異なる出力にすることができるというもの。これでいわゆる「ケツカンマ」を避けて正しい JSON を作ることができる。

※ 逆に JSON は jq -c . だけで NDJSON になるよという話でもあるんだけど、さすがにこれだけで独立したエントリ書くのははばかられますな。

About

例によって個人のなんちゃらです