jq 入門:コマンドラインで JSON を自在に操る
よるほろぐ編集部
API のレスポンスや設定ファイルを眺めていると、JSON をターミナル上でサクッと加工したくなる場面が頻繁にあります。python3 -m json.tool で整形はできても、特定フィールドの抽出や配列のフィルタリングとなると途端に手間がかかります。
そこで便利なのが jq です。jq は JSON を入力として受け取り、フィルタを適用して変換・抽出・整形した結果を出力するコマンドラインプロセッサです。curl と組み合わせて API レスポンスから必要なフィールドだけ抜き出す、JSON のログファイルを集計する、といった用途で広く使われています。
jq のプログラムは「フィルタ」です。フィルタは入力を受け取って出力を生成します。単純な . (ドット)から始まり、フィルタ同士を | でつないでパイプラインを構成するのが基本的な使い方です。
インストール
主要なパッケージマネージャで配布されているため、環境を問わずすぐに使えます。
# Debian/Ubuntu
sudo apt install jq
# Fedora/RHEL/AlmaLinux
sudo dnf install jq
# macOS (Homebrew)
brew install jq
インストール後、バージョンを確認しておきましょう。
jq --version
# jq-1.7.1 など
基本:JSON を整形する
jq の最もシンプルな使い方は、JSON の 整形(pretty-print) です。jq '.' に JSON を渡すだけで、インデント付きの読みやすい形式に変換されます。
echo '{"name":"Alice","age":30,"active":true}' | jq '.'
{
"name": "Alice",
"age": 30,
"active": true
}
. は「identity(恒等)フィルタ」と呼ばれ、入力をそのまま出力します。jq はデフォルトで pretty-print するため、生の JSON を整形するだけでもすぐ役立ちます。
フィールドの取得
オブジェクトのフィールド .key
.foo の形でオブジェクトの特定フィールドを取り出せます。キーが存在しない場合は null が返ります。
echo '{"name":"Alice","age":30}' | jq '.name'
"Alice"
ネストしたフィールドは .a.b で辿れます。
echo '{"user":{"name":"Alice","city":"Tokyo"}}' | jq '.user.city'
"Tokyo"
配列のインデックス .[N]
配列は .[0] で先頭、.[-1] で末尾の要素を取得できます。
echo '["apple","banana","cherry"]' | jq '.[1]'
"banana"
配列の全要素 .[]
.[] は配列の全要素を 個別に 出力するイテレータです。
echo '[{"name":"Alice"},{"name":"Bob"}]' | jq '.[]'
{"name": "Alice"}
{"name": "Bob"}
配列の各要素からフィールドを取り出したいときは .array[].field と書けます。
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | jq '.[].name'
"Alice"
"Bob"
.[] は複数の値を別々のアウトプットとして出力します。[.[] ] のように [ ] で囲うと配列として収集できます。一方 .[0] は最初の 1 要素のみを返します。フィルタをつないだときの挙動に影響するので意識しておきましょう。
フィルタとパイプ |
jq 内でも Unix シェルと同様に | でフィルタをつなげます。左のフィルタの出力が右のフィルタの入力になります。
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | jq '.[] | .name'
"Alice"
"Bob"
.[] | .name は「配列の各要素を展開して、それぞれの .name を取り出す」というパイプラインです。
複数フィールドを同時に取り出したいときはカンマで並べます。
echo '{"name":"Alice","age":30,"city":"Tokyo"}' | jq '.name, .age'
"Alice"
30
配列操作
map(f) — 全要素に変換を適用
map(f) は配列の各要素にフィルタ f を適用し、結果を配列として返します。[.[] | f] と同義です。
echo '[1,2,3,4,5]' | jq 'map(. * 2)'
[2, 4, 6, 8, 10]
select(f) — 条件で絞り込む
select(f) は f が真のときだけ入力を通過させます。map() と組み合わせて配列のフィルタリングに使います。
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
| jq 'map(select(.age >= 20))'
[
{"name": "Alice", "age": 30},
{"name": "Carol", "age": 25}
]
length — 長さ・要素数
配列なら要素数、文字列なら文字数、オブジェクトならキー数を返します。
echo '[1,2,3,4,5]' | jq 'length'
5
sort_by(f) — フィールドでソート
sort_by(.field) で配列を特定フィールドの値順に並べ替えます。
echo '[{"name":"Carol","age":25},{"name":"Alice","age":30},{"name":"Bob","age":17}]' \
| jq 'sort_by(.age)'
[
{"name": "Bob", "age": 17},
{"name": "Carol", "age": 25},
{"name": "Alice", "age": 30}
]
unique / unique_by(f) — 重複除去
unique は配列の重複要素を除いてソートした配列を返します。
echo '[3,1,2,1,3,2]' | jq 'unique'
[1, 2, 3]
group_by(f) — グルーピング
group_by(.field) は配列を指定フィールドの値でグループ化し、2次元配列として返します。
echo '[{"type":"A","val":1},{"type":"B","val":2},{"type":"A","val":3}]' \
| jq 'group_by(.type)'
[
[{"type": "A", "val": 1}, {"type": "A", "val": 3}],
[{"type": "B", "val": 2}]
]
add — 要素の集約
add は配列の要素を足し合わせます。数値なら合計、文字列なら連結、配列なら結合です。
echo '[1,2,3,4,5]' | jq 'add'
15
オブジェクトの構築と変換
新しいオブジェクトを作る {key: expr}
{} 構文で必要なフィールドだけを抽出した新しいオブジェクトを作れます。
echo '{"id":1,"name":"Alice","email":"alice@example.com","age":30}' \
| jq '{name: .name, email: .email}'
{
"name": "Alice",
"email": "alice@example.com"
}
キー名と参照フィールド名が同じなら {name, email} と短縮できます。
パイプで複数変換
パイプとオブジェクト構築を組み合わせると、配列の各要素を変換した新しい配列を作れます。
echo '[{"id":1,"name":"Alice","score":85},{"id":2,"name":"Bob","score":72}]' \
| jq 'map({name, passed: (.score >= 80)})'
[
{"name": "Alice", "passed": true},
{"name": "Bob", "passed": false}
]
to_entries / from_entries
to_entries はオブジェクトを {"key": k, "value": v} の配列に変換します。from_entries は逆変換です。キーや値を操作したいときに便利です。
echo '{"a":1,"b":2,"c":3}' | jq 'to_entries'
[
{"key": "a", "value": 1},
{"key": "b", "value": 2},
{"key": "c", "value": 3}
]
値を一律加工して戻す例:
echo '{"a":1,"b":2,"c":3}' | jq 'to_entries | map(.value *= 10) | from_entries'
{"a": 10, "b": 20, "c": 30}
よく使うオプション早見表
| オプション | 短縮形 | 意味 |
|---|---|---|
--raw-output | -r | 文字列をクォートなしで出力する |
--compact-output | -c | 1行のコンパクト形式で出力する |
--slurp | -s | 複数の JSON 入力を配列として読み込む |
--null-input | -n | 入力を読まず null をインプットとする |
--arg name val | — | 文字列変数 $name を定義する |
--argjson name val | — | JSON 値の変数 $name を定義する |
--exit-status | -e | 最後の出力が false/null なら exit 1 |
--sort-keys | -S | オブジェクトのキーをソートして出力する |
-r(raw output)
デフォルトでは文字列はダブルクォートで囲まれた JSON 形式で出力されます。シェルスクリプトで変数に代入するなど、クォートが不要な場合は -r を付けます。
echo '{"name":"Alice"}' | jq '.name'
# → "Alice" ← クォートあり
echo '{"name":"Alice"}' | jq -r '.name'
# → Alice ← クォートなし
シェルスクリプトで NAME=$(jq '.name' data.json) とすると NAME の値は "Alice" (クォート込み)になります。後続のコマンドに渡すと意図しない動作になることがあります。文字列を取り出す場合は -r を付けることを習慣にしましょう。
-c(compact output)
改行・インデントを省いた 1 行形式で出力します。ログとして記録したいときや、次のコマンドに渡したいときに使います。
echo '{"name":"Alice","age":30}' | jq -c '.'
# → {"name":"Alice","age":30}
-s(slurp)
複数の JSON を 1 つの配列にまとめて読み込みます。複数のファイルや改行区切りの JSON 行を集計するときに使います。
echo '{"x":1}
{"x":2}
{"x":3}' | jq -s 'map(.x) | add'
# → 6
--arg / --argjson
jq フィルタ内で外部の値を変数として参照したいときに使います。--arg は文字列、--argjson は JSON 値として渡します。
jq --arg user "Alice" '.[] | select(.name == $user)' users.json
jq --argjson min 20 '.[] | select(.age >= $min)' users.json
文字列・データ変換関数
@csv / @tsv — CSV/TSV 形式に変換
配列を CSV または TSV 文字列にフォーマットします。-r と組み合わせて使います。
echo '[["Alice",30,"Tokyo"],["Bob",25,"Osaka"]]' \
| jq -r '.[] | @csv'
"Alice",30,"Tokyo"
"Bob",25,"Osaka"
join(str) — 配列を結合
join(",") で配列要素を区切り文字つなぎにします。
echo '["apple","banana","cherry"]' | jq -r 'join(", ")'
# → apple, banana, cherry
split(str) — 文字列を分割
文字列を区切り文字で分割して配列にします。
echo '"a,b,c"' | jq 'split(",")'
# → ["a","b","c"]
ascii_downcase / ascii_upcase
英字を小文字・大文字に変換します。
echo '"Hello World"' | jq 'ascii_downcase'
# → "hello world"
test(regex) — 正規表現マッチ
文字列が正規表現にマッチするかどうかを真偽値で返します。select() と組み合わせてフィルタリングに使えます。
echo '[{"email":"alice@example.com"},{"email":"bob@test.org"}]' \
| jq 'map(select(.email | test("@example\\.com$")))'
[{"email": "alice@example.com"}]
has(key) — キーの存在確認
オブジェクトが指定のキーを持つかどうかを返します。
echo '{"name":"Alice","age":30}' | jq 'has("age")'
# → true
contains(val) — 包含確認
入力が指定の値を含むかどうかを確認します。文字列ならサブストリング、配列なら要素の包含、オブジェクトならサブセットの確認になります。
echo '{"name":"Alice","tags":["admin","editor"]}' \
| jq 'contains({"tags":["admin"]})'
# → true
実践例
curl で API を叩いて必要なフィールドだけ抽出
GitHub API からリポジトリ情報を取得して、名前と star 数だけ出力する例です。
curl -s "https://api.github.com/users/jqlang/repos" \
| jq '[.[] | {name: .name, stars: .stargazers_count}] | sort_by(-.stars)'
sort_by(-.stars) は負数でソートすることで降順にしています。
JSON 配列を CSV に変換
ユーザーリストの JSON をヘッダ付き CSV に変換します。
echo '[
{"name":"Alice","age":30,"city":"Tokyo"},
{"name":"Bob","age":25,"city":"Osaka"}
]' | jq -r '
["name","age","city"],
(.[] | [.name, .age, .city])
| @csv
'
"name","age","city"
"Alice",30,"Tokyo"
"Bob",25,"Osaka"
複数の JSON を集計(slurp)
JSON Lines 形式のログから特定フィールドを集計します。
cat access.log | jq -rs '
map(select(.status >= 400))
| group_by(.status)
| map({status: .[0].status, count: length})
'
-rs は -r(raw output)と -s(slurp)を組み合わせたもので、複数の JSON 行をまとめて読み込みます。
条件フィルタ:特定条件の要素だけ抽出
商品リストから在庫あり(stock > 0)かつ価格が 1000 円以下の商品を名前順で取得します。
echo '[
{"name":"商品A","price":800,"stock":5},
{"name":"商品B","price":1200,"stock":0},
{"name":"商品C","price":500,"stock":10},
{"name":"商品D","price":950,"stock":0}
]' | jq '[.[] | select(.stock > 0 and .price <= 1000)] | sort_by(.name)'
[
{"name": "商品A", "price": 800, "stock": 5},
{"name": "商品C", "price": 500, "stock": 10}
]
jq には公式のオンライン実行環境(https://jqlang.github.io/jq/tutorial/ のページや https://jqplay.org/ など)があります。複雑なフィルタを書くときは先に小さなサンプルで動作確認してから本番データに適用するのが安全です。
フィルタ早見表
よく使うフィルタ・関数をまとめます。
| フィルタ / 関数 | 意味 | 例 |
|---|---|---|
. | 入力をそのまま出力(整形) | jq '.' |
.foo | フィールド取得 | .name |
.a.b | ネストしたフィールド | .user.city |
.[0] | 配列のインデックス | .[0] / .[-1] |
.[] | 配列の全要素を展開 | .[] | .name |
map(f) | 全要素に変換を適用 | map(. * 2) |
select(f) | 条件で絞り込み | map(select(.age >= 20)) |
sort_by(f) | フィールドでソート | sort_by(.name) |
group_by(f) | フィールドでグループ化 | group_by(.type) |
unique | 重複除去 | [.[].tag] | unique |
add | 要素の集約 | map(.score) | add |
length | 要素数・文字数 | .items | length |
to_entries | オブジェクト → key/value 配列 | to_entries | map(.key) |
from_entries | key/value 配列 → オブジェクト | from_entries |
has(key) | キーの存在確認 | has("name") |
contains(b) | 包含確認 | contains({"role":"admin"}) |
test(regex) | 正規表現マッチ | select(.email | test("@example")) |
@csv | CSV 形式に変換 | [.name, .age] | @csv |
@tsv | TSV 形式に変換 | [.name, .age] | @tsv |
join(str) | 配列を文字列に結合 | join(", ") |
split(str) | 文字列を配列に分割 | split(",") |
ascii_downcase | 英字を小文字に | ascii_downcase |
代替ツール
jq の互換ツールとして gojq(Go 実装)があります。jq とほぼ同じ構文で動作し、整数演算の精度が改善されているなどの特徴があります。Go でシングルバイナリとして配布されるため、環境によっては導入しやすいケースもあります。
jq 本体で十分な場合がほとんどですが、長整数を扱う処理で精度の問題に当たったときなどに選択肢として覚えておくとよいでしょう。
まとめ
jq は覚えるフィルタの数こそ多いですが、基本パターンは「. で整形」「.field で抽出」「| map() | select() で変換・絞り込み」の繰り返しです。まず curl のレスポンスを jq に渡して整形することから始め、少しずつフィルタを組み合わせていくと自然と身についていきます。
公式マニュアルは読み物として丁寧に書かれているので、一度通読しておくと引き出しが増えます。
出典
- jq 公式マニュアル(v1.8): https://jqlang.github.io/jq/manual/
- jq GitHub リポジトリ: https://github.com/jqlang/jq