15 min to read
Understanding jq - The Powerful JSON Processor for Command Line
Learn how to use jq command effectively for JSON processing

What is jq?
It allows you to slice, filter, map, and transform structured data with the same ease that sed, awk, and grep let you play with text.
Why Use jq?
✅ Powerful: Process complex JSON structures with concise expressions
✅ Fast: Written in C, handles large JSON files efficiently
✅ Flexible: Can extract, modify, and restructure JSON data
✅ Scriptable: Perfect for shell scripts and automation
✅ Portable: Available on Linux, macOS, Windows and most Unix-like systems
✅ No Dependencies: Standalone tool with zero dependencies
Installation Methods
Standard Package Managers
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install jq
# Red Hat/CentOS/Fedora
sudo yum install jq # or sudo dnf install jq
# macOS with Homebrew
brew install jq
# Windows with Chocolatey
choco install jq
Installing Specific Versions
# apt (specific version)
sudo apt-get install jq=1.5*
# yum (specific version)
sudo yum install jq-1.5
From Source Code
For the latest features or if packages aren’t available:
git clone https://github.com/stedolan/jq.git
cd jq
autoreconf -i
./configure
make
sudo make install
Verifying Installation
jq --version
Basic jq Syntax
The basic syntax of jq follows this pattern:
jq [options] 'filter' [JSON_FILE]
If no JSON_FILE is provided, jq reads from stdin.
Filters and Expressions
jq uses a domain-specific language for its filters. Here are the basic components:
Symbol | Description | Example |
---|---|---|
. |
Identity operator | jq '.' (outputs the entire JSON input) |
.property |
Object property access | jq '.name' (outputs the value of "name") |
[] |
Array iterator | jq '.[]' (outputs each element of an array) |
| |
Pipe operator | jq '.[] | .name' (outputs "name" from each array element) |
select() |
Filter items | jq '.[] | select(.age > 30)' (outputs items where age > 30) |
{} |
Object constructor | jq '.[] | {name: .name}' (creates new objects with only name field) |
Basic Usage
JSON Pretty Printing
The most basic usage is to format JSON for readability:
echo '{"name":"Somaz","age":31,"skills":["Linux","Docker","AWS"]}' | jq '.'
Output:
{
"name": "Somaz",
"age": 31,
"skills": [
"Linux",
"Docker",
"AWS"
]
}
Simple Element Extraction
Accessing Object Properties
# Output single element
echo '{"name": "Somaz", "age": 31}' | jq '.name'
# Output
"Somaz"
# Accessing nested properties
echo '{"person": {"name": "Somaz", "details": {"age": 31}}}' | jq '.person.details.age'
# Output
31
Working with Arrays
# Access array elements
echo '{"skills": ["Linux", "Docker", "AWS"]}' | jq '.skills[1]'
# Output
"Docker"
# Extract all array elements
echo '{"team": [{"name": "Somaz"}, {"name": "Oh9Lee"}]}' | jq '.team[].name'
# Output
"Somaz"
"Oh9Lee"
Basic Filtering
# Filter by condition
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 28}]' | jq '.[] | select(.age < 30)'
# Output
{
"name": "Oh9Lee",
"age": 28
}
# Filter by pattern matching
echo '[{"name": "Oh9Lee", "face": "squid"}, {"name": "Oh9Lee", "face": "cuttlefish"}]' | jq '.[] | select(.face | test("^squid"))'
# Output
{
"name": "Oh9Lee",
"face": "squid"
}
# Multiple conditions (AND)
echo '[{"name": "Somaz", "age": 31, "role": "DevOps"}, {"name": "John", "age": 35, "role": "Developer"}]' | jq '.[] | select(.age > 30 and .role == "DevOps")'
# Output
{
"name": "Somaz",
"age": 31,
"role": "DevOps"
}
Advanced Usage
Mapping and Transformation
Create new JSON structures from input data:
# Transform objects in an array
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 28}]' | jq '.[] | {personName: .name, yearOfBirth: (2024 - .age + 1)}'
# Output
{
"personName": "Somaz",
"yearOfBirth": 1994
}
{
"personName": "Oh9Lee",
"yearOfBirth": 1997
}
# Transform array output back into an array
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 28}]' | jq '[.[] | {personName: .name, yearOfBirth: (2024 - .age + 1)}]'
# Output
[
{
"personName": "Somaz",
"yearOfBirth": 1994
},
{
"personName": "Oh9Lee",
"yearOfBirth": 1997
}
]
Conditional Processing
Apply conditional logic in jq expressions:
# Using if-then-else
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 28}]' | jq '.[] | {name: .name, status: (if .age >= 30 then "Senior" else "Junior" end)}'
# Output
{
"name": "Somaz",
"status": "Senior"
}
{
"name": "Oh9Lee",
"status": "Junior"
}
# Using map with conditions
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 28}]' | jq 'map(if .age > 30 then .name else empty end)'
# Output
[
"Somaz"
]
Working with Arrays and Objects
Powerful array manipulations:
# Count elements
echo '[{"name": "Somaz"}, {"name": "Oh9Lee"}, {"name": "John"}]' | jq 'length'
# Output
3
# Find minimum/maximum
echo '[{"value": 10}, {"value": 5}, {"value": 15}]' | jq 'map(.value) | min'
# Output
5
# Grouping by a field
echo '[{"name": "Somaz", "team": "DevOps"}, {"name": "John", "team": "Dev"}, {"name": "Jane", "team": "DevOps"}]' | jq 'group_by(.team)'
# Output
[
[
{
"name": "John",
"team": "Dev"
}
],
[
{
"name": "Somaz",
"team": "DevOps"
},
{
"name": "Jane",
"team": "DevOps"
}
]
]
String Manipulation
jq offers many string functions:
# String concatenation
echo '{"first": "Somaz", "last": "Kim"}' | jq '.first + " " + .last'
# Output
"Somaz Kim"
# String operations
echo '{"text": "hello world"}' | jq '.text | upcase'
# Output
"HELLO WORLD"
# Split and join
echo '{"csv": "a,b,c,d"}' | jq '.csv | split(",") | join("-")'
# Output
"a-b-c-d"
Useful Options and Features
Command Line Options
-r, --raw-output
: Output strings without quotes-c, --compact-output
: Produce compact output (no pretty-printing)-s, --slurp
: Read all inputs into an array before processing-f, --from-file
: Read filter from file--arg name value
: Pass a value to the jq program as a variable--argjson name value
: Pass a JSON-formatted value as a variable--sort-keys
: Output object keys in sorted order
Raw Output (-r)
Remove quotes from the output:
echo '{"name": "Somaz", "age": 31}' | jq -r '.name'
# Output
Somaz
# Useful for scripting
NAME=$(echo '{"name": "Somaz", "age": 31}' | jq -r '.name')
echo "Hello, $NAME!"
# Output
Hello, Somaz!
Compact Output (-c)
Output in a compact format, useful for piping to other tools:
echo '[{"name": "Somaz", "age": 31}, {"name": "Oh9Lee", "age": 25}]' | jq -c '.[]'
# Output
{"name":"Somaz","age":31}
{"name":"Oh9Lee","age":25}
Using Variables with –arg
Pass arguments to jq expressions:
# Create data.json
cat <<EOF > data.json
[
{"name": "Somaz", "age": 31},
{"name": "Jane", "age": 25},
{"name": "Doe", "age": 22},
{"name": "John", "age": 45}
]
EOF
# Filter using a variable
jq --arg min_age 30 '.[] | select(.age > ($min_age | tonumber))' data.json
# Output
{
"name": "Somaz",
"age": 31
}
{
"name": "John",
"age": 45
}
Slurping Multiple Inputs (-s)
Combine multiple inputs into an array:
echo '{"name": "file1"}' > file1.json
echo '{"name": "file2"}' > file2.json
jq -s '.' file1.json file2.json
# Output
[
{
"name": "file1"
},
{
"name": "file2"
}
]
Real-World Examples
Parsing API Responses
Working with REST API responses:
# Fetch and process GitHub API data
curl -s "https://api.github.com/repos/stedolan/jq/issues?per_page=3" |
jq '.[] | {title: .title, author: .user.login, labels: [.labels[].name]}'
# Output might look like:
# {
# "title": "Issue with parsing complex JSON",
# "author": "someuser",
# "labels": ["bug", "help wanted"]
# }
# ...
JSON to CSV Conversion
Transform JSON data to CSV format:
# Create sample data
cat <<EOF > users.json
[
{"name": "Somaz", "email": "somaz@example.com", "age": 31},
{"name": "Oh9Lee", "email": "oh9lee@example.com", "age": 28},
{"name": "John", "email": "john@example.com", "age": 42}
]
EOF
# Convert to CSV (header row + data rows)
jq -r '(["NAME","EMAIL","AGE"] | join(",")), (.[] | [.name, .email, .age] | join(","))' users.json
# Output
NAME,EMAIL,AGE
Somaz,somaz@example.com,31
Oh9Lee,oh9lee@example.com,28
John,john@example.com,42
Processing Configuration Files
Update values in a configuration file:
# Original config file
cat <<EOF > config.json
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"settings": {
"debug": false,
"timeout": 30,
"maxRetries": 3
}
}
}
EOF
# Update specific values
jq '.app.version = "1.1.0" | .app.settings.timeout = 60' config.json > config.new.json
Log Analysis
Parse and analyze JSON logs:
# Sample log file with JSON entries
cat <<EOF > app.log
{"timestamp": "2023-01-01T12:00:00Z", "level": "INFO", "message": "Application started", "user": "admin"}
{"timestamp": "2023-01-01T12:01:30Z", "level": "ERROR", "message": "Database connection failed", "user": "system"}
{"timestamp": "2023-01-01T12:02:15Z", "level": "INFO", "message": "User logged in", "user": "somaz"}
{"timestamp": "2023-01-01T12:05:00Z", "level": "ERROR", "message": "Invalid request", "user": "somaz"}
EOF
# Count log entries by level
jq -r '.level' app.log | sort | uniq -c
# Output
2 ERROR
2 INFO
# Filter error logs for a specific user
jq 'select(.level == "ERROR" and .user == "somaz")' app.log
# Output
{"timestamp": "2023-01-01T12:05:00Z", "level": "ERROR", "message": "Invalid request", "user": "somaz"}
jq Functions Reference
jq comes with a rich set of built-in functions:
Category | Functions | Example |
---|---|---|
Array Functions | length, map, select, sort, group_by, unique, flatten, range | jq '[1,2,3,1,2] | unique' → [1,2,3] |
Object Functions | has, keys, to_entries, from_entries, with_entries | jq '{a:1, b:2} | keys' → ["a", "b"] |
String Functions | length, split, join, ascii_downcase, ascii_upcase, startswith, endswith | jq '"abc" | split("")' → ["a","b","c"] |
Math Functions | +, -, *, /, %, floor, ceil, round, sqrt, pow | jq '10 / 3 | floor' → 3 |
Type Conversion | tostring, tonumber, type, tojson, fromjson | jq '[1,2,3] | tostring' → "[1,2,3]" |
Tips and Best Practices
- Testing Filters
- Start simple and build up complexity gradually
- Test each part of a complex filter separately
- Use online tools like jqplay.org for experimentation
- Performance
- Filter early to reduce the data being processed
- Use indices when accessing large arrays
- Avoid unnecessary array iterations
- Consider using streaming parsers for very large files
- Scripting
- Use -r with variables to avoid quote problems in shell scripts
- Store complex jq filters in separate files
- Use --arg for passing variables into filters
- Remember to escape quotes when embedding jq in scripts
- Error Handling
- Use try/catch for operations that might fail
- Validate input with the type function
- Provide defaults with the // operator
- Check the exit code in scripts
Shell Script Integration
Example of integrating jq into a shell script:
#!/bin/bash
# Sample script to update a configuration file
CONFIG_FILE="config.json"
NEW_VERSION="2.0.0"
DEBUG_MODE="true"
# Ensure the config file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo "Error: Config file not found!"
exit 1
fi
# Update configuration
jq --arg version "$NEW_VERSION" \
--arg debug "$DEBUG_MODE" \
'.version = $version | .settings.debug = ($debug == "true")' \
"$CONFIG_FILE" > "${CONFIG_FILE}.tmp"
# Check if jq succeeded
if [ $? -ne 0 ]; then
echo "Error: Failed to update configuration!"
rm -f "${CONFIG_FILE}.tmp"
exit 2
fi
# Replace the original file
mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
echo "Configuration updated successfully!"
Troubleshooting
Common Issues and Solutions
Solution: Check for malformed JSON. Ensure all strings are quoted, arrays/objects are properly closed, and there are no trailing commas.
Solution: Use the -r (raw) option to avoid JSON string escaping when you need plain text output.
Solution: Use the ?
operator to safely navigate potentially missing properties: .person.address?.zipcode
Solution: Use bracket notation: .["property-with-dashes"]
or .["@specialChars"]
Alternatives to jq
While jq is excellent, there are other tools for JSON processing:
Tool | Description | Best for |
---|---|---|
Python | General-purpose language with json module | Complex processing, integration with other Python libraries |
jq alternative (jaq) | Rust implementation of jq, faster for some operations | Performance-critical applications |
fx | Command-line JSON processing tool with interactive mode | Interactive JSON exploration |
gron | Makes JSON greppable by flattening it | Searching through JSON with grep and other text tools |
jsawk | JavaScript-based processor similar to awk | Those already familiar with JavaScript |
Comments