jqチートシート - JSON処理コマンドラインリファレンス

2026.04.10

公式ドキュメント

この記事の要点

jq '.'でJSON整形、jq '.key'で値抽出が基本
selectで条件フィルタ、mapで一括変換
-rオプションでクォートなしのraw出力(スクリプト連携に必須)

概要

jq は JSON データを変換・抽出するためのコマンドラインツールです。sed や awk が行指向のテキストに対して行う処理を、jq は構造化された JSON に対して行います。HTTP API のレスポンス整形、設定ファイルの加工、ログ解析、CI スクリプトでの値抽出など幅広く使われています。本チートシートは現行版 jq 1.7 系を対象に、よく使う構文と実用レシピを整理します。

基本コマンド

コマンド説明
jq '.' file.json整形表示
cat file.json | jq '.'パイプから読む
curl -s https://api.example.com | jq '.users[0]'API レスポンスから値抽出
jq -n '{a:1, b:2}'入力なしで生成
jq -r '.name' file.jsonraw 出力(クォートなし)

主要オプション

オプション説明
-r, --raw-output文字列を生のテキストとして出力(クォート除去)
-R, --raw-input入力を 1 行ずつ文字列として読む
-s, --slurp入力全体を 1 つの配列として読む
-c, --compact-output1 行コンパクト出力
-n, --null-input入力を読まず null から開始
-a, --ascii-output非 ASCII を \uXXXX でエスケープ
-S, --sort-keysキーをソートして出力
-e, --exit-status出力が null/false なら終了コード 1
--arg name value文字列変数を渡す
--argjson name jsonJSON 変数を渡す
--slurpfile name fileファイルを配列で読み込んで変数化
--rawfile name fileファイルを文字列で読み込んで変数化
-C / -Mカラー / モノクロ強制

ポイント: -r(raw出力)は変数代入時に必須。クォートが残るとシェルスクリプトで予期しない動作になります。

基本フィルタ

説明
.入力そのもの
.fooキー foo の値
.foo.barネストしたキー
.foo?キーがなくてもエラーにしない
.["foo bar"]特殊文字を含むキー
.[0]配列の最初の要素
.[-1]配列の最後の要素
.[2:5]配列スライス
.[]配列・オブジェクトを展開(イテレート)
.foo, .bar複数の値を出力
.foo | .barパイプで連結
(.a + .b)式のグルーピング

値の生成

1, 2, 3              # 3 つの値
"hello"              # 文字列
true, false, null    # 真偽値・null
[1, 2, 3]            # 配列リテラル
{a: 1, b: 2}         # オブジェクトリテラル
{user, id: .uid}     # ショートハンド(user: .user)

実践メモ: .foo?のように?を付けるとキーが存在しなくてもエラーになりません。安全アクセスパターンとして覚えておきましょう。

配列操作

説明
length配列・オブジェクト・文字列の長さ
reverse配列を逆順に
sort昇順ソート
sort_by(.age)キーでソート
unique重複削除+ソート
unique_by(.id)キーで重複削除
min, max最小・最大
min_by(.age), max_by(.age)キーで最小・最大
add要素を全部足す(concat にもなる)
flatten1 段階フラット化
flatten(2)2 段階フラット化
range(N)0..N-1 の数列
range(0;10;2)0..8 を 2 刻み
[.[] | .name]name フィールドの配列を作る
map(.name)上と等価
map_values(. + 1)オブジェクト値に関数適用
select(.age >= 20)条件にマッチする要素のみ
any, all真偽の論理
group_by(.dept)キーでグループ化

オブジェクト操作

説明
keysキー一覧(ソート)
keys_unsortedキー一覧(順序保持)
values値一覧
to_entries[{key,value}, ...] に変換
from_entriesto_entries の逆
with_entries(f)エントリ単位で関数適用
has("key")キーの存在判定
in({a:1})入力がオブジェクトのキーかを判定
del(.foo)キー削除
.foo // "default"null/false ならデフォルト
. + {x: 1}マージ(浅い)
. * {x: 1}再帰マージ

ポイント: selectで条件フィルタ、mapで一括変換、group_byで集計。この3つがデータ加工の三種の神器です。

文字列操作

