woshidan's loose leaf

ぼんやり勉強しています

整形されたJSON文字列を見たい時、minifyしたい時、jqコマンドがとても便利だったという話

昨日頑張って sed をかじったため

sed -e '1,10s/\([}\]]\),/\1,\
/g' -e '1,10s/:{/&\
  /g' -e '1,10s/e,/&,\
  /g' test.json 

みたいな涙ぐましい事してたんですが、検索してたら jq ってコマンドで簡単にできるらしいです。

まずは単に整形する

例えばこんなminifyされたJSONがあったとして

{"photo":{"taken_at":1506609841,"created_at":1504609841,"title":"さっちゃん"}}

これをこうじゃ。

$ echo '{"photo":{"taken_at":1506609841,"created_at":1504609841,"title":"さっちゃん"}}' | jq .
{
  "photo": {
    "taken_at": 1506609841,
    "created_at": 1504609841,
    "title": "さっちゃん"
  }
}

この標準出力をファイルへリダイレクトする事で、整形されたJSON文字列をファイルへ書き込むこともできます。

必要な要素だけを取り出してみる

jqコマンドは .キー名 で、そのキーの要素だけを取り出して表示させることが可能です*1

これを利用すると、

$ echo '{"photo":{"taken_at":1506609841,"created_at":1504609841,"title":"さっちゃん"}}' | jq .photo
{
  "taken_at": 1506609841,
  "created_at": 1504609841,
  "title": "さっちゃん"
}

$ echo '{"photo":{"taken_at":1506609841,"created_at":1504609841,"title":"さっちゃん"}}' | jq .photo.title
"さっちゃん"

といったことができます。

配列の中の指定した要素を列挙する

さらに、配列については以下のようなことも可能です。

こういうJSONがあったとして

// sample.json
{
  "order" : {
      "items" : [
          {
            "id": 1,
            "name": "野球ボール",
            "price": 1296,
            "count": 3
          },
          {
            "id": 2,
            "name": "野球バット",
            "price": 1600,
            "count": 1
          }
      ]
  }
}
$ cat sample.json | jq .order.items
[
  {
    "id": 1,
    "name": "野球ボール",
    "price": 1296,
    "count": 3
  },
  {
    "id": 2,
    "name": "野球バット",
    "price": 1600,
    "count": 1
  }
]

// []で出力から配列の[]をはぐ
$ cat sample.json | jq .order.items[]
{
  "id": 1,
  "name": "野球ボール",
  "price": 1296,
  "count": 3
}
{
  "id": 2,
  "name": "野球バット",
  "price": 1600,
  "count": 1
}

// [].キー名で配列の中の要素でそのキーだけを列挙する
$ cat sample.json | jq .order.items[].name
"野球ボール"
"野球バット"

出力から "(ダブルクオート) をはぐ

列挙した要素を他のコマンドの入力にしたい場合など " が邪魔な場合には -r オプションではげます

cat sample.json | jq .order.items[].name -r
野球ボール
野球バット

パイプが利用できる

なんと、 jq の中だけでもパイプを使うことができます。これによって複雑なJSONの整形、要素の抽出や簡単な集計処理が行えます。

$ cat sample.json | jq .order.items[].price | awk '{m+=$1} END{print m;}'
2896

minifyする

-c オプションを利用することで、整形されているJSON文字列をminifyすることも可能です。

$ jq -c . < sample.json
{"order":{"items":[{"id":1,"name":"野球ボール","price":1296,"count":3},{"id":2,"name":"野球バット","price":1600,"count":1}]}}

めっちゃ便利! 現場からは以上です。

なんか awk もやらねばいけないような気がするけど、明日は簡易自作コマンドの話をする。

参考

*1:先ほどの . は全体を表示する、という意味