やりたかったこと

curlでAPIを叩いてJSONのレスポンスを確認しようとしたら、出力が1行に詰まっていて全く読めなかった。 python3 -m json.tool で整形しようとしたが、Pythonが入っていないサーバーだったので jq を使うことにした。

環境

  • Ubuntu 22.04
  • jq 1.6
  • bash 5.1

jqのインストール

# Ubuntu / Debian
sudo apt install jq

# macOS
brew install jq

インストール確認:

jq --version
# jq-1.6

基本的な使い方

curlのレスポンスを整形するだけなら . を使う:

curl -s https://api.example.com/users | jq '.'

ファイルに保存してある場合:

jq '.' response.json

よく使うフィルタ

特定のキーを取り出す

# {"name": "taro", "age": 30} から name だけ取り出す
echo '{"name": "taro", "age": 30}' | jq '.name'
# "taro"

# クォートを外したい場合は -r オプション
echo '{"name": "taro", "age": 30}' | jq -r '.name'
# taro

配列の操作

# 配列の全要素を展開
echo '[{"id":1},{"id":2}]' | jq '.[]'

# 最初の要素だけ取り出す
echo '[{"id":1},{"id":2}]' | jq '.[0]'

# 配列から特定のキーだけを抽出してリストにする
echo '[{"name":"taro"},{"name":"hanako"}]' | jq '[.[].name]'

ネストしたキーの取り出し

# {"user": {"profile": {"email": "test@example.com"}}}
echo '{"user":{"profile":{"email":"test@example.com"}}}' | jq '.user.profile.email'
# "test@example.com"

select でフィルタリング

# ageが30以上の要素だけ取り出す
echo '[{"name":"taro","age":30},{"name":"hanako","age":25}]' | jq '[.[] | select(.age >= 30)]'

複数キーを組み合わせて出力

echo '[{"name":"taro","age":30}]' | jq '.[] | {user: .name, years: .age}'

試したこと・うまくいかなかったこと

最初は grep で必要なフィールドだけ取り出そうとしていたが、JSONが複数行にわたると全然うまくいかなかった。 grep '"name"' と打っても、値が次の行にあるケースで拾えなくて諦めた。

次に awk で区切ろうとしたが、JSONはネストがあるのでawkでパースするのは限界があった。 python3 -c "import json,sys;..." のワンライナーも試したが、毎回書くのが面倒すぎた。

解決策

jq をインストールして使ったら一発で解決した。 curlとパイプでつなぐだけで整形・抽出ができるので、それ以来APIデバッグはほぼ全部jqでやるようになった。

curl -s https://api.example.com/users/1 | jq '.name'

ハマったポイント

  • .name と書くと値にダブルクォートがついてくる。シェルスクリプトで変数に入れたい時は -r オプションが必要なのを最初は知らなかった
  • 配列を展開する .[].[0] の違いを最初は混同していた。.[] は全要素をバラバラに出力し、.[0] は先頭1件だけを返す
  • select() の中で文字列比較するとき == "value" の形にする必要があって、最初は = "value" と書いてエラーが出続けた
  • jqフィルタをシェルスクリプトに書くとき、シングルクォートで囲まないとbashが $| を展開してしまう

関連記事

おすすめのVPS/ドメイン/スクール

VPSを使って本番環境を構築するなら、以下のサービスがおすすめです。