| name | jq-yq |
| description | JSON and YAML processing with jq and yq command-line tools. Use when user asks to "parse JSON", "transform YAML", "extract from JSON", "filter JSON array", "convert YAML to JSON", "query JSON", "jq filter", "yq select", "process API response", "parse logs as JSON", "merge YAML files", "convert JSON to CSV", "stream large JSON", "jq reduce", "group_by", "unique_by", or manipulate structured data from the command line. |
jq & yq
Command-line JSON and YAML processing.
jq Fundamentals
Extract Values
echo '{"name":"John","age":30}' | jq '.name'
echo '{"user":{"name":"John"}}' | jq '.user.name'
echo '[1,2,3]' | jq '.[0]'
echo '{"a":1,"b":2,"c":3}' | jq '{a,b}'
echo '{"a":1}' | jq '.b?'
Array Operations
echo '[1,2,3]' | jq '.[]'
echo '[1,2,3,4,5]' | jq '[.[] | select(. > 2)]'
echo '[1,2,3]' | jq 'map(. * 2)'
echo '[1,2,3]' | jq 'length'
echo '[1,2,3]' | jq 'first'
echo '[[1,2],[3,[4,5]]]' | jq 'flatten'
echo '[10,20,30,40,50]' | jq '.[2:4]'
Object Arrays
echo '[{"name":"a"},{"name":"b"}]' | jq '.[].name'
echo '[{"age":20},{"age":30}]' | jq '[.[] | select(.age > 25)]'
echo '[{"a":2},{"a":1}]' | jq 'sort_by(.a)'
echo '[{"type":"a","v":1},{"type":"b","v":2},{"type":"a","v":3}]' | jq 'group_by(.type)'
echo '[{"id":1,"n":"a"},{"id":2,"n":"b"},{"id":1,"n":"c"}]' | jq 'unique_by(.id)'
echo '[{"score":80},{"score":95},{"score":72}]' | jq 'min_by(.score)'
Object Construction and Deconstruction
echo '{"first":"John","last":"Doe"}' | jq '{fullName: "\(.first) \(.last)"}'
echo '{"a":1}' | jq '. + {b:2}'
echo '{"a":1,"b":2}' | jq 'del(.b)'
echo '{"old":1}' | jq '{new: .old}'
echo '{"user":{"name":"Jo","addr":{"city":"NYC"}}}' | jq '{name: .user.name, city: .user.addr.city}'
echo '{"a":1,"b":2}' | jq '[to_entries[] | {(.key): (.value * 10)}] | add'
echo '{"a":1,"b":2}' | jq 'with_entries(.value += 100)'
String Interpolation and Formatting
echo '{"name":"Jo","age":30}' | jq -r '"Name: \(.name), Age: \(.age)"'
echo '["a","b","c"]' | jq 'join(", ")'
echo '"a,b,c"' | jq 'split(",")'
echo '"hello"' | jq 'test("^hel")'
echo '"2024-01-15"' | jq 'capture("(?<y>[0-9]{4})-(?<m>[0-9]{2})-(?<d>[0-9]{2})")'
Conditionals and Null Handling
echo '{"age":20}' | jq 'if .age >= 18 then "adult" else "minor" end'
echo '{"a":null}' | jq '.a // "default"'
echo '{"a":1}' | jq 'try .b.c.d catch "missing"'
echo '[1,2,3]' | jq 'all(. > 0)'
Reduce and Aggregation
echo '[1,2,3,4,5]' | jq 'add'
echo '[1,2,3,4,5]' | jq 'reduce .[] as $x (0; . + $x)'
echo '[{"k":"a","v":1},{"k":"b","v":2}]' | jq 'reduce .[] as $item ({}; . + {($item.k): $item.v})'
echo '[{"dept":"eng","sal":100},{"dept":"eng","sal":120},{"dept":"sales","sal":90}]' | \
jq 'group_by(.dept) | map({dept: .[0].dept, total: map(.sal) | add, count: length})'
Recursive Descent
echo '{"a":{"name":"x","b":{"name":"y"}}}' | jq '.. | .name? // empty'
echo '{"a":1,"b":"hello","c":{"d":"world"}}' | jq '[.. | strings]'
echo '{"a":1,"b":{"c":2},"d":[3,4]}' | jq '[.. | numbers]'
Output Flags and Format Encoders
echo '{"name":"John"}' | jq -r '.name'
echo '{"a":1}' | jq -c '.'
cat lines.json | jq -s '.'
echo -e "line1\nline2" | jq -R '.'
jq -n '{created: now | todate}'
echo '[{"n":"a","v":1},{"n":"b","v":2}]' | jq -r '.[] | [.n, .v] | @tsv'
echo '[{"n":"a","v":1},{"n":"b","v":2}]' | jq -r '.[] | [.n, .v] | @csv'
echo '{"q":"hello world"}' | jq -r '.q | @uri'
CSV/TSV Conversion
echo '[{"name":"a","age":1},{"name":"b","age":2}]' | \
jq -r '(.[0] | keys_unsorted) as $k | $k, (.[] | [.[$k[]]])| @csv'
cat data.csv | jq -R 'split(",") | {id: .[0], name: .[1], value: .[2]}'
Environment Variable Integration
NAME="John"
echo '{}' | jq --arg name "$NAME" '. + {name: $name}'
echo '{}' | jq --argjson count 42 '. + {count: $count}'
TAGS='["a","b"]'
echo '{}' | jq --argjson tags "$TAGS" '. + {tags: $tags}'
export MY_VAR="hello"
echo '{}' | jq -n 'env.MY_VAR'
yq YAML Processing
Read, Update, Delete
yq '.name' file.yaml
yq '.database.host' config.yaml
yq -i '.version = "2.0"' file.yaml
yq -i '.new_field = "value"' file.yaml
yq -i 'del(.unwanted)' file.yaml
yq 'keys' config.yaml
Select and Filter
yq '.items[] | select(.enabled == true)' config.yaml
yq '.services[] | select(has("port"))' config.yaml
yq 'select(.kind == "Service")' resources.yaml
yq '.spec.template.spec.containers[].image' deployment.yaml
Merge YAML Files
yq ea 'select(fileIndex == 0) * select(fileIndex == 1)' base.yaml override.yaml
yq ea '. as $item ireduce ({}; . * $item)' *.yaml
Convert Between Formats
yq -o=json file.yaml
yq -P file.json
yq -o=xml file.yaml
yq -o=props file.yaml
curl -s https://api.example.com/data | yq -P
Multiple Documents
yq 'select(documentIndex == 0)' multi.yaml
yq 'select(documentIndex >= 0) | .metadata.namespace = "prod"' multi.yaml
yq ea '[.] | length' multi.yaml
Real-World Pipelines
API Response Processing with curl
curl -s 'https://api.github.com/repos/jqlang/jq/issues?per_page=5' | \
jq '[.[] | {number, title, state, user: .user.login}]'
for page in $(seq 1 5); do
curl -s "https://api.example.com/items?page=$page"
done | jq -s 'map(.data[]) | flatten'
curl -s https://api.example.com/users | \
jq -r '.data[] | [.id, .name, .email] | @tsv' | column -t
Log Parsing
cat app.log | jq -R 'fromjson? | select(.level == "error")' 2>/dev/null
cat app.log | jq -R 'fromjson? | .level' 2>/dev/null | \
jq -s 'group_by(.) | map({level: .[0], count: length})'
Config File Manipulation
jq '.version = "1.2.3"' package.json > tmp.$$ && mv tmp.$$ package.json
jq -s '.[0] * .[1]' base.json override.json > merged.json
jq '.dependencies |= with_entries(if .key | test("^@myorg/") then .value = "latest" else . end)' package.json
jq -n --arg host "$DB_HOST" --argjson port "${DB_PORT:-5432}" \
'{database: {host: $host, port: $port, ssl: true}}'
Kubernetes and Infrastructure
kubectl get pods -o json | jq -r '.items[].metadata.name'
kubectl get pods -o json | jq '.items[] | select(.status.phase != "Running") | .metadata.name'
yq -i '.spec.replicas = 3' deployment.yaml
Error Handling in Pipelines
echo '[1,"two",3]' | jq '[.[] | try (. + 1)]'
if echo "$data" | jq empty 2>/dev/null; then
echo "$data" | jq '.result'
else
echo "Invalid JSON"
fi
echo '{"users":[{"name":"a"},{"email":"b@b.com"}]}' | \
jq '.users[] | {name: (.name // "unknown"), email: (.email // "none")}'
curl -sf https://api.example.com/data | jq -e '.results | length > 0' > /dev/null
Performance: Streaming Large Files
jq --stream 'select(.[0][-1] == "name") | .[1]' huge.json
jq -c '.[]' huge_array.json | head -100 | jq -s '.'
cat large.ndjson | jq -c 'select(.status == "error")'
diff <(jq -S '.' a.json) <(jq -S '.' b.json)
Quick Reference
| Task | jq | yq |
|---|
| Pretty print | jq '.' | yq '.' |
| Get field | jq '.key' | yq '.key' |
| Filter | jq 'select(.x > 1)' | yq 'select(.x > 1)' |
| Delete | jq 'del(.key)' | yq 'del(.key)' |
| Merge | jq -s '.[0] * .[1]' | yq ea '. as $i ireduce({}; . * $i)' |
| To JSON/YAML | -- | yq -o=json / yq -P |
| Raw output | jq -r | yq -r |
| In-place | temp file or sponge | yq -i |