jq
jq
is an extremely useful tool for querying JSON output from terminal programs.
Invoking
Typically, jq
will take in a JSON blob from stdin, and a query as an argument. Some CLI tools like the GitHub CLI have jq
builtin to their arguments.
# apple
echo '{"fruit":"apple"}' | jq '.fruit'
Querying
Querying in jq
is usually done through a series of piped or nested operations.
The simplest operation is .
, the identity, which returns whatever you pass in. Since jq
pretty-prints, you can use this to pretty-print minified JSON output:
# {
# "fruit": "apple"
# }
echo '{"fruit":"apple"}' | jq '.'
Otherwise, your most common use-cases will either involve grabbing a deeply-nested property, or iterating and filtering over a list. Or both.
Grabbing object properties
To get an object property in jq
, use the object identifier index. .foo
. This is a fancy term for "the key of the value that I want".
Chaining this index like .fruit.price
is equivalent to piping individual object identifiers together like .fruit | .price
.
You can also optionally chain like .fruit?
or .fruit?.price?
which will not error on non-objects, but just return undefined.
# < returns nothing, empty >
echo '{"fruit":"apple"}' | jq '.fruit?.price?'
Iterating and filtering
To iterate over an array, use the array / object value iterator. .[]
.
Optionally, this takes in a key and iterates over the result of that key in an object.
# outputs
# apple
# pear
# pomegranate
echo '{"fruits":["apple","pear","pomegranate"]}' | jq '.fruits[]'
This can be piped into an object identifier to grab key/values from an array of objects:
Given input
{
"fruits": [
{
"name": "apple",
"price": 2
},
{
"name": "pear",
"price": 3
},
{
"name": "pomegranate",
"price": 5
}
]
}
You could get the names of each of the fruits like: cat fruits.json | jq '.fruits[].name'
Which is equivalent to .fruits | .[] | .name
. This outputs:
"apple"
"pear"
"pomegranate"
Filtering
To filter a list while iterating over it, use select().
select()
takes in a single boolean expression of each entry, and filters it to any entry who is true for the expression.
To filter the above list of fruits to only ones with a high price, it would be: cat fruits.json | jq '.fruits[] | select(.price > 2)'
Which outputs:
{
"name": "pear",
"price": 3
}
{
"name": "pomegranate",
"price": 5
}
This could also be chained with the object identifier:
cat fruits.json | jq '.fruits[] | select(.price > 2).name'
Which outputs:
"pear"
"pomegranate"
test()
Commonly, you'll want to see if a string matches a certain regex pattern. Use test()
for this.
test()
expects to take in the sample string from a pipe, the regex pattern as its only argument (including any flags) and outputs a boolean if the input string matches the pattern.
To test fruits.json
for only fruits ending with the letter 'e', you would:
cat fruits.json | jq '.fruits[] | select(.name | test(".+e$"))'
Which outputs:
{
"name": "apple",
"price": 2
}
{
"name": "pomegranate",
"price": 5
}