広告が嫌いですか? 行く 広告なし 今日

jq One-Liners Filter and Transform JSON from the CLI Without Writing a Script

更新日

Seven practical jq recipes for backend devs and DevOps — covering select, map, to_entries, del, group_by, and real-world API reshaping. Input and output shown for every pattern.

jq One-Liners: Filter and Transform JSON from the CLI Without Writing a Script 1

You’re looking at a minified API response in your terminal. You need to extract 3 fields, filter out the nulls, and pipe the result to something else. Writing a Python script for this is 20 lines and 2 minutes you don’t have. jq handles it in one command — if you know the patterns.

Seven recipes below. Each one covers a pattern you’ll hit repeatedly when working with API responses or log files. Input, command, and output shown for every recipe.

Install

brew install jq        # macOS
apt-get install jq     # Ubuntu/Debian
apk add jq             # Alpine (Docker images)

Recipe 1: Extract a Field from Every Object in an Array

The most common thing you’ll do with jq: pull one field from every item in a JSON array.

Input (users.json)

[
  {"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"},
  {"id": 2, "name": "Bob",   "email": "bob@example.com",   "role": "user"},
  {"id": 3, "name": "Carol", "email": "carol@example.com", "role": "user"}
]
jq '.[].name' users.json
# → "Alice"
#   "Bob"
#   "Carol"  (newline-separated stream)

.[] iterates over every element in the array; .name plucks the field. The output is a stream — useful for piping to other commands. If you need a proper JSON array back:

jq 'map(.name)' users.json
# → ["Alice", "Bob", "Carol"]

map(.name) は、以下のプロパティのショートハンドです。 [.[] | .name] — it applies the expression to each item and wraps the results in an array. You’ll use map() a lot.

Recipe 2: Filter with select

Keep only the objects that match a condition; drop the rest.

jq 'map(select(.role == "admin"))' users.json
[
  {"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"}
]

select(expr) passes the item through only when the expression is truthy — everything else disappears. Wrapping it in map() keeps the output as an array. More examples:

# Numeric comparison
jq 'map(select(.score > 80))' results.json

# Not-null check
jq 'map(select(.error != null))' events.json

# String contains (requires test)
jq 'map(select(.message | test("timeout")))' logs.json

Recipe 3: Reshape Objects with map

Pick only the fields you need and optionally rename them in the same pass.

jq 'map({name: .name, role: .role})' users.json
[
  {"name": "Alice", "role": "admin"},
  {"name": "Bob",   "role": "user"},
  {"name": "Carol", "role": "user"}
]

You’re building a new object literal for each item. To rename a key, change the left side of the colon:

jq 'map({username: .name, access_level: .role})' users.json

One shorthand that saves keystrokes: {name} is equivalent to {name: .name}. If you want a field as-is, you don’t have to write the key twice:

jq 'map({id, name, role})' users.json

Recipe 4: Rename Keys with to_entriesfrom_entries

map is good when you know which keys exist. When you need to transform the keys themselves — add a prefix, convert naming conventions, or rename based on a lookup — to_entries is the right pattern.

Input (config.json)

{"api_url": "https://api.example.com", "timeout": 30, "retry_count": 3}
# Add cfg_ prefix to every key
jq 'to_entries | map(.key = "cfg_" + .key) | from_entries' config.json
{"cfg_api_url": "https://api.example.com", "cfg_timeout": 30, "cfg_retry_count": 3}

to_entries turns {"k": "v"} の中へ [{"key": "k", "value": "v"}]. After you mutate the entries in the resulting array, from_entries reconstructs the object. To rename one specific key without touching the others:

jq 'to_entries | map(if .key == "api_url" then .key = "endpoint" else . end) | from_entries' config.json

Recipe 5: Strip Fields with del

The inverse of reshaping: keep everything and remove a few specific fields. The main use case is stripping sensitive data before logging or before passing a payload to a third-party service.

jq 'map(del(.email))' users.json
[
  {"id": 1, "name": "Alice", "role": "admin"},
  {"id": 2, "name": "Bob",   "role": "user"},
  {"id": 3, "name": "Carol", "role": "user"}
]

Delete multiple fields at once, or delete nested paths:

# Multiple top-level fields at once
jq 'del(.password, .token, .refresh_token)' user.json

