1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

非JSONの文字列が含まれるファイルに対してjqを使いたい

Last updated at Posted at 2019-09-22

jq は CLI で使用できる JSON processor でみなさんも日々お使いのことと存じます。

問題

jq は標準入力に対して様々なフィルタや加工を行えるわけですが、基本的にはその入力フォーマットが JSON になっていることがベースになります。
このため、以下のように JSON の形ではない行が混ざると、問題になります。

{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
hoge
{"level":"info","msg":"hello world","time":"2019-09-01T06:58:28.99333+09:00"}
fuga
{"level":"info","msg":"hello world","time":"2019-09-01T07:03:28.99333+09:00"}

例えば上記のファイルを jq に通すと、エラーになります。

$ cat log.json | jq -c '.'
{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
parse error: Invalid numeric literal at line 3, column 0

最近は標準出力に対して様々なものが混ざってくるので、jq で処理できる行だけを処理し、処理できない行でエラーを起こしたくない。こういうときにどうすれば良いのかという話です。

解法

上記のようなケースにおいては、ぼくは以下のように jq -R 'fromjson?' 一度通すようにしています。


$ cat log.json | jq -cR 'fromjson?'
{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T06:58:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T07:03:28.99333+09:00"}

あとは後段に、jq を含む任意のコマンドをつなげれば良いですね。

解説

まず、-R (--raw-input) を使うことで、input を直接 JSON として parse しないようにし、文字列がそのまま jq のフィルタに渡るようにします。こうすることで、jq の入力処理でエラーになりません。
しかし、フィルタ部に渡るのは文字列ですから、これを JSON 化しなければなりません。これは fromjson で可能です。しかし、fromjson だけだと、JSON でない文字列に対してエラーが発生してしまいます。

$ cat log.json | jq -cR 'fromjson'
{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
jq: error (at <stdin>:2): Invalid numeric literal at EOF at line 1, column 4 (while parsing 'hoge')
{"level":"info","msg":"hello world","time":"2019-09-01T06:58:28.99333+09:00"}
jq: error (at <stdin>:4): Invalid literal at EOF at line 1, column 4 (while parsing 'fuga')
{"level":"info","msg":"hello world","time":"2019-09-01T07:03:28.99333+09:00"}

ここで fromjson の最後に ? を加えます。これは、jq におけるエラー抑制の省略形ですね。

$ cat log.json | jq -cR 'fromjson?'
{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T06:58:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T07:03:28.99333+09:00"}

省略しなければ以下のような形でしょうか。

$ cat log.json | jq -cR 'try fromjson?'
{"level":"info","msg":"hello world","time":"2019-09-01T07:01:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T06:58:28.99333+09:00"}
{"level":"info","msg":"hello world","time":"2019-09-01T07:03:28.99333+09:00"}
1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?