jq 是一个轻量级、灵活的命令行 JSON 处理器,已经成为每个与 API、配置文件或日志数据打交道的开发者不可或缺的工具。这份全面的教程涵盖了从基本过滤器到高级数据转换的 jq 命令示例,帮助你掌握终端中的 JSON 处理。
使用我们的在线 JSON 格式化工具格式化和查看 JSON →
1. 什么是 jq?
jq 就像 JSON 数据的 sed —— 一个命令行工具,让你可以轻松地切片、过滤、映射和转换结构化数据。它用 C 语言编写,零运行时依赖,因此在所有主要平台上都快速且可移植。
jq 接受 JSON 输入(来自文件或标准输入),应用一个或多个过滤器,并产生 JSON 输出。它的表达式语言强大而简洁,允许在单个命令中完成复杂的数据转换。
安装
在任何平台上几秒内安装 jq:
# Ubuntu / Debian
sudo apt-get install jq
# macOS (Homebrew)
brew install jq
# Windows (Chocolatey)
choco install jq
# Windows (Scoop)
scoop install jq
# Alpine Linux
apk add jq
# From source / binary
# Download from https://jqlang.github.io/jq/download/
wget https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64
chmod +x jq-linux-amd64 && sudo mv jq-linux-amd64 /usr/local/bin/jq
# Verify installation
jq --version基本语法
最简单的 jq 命令是恒等过滤器 .,它会美化打印 JSON 输入:
# Pretty-print JSON (identity filter)
echo '{"name":"Alice","age":30,"skills":["go","rust"]}' | jq '.'
# Output:
# {
# "name": "Alice",
# "age": 30,
# "skills": [
# "go",
# "rust"
# ]
# }
# Read from a file
jq '.' data.json
# Compact output (single line)
jq -c '.' data.json
# Raw string output (no quotes)
echo '{"name":"Alice"}' | jq -r '.name'
# Output: Alice (without quotes)
# Sort keys alphabetically
echo '{"z":1,"a":2,"m":3}' | jq -S '.'2. 基本过滤器
jq 过滤器从 JSON 输入中提取和转换数据。点表示法是 jq 中一切的基础。
Object Field Access
# Sample JSON
# {"name": "Alice", "age": 30, "address": {"city": "NYC", "zip": "10001"}}
# Access a top-level field
echo '{"name":"Alice","age":30}' | jq '.name'
# "Alice"
# Access a nested field
echo '{"address":{"city":"NYC","zip":"10001"}}' | jq '.address.city'
# "NYC"
# Multiple fields (comma-separated)
echo '{"name":"Alice","age":30,"role":"admin"}' | jq '.name, .age'
# "Alice"
# 30
# Optional field access (no error if missing)
echo '{"name":"Alice"}' | jq '.email?'
# null
# Field with special characters (use quotes)
echo '{"my-field": 42}' | jq '.["my-field"]'
# 42Array Access
# Access by index
echo '[10,20,30,40,50]' | jq '.[0]'
# 10
# Negative index (from end)
echo '[10,20,30,40,50]' | jq '.[-1]'
# 50
# Array slice
echo '[10,20,30,40,50]' | jq '.[1:3]'
# [20, 30]
# Slice from start
echo '[10,20,30,40,50]' | jq '.[:2]'
# [10, 20]
# Slice to end
echo '[10,20,30,40,50]' | jq '.[3:]'
# [40, 50]
# Iterate all elements (array value iterator)
echo '[1,2,3]' | jq '.[]'
# 1
# 2
# 3
# Iterate object values
echo '{"a":1,"b":2,"c":3}' | jq '.[]'
# 1
# 2
# 3Constructing New Objects & Arrays
# Build a new object from fields
echo '{"first":"Alice","last":"Smith","age":30}' | jq '{name: .first, years: .age}'
# {"name": "Alice", "years": 30}
# Wrap results in an array
echo '{"a":1,"b":2,"c":3}' | jq '[.a, .b, .c]'
# [1, 2, 3]
# Collect iterator results into an array
echo '[1,2,3,4,5]' | jq '[.[] | . * 2]'
# [2, 4, 6, 8, 10]3. 管道与链接
就像 Unix shell 管道一样,jq 使用 | 将过滤器链接在一起。左侧过滤器的输出成为右侧过滤器的输入。这种可组合性是 jq 如此强大的原因。
# Chain filters with pipe
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' | \
jq '.users[] | .name'
# "Alice"
# "Bob"
# Multiple pipes
echo '{"data":{"items":[{"id":1,"val":"a"},{"id":2,"val":"b"}]}}' | \
jq '.data.items[] | .val'
# "a"
# "b"
# Pipe into object construction
echo '{"users":[{"first":"Alice","last":"Smith"},{"first":"Bob","last":"Jones"}]}' | \
jq '.users[] | {full_name: (.first + " " + .last)}'
# {"full_name": "Alice Smith"}
# {"full_name": "Bob Jones"}
# Pipe with length
echo '{"users":[{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"}]}' | \
jq '.users | length'
# 3
# Pipe with multiple outputs
echo '{"a":{"x":1},"b":{"x":2}}' | jq '.a, .b | .x'
# 1
# 2
# Parentheses for grouping
echo '{"a":1,"b":2}' | jq '(.a + .b) * 2'
# 64. 选择与过滤
select() 函数根据条件过滤元素。与 map() 结合使用,它成为 JSON 数据的强大查询引擎。
# select() - filter by condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
jq '.[] | select(.age > 28)'
# {"name": "Alice", "age": 30}
# {"name": "Charlie", "age": 35}
# map(select()) - filter and keep as array
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
jq 'map(select(.age >= 30))'
# [{"name": "Alice", "age": 30}, {"name": "Charlie", "age": 35}]
# String matching with select
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Anna"}]' | \
jq '.[] | select(.name | startswith("A"))'
# {"name": "Alice"}
# {"name": "Anna"}
# select with contains
echo '[{"tags":["go","api"]},{"tags":["python","ml"]},{"tags":["go","cli"]}]' | \
jq '.[] | select(.tags | contains(["go"]))'
# {"tags": ["go", "api"]}
# {"tags": ["go", "cli"]}
# select with test (regex)
echo '[{"email":"alice@gmail.com"},{"email":"bob@company.org"},{"email":"charlie@gmail.com"}]' | \
jq '.[] | select(.email | test("gmail"))'
# {"email": "alice@gmail.com"}
# {"email": "charlie@gmail.com"}
# has() - check if key exists
echo '{"name":"Alice","email":"alice@example.com"}' | jq 'has("email")'
# true
echo '[{"name":"Alice","email":"a@b.com"},{"name":"Bob"}]' | \
jq '.[] | select(has("email"))'
# {"name": "Alice", "email": "a@b.com"}
# in() - check if key exists in object
echo '{"admin":true,"user":true}' | jq '"admin" | in({"admin":true,"user":true})'
# true
# type checks
echo '[1,"hello",null,true,[],{}]' | jq '.[] | select(type == "string")'
# "hello"
# Negated select (NOT matching)
echo '[{"status":"active"},{"status":"inactive"},{"status":"active"}]' | \
jq '.[] | select(.status != "active")'
# {"status": "inactive"}5. 字符串插值与格式化
jq 在双引号内提供 \(expr) 字符串插值,还有多种格式字符串用于将数据转换为不同的输出格式。
# String interpolation with \()
echo '{"name":"Alice","age":30}' | jq '"\(.name) is \(.age) years old"'
# "Alice is 30 years old"
# Use -r for raw output (no surrounding quotes)
echo '{"name":"Alice","age":30}' | jq -r '"\(.name) is \(.age) years old"'
# Alice is 30 years old
# @text - plain text (default)
echo '"hello"' | jq '@text'
# "hello"
# @html - HTML-escaped
echo '"<script>alert(1)</script>"' | jq '@html'
# "<script>alert(1)</script>"
# @csv - CSV format (use with -r)
echo '["Alice",30,"NYC"]' | jq -r '@csv'
# "Alice",30,"NYC"
# @tsv - Tab-separated values
echo '["Alice",30,"NYC"]' | jq -r '@tsv'
# Alice 30 NYC
# @json - JSON-encode a string
echo '"hello world"' | jq '@json'
# ""hello world""
# @base64 - Base64 encode
echo '"hello world"' | jq '@base64'
# "aGVsbG8gd29ybGQ="
# @base64d - Base64 decode
echo '"aGVsbG8gd29ybGQ="' | jq '@base64d'
# "hello world"
# @uri - URI-encode
echo '"hello world&foo=bar"' | jq '@uri'
# "hello%20world%26foo%3Dbar"
# Combining formats: CSV from array of arrays
echo '[[1,"Alice",30],[2,"Bob",25]]' | jq -r '.[] | @csv'
# 1,"Alice",30
# 2,"Bob",25
# Build formatted table with string interpolation
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
jq -r '.[] | "\(.name)\t\(.age)"'
# Alice 30
# Bob 256. 数组操作
jq 提供了丰富的内置函数来处理数组:排序、分组、过滤、展平等。
# length
echo '[1,2,3,4,5]' | jq 'length'
# 5
# map() - transform each element
echo '[1,2,3,4,5]' | jq 'map(. * 10)'
# [10, 20, 30, 40, 50]
echo '[{"name":"Alice"},{"name":"Bob"}]' | jq 'map(.name)'
# ["Alice", "Bob"]
# sort and sort_by
echo '[3,1,4,1,5,9,2,6]' | jq 'sort'
# [1, 1, 2, 3, 4, 5, 6, 9]
echo '[{"name":"Charlie","age":35},{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
jq 'sort_by(.age)'
# [{"name":"Bob","age":25},{"name":"Alice","age":30},{"name":"Charlie","age":35}]
# Reverse sort
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
jq 'sort_by(.age) | reverse'
# group_by
echo '[{"dept":"eng","name":"Alice"},{"dept":"sales","name":"Bob"},{"dept":"eng","name":"Charlie"}]' | \
jq 'group_by(.dept)'
# [[{"dept":"eng","name":"Alice"},{"dept":"eng","name":"Charlie"}],[{"dept":"sales","name":"Bob"}]]
# unique and unique_by
echo '[1,2,2,3,3,3]' | jq 'unique'
# [1, 2, 3]
echo '[{"city":"NYC"},{"city":"LA"},{"city":"NYC"}]' | jq 'unique_by(.city)'
# [{"city":"LA"},{"city":"NYC"}]
# flatten
echo '[[1,2],[3,[4,5]],6]' | jq 'flatten'
# [1, 2, 3, 4, 5, 6]
# flatten with depth
echo '[[1,[2]],[3,[4,[5]]]]' | jq 'flatten(1)'
# [1, [2], 3, [4, [5]]]
# first, last, nth
echo '[10,20,30,40,50]' | jq 'first'
# 10
echo '[10,20,30,40,50]' | jq 'last'
# 50
# min, max, min_by, max_by
echo '[3,1,4,1,5,9]' | jq 'min'
# 1
echo '[3,1,4,1,5,9]' | jq 'max'
# 9
echo '[{"name":"Alice","score":85},{"name":"Bob","score":92}]' | jq 'max_by(.score)'
# {"name": "Bob", "score": 92}
# add - sum numbers or concatenate arrays/strings
echo '[1,2,3,4,5]' | jq 'add'
# 15
echo '[["a","b"],["c","d"]]' | jq 'add'
# ["a", "b", "c", "d"]
# indices / index
echo '["a","b","c","b","a"]' | jq 'index("b")'
# 1
# limit and until
echo 'null' | jq '[limit(5; range(100))]'
# [0, 1, 2, 3, 4]
# range - generate number sequences
echo 'null' | jq '[range(5)]'
# [0, 1, 2, 3, 4]
echo 'null' | jq '[range(2;8;2)]'
# [2, 4, 6]7. 对象操作
jq 使用 keys、values、to_entries 和 with_entries 等内置函数,可以轻松地检查、转换和重构 JSON 对象。
# keys - get all keys as sorted array
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'keys'
# ["age", "city", "name"]
# keys_unsorted - preserve original order
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'keys_unsorted'
# ["name", "age", "city"]
# values - get all values
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'values'
# ["Alice", 30, "NYC"]
# to_entries - convert to key-value pair array
echo '{"name":"Alice","age":30}' | jq 'to_entries'
# [{"key": "name", "value": "Alice"}, {"key": "age", "value": 30}]
# from_entries - convert key-value pairs back to object
echo '[{"key":"name","value":"Alice"},{"key":"age","value":30}]' | jq 'from_entries'
# {"name": "Alice", "age": 30}
# from_entries also works with "name"/"value" pairs
echo '[{"name":"x","value":1},{"name":"y","value":2}]' | jq 'from_entries'
# {"x": 1, "y": 2}
# with_entries - transform entries (to_entries | map(f) | from_entries)
echo '{"name":"Alice","age":30}' | jq 'with_entries(.key = "prefix_" + .key)'
# {"prefix_name": "Alice", "prefix_age": 30}
# with_entries - filter by key
echo '{"name":"Alice","age":30,"_internal":true}' | \
jq 'with_entries(select(.key | startswith("_") | not))'
# {"name": "Alice", "age": 30}
# Add / merge objects with +
echo '{"a":1,"b":2}' | jq '. + {"c":3,"d":4}'
# {"a": 1, "b": 2, "c": 3, "d": 4}
# Merge with override
echo '{"a":1,"b":2}' | jq '. + {"b":99}'
# {"a": 1, "b": 99}
# * for recursive merge
echo '{"a":{"x":1},"b":2}' | jq '. * {"a":{"y":2}}'
# {"a": {"x": 1, "y": 2}, "b": 2}
# del() - remove a key
echo '{"name":"Alice","age":30,"tmp":true}' | jq 'del(.tmp)'
# {"name": "Alice", "age": 30}
# del() multiple keys
echo '{"a":1,"b":2,"c":3,"d":4}' | jq 'del(.b, .d)'
# {"a": 1, "c": 3}
# Update a field with |=
echo '{"name":"alice","age":30}' | jq '.name |= ascii_upcase'
# {"name": "ALICE", "age": 30}
# Update nested field
echo '{"user":{"name":"Alice","score":85}}' | jq '.user.score |= . + 10'
# {"user": {"name": "Alice", "score": 95}}8. 条件判断与错误处理
jq 支持 if-then-else 表达式、替代运算符 // 和 try-catch,用于构建健壮的数据处理管道。
# if-then-else
echo '{"age":25}' | jq 'if .age >= 18 then "adult" else "minor" end'
# "adult"
# if-then-elif-else
echo '{"score":85}' | jq '
if .score >= 90 then "A"
elif .score >= 80 then "B"
elif .score >= 70 then "C"
else "F"
end'
# "B"
# if-then-else with map
echo '[{"name":"Alice","age":30},{"name":"Bob","age":15}]' | \
jq 'map(if .age >= 18 then . + {"status":"adult"} else . + {"status":"minor"} end)'
# [{"name":"Alice","age":30,"status":"adult"},{"name":"Bob","age":15,"status":"minor"}]
# Alternative operator // (default value if null or false)
echo '{"name":"Alice"}' | jq '.email // "not set"'
# "not set"
echo '{"name":"Alice","email":"alice@example.com"}' | jq '.email // "not set"'
# "alice@example.com"
# Nested alternative
echo '{"config":{}}' | jq '.config.timeout // .config.default_timeout // 30'
# 30
# try-catch (jq 1.6+)
echo '"not a number"' | jq 'try tonumber catch "invalid number"'
# "invalid number"
# try without catch (silently suppress errors)
echo '{"a":1}' | jq 'try .b.c.d'
# (no output, no error)
# try with array of mixed types
echo '[1,"two",3,"four",5]' | jq '[.[] | try (. + 10)]'
# [11, 13, 15]
# Error handling with if and type
echo '{"value":"hello"}' | jq '
if (.value | type) == "number" then .value * 2
else "expected number, got \(.value | type)"
end'
# "expected number, got string"
# empty - produce no output (useful in select-like patterns)
echo '[1,2,3,4,5]' | jq '.[] | if . > 3 then . else empty end'
# 4
# 59. 实战示例
以下是你在日常工作中使用 API、云服务和日志文件时会用到的实用 jq 模式。
Parse GitHub API Responses
# List repos - extract name, stars, and language
curl -s "https://api.github.com/users/torvalds/repos?per_page=5" | \
jq '.[] | {name: .name, stars: .stargazers_count, lang: .language}'
# Find most starred repo
curl -s "https://api.github.com/users/torvalds/repos?per_page=100" | \
jq 'max_by(.stargazers_count) | {name, stars: .stargazers_count}'
# List open issues with labels
curl -s "https://api.github.com/repos/jqlang/jq/issues?state=open&per_page=5" | \
jq '.[] | {title: .title, labels: [.labels[].name], created: .created_at}'
# Count repos by language
curl -s "https://api.github.com/users/octocat/repos" | \
jq 'group_by(.language) | map({lang: .[0].language, count: length}) | sort_by(.count) | reverse'AWS CLI Output Processing
# List EC2 instances - extract ID, type, state
aws ec2 describe-instances | \
jq '.Reservations[].Instances[] | {
id: .InstanceId,
type: .InstanceType,
state: .State.Name,
name: (.Tags // [] | map(select(.Key == "Name")) | first | .Value // "unnamed")
}'
# Find running instances only
aws ec2 describe-instances | \
jq '[.Reservations[].Instances[] | select(.State.Name == "running")] | length'
# List S3 buckets with creation dates
aws s3api list-buckets | \
jq '.Buckets | sort_by(.CreationDate) | .[] | "\(.Name) - \(.CreationDate)"'
# Get Lambda function names and runtimes
aws lambda list-functions | \
jq '.Functions[] | {name: .FunctionName, runtime: .Runtime, memory: .MemorySize}'Log Processing
# Parse JSON log lines (one JSON object per line)
cat app.log | jq -r 'select(.level == "error") | "\(.timestamp) \(.message)"'
# Count errors by type
cat app.log | jq -s 'map(select(.level == "error")) | group_by(.error_code) |
map({code: .[0].error_code, count: length}) | sort_by(.count) | reverse'
# Extract slow requests (>1s)
cat access.log | jq 'select(.response_time_ms > 1000) |
{path: .request_path, time_ms: .response_time_ms, method: .method}'
# Aggregate stats from JSON logs
cat app.log | jq -s '{
total: length,
errors: map(select(.level == "error")) | length,
avg_response_ms: (map(.response_time_ms) | add / length),
unique_users: (map(.user_id) | unique | length)
}'Docker & Kubernetes
# Docker: list containers with ports
docker inspect $(docker ps -q) | \
jq '.[] | {name: .Name, image: .Config.Image, ports: .NetworkSettings.Ports}'
# Docker: get container IP addresses
docker network inspect bridge | \
jq '.[0].Containers | to_entries[] | {name: .value.Name, ip: .value.IPv4Address}'
# Kubernetes: get pod names and status
kubectl get pods -o json | \
jq '.items[] | {name: .metadata.name, status: .status.phase, restarts: (.status.containerStatuses[0].restartCount // 0)}'
# Kubernetes: find pods not in Running state
kubectl get pods -o json | \
jq '[.items[] | select(.status.phase != "Running") | .metadata.name]'10. jq 与 curl 配合使用
curl | jq 管道是 API 开发中最常见的模式之一。将 API 响应直接通过管道传递给 jq,即可立即格式化和提取数据。
# Basic: pretty-print API response
curl -s https://api.github.com/users/octocat | jq '.'
# Extract specific fields
curl -s https://api.github.com/users/octocat | jq '{name, bio, public_repos}'
# Process paginated API results
for page in 1 2 3; do
curl -s "https://api.example.com/items?page=$page" | jq '.items[]'
done | jq -s 'length'
# POST then parse response
curl -s -X POST https://api.example.com/auth \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"secret"}' | \
jq -r '.token'
# Chain: get token, then use it
TOKEN=$(curl -s -X POST https://api.example.com/auth \
-d '{"user":"admin","pass":"secret"}' | jq -r '.token')
curl -s -H "Authorization: Bearer $TOKEN" https://api.example.com/data | jq '.'
# Save extracted data to file
curl -s https://api.github.com/users/octocat/repos | \
jq '[.[] | {name, stars: .stargazers_count, url: .html_url}]' > repos.json
# Handle errors in API response
curl -s https://api.example.com/data | \
jq 'if .error then "Error: \(.error.message)" else .data end'
# Headers + jq for debugging
curl -s -D- https://api.example.com/data | \
sed '1,/^\r$/d' | jq '.'
# Multiple API calls with xargs
echo "octocat torvalds gvanrossum" | tr ' ' '\n' | \
xargs -I {} curl -s "https://api.github.com/users/{}" | \
jq '{login, name, public_repos}'
# GraphQL API with jq
curl -s -X POST https://api.github.com/graphql \
-H "Authorization: bearer $GITHUB_TOKEN" \
-d '{"query":"{ viewer { login name }}"}' | \
jq '.data.viewer'11. 高级 jq
对于复杂的数据转换,jq 提供了 reduce、foreach、自定义函数定义、环境变量和命令行参数。
reduce
# Sum with reduce
echo '[1,2,3,4,5]' | jq 'reduce .[] as $x (0; . + $x)'
# 15
# Build object from array with reduce
echo '[["name","Alice"],["age","30"],["city","NYC"]]' | \
jq 'reduce .[] as $pair ({}; . + {($pair[0]): $pair[1]})'
# {"name": "Alice", "age": "30", "city": "NYC"}
# Running total with reduce
echo '[10,20,30,40]' | \
jq 'reduce .[] as $x ([]; . + [((. | last) // 0) + $x])'
# [10, 30, 60, 100]
# Count occurrences with reduce
echo '["a","b","a","c","b","a"]' | \
jq 'reduce .[] as $x ({}; .[$x] = ((.[$x] // 0) + 1))'
# {"a": 3, "b": 2, "c": 1}foreach
# foreach produces intermediate results
echo 'null' | jq '[foreach range(5) as $x (0; . + $x)]'
# [0, 1, 3, 6, 10]
# foreach with extract expression
echo 'null' | jq '[foreach range(1;6) as $x (1; . * $x; .)]'
# [1, 2, 6, 24, 120] (factorials)Custom Functions (def)
# Define a reusable function
echo '["hello","world"]' | jq 'def capitalize: (.[0:1] | ascii_upcase) + .[1:]; map(capitalize)'
# ["Hello", "World"]
# Function with parameters
echo '[1,2,3,4,5]' | jq 'def clamp(min; max): if . < min then min elif . > max then max else . end; map(clamp(2;4))'
# [2, 2, 3, 4, 4]
# Recursive function
echo '{"a":{"b":{"c":{"d":"found"}}}}' | \
jq 'def depth: if type == "object" then (to_entries | map(.value | depth) | max) + 1 elif type == "array" then (map(depth) | max) + 1 else 0 end; depth'
# 4
# Function for formatting bytes
echo '{"size":1073741824}' | jq 'def bytes:
if . >= 1073741824 then "\(. / 1073741824 | floor)GB"
elif . >= 1048576 then "\(. / 1048576 | floor)MB"
elif . >= 1024 then "\(. / 1024 | floor)KB"
else "\(.)B"
end;
.size | bytes'
# "1GB"Environment Variables & Arguments
# Access environment variables with $ENV
export MY_VAR="hello"
echo 'null' | jq '$ENV.MY_VAR'
# "hello"
# Access all env vars
echo 'null' | jq '$ENV | keys[:5]'
# --arg: pass string arguments
jq -n --arg name "Alice" --arg age "30" '{name: $name, age: ($age | tonumber)}'
# {"name": "Alice", "age": 30}
# --argjson: pass JSON arguments
jq -n --argjson count 5 --argjson active true '{count: $count, active: $active}'
# {"count": 5, "active": true}
# --slurpfile: read JSON from file into variable
echo '{"name":"Alice"}' > /tmp/user.json
jq -n --slurpfile user /tmp/user.json '$user[0]'
# {"name": "Alice"}
# --slurp (-s): read all inputs into an array
echo -e '{"a":1}\n{"a":2}\n{"a":3}' | jq -s 'map(.a) | add'
# 6
# --null-input (-n): don't read stdin
jq -n '{timestamp: now, message: "hello"}'
# --rawfile: read raw file content as string
jq -n --rawfile tmpl template.txt '$tmpl'
# --jsonargs: pass remaining args as JSON
jq -n '$ARGS.positional' --jsonargs 1 2 3
# [1, 2, 3]
# --join-output / -j: no newline at end
echo '{"name":"Alice"}' | jq -j '.name'
# Alice (no trailing newline)
# --exit-status / -e: set exit code based on output
echo '{"ok":true}' | jq -e '.ok' > /dev/null && echo "success"
# success12. 速查表:快速参考
最常用的 jq 模式一览。收藏此表以便快速查找。
| 模式 | 描述 | 示例 |
|---|---|---|
. | Identity (pretty-print) | jq '.' |
.field | Get object field | jq '.name' |
.a.b.c | Nested field access | jq '.user.address.city' |
.[n] | Array index | jq '.[0]' |
.[] | Iterate array/object values | jq '.users[]' |
.[m:n] | Array slice | jq '.[2:5]' |
| | Pipe (chain filters) | jq '.[] | .name' |
select() | Filter by condition | jq '.[] | select(.age>30)' |
map() | Transform array elements | jq 'map(.name)' |
sort_by() | Sort array by field | jq 'sort_by(.age)' |
group_by() | Group by field | jq 'group_by(.type)' |
unique_by() | Deduplicate by field | jq 'unique_by(.id)' |
keys | Get object keys | jq 'keys' |
values | Get object values | jq 'values' |
to_entries | Object to key-value pairs | jq 'to_entries' |
from_entries | Key-value pairs to object | jq 'from_entries' |
with_entries() | Transform entries in place | jq 'with_entries(.key|=ascii_upcase)' |
length | Array/object/string length | jq '.items | length' |
// | Alternative (default value) | jq '.x // "default"' |
del() | Delete key from object | jq 'del(.tmp)' |
add | Sum array / concat | jq '[.[] | .score] | add' |
flatten | Flatten nested arrays | jq 'flatten' |
@csv / @tsv | Format as CSV/TSV | jq -r '.[] | @csv' |
@base64 | Base64 encode | jq '.token | @base64' |
--arg k v | Pass string argument | jq --arg n "Alice" '.name==$n' |
-r | Raw output (no quotes) | jq -r '.name' |
-s | Slurp: read all inputs as array | jq -s 'add' |
-c | Compact output | jq -c '.' |
-e | Exit status based on output | jq -e '.ok' |
reduce | Accumulate values | jq 'reduce .[] as $x (0;.+$x)' |
常见问题
jq 用来做什么?
jq 是一个命令行 JSON 处理器,用于解析、过滤、转换和格式化 JSON 数据。它通常用于处理 API 响应、解析日志文件、转换配置文件以及从复杂 JSON 结构中提取特定字段。可以把它理解为专为 JSON 设计的 grep/sed/awk。
如何用 jq 美化打印 JSON?
只需将 JSON 通过管道传递给 jq 的恒等过滤器:echo '{"name":"Alice","age":30}' | jq '.'。这会输出带有适当缩进和语法高亮的 JSON。也可以用 jq '.' file.json 美化打印 JSON 文件。要使用紧凑输出,添加 -c 标志:jq -c '.' file.json。
如何用 jq 提取嵌套字段?
使用点表示法导航嵌套对象:jq '.user.address.city' data.json。对于数组,使用 .[index] 访问特定元素:jq '.users[0].name' data.json。要遍历所有数组元素,使用 .[]:jq '.users[].name' data.json。可以根据需要无限嵌套。
jq 的 map() 和 select() 有什么区别?
map() 对数组中的每个元素应用转换,返回相同长度的新数组。select() 根据条件过滤元素,只返回匹配的元素。它们经常组合使用:jq '.users | map(select(.age > 30))' 过滤用户数组,只保留年龄大于 30 的用户。map() 负责转换,select() 负责过滤。
如何将 jq 与 curl 配合使用来解析 API 响应?
将 curl 输出直接通过管道传递给 jq:curl -s https://api.github.com/users/octocat | jq '.name, .bio'。-s 标志静音 curl 的进度输出。可以使用任何 jq 过滤器来提取、转换或格式化 API 响应。对于需要认证的 API,添加请求头:curl -s -H "Authorization: Bearer TOKEN" url | jq '.results[]'
收藏这份教程,随时查阅 jq 参考。要在浏览器中处理 JSON 数据,请试试我们的在线工具。