3609

Is there a (Unix) shell script to format JSON in human-readable form?

Basically, I want it to transform the following:

{ "foo": "lorem", "bar": "ipsum" }

... into something like this:

{
    "foo": "lorem",
    "bar": "ipsum"
}
Paul P
  • 3,346
  • 2
  • 12
  • 26
  • http://stackoverflow.com/a/12892039/998291 – shluvme Oct 15 '12 at 08:51
  • Stumbled on to this but then found [Json Pretty](https://github.com/nicksieger/jsonpretty) and I quite like it. Typekit uses it in their API examples, so there's some klout behind it ^^ – Nick Tomlin Nov 21 '12 at 14:42
  • 10
    I rolled my own a short while back: https://github.com/exhuma/braindump/tree/master/jsonformat The code is very simple, using python's own `json` library, but I added pygments as well to get syntax highlighting. – exhuma Nov 09 '12 at 13:40
  • If you don't mind copying pasting, there's also some simple tools online like http://www.jsonprettyprint.net where you can quickly pretty print your raw JSON. – Javaaaa Nov 09 '14 at 16:56
  • Just a little cool tidbit that might be super obvious, but for anyone trying to pretty print a file containing JSON this works `echo "$(cat nameOfYourFile.js)" | python -m json.tool` – beckah Apr 23 '15 at 15:31
  • 13
    Be warned: *python -m json.tool* does not always produce valid JSON. (Hint: 1e1000) – peak Sep 11 '15 at 16:48
  • Is the json only one level deep? This cuts out regex based solutions in case of negative response. – sixFingers Jun 29 '16 at 01:46
  • Anyone have a convenient way to pretty-print a JSON file in-place? – LarsH Aug 28 '18 at 21:41
  • @LarsH here is interactive JSON viewer https://github.com/antonmedv/fx – Anton Medvedev Nov 25 '18 at 06:09
  • Too many (identical) answers, it is hard to find a listing of possible solutions. [I've made a benchmark to try and summarise those](https://stackoverflow.com/a/61119751/6320039). I hope this won't be yet another useless answer! – Ulysse BN Apr 09 '20 at 11:08
  • If you want to format your json as a table, you can use jtab, a tool written in rust that allows you to do that: https://github.com/wlezzar/jtab – Lezzar Walid Jun 15 '20 at 18:59
  • Also don't include `-D` – dimitrieh Dec 28 '21 at 19:46
  • use [smart json](https://fe-tool.com/en-us/formatter/json) which format json/json5 to compact json format – cwtuan Jan 10 '23 at 13:08

62 Answers62

5100

With Python 2.6+ you can do:

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.

Rayman
  • 61
  • 1
  • 8
B Bycroft
  • 3,480
  • 1
  • 15
  • 5
  • 3
    With other versions of Python you can install simplejson and use python -msimplejson.tool – YOUR ARGUMENT IS VALID Apr 19 '11 at 16:33
  • 77
    You could pipe that onto `pygmentize -l javascript` to get syntax colored output in your command line. **Edit**: If you have pygments installed that is. – sharat87 Dec 03 '11 at 03:24
  • 4
    alias ppj='python -mjson.tool'; echo '{"foo": "lorem", "bar": "ipsum"}' | ppj – Everett Toews May 03 '12 at 19:19
  • 192
    A great answer, only caution I have with it is it *does* sort the keys on output - which you might need to be aware of. – Chris Nash Jun 26 '12 at 20:35
  • 16
    In myy .vimrc "nnoremap :%!python -m json.tool:w" – imwilsonxu Oct 15 '12 at 06:59
  • 48
    This seems to escape Unicode characters into \uXXXX, which might be a disadvantage. – user1071136 Oct 16 '12 at 11:24
  • 1
    This is tip is super handy when viewing Riak or (other JSON-capable servers) output! e.g. curl http://blah.com:8089 | python -mjson.tool You absolutely don't need to install or configiure anything except python, which is usually there already. – Andz Nov 19 '12 at 03:56
  • hey can anyone help with adding this as a external command in gedit? Edit: got it; Tools -> Manage External Toosl -> new (+) -> add "python -mjson.tool " -> Select Input = Current Document, Output = Replace Current Document. Cheers! – Aswin Kumar Mar 03 '13 at 20:29
  • 1
    Anyone got the same for XML? – Mike Weller Mar 08 '13 at 11:20
  • @MikeWeller http://stackoverflow.com/questions/16090869/how-to-pretty-print-xml-from-the-command-line – svidgen Apr 18 '13 at 18:54
  • 2
    and add syntax highlighting by piping the output into 'colout -t json'. Requires 'pip install colout' first. – Jonathan Hartley Jul 11 '13 at 09:12
  • 6
    @user1071136 To keep the Unicode characters in the output it is necessary to make your own script. import sys import json j = json.load(sys.stdin) json.dump(j, sys.stdout, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ': ')) – user7610 Feb 03 '14 at 15:20
  • 2
    It doesn't accept top level arrays, so not all json sadly. – J.N. Feb 24 '14 at 07:12
  • 1
    @ShrikantSharat: since version 1.5 Pygments support `json` type as well. – piotr.d Feb 06 '15 at 16:42
  • 16
    I've created an alias: `alias pretty='python -mjson.tool | pygmentize -l json` so that I can just run: `command params | pretty`. Hope this helps. PS: Should anyone manages to extend this to a) remove the curl-output I'm seeing every time and/or b) NOT sort the json keys; please do let me know, I will be highly thankful. – Clint Eastwood Feb 25 '15 at 17:42
  • 1
    And if the JSON is in a file: `$ cat file.json | python -m json.tool` – nishanthshanmugham May 03 '15 at 04:08
  • 4
    Another problem with *python -m json.tool* as a JSON pretty-printer is that it does not always print valid JSON values. E.g. 1e1000 is converted to Infinity. – peak Sep 04 '15 at 02:44
  • python does not support non-ascii – Yin Jan 13 '16 at 08:40
  • 13
    Changed in Python 3.5: Output now same order as Input. Use `--sort-keys` to sort keys alphabetically. In response to comment by @ChrisNash. – pnd Feb 18 '16 at 11:49
  • 2
    If you're on macOS and you have some json on the clipboard that you want formatted `pbpaste | python -m json.tool | pbcopy`. – arete Jun 21 '16 at 22:54
  • Amazing! Thanks for sharing this. Also, in case you have passed in the "-i" option to cURL, it won't be able to pretty print the json as you have now got HTTP headers as well. – asgs Nov 18 '16 at 06:24
  • What if I want to `cat` it using `python -m json.tool /path.json`? – Jack Aug 07 '17 at 14:09
  • Is there a way to format the brackets in a better way? (Use same column for the left bracket and the corresponding right bracket) – 12431234123412341234123 Aug 08 '17 at 12:46
  • 2
    @ClintEastwood - the curl -s option will supress the output e.g. `curl -s http://my_url/ | python -m json.tool` Should just print the JSON. – Loftx Dec 21 '17 at 11:35
  • This effectively just answers how to do it in Python, or on the web. The letter of the question seems to be satisfied, but I don't think the spirit of it has been at all. 3,551 upvotes seems like a gross overreaction. – Lightness Races in Orbit Feb 16 '18 at 00:41
  • which module is required to be installed? I get: /usr/bin/python: `No module named json.module` – Wakan Tanka Feb 20 '19 at 13:42
  • @ClintEastwood To suppress the progress report / bar of `curl`, just pass the silent flag: `curl -s` – Wu Wei Sep 30 '19 at 12:18
  • 1
    is this the highest voted unaccepted answer of all time – Alex M Oct 18 '19 at 17:06
  • The technique from this answer, for all `.json` files in your current directory: `for file in *.json; do python -m json.tool $file > ${file/.json/.pretty.json}; done` – tanius Oct 22 '19 at 23:53
  • `json.tool` does not work well for large files. There is a `fp.read()` in there somewhere reading the entire JSON file. – Finn Årup Nielsen Oct 29 '19 at 12:52
  • This does not work if your json contains unicode. Pretty sad that this is the most up voted answer. – Ivan C Sep 20 '21 at 11:23
  • I just want to add that to anyone who cannot print no ascii values with this approach that as of python >=3.9 you can do: $ python -m json.tool --no-ensure-ascii to print them. – Pepe Alvarez Jan 07 '22 at 08:07
  • Since python 3 is default for Ubuntu, the new alias is: `alias pretty='python3 -mjson.tool | pygmentize -l json'` – Kellen Stuart Jan 08 '22 at 02:23
1491

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"
David Moles
  • 48,006
  • 27
  • 136
  • 235
Vita Pluvia
  • 470
  • 1
  • 4
  • 10
  • 18
    There is also a `--sort-keys` option, which is helpful in some cases. – Matthew Flaschen Nov 04 '14 at 01:17
  • jq is a great tool, which I discovered through this answer. Be aware however that it requires whole objects to work on. It won't start outputting results until it has read in the whole input object. – jimbo Jan 02 '15 at 23:00
  • 23
    Working with curl: `curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.'` – Hover Ruan Apr 21 '15 at 07:44
  • 32
    "jq ." is great as a pretty-printer, but it comes with a caveat: jq (up to and including jq version 1.5) will alter the values of very large and very small numbers because it parses numeric values as IEEE 754 64-bit values. To check whether your favorite pretty-printer has the same issue, try this value: 1e1000. Note that *python -mjson.tool* fails this test badly in that it produces Infinity, which is not even JSON. – peak Sep 04 '15 at 02:38
  • 1
    As a note, you can redirect the formatted result to a file: `echo '{ "foo": "lorem", "bar": "ipsum" }' | jq . > myfile`. – Leo Nov 18 '16 at 05:33
  • 28
    @Meekohi the alternative is "unnecessary use of echo". Super happy to have found the `<<<` operator – exactly what I was looking for. – jchook Dec 28 '16 at 20:10
  • Here's a nice runthru of `jq`'s features, including a section on pretty-printing: https://shapeshed.com/jq-json/#how-to-pretty-print-json. One way to write your ugly file to a pretty one: `cat ugly.json | jq '.' | cat > pretty.json` – ericsoco May 11 '17 at 20:39
  • Typing `cat | jq .` and then pasting used to work. No longer, it seems... jq just exits for some reason. Now I use my paste-from-clipboard alias: `clipread | jq`. The alias is `alias clipread='xclip -out -selection clipboard'` (add this to your `~/.bashrc` or zshrc or whatever-rc, and choose an alias name that you like). – Luc Aug 16 '17 at 07:44
  • Reading from a file `jq . <<< cat filename.json` – Hendry Oct 13 '17 at 10:59
  • 5
    `jq` is the best because it prints in colors! – phil294 Jan 13 '18 at 23:07
  • @Luc . Try `cat - | jq .` with pasted text. Good luck to all. – shellter Mar 19 '18 at 12:39
  • `jq -C ` to include colors. If you piping the output to `less`, then `export LESS="-R"` and then use `jq -C ... | less`. Without `-C`, `jq` suppresses colors when the output is not directed to a terminal, as in `| command` or `> file`. – codeforester Nov 09 '18 at 23:56
  • jq has the irritating property that it will silently loose precision on numbers. E.g. if your input has `"foo": 16962331779841739123` then `jq '.'` will silently round the number to `"foo": 16962331779841739000`. If I'm only looking for a pretty-printer, then I'd chose one that's not lossy. – Lucian Wischik May 27 '19 at 05:18
  • +1 unlike the python solution, jq also handles some improperly formatted data (e.g. Ubiquiti's NVR backup files) like this: `echo '{"foo":0}{"bar":1}' | jq` where python chokes on the missing comma and gives no formatted output. – TheAmigo Jul 24 '20 at 20:42
  • `echo '{"value": 1e1000}' | fx .value` – Anton Medvedev Sep 03 '20 at 22:36
  • 2
    Why on earth is this answer with more than 1000 upvotes hidden on page 2? `jq` is by far one of the best tools for the job. Stack Overflow needs to improve its answer sorting algorithm. – friederbluemle Dec 09 '20 at 09:06
  • On macOS: `brew install jq` – Sliq Jul 14 '21 at 14:49
  • Inspired by @HoverRuan and [this](https://stackoverflow.com/a/69821438/1705829), remove `.`: `curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq` – Timo Apr 14 '22 at 21:18
  • I also like `pbpaste | jq` – Peter Ehrlich Apr 30 '23 at 16:41
409

I use the "space" argument of JSON.stringify to pretty-print JSON in JavaScript.

Examples:

// Indent with 4 spaces
JSON.stringify({"foo":"lorem","bar":"ipsum"}, null, 4);

// Indent with tabs
JSON.stringify({"foo":"lorem","bar":"ipsum"}, null, '\t');

From the Unix command-line with Node.js, specifying JSON on the command line:

$ node -e "console.log(JSON.stringify(JSON.parse(process.argv[1]), null, '\t'));" \
  '{"foo":"lorem","bar":"ipsum"}'

Returns:

{
    "foo": "lorem",
    "bar": "ipsum"
}

From the Unix command-line with Node.js, specifying a filename that contains JSON, and using an indent of four spaces:

$ node -e "console.log(JSON.stringify(JSON.parse(require('fs') \
      .readFileSync(process.argv[1])), null, 4));"  filename.json

Using a pipe:

echo '{"foo": "lorem", "bar": "ipsum"}' | node -e \
"\
 s=process.openStdin();\
 d=[];\
 s.on('data',function(c){\
   d.push(c);\
 });\
 s.on('end',function(){\
   console.log(JSON.stringify(JSON.parse(d.join('')),null,2));\
 });\
"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Somu
  • 3,593
  • 6
  • 34
  • 44
  • 10
    For debugging objects in Node.js, you should really use sys.inspect() instead of JSON.stringify(). Here's why: http://markhansen.co.nz/inspecting-with-json-stringify/ – Gurpartap Singh Aug 11 '11 at 18:05
  • 12
    Downvoted. The OP is about a "*nix command-line script" and this answer is a different context. – danorton Sep 02 '12 at 14:30
  • 54
    @danorton: JS can be used from the commandline via node.js and other similar solutions. – calvinf Sep 17 '12 at 20:08
  • Use `node -e "console.log(JSON.stringify(JSON.parse(process.argv[1]), null, '\t'));"` on the Unix command-line (with nodejs) – Timo Tijhof May 02 '13 at 02:30
  • node -e 'var f = require("./package.json"); console.log(f.name);' Even shorter :D :D :D – RusHughes Jun 25 '13 at 14:00
  • 11
    No need for the console: `node -p "JSON.stringify(JSON.parse(process.argv[1]), null, '\t');"` also outputs the result to STDOUT. – Julian D. Nov 05 '14 at 16:26
  • JSON.stringify i always use – kplshrm7 Sep 19 '15 at 12:50
  • 3
    It sucks that the script is different for a filename vs. stdin – Lukasz Wiktor Feb 17 '16 at 13:39
  • 1
    @LukaszWiktor it doesn't have to be if your *nix supports `/dev/stdin`! – strugee Apr 08 '18 at 06:41
  • 1
    Why don't you use `require('util').inspect(JSON.parse(obj))`? It provides pretty printing, colors and [a bunch of other features](https://dev.to/siddharthshyniben/the-node-js-util-module-3nbd#:~:text=now%2C%20you%20may%20think%20it%20is%20just%20an%20equivalent%20of%20console.log(json.stringify(obj))%2C%20but%20there%20is%20a%20lot%20more%20functionality%20available%20using%20the%20options%20object.%20some%20of%20the%20more%20useful%20options%20are%3A) – Siddharth Shyniben Jun 01 '21 at 13:37
  • the article @GurpartapSingh linked is not available anymore. for anyone who wanted to read it, [here's the most recent capture](https://web.archive.org/web/20130208101422/http://markhansen.co.nz/inspecting-with-json-stringify) from the wayback machine – starwarswii May 11 '23 at 14:21
  • @GurpartapSingh your link is dead. That's why I don't like external links. – Lucio Mollinedo Jun 27 '23 at 14:22
355

I wrote a tool that has one of the best "smart whitespace" formatters available. It produces more readable and less verbose output than most of the other options here.

underscore-cli

This is what "smart whitespace" looks like:

I may be a bit biased, but it's an awesome tool for printing and manipulating JSON data from the command-line. It's super-friendly to use and has extensive command-line help/documentation. It's a Swiss Army knife that I use for 1001 different small tasks that would be surprisingly annoying to do any other way.

Latest use-case: Chrome, Dev console, Network tab, export all as HAR file, "cat site.har | underscore select '.url' --outfmt text | grep mydomain"; now I have a chronologically ordered list of all URL fetches made during the loading of my company's site.

Pretty printing is easy:

underscore -i data.json print

Same thing:

cat data.json | underscore print

Same thing, more explicit:

cat data.json | underscore print --outfmt pretty

This tool is my current passion project, so if you have any feature requests, there is a good chance I'll address them.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dave Dopson
  • 41,600
  • 19
  • 95
  • 85
  • 4
    I also updated my ~/.bash_profile to have the following line: alias underscor='underscore print --outfmt pretty' now I can just do curl http://example.com/result.json | underscor and still use underscore for other formatting – Gal Bracha Nov 20 '13 at 18:42
  • Thanks Dave! Tool is good! alias pretty-json="underrsore pretty" and curl output pleasing an eye – Maxim Ponomarev Jan 20 '15 at 09:44
  • Great formatting tool, just one note: forwarding output to a file (either with _-o_ option or with _>_ ) works only with _underscore print_. _underscore pretty_ saves a file with color formatting signs being inserted, smth like: `[32m`, `[33m`, `[39m` along with some non-printable before each of them, which makes JSON not valid. However, _underscore print_ alone doesn't add anything to a file and does its formatting job perfectly. – tiurin Jan 24 '15 at 12:18
  • I love `jq` but this worked great for my "JSON" that didn't have double quoted keys. – Bluu Feb 27 '15 at 00:37
  • @DaveDopson thanks for the great tool!! Gonna try using it alongside http://jsonselect.org/#tryit ... – mycargus May 14 '15 at 02:37
  • Also, using `npm` (use creationix/nvm :) ) to install, because it should be global: npm install -g underscore-cli ... then in `.bash_profile`: alias json='underscore print --color' ... and use like: cat some.json | json Underscore-CLI is really great and easy to integrate into your development environment. – mysterlune Jan 19 '16 at 19:32
184

I usually just do:

echo '{"test":1,"test2":2}' | python -mjson.tool

And to retrieve select data (in this case, "test"'s value):

echo '{"test":1,"test2":2}' | python -c 'import sys,json;data=json.loads(sys.stdin.read()); print data["test"]'

If the JSON data is in a file:

python -mjson.tool filename.json

If you want to do it all in one go with curl on the command line using an authentication token:

curl -X GET -H "Authorization: Token wef4fwef54te4t5teerdfgghrtgdg53" http://testsite/api/ | python -mjson.tool
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jassinm
  • 7,323
  • 3
  • 33
  • 42
  • if the json is supposed to come directly froma http api this is also a nice tool implemented in python: https://github.com/jkbr/httpie – Florian Nov 07 '13 at 12:51
  • If you have node installed (and don't mind the YAML style output) there's also this package: http://rafeca.com/prettyjson/ so you can end a curl with `| prettyjson` – Iolo Feb 16 '15 at 09:47
  • 3
    As noted above, one of the problems with *python -mjson.tool* as a JSON pretty-printer is that it does not always emit JSON. E.g. 1e1000 becomes Infinity (whether using python 2.x or 3.x). 'jq .' always produces JSON, but it does not guarantee that very large (or very small values) are preserved exactly. – peak Sep 04 '15 at 02:54
100

If you use npm and Node.js, you can do npm install -g json and then pipe the command through json. Do json -h to get all the options. It can also pull out specific fields and colorize the output with -i.

curl -s http://search.twitter.com/search.json?q=node.js | json
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
isaacs
  • 16,656
  • 6
  • 41
  • 31
96

It is not too simple with a native way with the jq tools.

For example:

cat xxx | jq .
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Olexandr Minzak
  • 156
  • 3
  • 9
  • 7
    WARNING: jq encodes numbers as IEEE 754 64-bit floats, and thus their representation is likely to change. The precision of very small and very large numbers is likely to be lost. To check whether your favorite pretty-printer has the same issue, try this value: 1e1000. – peak Oct 20 '17 at 07:23
  • 5
    or simply: `jq . file.json` ; but also `cat file.json | jq` (without the filter `.`) also works. (on ubuntu/linux; ymmv across platforms) – michael Dec 01 '17 at 07:33
94

Thanks to J.F. Sebastian's very helpful pointers, here's a slightly enhanced script I've come up with:

#!/usr/bin/python

"""
Convert JSON data to human-readable form.

Usage:
  prettyJSON.py inputFile [outputFile]
"""

import sys
import simplejson as json


def main(args):
    try:
        if args[1] == '-':
            inputFile = sys.stdin
        else:
            inputFile = open(args[1])
        input = json.load(inputFile)
        inputFile.close()
    except IndexError:
        usage()
        return False
    if len(args) < 3:
        print json.dumps(input, sort_keys = False, indent = 4)
    else:
        outputFile = open(args[2], "w")
        json.dump(input, outputFile, sort_keys = False, indent = 4)
        outputFile.close()
    return True


def usage():
    print __doc__


if __name__ == "__main__":
    sys.exit(not main(sys.argv))
Peter Rincker
  • 43,539
  • 9
  • 74
  • 101
  • 3
    When the values are loaded into the dictionary, the order is lost: normal `dict` objects do not have a defined order. Try `json.dumps(json.loads('{"b": 1, "a": 2}'), sort_keys=False)` and you'll find they're swapped anyway. To fix it, import `OrderedDict` and `load` passing `object_pairs_hook=OrderedDict`. – icktoofay May 31 '13 at 02:58
  • You can change the script to read from standard input with this: `inputFile = sys.stdin`. This lets you pipe stuff to the script like so: `curl http://somewhere.com/foo.json | pp_json.py` – Gabe Johnson Oct 31 '14 at 18:37
  • 1
    And to avoid sorting with @icktoofay's comment, import OrderedDict like this: `from collections import OrderedDict`. – Hugo Sep 22 '15 at 09:30
  • 2
    Thanks @icktoofay. This allowed me to create the following vim function: `com! FormatJSON %!python -c "from collections import OrderedDict; import sys; import json; j = json.load(sys.stdin, object_pairs_hook=OrderedDict); json.dump(j, sys.stdout, sort_keys=False, indent=4, separators=(',', ': '))"` Note that the separators must be set as (',', ': ') to avoid trailing whitespace being added: https://bugs.python.org/issue16333 – blindsnowmobile Jun 13 '16 at 17:05
  • Great snippet! I've used `sort_keys = True` instead, because I want to use this to compare json files and it works like a charm. – JL Peyret Jan 25 '17 at 20:40
84

a simple bash script for pretty json printing

json_pretty.sh

#/bin/bash

grep -Eo '"[^"]*" *(: *([0-9]*|"[^"]*")[^{}\["]*|,)?|[^"\]\[\}\{]*|\{|\},?|\[|\],?|[0-9 ]*,?' | awk '{if ($0 ~ /^[}\]]/ ) offset-=4; printf "%*c%s\n", offset, " ", $0; if ($0 ~ /^[{\[]/) offset+=4}'

Example:

cat file.json | json_pretty.sh
Evgeny Karpov
  • 2,386
  • 26
  • 16
  • 1
    Thanks for the feedback. I just wrote this script today for personal using and it worked fine in my cases. I made fixes, now it's smaller and without this problem. There is not a goal to support completely format, but i can make other fixes if necessary. – Evgeny Karpov Jul 27 '16 at 16:58
  • 7
    That is only working answer I found. I have an embedded linux - no rubby, no javascript, no access to internet to download python modules... I have slightly different awk that does not support `%*c` notation so I changed the `printf` to `c=0; while (c++ – Zaboj Campula Oct 06 '16 at 10:21
  • 6
    This should be the accepted, as it's full native and don't require third party software... – Blag Feb 20 '18 at 14:12
  • @Blag the script looked broken after your editing, please explain or correct it. thanks! – Evgeny Karpov Feb 21 '18 at 03:31
  • 1
    @EvgenyKarpov nice catch, no need for a full rollback, just the `grep` that was erased by mistake ;) – Blag Feb 21 '18 at 06:47
  • 2
    This script is pretty fragile and it doesn't support full json syntax. For example it turns `{ "\"" : "quote" }` into `{ "\" " : " }` (on multiple lines). – Rotsor Jun 23 '19 at 15:45
  • This works pretty well with piping. `getMyLogs | grep -Eo ...` – Matthis Kohli Aug 15 '19 at 11:41
  • 1
    Thanks dude, I wanted a quick way to format an 8MB one-liner json, in bare simple bash. – Ahmed M Aug 19 '19 at 09:40
  • 1
    In my case, I also needed to execute `json_pretty.sh`, e.g. `cat file.json | ./json_pretty.sh` – pcko1 Mar 09 '20 at 15:36
  • 1
    Best solution if you have a stand-alone script and you don't want to make someone install Homebrew, python, ruby, node.js... – njh Jan 01 '21 at 23:46
  • Really good answer. This is the only method that worked for me to deal with a broken json oneline file. Thanks – hmontoliu Jan 17 '22 at 11:47
  • @UrsineRaven feel free to bring your changes to the post if it brings improvements – Evgeny Karpov Apr 14 '22 at 12:06
  • @EvgenyKarpov I apparently need 100 reputation to do that, but I also just noticed that I should have changed `[0-9 ]*,?` to `[0-9]+ *,?|,` instead of `[0-9]+ *,?`, so that we don't lose the commas after arrays in objects (i.e. with my above comment, we lose the comma after `]` in `{"a":[1,2],"b":"c"}`). So, I guess I'll just have to delete my comment and repost it with the fix for now. – UrsineRaven Apr 14 '22 at 20:21
  • I made @ZabojCampula's changes (also necessary for me) and I also made a fix for what @Rotsor mentioned and came up with this: `grep -Eo '"([^"\]*(\\")*(\\[^"])*)*" *(: *([0-9]*|"([^"\]*(\\")*(\\[^"])*)*")[^{}\["]*|,)?|[^"\]\[\}\{]*|\{|\},?|\[|\],?|[0-9]+ *,?|,' | awk '{if ($0 ~ /^[]}]/ ) offset-=4; c=0; while (c++ – UrsineRaven Apr 14 '22 at 20:24
  • I ended up making [a script](https://gist.github.com/UrsineRaven/95061d097de04d9130f470a4c0200a91) (based on the JSON definition on json.org) that should be mostly language complete for JSON and pretty-prints the JSON that is piped into it. – UrsineRaven May 18 '23 at 20:30
77

With Perl, use the CPAN module JSON::XS. It installs a command line tool json_xs.

Validate:

json_xs -t null < myfile.json

Prettify the JSON file src.json to pretty.json:

< src.json json_xs > pretty.json

If you don't have json_xs, try json_pp . "pp" is for "pure perl" – the tool is implemented in Perl only, without a binding to an external C library (which is what XS stands for, Perl's "Extension System").

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
knb
  • 9,138
  • 4
  • 58
  • 85
  • 9
    Seems to come standard with Cygwin! – Janus Troelsen May 15 '12 at 11:16
  • 15
    json_pp can be used in the same way and is most probably readily installed on your system (on Debian it is in the 'perl' package). – MichielB Dec 06 '13 at 09:42
  • 8
    FYI, on my Mac OS X 10.9 system, json_pp is available automatically. – Gregg Williams May 13 '14 at 03:38
  • `-t null` gave me _null: not a valid toformat_... but leaving it off worked splendidly. Thanks. – Lucas Mar 04 '17 at 20:53
  • pp is for pure perl, not pretty print here :) Since json_xs and json_pp can do more than just pretty print and also with -json_opt do other things instead of pretty printing. Although pretty printing is the default behaviour. – Kjetil S. Mar 20 '17 at 18:57
  • `json_xs` and `json_pp` neither preserve key order nor sort the keys. Pretty-printing the same JSON file twice is likely to produce different results. (Tested with perl-5.26.1-6 and libjson-xs-perl-3.040-1 on Ubuntu 18.04.) –  May 24 '18 at 12:00
74

On *nix, reading from stdin and writing to stdout works better:

#!/usr/bin/env python
"""
Convert JSON data to human-readable form.

(Reads from stdin and writes to stdout)
"""

import sys
try:
    import simplejson as json
except:
    import json

print json.dumps(json.loads(sys.stdin.read()), indent=4)
sys.exit(0)

Put this in a file (I named mine "prettyJSON" after AnC's answer) in your PATH and chmod +x it, and you're good to go.

serverhorror
  • 779
  • 5
  • 21
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173
  • Indeed, using stdin/stdout is much more flexible and simple. Thanks for pointing it out. – AnC Aug 01 '09 at 07:28
  • 3
    For programs that expect a named file, use /dev/stdin, ditto for out and err. – dvogel Aug 04 '10 at 21:08
  • 4
    FYI [`fileinput.input()`](http://docs.python.org/library/fileinput.html#fileinput.input) reads from stdin if there are no files given at a command-line. [Example](http://stackoverflow.com/questions/352098/how-to-pretty-print-json-script/352160#352160) – jfs May 19 '11 at 06:41
  • fileinput.input() can't deal well with files with no newline at the end, last time I checked. – Zachary Vance Apr 18 '13 at 20:53
  • he askes in shell script, not python other language. With JQ can do it perfectly. – Bui Anh Tuan Aug 22 '17 at 08:34
73

That's how I do it:

curl yourUri | json_pp

It shortens the code and gets the job done.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tedi
  • 6,350
  • 5
  • 52
  • 67
  • 4
    Ubuntu server: If you have production machines with very restricted installations, this might be the best choice as it is installed by default under a specific name. Python is often installed in different ways (eg python3, python or not at all) depending on the version. – jonathanjo Jun 21 '19 at 13:22
  • 1
    works for mac :) – Fabian Rios Jun 09 '22 at 09:18
  • 2
    Works for both MacOS and Linux (Debian) by default. I'd recommend this answer – Mitrakov Artem Sep 21 '22 at 11:05
68

The JSON Ruby Gem is bundled with a shell script to prettify JSON:

sudo gem install json
echo '{ "foo": "bar" }' | prettify_json.rb

Script download: gist.github.com/3738968

Tilo
  • 33,354
  • 5
  • 79
  • 106
Paul Horsfall
  • 8,122
  • 1
  • 19
  • 7
  • 7
    Note that this solution decode the unicode "\uxxxx" escape sequences, unlike the Python one with `json.tool`. However, it also seems to have nesting depth limitations (`nesting of 20 is too deep (JSON::NestingError)`). – a3nm May 30 '11 at 06:40
  • 2
    on Ubuntu you can do: ``sudo apt-get install ruby-json-pure`` instead of ``gem install`` – Janus Troelsen Mar 27 '12 at 17:45
  • 1
    ```eric-mbp:~ ericstob$ sudo gem install json Password: Fetching: json-1.7.3.gem (100%) Building native extensions. This could take a while... Successfully installed json-1.7.3 1 gem installed Installing ri documentation for json-1.7.3... Installing RDoc documentation for json-1.7.3... eric-mbp:~ ericstob$ prettify_json.rb -bash: prettify_json.rb: command not found – Eric Hartford May 31 '12 at 18:05
  • maybe you could post the contents of your `prettify_json.rb`? – Andrew Aug 23 '12 at 16:56
  • You can download the script, move it to your `~/bin` folder (make sure it's in your PATH) rename `prettify_json.rb` to `ppj` and run `chmod +x ppj`. Now you can do something like `curl www.jsonsring.com/something.json | ppj` – Uri Oct 02 '12 at 14:39
  • `prettify_json.rb` ships with Ruby 1.9 and later – Benjamin Oakes Dec 03 '12 at 14:46
66
$ echo '{ "foo": "lorem", "bar": "ipsum" }' \
> | python -c'import fileinput, json;
> print(json.dumps(json.loads("".join(fileinput.input())),
>                  sort_keys=True, indent=4))'
{
    "bar": "ipsum",
    "foo": "lorem"
}

NOTE: It is not the way to do it.

The same in Perl:

$ cat json.txt \
> | perl -0007 -MJSON -nE'say to_json(from_json($_, {allow_nonref=>1}), 
>                                     {pretty=>1})'
{
   "bar" : "ipsum",
   "foo" : "lorem"
}

Note 2: If you run

echo '{ "Düsseldorf": "lorem", "bar": "ipsum" }' \
| python -c'import fileinput, json;
print(json.dumps(json.loads("".join(fileinput.input())),
                 sort_keys=True, indent=4))'

the nicely readable word becomes \u encoded

{
    "D\u00fcsseldorf": "lorem", 
    "bar": "ipsum"
}

If the remainder of your pipeline will gracefully handle unicode and you'd like your JSON to also be human-friendly, simply use ensure_ascii=False

echo '{ "Düsseldorf": "lorem", "bar": "ipsum" }' \
| python -c'import fileinput, json;
print json.dumps(json.loads("".join(fileinput.input())),
                 sort_keys=True, indent=4, ensure_ascii=False)'

and you'll get:

{
    "Düsseldorf": "lorem", 
    "bar": "ipsum"
}
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • actually I do the same but with javascript itself :) – Robert Gould Dec 09 '08 at 08:55
  • 2
    In the version of the JSON module I have, `to_json` doesn't seem to accept options. But this works: `perl -MJSON -nE 'say JSON->new->pretty->encode(from_json $_)' text.json` – Rörd Dec 16 '11 at 15:12
  • 2
    The Python example could be simplified. It's much easier to pipe JSON output straight into `python -m json.tool`. – Dan Loewenherz Mar 17 '14 at 02:28
  • @Dan: yes. And there are several answers that show `json.tool` code examples. 1. this version allows you to change some parameters e.g., `indent` 2. At the time of the posting (2008) Python 2.4 was still used [that doesn't support `-mjson.tool`](http://stackoverflow.com/questions/352098/how-can-i-pretty-print-json#comment7007134_1920585) – jfs Mar 17 '14 at 07:21
  • @dwlz command-line version with unicode characters (requires python3.9+): python -m json.tool --no-ensure-ascii in.json out.json – Guram Savinov Mar 30 '23 at 12:53
60

UPDATE I'm using jq now as suggested in another answer. It's extremely powerful at filtering JSON, but, at its most basic, also an awesome way to pretty print JSON for viewing.

jsonpp is a very nice command line JSON pretty printer.

From the README:

Pretty print web service responses like so:

curl -s -L http://<!---->t.co/tYTq5Pu | jsonpp

and make beautiful the files running around on your disk:

jsonpp data/long_malformed.json

If you're on Mac OS X, you can brew install jsonpp. If not, you can simply copy the binary to somewhere in your $PATH.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jordelver
  • 8,292
  • 2
  • 32
  • 40
  • 1
    I tried jsonpp (used in the past successful) against a huge file (>60MB). I stopped it after 5min. I piped it into `python -mjson.tool` (from other answer here) and it took 10-20sec... – volker Apr 28 '15 at 19:27
  • 60MB of JSON? Wow! I don't typically deal with files that big but useful to know. Thanks. – jordelver Apr 28 '15 at 21:43
  • On my ubuntu box I have a `json_pp` - which does format json nicely, although despite the similarity in naming, I believe this to be an entirely different project from the `jsonpp` mentioned here – davidpricedev Jul 29 '16 at 11:24
54

Try pjson. It has colors!

echo '{"json":"obj"} | pjson

Install it with pip:

⚡ pip install pjson

And then pipe any JSON content to pjson.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
43

Or, with Ruby:

echo '{ "foo": "lorem", "bar": "ipsum" }' | ruby -r json -e 'jj JSON.parse gets'
darscan
  • 963
  • 1
  • 12
  • 17
  • That gives me an error. Do you need some ruby json package installed? – mjs Jan 06 '10 at 12:09
  • 3
    Yes, you need the JSON Ruby Gem: sudo gem install json – darscan Jan 09 '10 at 13:38
  • @MatSchaffer Note that this does not work if you are using JSON to serialize objects with custom `to_json` methods; `Kernel#jj` only pretty-prints arrays and hashes of the same (or numbers/strings/booleans). – Phrogz Jun 27 '11 at 15:59
  • On Windows, try this: `echo { "foo": "lorem", "bar": "ipsum" } | ruby -r json -e 'jj JSON.parse gets'` – Ross Attrill Feb 14 '16 at 22:43
42

You can use this simple command to achieve the result:

echo "{ \"foo\": \"lorem\", \"bar\": \"ipsum\" }"|python -m json.tool
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Arpit Rathod
  • 91
  • 1
  • 4
  • 11
41

I use jshon to do exactly what you're describing. Just run:

echo $COMPACTED_JSON_TEXT | jshon

You can also pass arguments to transform the JSON data.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
yar
  • 2,428
  • 1
  • 18
  • 6
  • Thanks, jshon is a lot faster than using python or ruby for the same task – Alexander Jun 13 '12 at 22:45
  • 2
    @Alexander - How fast a pretty printer do you need? I'm on OSx Lion that comes with Python preinstalled. With python -mjson.tool I can pretty print a 96KB json file in 0.1s - the json output of earthporn that jshon links to is about 24KB and I can pretty print that in 0.08s. How much faster is jshon for you? – joensson Jun 20 '12 at 11:32
  • 1
    I'm working with 1+GB compressed (who even knows how big uncompressed) JSON data files, so I very much appreciate the suggestion that jshon is faster. – Ryan Ballantyne Apr 22 '13 at 20:48
39

Check out Jazor. It's a simple command line JSON parser written in Ruby.

gem install jazor
jazor --help
Mike Conigliaro
  • 1,144
  • 1
  • 13
  • 28
  • 5
    Is it just me or is this the only suggestion that actually answers the OP's question? I came here looking for a simple command into which I could pipe the output of `curl` and this is the only one that did it for me. – Leo Cassarani Nov 23 '11 at 00:32
  • 2
    I like that it has the option to colorize the output. Makes it easier to read. – Andrew Aug 23 '12 at 18:07
  • ooh I also like the option to pass a url since I am using this to view the output of my REST API – Andrew Aug 23 '12 at 18:11
37

You only need to use jq

If jq is not installed then you need to install jq first:

sudo apt-get update
sudo apt-get install jq

After installing jq then only need to use jq:

echo '{ "foo": "lorem", "bar": "ipsum" }' | jq

Output looks like

{
  "foo": "lorem",
  "bar": "ipsum"
}
The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
Techie
  • 8,594
  • 1
  • 13
  • 7
31

JSONLint has an open-source implementation on GitHub that can be used on the command line or included in a Node.js project.

npm install jsonlint -g

and then

jsonlint -p myfile.json

or

curl -s "http://api.twitter.com/1/users/show/user.json" | jsonlint | less
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Salman A
  • 262,204
  • 82
  • 430
  • 521
  • I recommend not installing nodejs/npm dependencies globally => I'd use `npx` instead: `curl -s "http://api.twitter.com/1/users/show/user.json" | npx jsonlint | less` (i.e. no `npm install` necessary) – Adrien Joly Jun 18 '20 at 12:50
30

Simply pipe the output to jq ..

Example:

twurl -H ads-api.twitter.com '.......' | jq .
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Ackshaey Singh
  • 863
  • 10
  • 5
  • Nice answer @Ackshaey Singh and one can re-direct the same to a file easily as well. e.g. `cat | jq . > ` – Pramit Oct 07 '16 at 21:50
  • 9
    `brew install jq` if your are on mac os. – Distwo Oct 14 '16 at 16:38
  • 1
    Unfortunately, using `jq .` for pretty-printing has one **potential** drawback: all extant versions of jq insist on treating JSON numbers as IEEE numbers, so precision is easily lost, e.g. for very large integers. – peak Oct 21 '16 at 06:00
  • 2
    @Pramit `cat file |` is invariably a waste of a process; just do `jq . output_name.txt` (with literal `<` and `>` characters). – Mark Reed Jan 31 '17 at 13:08
29

You can simply use standard tools like jq or json_pp.

echo '{ "foo": "lorem", "bar": "ipsum" }' | json_pp

or

echo '{ "foo": "lorem", "bar": "ipsum" }' | jq

will both prettify output like the following (jq even more colorful):

{
  "foo": "lorem",
  "bar": "ipsum"
}

The huge advantage of jq is that it can do A LOT more if you'd like to parse and process the json.

Schmitzi
  • 149
  • 3
  • 11
25

Pygmentize

I combine Python's json.tool with pygmentize:

echo '{"foo": "bar"}' | python -m json.tool | pygmentize -g

There are some alternatives to pygmentize which are listed in my this answer.

Here is a live demo:

Demo

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shubham Chaudhary
  • 47,722
  • 9
  • 78
  • 80
25

With Perl, if you install JSON::PP from CPAN you'll get the json_pp command. Stealing the example from B Bycroft you get:

[pdurbin@beamish ~]$ echo '{"foo": "lorem", "bar": "ipsum"}' | json_pp
{
   "bar" : "ipsum",
   "foo" : "lorem"
}

It's worth mentioning that json_pp comes pre-installed with Ubuntu 12.04 (at least) and Debian in /usr/bin/json_pp

Community
  • 1
  • 1
Philip Durbin
  • 4,042
  • 2
  • 25
  • 36
20

I recommend using the json_xs command line utility which is included in the JSON::XS perl module. JSON::XS is a Perl module for serializing/deserializing JSON, on a Debian or Ubuntu machine you can install it like this:

sudo apt-get install libjson-xs-perl

It is obviously also available on CPAN.

To use it to format JSON obtained from a URL you can use curl or wget like this:

$ curl -s http://page.that.serves.json.com/json/ | json_xs

or this:

$ wget -q -O - http://page.that.serves.json.com/json/ | json_xs

and to format JSON contained in a file you can do this:

$ json_xs < file-full-of.json

To reformat as YAML, which some people consider to be more humanly-readable than JSON:

$ json_xs -t yaml < file-full-of.json
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
htaccess
  • 2,800
  • 26
  • 31
20

jj is super-fast, can handle ginormous JSON documents economically, does not mess with valid JSON numbers, and is easy to use, e.g.

jj -p # for reading from STDIN

or

jj -p -i input.json

It is (2018) still quite new so maybe it won’t handle invalid JSON the way you expect, but it is easy to install on major platforms.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
peak
  • 105,803
  • 17
  • 152
  • 177
17

Install yajl-tools with the command below:

sudo apt-get install yajl-tools

then,

echo '{"foo": "lorem", "bar": "ipsum"}' | json_reformat
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
17

bat is a cat clone with syntax highlighting:

Example:

echo '{"bignum":1e1000}' | bat -p -l json

-p will output without headers, and -l will explicitly specify the language.

It has colouring and formatting for JSON and does not have the problems noted in this comment: How can I pretty-print JSON in a shell script?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Grav
  • 1,714
  • 14
  • 27
17

When you have node installed on your system the following works.

echo '{"test":1,"test2":2}' | npx json

{
  "test": 1,
  "test2": 2
}
Rafiek
  • 1,434
  • 1
  • 16
  • 24
16
  1. brew install jq
  2. command + | jq
  3. (example: curl localhost:5000/blocks | jq)
  4. Enjoy!

enter image description here

13

Use Ruby in one line:

echo '{"test":1,"test2":2}' | ruby -e "require 'json'; puts JSON.pretty_generate(JSON.parse(STDIN.read))"

And you can set an alias for this:

alias to_j="ruby -e \"require 'json';puts JSON.pretty_generate(JSON.parse(STDIN.read))\""

Then you can use it more conveniently

echo '{"test":1,"test2":2}' | to_j

{
  "test": 1,
  "test2": 2
}

And if you want display JSON with color, your can install awesome_print,

gem install awesome_print

then

alias to_j="ruby -e \"require 'json';require 'awesome_print';ap JSON.parse(STDIN.read)\""

Try it!

echo '{"test":1,"test2":2, "arr":["aa","bb","cc"] }' | to_j

Enter image description here

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fangxing
  • 5,716
  • 2
  • 49
  • 53
13

A one-line solution using Node.js will look like this:

$ node -e "console.log( JSON.stringify( JSON.parse(require('fs').readFileSync(0) ), 0, 1 ))"

For example:

$ cat test.json | node -e "console.log( JSON.stringify( JSON.parse(require('fs').readFileSync(0) ), 0, 1 ))"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
harish2704
  • 591
  • 6
  • 16
  • no output for me with this example even though I voted this up long time ago. Something changed ... – Matthis Kohli Mar 09 '20 at 14:55
  • 1
    @MatthisKohli: I just rechecked this on Node V12.x and it is working. There is nothing magic in this code. `fs.readFileSync(0)` reads `stdin` of the current process and `JSON.stringify` formats the JSON. So, there is very less chance for breaking API change – harish2704 Mar 09 '20 at 16:22
10

Here is a Ruby solution that is better than Json's prettify command. The gem colorful_json is fairly good.

gem install colorful_json
echo '{"foo": "lorem", "bar": "ipsum"}' | cjson
{
  "foo": "lorem",
  "bar": "ipsum"
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pablo Fernandez heelhook
  • 11,985
  • 3
  • 21
  • 20
10

yajl is very nice, in my experience. I use its json_reformat command to pretty-print .json files in vim by putting the following line in my .vimrc:

autocmd FileType json setlocal equalprg=json_reformat
William Roe
  • 559
  • 1
  • 5
  • 14
Hank Gay
  • 70,339
  • 36
  • 160
  • 222
9

The PHP version, if you have PHP >= 5.4.

alias prettify_json=php -E '$o = json_decode($argn); print json_encode($o, JSON_PRETTY_PRINT);'
echo '{"a":1,"b":2}' | prettify_json
datashaman
  • 8,301
  • 3
  • 22
  • 29
svidgen
  • 13,744
  • 4
  • 33
  • 58
  • 3
    A one liner : `echo '{"a":1,"b":2}' | php -r 'echo json_encode(json_decode(fgets(STDIN)), JSON_PRETTY_PRINT)."\n";'` – Fabien Sa Mar 05 '16 at 13:42
  • 1
    Multiline capable: `printf '{\n"a":1,\n"b":2\n}' | php -r 'echo json_encode(json_decode(file_get_contents("php://stdin")), JSON_PRETTY_PRINT) . PHP_EOL;'` – Zack Morris Feb 23 '17 at 01:35
9

TL;DR: for performances, use jj -p < my.json.

Benchmark

I took some solutions here and benchmarked them with the next dummy script:

function bench {
    time (
      for i in {1..1000}; do
        echo '{ "foo" : { "bar": { "dolorem" : "ipsum", "quia" : { "dolor" : "sit"} } } }' \
        | $@ > /dev/null
      done
    )
}

Here's the result on my mac (32 GB, Apple M1 Max, YMMV):

bench python -m json.tool
# 8.39s user 12.31s system 42% cpu 48.536 total
bench jq
# 13.12s user 1.28s system 87% cpu 16.535 total
bench bat -p -l json # NOTE: only syntax colorisation.
# 1.87s user 1.47s system 66% cpu 5.024 total
bench jj -p
# 1.94s user 2.44s system 57% cpu 7.591 total
bench xidel -s - -e '$json' --printed-json-format=pretty                      
# 4.32s user 1.89s system 76% cpu 8.101 total

Thanks @peak and your answer for this discovery of jj!

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
  • Great, but it would be even nicer if it were a more complex and longer JSON test string. – Hilton Fernandes Feb 18 '22 at 16:01
  • 1
    @HiltonFernandes feel free to edit :) – Ulysse BN Feb 18 '22 at 17:15
  • Dear @Ulysse BN, if I do edit it to add more complexity to the JSON string, would you please try to run your benchmark again ? Unfortunately I don't have a mac (8 GB 2133 MHz LPDDR3, 2.3 GHz Intel Core i5) at hand here. – Hilton Fernandes Mar 03 '22 at 12:41
  • 1
    @HiltonFernandes me neither anymore! But sure I could install stuff and run the benchmark. I'm on an M1 chip now though, so YMMV... BTW steps to install and run the benchmark on a mac: (1.) `brew install jq bat tidwall/jj/jj xidel`, (2.) copy and paste the function block, (3.) copy and paste the bench block, (4.) edit this post with your configuration (about my mac). Also please, no need to be complacent, I get the gist... – Ulysse BN Mar 03 '22 at 16:41
  • Hello, @Ulysse BN, your idea is great and its implementation is very elegant. Congrats also to your M1 powered Mac. Please consider my suggestion of a benchmark in https://gist.github.com/hgfernan/716f599503c21d56ca141da04349ffa1 – Hilton Fernandes Mar 03 '22 at 19:51
  • 1
    @HiltonFernandes there you go – Ulysse BN Mar 03 '22 at 22:48
  • Many thanks for accepting my suggestion, @Ulysse BN ! Would you mind if I ask you what have been the changes in your benchmark list ? – Hilton Fernandes Mar 04 '22 at 01:24
  • @HiltonFernandes you can see changes via the link below the answer ([edited _some time ago_](https://stackoverflow.com/posts/61119751/revisions)) – Ulysse BN Mar 04 '22 at 09:32
  • For everyone reading this; the Xidel version used here (v0.9.8) is NOT the recommended binary to use. Binaries from the development branch are, eventhough they might be considered beta! The latest Xidel dev-build is aprox. 3.5-4.5x faster than v0.9.8 in this particular benchmark. – Reino Mar 04 '22 at 12:10
  • 1
    @Reino I've finally installed xidel 0.9.9, it has **a lot** of dependencies and is not packaged efficiently (TL;DR: `brew install xidel --head` and feel the svn pain). However I'll have to admit, it is fast (`5s`, beats jj). I'd still not advise it: the installation process is heavy, and the the build is yet to be official... **DISCLAIMER:** I'll stop editing this post from now on. I've added enough information in the comment for anyone else to do it, so **please do!** I'm not paid more than you to do that. – Ulysse BN Mar 04 '22 at 12:37
  • 1
    Great @UlysseBN ! I was wondering that in your original form, the cost of starting lots of light threads could become stronger than the pretty printing itself. Now that each run do a little more work, the thread startup cost is probably proportionally smaller. – Hilton Fernandes Mar 04 '22 at 12:40
  • 1
    BTW, sorry to have abused of your time, @UlysseBN. People got very interested in your post. – Hilton Fernandes Mar 04 '22 at 12:42
  • There's no need to compile Xidel yourself when there are lots of [pre-compiled binaries](https://sourceforge.net/projects/videlibri/files/Xidel/Xidel%20development/) available. I'm not a Linux user, but if you're referring to https://github.com/Homebrew/homebrew-core/blob/master/Formula/xidel.rb, it's outdated and using the wrong sources. The pre-compiled Linux binaries only rely on OpenSSL afaik. – Reino Mar 04 '22 at 13:33
8

J.F. Sebastian's solutions didn't work for me in Ubuntu 8.04.
Here is a modified Perl version that works with the older 1.X JSON library:

perl -0007 -MJSON -ne 'print objToJson(jsonToObj($_, {allow_nonref=>1}), {pretty=>1}), "\n";'
Ulf Gjerdingen
  • 1,414
  • 3
  • 16
  • 20
pimlottc
  • 3,066
  • 2
  • 29
  • 24
8

I'm using httpie

$ pip install httpie

And you can use it like this

 $ http PUT localhost:8001/api/v1/ports/my 
 HTTP/1.1 200 OK
 Connection: keep-alive
 Content-Length: 93
 Content-Type: application/json
 Date: Fri, 06 Mar 2015 02:46:41 GMT
 Server: nginx/1.4.6 (Ubuntu)
 X-Powered-By: HHVM/3.5.1

 {
     "data": [], 
     "message": "Failed to manage ports in 'my'. Request body is empty", 
     "success": false
 }
slashmili
  • 1,190
  • 13
  • 16
8

There is TidyJSON.

It's C#, so maybe you can get it to compile with Mono, and working on *nix. No guarantees though, sorry.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Robert Gould
  • 68,773
  • 61
  • 187
  • 272
7

For Node.js you can also use the "util" module. It uses syntax-highlighting, smart indentation, removes quotes from keys and just makes the output as pretty as it gets.

cat file.json | node -e "process.stdin.pipe(new require('stream').Writable({write: chunk =>  {console.log(require('util').inspect(JSON.parse(chunk), {depth: null, colors: true}))}}))"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
adius
  • 13,685
  • 7
  • 45
  • 46
6

The tool ydump is a JSON pretty-printer:

$ ydump my_data.json
{
  "foo": "lorem",
  "bar": "ipsum"
}

Or you can pipe in the JSON:

$ echo '{"foo": "lorem", "bar": "ipsum"}' | ydump
{
  "foo": "lorem",
  "bar": "ipsum"
}

This is probably the shortest solution apart from using the jq tool.

This tool is part of the yojson library for OCaml, and is documented here.

On Debian and derivatives, the package libyojson-ocaml-dev contains this tool. Alternatively, yojson can be installed via OPAM.

josch
  • 6,716
  • 3
  • 41
  • 49
5

If you have Node.js installed you can create one on your own with one line of code. Create a file pretty:

> vim pretty

#!/usr/bin/env node

console.log(JSON.stringify(JSON.parse(process.argv[2]), null, 2));

Add execute permission:

> chmod +x pretty

> ./pretty '{"foo": "lorem", "bar": "ipsum"}'

Or if your JSON is in a file:

#!/usr/bin/env node

console.log(JSON.stringify(require("./" + process.argv[2]), null, 2));

> ./pretty file.json

Community
  • 1
  • 1
Nikhil Ranjan
  • 994
  • 12
  • 16
  • 1
    process.stdin.resume(); var input = ''; process.stdin.on('data', (data) => { input += data; }); process.stdin.on('end', () => { console.log(JSON.stringify(JSON.parse(input), null, 2)); }); – Nikhil Ranjan May 30 '17 at 17:33
5
$ sudo apt-get install edit-json
$ prettify_json myfile.json
Bryan Larsen
  • 9,468
  • 8
  • 56
  • 46
5

You can use Prettier to do this.

npx prettier <JSON file> should print a prettified version of the JSON in the given file, while npx prettier --write <JSON file> will overwrite the given JSON file with prettified JSON.

Caleb Koch
  • 656
  • 1
  • 9
  • 15
4

I've came up with this solution: https://calbertts.medium.com/unix-pipelines-with-curl-requests-and-serverless-functions-e21117ae4c65

# this in your bash profile
jsonprettify() {
  curl -Ss -X POST -H "Content-Type: text/plain" --data-binary @- https://jsonprettify.vercel.app/api/server?indent=$@
}
echo '{"prop": true, "key": [1,2]}' | jsonprettify 4
# {
#     "prop": true,
#     "key": [
#         1,
#         2
#     ]
# }

There's no need to install anything, if you have an internet connection and cURL installed, you can use this function.

Are you in another host where you can't install anything, this would be a perfect solution to that issue.

calbertts
  • 1,513
  • 2
  • 15
  • 34
4

Here is how to do it with Groovy script.

Create a Groovy script, let's say "pretty-print"

#!/usr/bin/env groovy

import groovy.json.JsonOutput

System.in.withReader { println JsonOutput.prettyPrint(it.readLine()) }

Make script executable:

chmod +x pretty-print

Now from the command line,

echo '{"foo": "lorem", "bar": "ipsum"}' | ./pretty-print
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
numan salati
  • 19,394
  • 9
  • 63
  • 66
  • 1
    As much as I love Groovy, it isn't a great fit for little scripts like this due to the overhead of the JVM. My informal measurements show `jq` approximately 50x faster. – MarkHu Jan 19 '18 at 02:10
3

Here is a Groovy one-liner:

echo '{"foo": "lorem", "bar": "ipsum"}' | groovy -e 'import groovy.json.*; println JsonOutput.prettyPrint(System.in.text)'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Orest Ivasiv
  • 181
  • 2
  • 7
3
gem install jsonpretty
echo '{"foo": "lorem", "bar": "ipsum"}' | jsonpretty

This method also "Detects HTTP response/headers, prints them untouched, and skips to the body (for use with `curl -i')".

lev
  • 2,877
  • 23
  • 22
3

https://github.com/aidanmelen/json_pretty_print

from __future__ import unicode_literals
from __future__ import absolute_import
from __future__ import print_function
from __future__ import division

import json
import jsonschema

def _validate(data):
    schema = {"$schema": "http://json-schema.org/draft-04/schema#"}
    try:
        jsonschema.validate(data, schema,
                            format_checker=jsonschema.FormatChecker())
    except jsonschema.exceptions.ValidationError as ve:
        sys.stderr.write("Whoops, the data you provided does not seem to be " \
        "valid JSON.\n{}".format(ve))

def pprint(data, python_obj=False, **kwargs):
    _validate(data)
    kwargs["indent"] = kwargs.get("indent", 4)
    pretty_data = json.dumps(data, **kwargs)
    if python_obj:
        print(pretty_data)
    else:
       repls = (("u'",'"'),
                ("'",'"'),
                ("None",'null'),
                ("True",'true'),
                ("False",'false'))
    print(reduce(lambda a, kv: a.replace(*kv), repls, pretty_data))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aidanmelen
  • 6,194
  • 1
  • 23
  • 24
3

I'm the author of json-liner. It's a command line tool to turn JSON into a grep friendly format. Give it a try.

$ echo '{"a": 1, "b": 2}' | json-liner
/%a 1
/%b 2
$ echo '["foo", "bar", "baz"]' | json-liner
/@0 foo
/@1 bar
/@2 baz
Wu Yongzheng
  • 1,707
  • 17
  • 23
3

With JavaScript/Node.js: take a look at the vkBeautify.js plugin, which provides pretty printing for both JSON and XML text.

It's written in plain JavaScript, less than 1.5 KB (minified) and very fast.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vadimk
  • 1,461
  • 15
  • 11
2

If you don't mind using a third-party tool, you can simply curl to jsonprettyprint.org. This is for the case where you can't install packages on the machine.

curl -XPOST https://jsonprettyprint.org/api -d '{"user" : 1}'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yada
  • 30,349
  • 24
  • 103
  • 144
  • To pipe stdin to this command, do something like this: `echo '{ "foo": "lorem", "bar": "ipsum" }' | curl -XPOST https://jsonprettyprint.org/api -d @-` – Niel de Wet May 29 '17 at 13:13
1

Also be sure to check out JSONFUI: A command line JSON viewer that supports folding

chronos
  • 444
  • 4
  • 13
1

You can use .

Xidel is a command line tool to download and extract data from HTML/XML pages or JSON-APIs, using CSS, XPath 3.0, XQuery 3.0, JSONiq or pattern templates. It can also create new or transformed XML/HTML/JSON documents.

Xidel pretty-prints by default:

$ xidel -se '$json' <<< '{"foo":"lorem","bar":"ipsum"}'
{
  "foo": "lorem",
  "bar": "ipsum"
}

or:

$ echo '{"foo":"lorem","bar":"ipsum"}' | xidel -se '$json'
{
  "foo": "lorem",
  "bar": "ipsum"
}
Reino
  • 3,203
  • 1
  • 13
  • 21
1

yq can be used to pretty print JSON

echo '{"foo": "lorem", "bar": "ipsum"}' | yq -o json

It has an option to define the indent

echo '{"foo": "lorem", "bar": "ipsum"}' | yq -o json --indent 3

You can choose between coloured and monochrome output

echo '{"foo": "lorem", "bar": "ipsum"}' | yq -o json --colors
echo '{"foo": "lorem", "bar": "ipsum"}' | yq -o json --no-colors
jpseng
  • 1,618
  • 6
  • 18
1

My JSON files were not parsed by any of these methods.

My problem was similar to the post Is Google data source JSON not valid?.

The answer to that post helped me find a solution.

It is considered to be invalid JSON without the string keys.

{id:'name',label:'Name',type:'string'}

must be:

{"id": "name", "label": "Name", "type": "string"}

This link gives a nice comprehensive comparison of some of the different JSON parsers: http://deron.meranda.us/python/comparing_json_modules/basic

Which led me to http://deron.meranda.us/python/demjson/. I think this one parser is much more fault tolerant than many others.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nelaaro
  • 3,006
  • 5
  • 38
  • 56
0

If you want to visualize json log at console you can use munia-pretty-json

npm install -g munia-pretty-json

Your json data (app-log.json)

{"time":"2021-06-09T02:50:22Z","level":"info","message":"Log for pretty JSON","module":"init","hostip":"192.168.0.138","pid":123}
{"time":"2021-06-09T03:27:43Z","level":"warn","message":"Here is warning message","module":"send-message","hostip":"192.168.0.138","pid":123}

Run the command:

munia-pretty-json app-log.json

Here is readable output on console:

enter image description here

You can format the output with the template. The default template is '{time} {level -c} {message}'

Using template:

munia-pretty-json -t '{module -c} - {level} - {message}' app-log.json

Output:

enter image description here

Gagan
  • 1,267
  • 3
  • 18
  • 28
0

Agree about jq. You can add the following function to your $HOME/.bashrc:

jqless () {
  args=$1
  shift
  jq --color-output . $args "$@" | less --raw-control-chars
}

This allows an arbitrary number of input JSON files.

Adam Erickson
  • 6,027
  • 2
  • 46
  • 33
-2

You can also use online tools instead if that is an option for you.

I find http://jsonprettyprint.net to be the simplest and easiest.

Adam Parkin
  • 17,891
  • 17
  • 66
  • 87
Javaaaa
  • 3,788
  • 7
  • 43
  • 54
-3

I know that the original post asked for a shell script, but there are so many useful and irrelevant answers that probably did not help the original author. Adding on to irrelevance :)

BTW I could not get any command line tools to work.

If somebody want simple JSON JavaScript code, they could do:

JSON.stringfy(JSON.parse(str), null, 4)

http://www.geospaces.org/geoweb/Wiki.jsp?page=JSON%20Utilities%20Demos

Here is JavaScript code that not only pretties the JSON, but orders them by their attribute or by attribute and level.

If input is

{ "c": 1, "a": {"b1": 2, "a1":1 }, "b": 1},

it either prints (groups all the objects together):

{
     "b": 1,
     "c": 1,
     "a": {
          "a1": 1,
          "b1": 2
     }
}

OR (just orders by key):

{
 "a": {
      "a1": 1,
      "b1": 2
 },
 "b": 1,
 "c": 1
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131