2018年6月28日

はじめまして、湯尾(ゆお)と申します。

初投稿となりますので、簡単に自己紹介させていただきます。
経歴としては、10数年ほどRed Hat系Linuxの構築から運用監視を生業にしておりました。趣味は釣りで、社内の釣り部にも所属しております。今年も日焼けにやられて痛い目を見ています…

さて、早速ですが掲題のgronでjsonの扱いが楽になった、について。
まずはgronの紹介からはじめさせていただきます。

gronはgithubにて公開されているjsonをgrepしやすい形に置き換える(Make JSON greppable!)ツールです。

https://github.com/tomnomnom/gron

また、gronで変換した形式から、json形式に戻すこともできるため情報の切り出しにとても便利なツールとなっています。

インストールもとても簡単で、ダウンロードして解凍したファイルを使うだけ、となります。

ダウンロードしたファイルを解凍
-sh-4.2$ tar zxf gron-linux-386-0.5.2.tgz

解凍後のファイルの権限確認
-sh-4.2$ ls -lh gron
-rwxr-xr-x 1 yuo Domain Users 5.8M Apr 4 19:15 gron

動作確認(バージョン情報表示)
-sh-4.2$ ./gron --version
gron version 0.5.2

あとは上記ファイルをパスが通っているディレクトリ(例:/usr/local/bin)に置くと、より一層便利にご利用いただけます。

さて、続いてはjsonの扱いが楽になった件、どんな点が楽になったかを下記のデータを例にして説明致します。

-sh-4.2$ cat test.txt
[{"Server_A": {"customer": "AAA corp","role": "WEB"},"Server_B": {"customer": "BBB build","role": "e-mail"},"Server_C": {"customer": "CCC games","role": "gaming"},"Server_D": {"customer": "DDD corp","role": "WEB"},"Server_E": {"customer": "EEE corp","role": "e-mail"}}]

上記は成形前のデータとなります。とても人間が読みたくなる代物ではありません。また、grepやsed、awkなどのコマンドで必要な情報を取得するのも、とても難しい状態です。

次に、jqを使って可読性の高いフォーマットに成形したものが下記になります。

-sh-4.2$ cat test.txt | jq .
[
  {
    "Server_A": {
      "customer": "AAA corp",
      "role": "WEB"
  },
    "Server_B": {
      "customer": "BBB build",
      "role": "e-mail"
  },
    "Server_C": {
      "customer": "CCC games",
      "role": "gaming"
  },
    "Server_D": {
      "customer": "DDD corp",
      "role": "WEB"
  },
    "Server_E": {
      "customer": "EEE corp",
      "role": "e-mail"
    }
  }
]

改行とインデントが施されるだけで大幅に読みやすくなりました。
しかし、実際に特定の情報を取得しようとしたときに困るケースがあります。

例えば、上記のデータで「KeyがroleでValueがWEBのオブジェクトだけを取り出したい」となった場合、オブジェクトの配下にroleが置かれているため、まず各オブジェクト名を取得し、そのオブジェクトの中のroleをチェックするという形になると思います。

しかし、gronを通して見てみますと下記の様になります。

-sh-4.2$ cat test.txt | gron 
json = [];
json[0] = {};
json[0].Server_A = {};
json[0].Server_A.customer = "AAA corp";
json[0].Server_A.role = "WEB";
json[0].Server_B = {};
json[0].Server_B.customer = "BBB build";
json[0].Server_B.role = "e-mail";
json[0].Server_C = {};
json[0].Server_C.customer = "CCC games";
json[0].Server_C.role = "gaming";
json[0].Server_D = {};
json[0].Server_D.customer = "DDD corp";
json[0].Server_D.role = "WEB";
json[0].Server_E = {};
json[0].Server_E.customer = "EEE corp";
json[0].Server_E.role = "e-mail";

人間には若干読みにくい形式ではありますが、Valueごとに配列やオブジェクトを1行の階層構造の様にまとめて表記しています。

さて、本題ですが、本家README で宣言されている Make JSON greppable! の言葉通り、gronを通したデータはgrepしやすい形式になっております。極端に言えば、role が WEB である情報だけを取得したい場合は下記の様にするだけでOKです。

-sh-4.2$ cat test.txt | gron |grep WEB
json[0].Server_A.role = "WEB";
json[0].Server_D.role = "WEB";

grepした結果を再度json形式に戻したい場合は次の様にして簡単に戻せます。

-sh-4.2$ cat test.txt | gron |grep WEB | gron --ungron
[
  {
    "Server_A": {
      "role": "WEB"
    },
    "Server_D": {
      "role": "WEB"
    }
  }
]

また、1行にValueまでの情報がまとめられていますので、grepした結果をsedやawkを使って自由に成形できる、というのも(お行儀悪いかもですが)個人的には大変助かっております。

 

APIを使って取得したjson形式のデータを取り扱おう、とした時にgrepやsed、awkといったサーバエンジニアが普段使いするコマンドと相性が良いとは言えず、jqと繰り返し処理を駆使して必要な情報を取得する… という苦労をした方は少なくないと思います。そういった時に、gronを使えばいつもの調子で抽出や成形ができてしまいます。

本格的にjson形式のデータと向き合うのであれば各種parserを利用するのがベターな方法だとは思います。しかし、Linux操作の延長としてjson形式のデータを扱えるというのは、json形式でデータを提供してくれるAPIなどを扱うことへの障壁を1つ下げることができる、ということにつながるのではないでしょうか。

私的にではありますが「ひとまずやってみる」という気軽さを提供できるのが、gronの素晴らしいところだと感じています。

 

以上、最後までお読みいただきありがとうございました。

本ブログの情報につきましては、自社の検証に基づいた結果からの情報提供であり、
品質保証を目的としたものではございません。

投稿者: Yuo

Red Hat系Linuxを少し使えるbashでスクリプト作るのが好きな生き物。