The jq utility for Linux
Use the powerful Linux jq utility to manipulate JSON data, prettify output, and filter nodes directly from your command line and shell scripts.
This article is part of the Modern CLI tools for your terminal series:
- The jq utility for Linux
- The xmlstarlet utility for Linux
- Introduction to fzf - Fuzzy Finder
- Let's revisit the ls command thanks to eza
- Master your ssh command and select the host from a list
- FZF + ripgrep: Interactive Code Search with Live Preview
- delta: a Syntax-Highlighted Pager for git diff
- ripgrep — The Search Tool That Changed My WSL2 Workflow
- yq — The YAML Processor You Already Know How to Use
Changelog

This article introduces jq, a command-line JSON processor: piping raw API output (using the random-user API as an example) through jq alone pretty-prints it, and adding a filter expression like jq '.results[0].name' extracts just a specific node from the JSON structure.
jq is a powerful utility for Linux that lets you manipulate JSON data from the command line and can be integrated into shell scripts.
The same answer, twice
By running curl https://randomuser.me/api/ you'll get something like
{"results":[{"gender":"female","name":{"title":"Mademoiselle","first":"Milena","last":"Martin"},"location":{"street":{"number":9831,"name":"Rue de L'Abbé-Migne"},"city":"Lengnau (Ag)","state":"Basel-Landschaft","country":"Switzerland","postcode":3789,"coordinates":{"latitude":"-60.0739","longitude":"135.1462"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"milena.martin@example.com","login":{"uuid":"bafdf972-4183-484a-903a-84f2654f0fec","username":"purpleleopard344","password":"cameron","salt":"gGoFrP1a","md5":"af359ca6697c3ac68f4c190583544619","sha1":"19033bc1630d96bba29726823ef91f53800e67d1","sha256":"cac6a35f5135f14707b8b3ec48617f23b4105b1c5e33a2b64597e7a0c7c891a0"},"dob":{"date":"1998-10-10T02:42:04.525Z","age":25},"registered":{"date":"2005-05-01T01:26:36.354Z","age":18},"phone":"079 098 73 86","cell":"077 411 83 18","id":{"name":"AVS","value":"756.9632.2579.59"},"picture":{"large":"https://randomuser.me/api/portraits/women/37.jpg","medium":"https://randomuser.me/api/portraits/med/women/37.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/37.jpg"},"nat":"CH"}],"info":{"seed":"213f93e3e854d33c","results":1,"page":1,"version":"1.4"}}
The JSON is just echoed on the screen, not really readable.
But, as soon as we are redirecting to jq, it'll be better:
{
"results": [
{
"gender": "female",
"name": {
"title": "Mademoiselle",
"first": "Salomé",
"last": "Roy"
},
"location": {
"street": {
"number": 2361,
"name": "Rue Dumenge"
},
"city": "Dierikon",
[...]
},
"email": "salome.roy@example.com",
[...]
}
],
"info": {
"seed": "b7ef95d3b252edca",
"results": 1,
"page": 1,
"version": "1.4"
}
}
Same bytes, same API, one extra word on the command line. That already earns jq its place in a pipe, but the reason I really use it is below.
Filtering the output
Imagine we just need to retrieve the name. To do this, we need to better understand the JSON object.
{
"results": [
{
"gender": "female",
"name": {
"title": "Mademoiselle",
"first": "Salomé",
"last": "Roy"
},
"location": {
[...]
},
[...]
],
[...]
}
The output is a JSON representation having a root property called results. That property is an array. Each element in that array has a name node with a few properties like title, first and last.
If we just want to retrieve the name node, the filter to use with jq is .results[0].name.
{
"title": "Ms",
"first": "Brooke",
"last": "Morgan"
}
Learn more about jq filtering.
Seeing It in Action with Docker
Before installing anything, try both commands from above in a throwaway container. It ships jq
and a static snapshot of the randomuser.me response used throughout this article, so the demo
works even without network access — though the live API is still reachable if you want to try it
for real.
Why Docker first?
The Dockerfile below installs jq and drops a ready-to-use sample.json in the working
directory. Nothing to type, download or configure — just pipe it through jq.
Build and run it:
Same filter as above, same result, no curl even required. Drop the filter and run cat sample.json | jq alone to see the whole object prettified, or, since the container has network
access, try the live version too: curl --silent https://randomuser.me/api/ | jq.
Installing jq
To verify if jq is already installed on your system, simply run which jq. If you get jq not found as an answer:
Prerequisite: jq
Verify:
Let's play
jq can be used without any arguments and in that case, the JSON output will be prettified.
To reproduce the examples above, we'll use a simple JSON free API like https://randomuser.me/api/. If you wish to use another API tool, take a look on https://github.com/public-apis/public-apis#test-data; free ones are those having No in the Auth columns.
randomuser API return every time a new user
On each request, the randomuser API is returning a new object. Don't be surprised if your names differ from mine.
The full prettified answer (click for the details)
Here is the complete object returned by the API, as jq renders it:
{
"results": [
{
"gender": "female",
"name": {
"title": "Mademoiselle",
"first": "Salomé",
"last": "Roy"
},
"location": {
"street": {
"number": 2361,
"name": "Rue Dumenge"
},
"city": "Dierikon",
"state": "Basel-Stadt",
"country": "Switzerland",
"postcode": 5075,
"coordinates": {
"latitude": "-58.3405",
"longitude": "134.0131"
},
"timezone": {
"offset": "+4:30",
"description": "Kabul"
}
},
"email": "salome.roy@example.com",
"login": {
"uuid": "dfda3e32-b8b1-44c9-9aa9-194fc17833d3",
"username": "organiccat614",
"password": "nacked",
"salt": "HRepWJ2P",
"md5": "643f7a890ba9c9fbe04ea971287f57ba",
"sha1": "9407fd8fdf0c344ac1990a89d8d0190f6baabd19",
"sha256": "1317478dbfc61c3feaccea4485a367fb6b195009f15eecd9175f2d1a9215d5df"
},
"dob": {
"date": "1960-05-12T07:27:42.104Z",
"age": 63
},
"registered": {
"date": "2021-05-02T04:18:14.996Z",
"age": 2
},
"phone": "077 228 21 12",
"cell": "078 051 38 48",
"id": {
"name": "AVS",
"value": "756.1071.1525.27"
},
"picture": {
"large": "https://randomuser.me/api/portraits/women/74.jpg",
"medium": "https://randomuser.me/api/portraits/med/women/74.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/women/74.jpg"
},
"nat": "CH"
}
],
"info": {
"seed": "b7ef95d3b252edca",
"results": 1,
"page": 1,
"version": "1.4"
}
}
Conclusion
Two things to remember: jq alone makes any JSON readable, and jq '.some.path' extracts exactly the node you need — which is what turns an API answer into something a shell script can consume.
jq quickly becomes a reflex: I use it in Troubleshooting for Docker containers to read docker inspect output, and in building a blog post analyzer with Ollama to format the local LLM's JSON responses, for instance.
And on the days when the filter you need — a group_by, a select on a date — just won't come back to you, ai-data asks a local LLM for five jq commands tailored to your own file, and drops the one you pick at your prompt, ready to read before you run it.
For the times when the console is not the right tool for JSON, this blog has three more: Rendering a JSON file as a mind map, JSON - Online linter and JSON - Faker & Mockup.
This article is part of the Modern CLI tools for your terminal series:
- The jq utility for Linux
- The xmlstarlet utility for Linux
- Introduction to fzf - Fuzzy Finder
- Let's revisit the ls command thanks to eza
- Master your ssh command and select the host from a list
- FZF + ripgrep: Interactive Code Search with Live Preview
- delta: a Syntax-Highlighted Pager for git diff
- ripgrep — The Search Tool That Changed My WSL2 Workflow
- yq — The YAML Processor You Already Know How to Use





