JSON Processing¶
Working with JSON data on the command line using jq.
jq - JSON Processor¶
jq is a lightweight command-line JSON processor. It's essential for working with APIs, configuration files, and data processing.
Installation¶
Basic Usage¶
# Pretty print
echo '{"name":"Alice","age":30}' | jq '.'
# Read from file
jq '.' data.json
# Compact output
jq -c '.' data.json
Selecting Data¶
Simple Selection¶
echo '{"name":"Alice","age":30}' | jq '.name'
# "Alice"
echo '{"name":"Alice","age":30}' | jq '.age'
# 30
Nested Objects¶
echo '{"user":{"name":"Alice","address":{"city":"NYC"}}}' | jq '.user.name'
# "Alice"
echo '{"user":{"name":"Alice","address":{"city":"NYC"}}}' | jq '.user.address.city'
# "NYC"
Array Access¶
echo '[1,2,3,4,5]' | jq '.[0]'
# 1
echo '[1,2,3,4,5]' | jq '.[-1]'
# 5
echo '[1,2,3,4,5]' | jq '.[1:3]'
# [2,3]
Array of Objects¶
data='[{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"}]'
echo "$data" | jq '.[0].name'
# "Alice"
echo "$data" | jq '.[].name'
# "Alice"
# "Bob"
# "Charlie"
echo "$data" | jq '.[1:].name'
# Error - use map instead
Iterating Arrays¶
Get All Elements¶
Map Over Array¶
echo '[{"name":"Alice"},{"name":"Bob"}]' | jq '.[].name'
# "Alice"
# "Bob"
# Or using map
echo '[1,2,3]' | jq 'map(. * 2)'
# [2,4,6]
Filters and Conditions¶
Select¶
Filter array elements:
echo '[1,2,3,4,5]' | jq '.[] | select(. > 3)'
# 4
# 5
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | jq '.[] | select(.age > 28)'
# {"name":"Alice","age":30}
Multiple Conditions¶
data='[{"name":"Alice","age":30,"active":true},{"name":"Bob","age":25,"active":false}]'
echo "$data" | jq '.[] | select(.age > 20 and .active == true)'
# {"name":"Alice","age":30,"active":true}
Contains¶
echo '["apple","banana","cherry"]' | jq '.[] | select(contains("an"))'
# "banana"
echo '{"tags":["linux","bash","shell"]}' | jq '.tags | contains(["bash"])'
# true
Transforming Data¶
Create New Objects¶
echo '{"first":"Alice","last":"Smith","age":30}' | jq '{name: .first, years: .age}'
# {"name":"Alice","years":30}
Add Fields¶
Modify Fields¶
echo '{"name":"Alice","age":30}' | jq '.age = .age + 1'
# {"name":"Alice","age":31}
echo '{"name":"Alice","age":30}' | jq '.age += 1'
# {"name":"Alice","age":31}
Delete Fields¶
Rename Fields¶
String Operations¶
Length¶
String Manipulation¶
echo '{"name":"alice"}' | jq '.name | ascii_upcase'
# "ALICE"
echo '{"text":"hello world"}' | jq '.text | split(" ")'
# ["hello","world"]
echo '{"words":["hello","world"]}' | jq '.words | join("-")'
# "hello-world"
String Interpolation¶
Numbers and Math¶
echo '[1,2,3,4,5]' | jq 'add'
# 15
echo '[1,2,3,4,5]' | jq 'add / length'
# 3
echo '{"a":10,"b":3}' | jq '.a / .b'
# 3.3333333333333335
echo '[3,1,4,1,5]' | jq 'min'
# 1
echo '[3,1,4,1,5]' | jq 'max'
# 5
echo '[3,1,4,1,5]' | jq 'sort'
# [1,1,3,4,5]
echo '[3,1,4,1,5]' | jq 'unique'
# [1,3,4,5]
Grouping and Aggregating¶
Group By¶
data='[{"type":"a","val":1},{"type":"b","val":2},{"type":"a","val":3}]'
echo "$data" | jq 'group_by(.type)'
# [[{"type":"a","val":1},{"type":"a","val":3}],[{"type":"b","val":2}]]
Count By Type¶
echo "$data" | jq 'group_by(.type) | map({type: .[0].type, count: length})'
# [{"type":"a","count":2},{"type":"b","count":1}]
Output Formatting¶
Raw Output¶
Remove quotes from strings:
Compact Output¶
Tab-Separated Values¶
CSV Output¶
Working with APIs¶
curl + jq¶
# Get and parse JSON
curl -s https://api.github.com/users/octocat | jq '.name, .company'
# Extract specific fields
curl -s https://api.example.com/data | jq '.results[] | {id, name}'
# Filter results
curl -s https://api.example.com/items | jq '.[] | select(.status == "active")'
Handling Arrays¶
# Pretty print API response
curl -s https://api.example.com/users | jq '.'
# Get first item
curl -s https://api.example.com/users | jq '.[0]'
# Count items
curl -s https://api.example.com/users | jq 'length'
# Get all names
curl -s https://api.example.com/users | jq -r '.[].name'
Advanced Patterns¶
Recursive Descent¶
Find all values of a key anywhere in the structure:
Conditionals¶
Error Handling¶
# Optional object access (no error if missing)
echo '{"name":"Alice"}' | jq '.address.city?'
# null
# Default value
echo '{"name":"Alice"}' | jq '.age // 0'
# 0
Variables¶
echo '{"items":[1,2,3]}' | jq --arg n 2 '.items | map(. * ($n | tonumber))'
# [2,4,6]
# Pass JSON as argument
echo '{}' | jq --argjson data '{"key":"value"}' '. + $data'
# {"key":"value"}
Practical Examples¶
Parse Docker JSON¶
Parse kubectl Output¶
Transform Config File¶
# Add new field
jq '.newField = "value"' config.json > config_new.json
# Update nested field
jq '.database.host = "newhost"' config.json
API Response Processing¶
# Get paginated results
page=1
while true; do
result=$(curl -s "https://api.example.com/items?page=$page")
count=$(echo "$result" | jq '.items | length')
[[ $count -eq 0 ]] && break
echo "$result" | jq -r '.items[].name'
((page++))
done
Build JSON¶
# Create JSON from variables
name="Alice"
age=30
jq -n --arg name "$name" --argjson age "$age" '{name: $name, age: $age}'
# {"name":"Alice","age":30}
Try It¶
-
Basic selection:
-
Filtering:
-
Transformation:
-
Array operations:
Summary¶
| Operation | Syntax |
|---|---|
| Select field | .field |
| Select nested | .a.b.c |
| Array element | .[0] |
| All elements | .[] |
| Filter | select(condition) |
| Create object | {key: .value} |
| Add field | . + {key: value} |
| Delete field | del(.field) |
| Raw output | -r |
| Length | length |
| Map | map(expr) |
| Sort | sort |
| Unique | unique |
| Sum | add |
Key flags:
| Flag | Purpose |
|---|---|
-r | Raw string output |
-c | Compact output |
-e | Exit with error if null |
--arg name val | Pass string variable |
--argjson name val | Pass JSON variable |