nikkie-ftnextの日記

イベントレポートや読書メモを発信

JSON Linesをjqコマンドで扱う方法、『jqハンドブック』で完全に理解した!

※ダニング・クルーガー効果の最初の山の状態です。おそらく近い未来に「何も分からない…」となるでしょう!

はじめに

2021年、大変お世話になりました。nikkieです。

2021年、PyCon JP最優先で来たため、アウトプットが著しく衰えています。
少しずつでもリハビリしていこうと、小さくアウトプットです。
今回は、最近インプットしたjqコマンドについてです。

目次

前提

タイトルに含まれる2つについて確認しましょう。

JSON Lines

JSONが改行文字で区切られたファイル形式と理解しています。
例えば以下のように、JSON形式の行複数からなるファイルです1example.jsonlと名付けます)。

{"name": "Gilbert", "wins": [["straight", "7♣"], ["one pair", "10♥"]]}
{"name": "May", "wins": []}

詳細が気になる方は、以下をご覧ください。
「Examples」のページには、「Better than CSV」として、表形式のデータを曖昧さなしにちゃんと扱えると記載されています。

『jqハンドブック』

『jqハンドブック』をやっていく会 を知り、「この本、読んでみたい!」と思いました。

なぜ『jqハンドブック』を読みたかったのか?(jqコマンドで何がやりたかったのか?)

JSON Lines形式のファイルは、Pythonjsonlinesというライブラリで普段扱っています。

>>> with jsonlines.open("example.jsonl") as reader:
...   for line in reader:
...     print(line["name"], line["wins"])
...
Gilbert [['straight', '7♣'], ['one pair', '10♥']]
May []

jsonlinesは使いやすいと感じていますし、いくつかのキーをまたがった加工はやはりPythonスクリプトでやりたいです。
ただ、ちょっとした値の取り出しは、「そもそもPythonスクリプトを不要にできるのでは?」と思い付きました。

そこで、『jqハンドブック』でインプットし、ちょっとした値の取り出しをjqコマンドで完結させられるようになろうと取り組みました。

完全に理解した!

以下のようにして(Pythonを書かずに)できました!🙌
jqコマンドの出力をファイルにリダイレクトしておき、それを後続処理に渡すような使い方を想定しています。

# 各行のnameの取り出し
$ jq --raw-output '.name' example.jsonl
Gilbert
May
# JSON Linesに含まれるwinsの取り出し
$ jq --compact-output '.wins[]' example.jsonl
["straight","7♣"]
["one pair","10♥"]

以下を学びました:

  • jqコマンドの第1引数はフィルタ
  • フィルタにおけるイテレータ[]:配列の値の要素それぞれをループ(キー: 値に対しても使え、値のループになる)
  • --raw-output:出力をクォートで囲まない指定
  • --compact-output:縦長ではなく、横長に出力する指定

また、行によってはキーがない場合も、?をフィルタに使うことで、エラーを出さずに処理できます。
この例では2行目の.winsがnullであることによって送出される「Cannot iterate over null」を出ないようにしています。

{"name": "Gilbert", "wins": [["straight", "7♣"], ["one pair", "10♥"]]}
{"name": "May"}
$ jq --compact-output '.wins[]?' example.jsonl
["straight","7♣"]
["one pair","10♥"]

終わりに

恥を忍んで白状すると、jq '.' example.jsonlという使い方しか知らず、整形して表示する目的でしか使えていませんでした。
『jqハンドブック』で少しだけインプットしましたが、これからは文字通りフィルタとしてjqコマンドが使っていけそうでワクワクしています。

jqコマンドもgitコマンドのように、コマンドの仕様は2割程度しか知らなくても、使いたいケースの8割はカバーできそう2という感触を得ました。

動作環境

  • Python 3.9.4
  • jsonlines==3.0.0

  1. 例は https://jsonlines.org/examples/ より

  2. Clean Agile』の第6章の中で登場した「80/20ルール」を思い出しています。「Gitの機能の一部(20%程度)を使えば、ソース管理の日常的なニーズの80%はまかなえる (Kindle の位置No.2778-2779)」