1. json(1)
  2. json tool manual
  3. json(1)

NAME

json - (aka "jsontool") JSON love for your command line.

SYNOPSIS

something-generating-JSON-on-stdout | json [OPTIONS] [LOOKUPS]

json -f FILE [OPTIONS] [LOOKUPS...]

DESCRIPTION

Pipe in your JSON for pretty-printing, JSON validation, filtering, and modification. Supply one or more LOOKUPS to extract a subset of the JSON. HTTP header blocks are skipped by default.

Grouping

(Added in json v4.) Use '-g' or '--group' to group adjacent objects into a single JSON array or to concatenate adjacent arrays into a single array. E.g.:

$ echo '{"a":1}
{"b": 2}' | json -g
[
  {
    "a": 1
  },
  {
    "b": 2
  }
]

$ echo '["one"]
["two"]' | json -g
[
  "one",
  "two"
]

"Adjacent" objects means objects separated by a newline, or by no space at all. Adjacent arrays means separate by a newline. These conditions are chosen as a balance between (a) not being ambiguous to parse with a simple regex and (b) enough to be useful for common cases.

Grouping can be helpful for "one JSON object per line" formats (like Bunyan) or for things such as:

$ cat *.json | json -g ...

As of json v5.1, json -ga will stream, e.g.:

$ yes '{"foo":"bar"}' | json -ga

In json v3 and earlier, this used to be called "auto-arrayification" and was implicit. In json v4 and v5 grouping of adjacent arrays separate by no space was allowed. That was dropped in v6 (see issue #55. See the COMPATIBILITY section below.

Merging

(Added in json v4.) Use '--merge' or '--deep-merge' to merge adjacent JSON objects in the input. Keys in the last object win.

$ echo '{"one":"un","two":"deux"}
{"one":"uno","three":"tres"}' | json --merge
{
  "one": "uno",
  "two": "deux",
  "three": "tres"
}

This could be useful for merging multiple config files, e.g.:

$ cat /opt/app/etc/defaults.json \
    /etc/app/config.json \
    ~/.app/config.json | json --merge
...

Execution

Use the -e CODE option to execute (JavaScript) code on the input JSON.

$ echo '{"name":"trent","age":38}' | json -e 'this.age++'
{
  "name": "trent",
  "age": 39
}

If input is an array, this will automatically process each item separately.

Conditional filtering

Use the -c CODE option to run JavaScript code ending with a statement returning a boolean to filter the input JSON.

$ echo '[{"age":38},{"age":4}]' | json -c 'this.age > 21'
[{"age":38}]

If input is an array, this will automatically process each item separately.

Lookups

Use lookup arguments to extract particular values:

$ echo '{"name":"trent","age":38}' | json name
trent

Use -a for array processing of lookups and tabular output:

$ echo '{"name":"trent","age":38}' | json name
trent
$ echo '[{"name":"trent","age":38},
         {"name":"ewan","age":4}]' | json -a name age
trent 38
ewan 4

Integral values work for array index lookups:

$ echo '["a", "b", "c"]' | json 1
b

Negative array indices are also supported:

$ echo '["a", "b", "c"]' | json -- -1
c
$ echo '["a", "b", "c"]' | json -- -2
b

If your lookup isn't a number or a JS indentifier you can always use JavaScript array-style lookups like this:

$ echo '{"http://example.com": "my-value"} | json '["http://example.com"]'
my-value

just like you would in JavaScript:

$ node
> var d = '{"http://example.com": "my-value"}
> d["http://example.com"]
'my-value'

Pretty-printing

Output is "jsony" by default: 2-space indented JSON with one exception, a single string value is printed without quotes.

$ echo '{"name": "trent", "age": 38}' | json
{
  "name": "trent",
  "age": 38
}

Use -o json for explicit JSON, -o json-N for N-space indent:

$ echo '{"name": "trent", "age": 38}' | json -o json-0
{"name":"trent","age":38}

Use -H to exclude a leading HTTP header block as from curl -i.

Listing keys

Sometimes you want the list of keys for an object. Use -k or --keys for that:

$ echo '{"name": "trent", "age": 38}' | json -k
[
  "name",
  "age"
]
$ echo '{"name": "trent", "age": 38}' | json -ka
name
age

OPTIONS

-h, --help

Print this help info and exit.

--version

Print version of this command and exit.

-q, --quiet

Don't warn if input isn't valid JSON.

By default json will process input from stdin. Alternatively, an input file (or files) can be specified:

-f FILE
Specify an input file (instead of stdin).