説明
tostring文字列化
tonumber数値化
ascii_downcase / ascii_upcase大文字小文字変換
ltrimstr("foo") / rtrimstr("bar")接頭・接尾文字列を削除
startswith("a") / endswith("z")接頭・接尾判定
contains("x")部分一致
split(",")文字列を配列に
join(",")配列を文字列に
test("regex")正規表現マッチ判定
match("regex")マッチ情報を返す
capture("(?<n>\\w+)")名前付きキャプチャ
sub("a"; "b")1 回置換
gsub("a"; "b")全置換
\(expr)文字列補間
"User: \(.name) (\(.age))"

数値・型

説明
floor, ceil, round整数化
fabs絶対値
sqrt, pow(x;y)平方根・累乗
type”string”/“number”/“object”/…
isnan, isinfinite特殊値判定
tonumber, tostring型変換

注意: |(パイプ)は値を次のフィルタに流し、,は同じ入力に複数の値を出力します。両者を混同しないように注意しましょう。

制御構文

if .age >= 20 then "adult" else "minor" end

# elif
if .x == 0 then "zero"
elif .x > 0 then "positive"
else "negative"
end

# try / catch
try .a.b.c catch "missing"

# 代入
.user.name = "Alice"          # 上書き
.user.name |= ascii_upcase    # 既存値に関数適用
.tags += ["new"]              # 配列追加
.count += 1                   # 数値加算
.user |= . + {active:true}    # オブジェクト更新

# 削除
del(.user.password)

変数と束縛

. as $root | .users[] | {name, root_id: $root.id}

# 複数値の分解
.coord as [$x, $y] | $x + $y
{a, b} as {a: $a, b: $b} | $a * $b

reduce / foreach

# 配列の合計
reduce .[] as $x (0; . + $x)

# 累積配列
[foreach .[] as $x (0; . + $x; .)]

関数定義

def double: . * 2;
def addn(n): . + n;
def stats: {min: min, max: max, count: length};

[1,2,3] | map(double) | stats

実践メモ: --argで外部値を安全に渡せます。シェル変数をフィルタに直接埋め込むとインジェクションのリスクがあるため、必ず--argを使いましょう。

実用レシピ

1. 配列から特定フィールドだけ抽出

jq '[.users[] | {id, name}]' data.json

2. 条件で絞り込み

jq '.users[] | select(.age >= 20 and .active)' data.json

3. CSV 風出力

jq -r '.users[] | [.id, .name, .email] | @csv' data.json
jq -r '.users[] | [.id, .name] | @tsv' data.json

4. キーをソートして出力

jq -S '.' config.json

5. ネストの深いキーのデフォルト

jq '.user.profile.bio // "no bio"' user.json

6. 環境変数との連携

NAME="Alice" jq --arg name "$NAME" '.users[] | select(.name == $name)' data.json

7. JSON Lines を読む

# 既定で JSON Lines もそのまま読める
cat events.jsonl | jq 'select(.level == "error")'

# 1 配列にまとめる
jq -s '.' events.jsonl > events.json

8. オブジェクトを配列に展開

jq 'to_entries | map({k: .key, v: .value})' map.json

9. 値で集計

jq '[.events[] | .type] | group_by(.) | map({type: .[0], count: length})' data.json

10. ネストしたフィールドを更新

jq '.user.profile.bio = "updated"' user.json
jq '(.users[] | select(.id == 1)).active = false' data.json

11. 複数 JSON をマージ

jq -s '.[0] * .[1]' a.json b.json

12. 配列差分

jq -n --slurpfile a a.json --slurpfile b b.json '$a[0] - $b[0]'

13. キー名の一括変換

jq 'with_entries(.key |= ascii_downcase)' data.json

14. null や空文字を除外

jq '.users | map(select(.email != null and .email != ""))' data.json

15. JSON を Bash 変数に取り込む

NAME=$(jq -r '.user.name' data.json)
mapfile -t IDS < <(jq -r '.users[].id' data.json)

16. curl の API レスポンスから値抜き出し

curl -s https://api.github.com/repos/jqlang/jq | jq -r '.stargazers_count'

17. 配列要素の追加・削除

jq '.tags += ["new-tag"]' data.json
jq '.tags -= ["old-tag"]' data.json
jq 'del(.tags[1])' data.json

18. パスを取得

jq 'paths(scalars)' data.json
jq 'paths(. == "target")' data.json

19. 再帰的に値を探す

jq '.. | objects | select(has("email")) | .email' data.json

