jqの使い方

jqとは、jsonの解析を行うコマンドです。
APIの応答のjsonを解析するのに使うのですが、構文を忘れがちなので、個人的によく使うものだけ、覚え書き的に書き出しています。



サンプルjson

API応答のjsonという形を再現するために、テキストファイルにjson形式でデータを書いたものを用意しました。

# test.json

{
  "title": "User Information",
  "data": [
    {
      "name": "John Doe",
      "age": 30,
      "hobbies": ["football", "reading", "coding"]
    },
    {
      "name": "Jane Doe",
      "age": 28,
      "hobbies": ["painting", "music", "traveling"]
    }
  ]
}


jsonをjqに読み込む

標準出力をパイプで渡します。

cat test.json | jq
cat test.json | jq .
{
  "title": "User Information",
  "data": [
    {
      "name": "John Doe",
      "age": 30,
      "hobbies": [
        "football",
        "reading",
        "coding"
      ]
    },
    {
      "name": "Jane Doe",
      "age": 28,
      "hobbies": [
        "painting",
        "music",
        "traveling"
      ]
    }
  ]
}

元のファイルとほとんど同じですが、値の並べ方や括弧の位置が調整されています。
APIの出力ではjsonなのに1行で表示されてしまう、といった場合に、jqを通すことで表示の整形が可能です。


指定した項目を表示

項目名を書くことで、その項目の値を取り出すことができます。

cat test.json | jq .title
"User Information"


値のダブルクォートを消す

r オプションを付けると、ダブルクォーテーションを消すことができます。
取り出した値を変数に入れて使うときなどに便利です。

cat test.json | jq -r .title
User Information


配列の場合も項目の取り方は同じ

項目の中で値が配列になっていても、項目の取り出し方は変わりません。

cat test.json | jq .data
[
  {
    "name": "John Doe",
    "age": 30,
    "hobbies": [
      "football",
      "reading",
      "coding"
    ]
  },
  {
    "name": "Jane Doe",
    "age": 28,
    "hobbies": [
      "painting",
      "music",
      "traveling"
    ]
  }
]

取り出した値は、配列になっています。


配列内の件数をカウント

取り出した配列の中のデータの数をカウントすることができます。

cat test.json | jq '.data | length'
2


配列の中身を取り出す

取り出した値が配列のときは、その中身を取り出すことができます。
今回のサンプルのように、配列の中にさらにjsonが入っている場合など、さらに解析が必要な場合に役立ちます。

cat test.json | jq .data[]
{
  "name": "John Doe",
  "age": 30,
  "hobbies": [
    "football",
    "reading",
    "coding"
  ]
}
{
  "name": "Jane Doe",
  "age": 28,
  "hobbies": [
    "painting",
    "music",
    "traveling"
  ]
}

配列の中身が取り出されて、2件のデータが列挙された状態になりました。


配列なので、何番目か指定して値を取り出すこともできます。
[0] で先頭のデータが取り出されます。

cat test.json | jq .data[0]
{
  "name": "John Doe",
  "age": 30,
  "hobbies": [
    "football",
    "reading",
    "coding"
  ]
}
cat test.json | jq .data[1]
{
  "name": "Jane Doe",
  "age": 28,
  "hobbies": [
    "painting",
    "music",
    "traveling"
  ]
}


配列内のjson項目を取り出す

配列内のjsonにある項目を指定して、その値を取り出すことができます。

cat test.json | jq .data[].age
30
28

配列に入っていたうちの、どのデータなのか絞り込まれていない場合は、全て取り出されます。


数値の合計を表示

取り出した値が数値の場合、その合計値を計算することができます。

cat test.json | jq .data[].age | jq -s add
58

今回のサンプルでは年齢を合計しているので、あまり意味はありませんが、最終的に合計値を算出したいデータの場合、他のコマンドを使わずに完結することができます。


特定のデータのみを抽出

条件を設定して、それを満たすデータのみを抽出することができます。
今回のサンプルでは、趣味に音楽がある人のみを抽出しています。

cat test.json | jq .data[] | jq 'select(.hobbies[] | contains("music"))'
{
  "name": "Jane Doe",
  "age": 28,
  "hobbies": [
    "painting",
    "music",
    "traveling"
  ]
}

指定どおり、hobbiesの配列内にmusicという文字列のある人のデータだけが抽出されました。


jqの中でパイプすることも可能

ここまでの例では基本的に、jqの結果をjqにパイプしていましたが、jqの中でパイプすることが可能です。
どちらの書き方でも結果は同じですが、1回のコマンドにまとめようとすればするほど、括弧やクォートの扱いが煩雑になっていきます。

cat test.json | jq '.data[] | select(.hobbies[] | contains("music"))'
{
  "name": "Jane Doe",
  "age": 28,
  "hobbies": [
    "painting",
    "music",
    "traveling"
  ]
}


抽出した結果から、指定の項目のみを表示

抽出結果がjsonなら、そこからさらにjqの処理をかけることができます。
サンプルから、趣味に音楽がある人のみを抽出して、その人の名前のみを表示させます。

cat test.json | jq '.data[] | select(.hobbies[] | contains("music")) | .name'
"Jane Doe"

このようにすることで、特定の条件に当てはまるデータ内の必要項目のみを取り出す、といった使い方ができます。


二つの項目を表示

ここまでの例では、1つの項目だけを取り出してきましたが、複数の項目を指定することも可能です。

cat test.json | jq .data[] | jq '.name, .age'
cat test.json | jq '.data[] | .name, .age'
"John Doe"
30
"Jane Doe"
28

配列内の全データから、名前と年齢を取り出すことができました。


最後に

jqにはもっといろいろな機能がありますが、ここに書いたものだけでも、だいぶいろいろな分析ができます。

APIを叩くとjsonで返るからjqで何とかしないと、と頭を悩ませることが多かったのですが、何とか取り組んだおかげで、jqやjsonだけでなく、配列についても理解を深められてよかったです。


この記事が気に入ったらサポートをしてみませんか?