By default json output is to stdout. Together with -f FILE, in-place editing can be done:

-I, --in-place
Edit the file given with -f FILE in-place. Lookups are not allowed with in-place editing, because it is too easy to accidentally lose file data.

If your JSON output is a REST API response, it might include the headers (e.g. when calling with curl -i). By default json will pass those headers through (without choking on them). However if you want them stripped you can use:

-H
drop any HTTP header block (as from curl -i ...)

Other pre-JSON input handling:

-g, --group

Group adjacent objects into an array of objects, or concatenate adjacent arrays into a single array.

--merge, --deep-merge

Merge adjacent objects into a single object with merged keys. Values in later objects win. Use --deep-merge to recursively merge keys in objects.

You can process elements of an input array separately and generate tabular output:

-a, --array

Process input as an array of separate inputs and output in tabular form.

-d DELIM

Delimiter character for tabular output (default is ' ').

-A

Process input as a single object, i.e. stop -e and -c automatically processing each item of an input array.

You can execute code on (-e) and filter (-c) the input (this is done before LOOKUPS are processed, if any). If datum is an object, then a shortcut is <key>. To remove a key, use this.<key> = undefined. For array items, use this[<index>] = 42.

-e CODE

Execute the given JavaScript code on the input. If input is an array, then each item of the array is processed separately (use -A to override).

-c CODE

Filter the input with JavaScript CODE. If CODE returns false-y, then the item is filtered out. If input is an array, then each item of the array is processed separately (use -A to override).

Finally, if LOOKUP arguments are given, these are extracted from the JSON. By default . is used as a separator for nested object lookup. This can be overridden:

-D DELIM
Delimiter char between LOOKUPS (default is '.'). For example: $ echo '{"a.b": {"b": 1}}' | json -D / a.b/b

An alternative to lookups is to output the keys of the input object:

-k, --keys
Output the input object's keys.

json can be restricting to just validating its input, i.e. processing and output of the input is skipped:

-n, --validate
Just validate the input, no processing or output of the JSON content.

By default json outputs in "jsony" mode. Basically this is JSON output, with the exception that a single string output value is emitted without the quotes. The intention here is to be of most use to the UNIX command-line. Other output formats are supported:

-o MODE, --output MODE

Specify an output mode. One of jsony (the default; JSON, if a single string then quotes are elided), json (JSON output, 2-space indent), json-N (JSON output, N-space indent, e.g. 'json-4'), or inspect (node.js util.inspect output).

-i

Shortcut for -o inspect.

-j

Shortcut for -o json.

EXAMPLES

A typical JSON REST API response:

$ curl -s http://ifconfig.me/all.json
{"connection":"","ip_addr":"216.57.203.67","lang":"","remote_host":...

Nice output by default:

$ curl -s http://ifconfig.me/all.json | json
{
  "connection": "",
  "ip_addr": "201.73.103.12",
  "lang": "",
  "remote_host": "",
  "user_agent": "curl/7.23.1 (i386-sun-solaris2.11) libcurl/7.23.1 OpenSSL/0.9.8w zlib/1.2.3 libidn/1.23 libssh2/1.2.2",
  "charset": "",
  "port": "63713",
  "via": "",
  "forwarded": "",
  "mime": "*/*",
  "keep_alive": "",
  "encoding": ""
}

Say you just want to extract one value:

$ curl -s http://ifconfig.me/all.json | json ip_addr
201.73.103.12

Or, looking at the node.js project using the Github API:

$ curl -s https://api.github.com/repos/joyent/node | json open_issues
517

If you use curl -i to get HTTP headers (because perhaps they contain relevant information), json will skip the HTTP headers automatically:

$ curl -is https://api.github.com/repos/joyent/node | json
HTTP/1.1 200 OK
Server: nginx/1.0.13
Date: Tue, 24 Jul 2012 04:01:08 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Status: 200 OK
ETag: "1a21d980a01768dde42145ce2b58694c"
X-RateLimit-Remaining: 4997
Content-Length: 1513
Cache-Control: public, max-age=60
Vary: Accept
X-RateLimit-Limit: 5000
Last-Modified: Tue, 24 Jul 2012 03:50:11 GMT

{
  "master_branch": "master",
  "has_issues": true,
  "has_downloads": false,
  "homepage": "http://nodejs.org/",
  "html_url": "https://github.com/joyent/node",
...

Or, say you are stuck with the headers in your pipeline, 'json -H' will drop HTTP headers:

$ curl -is https://api.github.com/repos/joyent/node | json -H forks
2158

Here is an example that shows indexing a list. (The given "lookup" argument is basically JavaScript code appended, with '.' if necessary, to the JSON data and eval'd.)

$ curl -s https://api.github.com/legacy/repos/search/nodejs \
    | json 'repositories[2].name'
socket.io

Having the quote to avoid shell interpretation of '[' is annoying, so json allows a special case for an integer lookup:

$ curl -s https://api.github.com/legacy/repos/search/nodejs \
    | json 'repositories.2.name'
socket.io

Array processing with -a

json includes the -a (aka --array) option for processing each element of an input JSON array independently and using tabular output. Let's first get a list of open node.js issues (note that this is a subset because of GH API pagination):

$ curl -s https://api.github.com/repos/joyent/node/issues?state=open\&per_page=100
[
  {
    "number": 3757,
    "html_url": "https://github.com/joyent/node/issues/3757",
    "body": "Fix #3756.\n\nReview, please: @TooTallNate",
    "milestone": null,
    "user": {
      "gravatar_id": "73a2b24daecb976af81e010b7a3ce3c6",
      "login": "isaacs",
      "avatar_url": "https://secure.gravatar.com/avatar/73a2b24dae...
...

We can then print a table with just some fields as follows:

$ curl -s https://api.github.com/repos/joyent/node/issues?state=open\&per_page=100 \
    | json -a comments number title
0 3757 readline: Remove event listeners on close
0 3756 readline: No way to completely unhook interface from input/output
1 3755 node-v0.6.20 hello example segfaults on RaspberryPi (w/Arch + bash)
0 3753 Prohibit same listeners in EventEmitter. Closes #964.
1 3752 Auto-detect hardfloat eabi and armv7 variables on ARM based on compiler
3 3751 persistent REPL history
0 3749 glibc errors on SheevaPlug / Debian Squeeze
...

Ultimately this can be useful for then using other command-line tools. For example, we could get the list of top-five most commented open node issues:

$ curl -s https://api.github.com/repos/joyent/node/issues?state=open\&per_page=100 \
    | json -a comments number title | sort -n  | tail -5
9 3510 Automatically `.toString()` functions in REPL.
11 3668 JSON documentation index listing
12 3624 Add a return value to Buffer.write* methods that returns the ...
12 3655 defer dgram listening event
14 3613 Connections closed by node stay permanently in FIN_WAIT2

Or get a breakdown by ISO language code of the recent tweets mentioning "nodejs":

$ curl -s http://search.twitter.com/search.json?q=nodejs\&rpp=100 \
    | json results | json -a iso_language_code | sort | uniq -c | sort
   1 es
   1 no
   1 th
   4 ru
  12 ja
  23 pt
  58 en

The -d option can be used to specify a delimiter:

$ curl -s https://api.github.com/repos/joyent/node/issues?state=open \
        | json -a created_at number title -d,
2012-07-24T03:45:03Z,3757,readline: Remove event listeners on close
2012-07-24T03:32:10Z,3756,readline: No way to completely unhook inte...
2012-07-23T21:17:50Z,3755,node-v0.6.20 hello example segfaults on Ra...
2012-07-22T16:17:49Z,3753,Prohibit same listeners in EventEmitter. C...
2012-07-22T13:43:40Z,3752,Auto-detect hardfloat eabi and armv7 varia...

Grouping

You can use the '-g' or '--group' option to group adjacent objects into an array of those objects; or to concatenate adjacent arrays into a single array. To attempt to avoid false positives inside JSON strings, adjacent elements must have either no whitespace separation or at least a newline separation. Examples:

$ echo '{"a":1}{"b":2}' | json -g       # group into array of objects
[
  {
    "a": 1
  },
  {
    "b": 2
  }
]
$ echo '[1,2][3,4]' | json -g           # concantenate into one array
[
  1,
  2,
  3,
  4
]

This can be useful when processing a number of JSON files, e.g.:

$ cat my_data/*.json | json -g ...

Or when composing multiple JSON API response, e.g. this somewhat contrived search for node.js bugs mentioning "tty" or "windows":

$ echo tty windows | xargs -n1 -I{} curl -s \
    https://api.github.com/legacy/issues/search/joyent/node/open/{} \
    | json -g -a issues | json -g -a number title
623 Non-userfacing native modules should be prefixed with _
861 child_process fails after stdin close
1157 `child_process` module should read / write password prompts
1180 Ctrl+Shift+BS can't be input.
...

Output formatting

You can use the '-o MODE' option (or '--output MODE') to control the output flavour. By default the output is "jsony" (JSON, except that a simple string is printed without the quotes):

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json
[
  {
    "name": "Trent"
  },
  {
    "name": "Ewan"
  }
]

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json '0.name'
Trent

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json '0.name' -o jsony
Trent

Or for strict JSON output:

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json -o json
[
  {
    "name": "Trent"
  },
  {
    "name": "Ewan"
  }
]

By default this uses a 2-space indent. That can be changed with a "-N" suffix:

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json -o json-4
[
    {
        "name": "Trent"
    },
    {
        "name": "Ewan"
    }
]

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json -o json-0
[{"name":"Trent"},{"name":"Ewan"}]

You can get colored (non-JSON) output using node.js's util.inspect:

$ echo '[{"name": "Trent"},{"name": "Ewan"}]' | json -o inspect
[ { name: 'Trent' },
  { name: 'Ewan' } ]

Validation

Since v1.2.0 json will give position information and context for JSON syntax errors (SyntaxError). This can be handy for validating data and config files:

$ cat config.json | json
json: error: input is not JSON: Unexpected ',' at line 17, column 5:
            , { "name": "smartos64-1.4.7"
        ....^
{
    "use-proxy": false
...
$ echo $?
1

Processing and output of the input JSON can be suppressed with the -n, --validate option:

$ cat config.json | json --validate
json: error: input is not JSON: Unexpected ',' at line 17, column 5:
            , { "name": "smartos64-1.4.7"
        ....^

Together with the -q you can get silent, exit-status-only, JSON validation:

$ cat config.json | json -nq
$ echo $?
1

Executing code snippets on input

You can use the -e CODE option to execute small code snippets to massage the input data. Some examples (generally use this.<key> to refer to a key):

$ echo '{"foo": "bar"}' | json -e 'this.foo="baz"'
{"foo":"baz"}

Or omit the this. as a shortcut:

$ echo '{"foo": "bar"}' | json -e 'foo="baz"'
{"foo":"baz"}
$ echo '{"age": 38}' | json -e 'age++'
{"age":39}

Set a key to undefined to remove it:

$ echo '{"one": 1, "two": 2}' | json -e 'this.one=undefined'
{"two":2}

If the input is an array, then -e will automatically process each element separately (use -A to override this):

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' \
    | json -e 'age++'
[
  {
    "name": "trent",
    "age": 39
  },
  {
    "name": "ewan",
    "age": 5
  }
]

Filtering with '-c'

You can use the -c CODE option to filter the input (this is JavaScript code):

$ echo '{"name":"trent", "age":38}' | json -c 'this.age > 21'
{
  "name": "trent",
  "age": 38
}
$ echo '{"name":"trent", "age":38}' | json -c 'this.age==16'
$

If the input is an array, then -c will automatically process each element separately (use -A to override this):

$ echo '[{"name":"trent", "age":38}, {"name":"ewan", "age":4}]' \
    | json -c 'this.age>21'
[
  {
    "name": "trent",
    "age": 38
  }
]

In-place editing

You can edit a file in place with -I and -f FILE:

$ cat config.json
{"hostname":"127.0.0.1"}

$ json -I -f config.json                   # format the file
json: updated "config.json" in-place
$ cat config.json
{
  "hostname": "127.0.0.1"
}

$ json -I -f config.json -e 'this.port=8080'  # add bar field
json: updated "config.json" in-place
$ cat config.json
{
  "hostname": "127.0.0.1",
  "port": 8080
}

Some limitations. Only one file at a time:

$ json -I -f foo.json -f bar.json
json: error: must specify exactly one file with '-f FILE' to use -I/--in-place

Lookups are not allowed:

$ json -I -f foo.json key.subkey
json: error: lookups cannot be specified with in-place editing (-I/--in-place), too easy to lose content

because that can too easily result in data loss, e.g. with something like:

$ json -I -f *.json    # if there is more than match to the glob
json: error: lookups cannot be specified with in-place editing (-I/--in-place), too easy to lose content

COMPATIBILITY

The json tool major version is incremented when there is a backward incompatible change. An overview of those changes is here.

See the changelog for full compatibility and change details.

PROJECT & BUGS

json is written in JavaScript and requires node.js (node). The project lives at https://github.com/trentm/json and is published to npm as "jsontool" ("json" was already taken, boo).

LICENSE

MIT License (see https://github.com/trentm/json/blob/master/LICENSE.txt)

json is Copyright (c) 2012 Trent Mick

  1. June 2013
  2. json(1)
Fork me on GitHub