jq . file.json
is what I was looking for. I didn't realize that the . is a filter and not a placeholder for the piped in content:
.The absolute simplest (and least interesting) filter is
.. This is a filter that takes its input and produces it unchanged as output.
And the man page makes it clear that the filter is a required argument.
Answer from k0pernikus on Stack ExchangeI did find a solution while I was writing the question: don't put the input inside string interpolation, output a stream of things:
echo '{"foo":"bar", "baz":[1,2,3]}' | jq -r '"My value is:", . , "Some other stuff"'
# .........................................................^^^^^
outputs
My value is:
{
"foo": "bar",
"baz": [
1,
2,
3
]
}
Some other stuff
This might not fit your actual use case, but instead of creating a single JSON string in jq, just use a shell command group.
echo '{"foo":"bar", "baz":[1,2,3]}' | { echo "My value is:"; jq .; echo "Some other stuff"; }
Videos
While it is probably best to use a tool like the one peak suggested if your json isn't too complex you could use a second jq invocation to postprocess the output of the first. For example if your data is in data.json
$ jq -M . data.json | jq -MRsr 'gsub("\n +";"")|gsub("\n ]";"]")'
produces
{
"frameGrid": {
"size": [24,24],
"dimensions": [1,1],
"names": [["default"]]
}
}
As @jq170727 mentioned, postprocessing after a pretty-printing run of jq (e.g. jq .) is worth considering. In that vein, here is an awk script that might suffice:
#!/bin/bash
awk '
function ltrim(x) { sub(/^[ \t]*/, "", x); return x; }
s && NF > 1 && $NF == "[" { s=s $0; next}
s && NF == 1 && $1 == "]," { print s "],"; s=""; next}
s && NF == 1 && $1 == "[" { print s; s=$0; next}
s && NF == 1 && $1 == "{" { print s; print; s=""; next}
s && NF == 1 && $1 == "]" { print s $1; s=""; next}
s && NF == 1 && $1 == "}" { print s; s=$0; next}
s { s=s ltrim($0); next}
$NF == "[" { s=$0; next}
{print}
'
Examples
With the example input, the invocation:
jq . example.json | ./pp
produces:
{
"frameGrid": {
"size": [24,24],
"dimensions": [1,1],
"names": [
["default"]
]
}
}
The invocation:
jq -n '{a:[1,2,3,[1,2,3,4]],b:2,c:{d:[1,2,{e:[3,4]}]}}' | ./pp
produces:
{
"a": [1,2,3,
[1,2,3,4]
],
"b": 2,
"c": {
"d": [1,2,
{
"e": [3,4]
}
]
}
}
You need to supply a filter as an argument. To pass the JSON through unmodified other than the pretty printing jq provides by default, use the identity filter .:
curl -s https://api.github.com/users/octocat/repos | jq '.' | cat
One use case I have found myself doing frequently as well is "How do I construct JSON data to supply into other shell commands, for example curl?" The way I do this is by using the --null-input/-n option:
Don’t read any input at all! Instead, the filter is run once using
nullas the input. This is useful when usingjqas a simple calculator or to construct JSON data from scratch.
And an example passing it into curl:
jq -n '{key: "value"}' | curl -d @- \
--url 'https://some.url.com' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'
With Python 2.6+ or 3 you can use the json.tool module:
echo '{"foo": "lorem", "bar": "ipsum"}' | python -m json.tool
or, if the JSON is in a file, you can do:
python -m json.tool my_json.json
if the JSON is from an internet source such as an API, you can use
curl http://my_url/ | python -m json.tool
For convenience in all of these cases you can make an alias:
alias prettyjson='python -m json.tool'
For even more convenience with a bit more typing to get it ready:
prettyjson_s() {
echo "$1" | python -m json.tool
}
prettyjson_f() {
python -m json.tool "$1"
}
prettyjson_w() {
curl "$1" | python -m json.tool
}
for all the above cases. You can put this in .bashrc and it will be available every time in shell. Invoke it like prettyjson_s '{"foo": "lorem", "bar": "ipsum"}'.
Note that as @pnd pointed out in the comments below, in Python 3.5+ the JSON object is no longer sorted by default. To sort, add the --sort-keys flag to the end. I.e. ... | python -m json.tool --sort-keys.
Another useful option might be --no-ensure-ascii which disables escaping of non-ASCII characters (new in version 3.9).
You can use: jq
It's very simple to use and it works great! It can handle very large JSON structures, including streams. You can find their tutorials here.
Usage examples:
$ jq --color-output . file1.json file1.json | less -R
$ command_with_json_output | jq .
$ jq # stdin/"interactive" mode, just enter some JSON
$ jq <<< '{ "foo": "lorem", "bar": "ipsum" }'
{
"bar": "ipsum",
"foo": "lorem"
}
Or use jq with identity filter:
$ jq '.foo' <<< '{ "foo": "lorem", "bar": "ipsum" }'
"lorem"