20. テンプレ的な文字列生成

jq -r '.users[] | "\(.id),\(.name),\(.email)"' data.json

よく使うフォーマット出力

演算子説明
@text文字列としてそのまま
@jsonJSON 文字列にエンコード
@csvCSV 行(要素は配列)
@tsvTSV 行
@shシェル安全クォート
@base64Base64 エンコード
@base64dBase64 デコード
@uriURI エスケープ
@htmlHTML エスケープ

注意: jqは内部でdoubleを使うため、大きな整数ID(例: Snowflake ID)は精度がロスします。文字列として扱うか、tostringで変換しましょう。

トラブルシューティング

症状原因と対処
Cannot index array with string "foo"配列に対してキー参照している。.[] | .foo のように展開する
null (null) and string ("x") cannot be addednull チェックを // "" で行う
出力にダブルクォートが付く-r を付けて raw 出力にする
複数 JSON を 1 つにまとめたい-s(slurp)で配列化
エラーで終了したい-e で値が null/false の場合に終了コード 1
大きな数値の精度ロスjq は内部で double を使う。整数 ID は文字列で扱う
Bash の $ 展開と競合フィルタを 'シングルクォート' で囲む
Windows で日本語が文字化けchcp 65001 で UTF-8 に切り替え

Tips & ベストプラクティス

  • フィルタは必ずシングルクォートで囲んでシェル展開を防ぐ。
  • 値だけ欲しいときは -r を忘れない(特に変数代入時)。
  • 複数行の複雑なフィルタは def で関数化して読みやすくする。
  • パイプライン | は左から右へ値を流す。, は同じ入力に対して複数の値を出力する。両者を混同しないこと。
  • 安全アクセスは ? を活用する(.a.b?.c?)。
  • スクリプトに埋め込むときは --arg / --argjson で値を渡し、文字列連結による注入を避ける。
  • 集計は group_bymap パターンで簡潔に書ける。
  • フォーマット出力は @csv / @tsv を使えば、エスケープを自分で書く必要がない。
  • 1.7 系では SQL 風の ltrimstr / rtrimstr、改善された I/O オプションが入っている。最新版を使うのが安全。
  • フィルタを試すときは jqplay.org の利用が便利。

さらに進んだ機能

入力ストリーム関数

関数説明
input次の入力を読む
inputs残りすべての入力をストリームで返す
input_filename現在処理中のファイル名
input_line_number入力行番号
debugデバッグメッセージを stderr に出して値を素通し
debug("label")ラベル付きデバッグ
stderrstderr に出力して値を素通し
error("msg")エラーで停止
haltエラーなしで終了
halt_error(N)終了コード N で終了
# 複数 JSON を順に処理
jq -n 'inputs | select(.level == "error")' a.json b.json c.json

# パイプの中間値をデバッグ
jq '.users | map(. | debug("user")) | length' data.json

パスと割り当て

# 値を持つすべてのパスを列挙
[paths]

# スカラー値のパスのみ
[paths(scalars)]

# 特定値を持つパス
[paths(. == "target")]

# パスを使った代入
getpath(["a", "b"])
setpath(["a", "b"]; 42)
delpaths([["a", "b"], ["c"]])

walk 関数

walk(f) でツリー全体を再帰的に変換できます。

# 文字列値を全て大文字に
jq 'walk(if type == "string" then ascii_upcase else . end)' data.json

# null を空文字に置換
jq 'walk(if . == null then "" else . end)' data.json

env と $ENV

HOME_PATH=/srv jq -n '{home: env.HOME_PATH, all: $ENV}'

SQL 風スタイル関数

関数説明
INDEX(.id)id をキーとしたオブジェクトに変換
IN(...)いずれかと等しい
GROUP_BY(.dept)グループ化(group_by のラッパー)
UNIQUE_BY(.id)重複削除
jq '[.users[]] | INDEX(.id)' data.json
# => { "1": {...}, "2": {...} }

モジュール / インポート

jq はライブラリパスからモジュールを読み込めます。~/.jq または -L <path> で指定したディレクトリ配下に .jq ファイルを配置します。

# ~/.jq/lib.jq
def percent(total): . / total * 100;
jq 'import "lib" as lib; .count | lib::percent(100)' data.json

組み込み定義は include で取り込めます。

参考リソース

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

メールで無料相談する
← 一覧に戻る