# Nested path
jq 'del(.user.internal_id)' response.json

# All fields named "debug" at any depth (recursive descent)
jq 'del(.. | .debug? // empty)' response.json

Recipe 6: Filter, Reshape, and Sort in One Pass

The real payoff is chaining these primitives. Here’s a pattern that shows up constantly when working with paginated API responses: descend into a nested array, filter it, reshape the objects, and sort the result.

Input (repos.json)

{
  "total_count": 3,
  "items": [
    {"id": 1, "name": "repo-alpha", "stargazers_count": 142, "language": "Go",     "private": false},
    {"id": 2, "name": "repo-beta",  "stargazers_count": 89,  "language": "Python", "private": true},
    {"id": 3, "name": "repo-gamma", "stargazers_count": 310, "language": "Go",     "private": false}
  ]
}
jq '.items
  | map(select(.private == false and .language == "Go"))
  | sort_by(-.stargazers_count)
  | map({name, stars: .stargazers_count})' repos.json
[
  {"name": "repo-gamma", "stars": 310},
  {"name": "repo-alpha", "stars": 142}
]

The pipeline:

  • .items — descend into the nested array
  • map(select(...)) — filter in a single pass; and chains conditions
  • sort_by(-.stargazers_count) — negate the value for descending sort; sort_by(.field) alone gives ascending
  • map({name, stars: .stargazers_count}) — final reshape; {name} は、以下のプロパティのショートハンドです。 {name: .name}

Recipe 7: Count Log Levels with group_by

Frequency analysis on structured log output — no database needed, no awk gymnastics.

Input (logs.json)

[
  {"level": "error", "msg": "connection timeout",     "service": "auth"},
  {"level": "info",  "msg": "request received",       "service": "api"},
  {"level": "error", "msg": "null pointer exception", "service": "worker"},
  {"level": "warn",  "msg": "slow query detected",    "service": "db"},
  {"level": "error", "msg": "rate limit exceeded",    "service": "api"}
]
jq 'group_by(.level) | map({level: .[0].level, count: length}) | sort_by(-.count)' logs.json
[
  {"level": "error", "count": 3},
  {"level": "info",  "count": 1},
  {"level": "warn",  "count": 1}
]

group_by(.level) returns an array of arrays — each sub-array holds all entries that share the same level value. .[0].level grabs the level name from the first item in the group; length counts how many entries are in the group.

Add a per-service breakdown in the same query:

jq 'group_by(.level) | map({
  level:    .[0].level,
  count:    length,
  services: map(.service) | unique
})' logs.json

速携帯用参考

The patterns above in table form for when you need a quick reminder:

What you wantjq expression
All values of a fieldmap(.field)
Filter matching itemsmap(select(.field == "val"))
Reshape each objectmap({newKey: .oldKey})
Rename all keysto_entries | map(.key = ...) | from_entries
Remove fieldsmap(del(.field1, .field2))
Sort ascendingsort_by(.field)
Sort descendingsort_by(-.field)
Count by groupgroup_by(.field) | map({key: .[0].field, count: length})
Get all keys of an objectkeys
Count items in arraylength
Unique values of a fieldmap(.field) | unique

Before You Start: Tame the Blob

API responses often come back minified or deeply nested. If you’re not sure of the path you need, paste the JSON into the JSONフォーマッタ — it pretty-prints with collapsible nodes so you can spot the path before writing the jq expression. After running a transformation, the JSON比較 tool is useful for verifying the before/after diff when you’re reshaping or stripping fields and want to confirm nothing unexpected changed.

These seven patterns cover the bulk of JSON wrangling you’ll do at the command line. The real power is chaining them — once you can filter, reshape, and sort, you can process most API responses without touching a script file.

広告なしで楽しみたいですか? 今すぐ広告なしで

拡張機能をインストールする

お気に入りのブラウザにIOツールを追加して、すぐにアクセスし、検索を高速化します。

に追加 Chrome拡張機能 に追加 エッジ拡張 に追加 Firefox 拡張機能 に追加 Opera 拡張機能

スコアボードが到着しました!

スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!

ニュースコーナー 技術ハイライト付き

参加する

価値ある無料ツールの提供を継続するためにご協力ください

コーヒーを買って