How to Use the jq Command to Parse and Format JSON in Linux

The Problem with Processing JSON on the Command Line

Modern Linux system administration, cloud orchestration, and software development revolve around JSON (JavaScript Object Notation). REST APIs, container daemons (like Docker and Podman), cloud CLI utilities (AWS CLI, Google Cloud SDK), and system monitoring tools output vast payloads of structured JSON data. However, raw JSON delivered to standard terminal output is typically minified into an impenetrable, single-line text wall that is virtually impossible for humans to read or pipe into standard text utilities like grep, awk, or sed.

Because traditional Unix tools process stream data line-by-line, attempting to parse nested key-value pairs using regular expressions frequently produces fragile, error-prone scripts. jq is the dedicated, high-performance command-line JSON processor designed specifically to slice, filter, map, and transform JSON data with mathematical elegance.

Installing jq on Linux Distributions

While jq is not always pre-installed on minimal server base images, it is available across all primary official package repositories:

Ubuntu / Debian

sudo apt update && sudo apt install -y jq

Fedora / RHEL / CentOS Stream

sudo dnf install -y jq

Arch Linux

sudo pacman -S jq

Step 1: Pretty-Printing and Validating Raw JSON

The simplest and most immediate use case for jq is formatting minified JSON into structured, human-readable output with syntax colour highlighting. Pass input via a pipe (|) or point directly to a file using the identity filter (.):

curl -s https://api.github.com/users/octocat | jq .

The . filter takes the raw input stream and pretty-prints it with standard indentation. If the incoming payload contains malformed JSON syntax, jq immediately throws a descriptive parse error and returns an exit code of 5, making it an ideal pre-flight validator in shell scripts.

Step 2: Extracting Specific Keys and Nested Properties

To extract values from JSON objects, chain key names with period operators:

Top-Level Key Extraction

curl -s https://api.github.com/users/octocat | jq '.name'

This returns "The Octocat" (with surrounding quotation marks). To output raw plaintext without string quotes (perfect for assigning directly into bash environment variables), use the -r (raw output) flag:

USER_NAME=$(curl -s https://api.github.com/users/octocat | jq -r '.name')
echo "Extracted user: $USER_NAME"

Accessing Nested Objects

Given a payload where location data is nested under {"company": {"location": {"city": "London"}}}:

cat payload.json | jq -r '.company.location.city'

Step 3: Iterating Across JSON Arrays

When working with lists of objects (such as a list of virtual machines or server containers), use the array bracket operator [] to unpack the elements.

Unpack All Items in an Array

cat servers.json | jq '.[]'

Extract a Specific Key from Every Object in an Array

cat servers.json | jq -r '.[].ip_address'

Extracting by Array Index

To extract only the first element from an array, specify index 0:

cat servers.json | jq '.[0]'

To slice a specific subset (e.g. elements 0 through 2):

cat servers.json | jq '.[0:3]'

Step 4: Filtering and Conditional Logic

You can filter JSON streams using conditional operators. For example, to filter a server list and output only nodes where the status property equals "active":

cat servers.json | jq '.[] | select(.status == "active")'

To filter by numeric thresholds (e.g., servers where memory usage exceeds 80%):

cat servers.json | jq '.[] | select(.memory_usage > 80) | .hostname'

Constructing New JSON Objects on the Fly

You can transform verbose API responses into compact, bespoke JSON structures by building a custom object template:

curl -s https://api.github.com/users/octocat | jq '{user: .login, repos: .public_repos, followers: .followers}'

This outputs a clean three-line JSON object containing strictly the required data.

Frequently Asked Questions

How do I handle null or missing keys gracefully in jq?

Append a question mark (?) after a property query (e.g. .user?.profile?). If the parent key is missing, jq returns null rather than aborting with a type error.

Can jq modify a file in-place like sed -i?

The jq binary does not feature an in-place flag directly. The recommended pattern is using a temporary file or sponge from moreutils: jq '.version = "2.0"' config.json | sponge config.json.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.