Make JSON greppable!

gron

Build Status

Make JSON greppable!

gron transforms JSON into discrete assignments to make it easier to grep for what you want and see the absolute 'path' to it. It eases the exploration of APIs that return large blobs of JSON but have terrible documentation.

gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | fgrep "commit.author"
json[0].commit.author = {};
json[0].commit.author.date = "2016-07-02T10:51:21Z";
json[0].commit.author.email = "[email protected]";
json[0].commit.author.name = "Tom Hudson";

gron can work backwards too, enabling you to turn your filtered data back into JSON:

▶ gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | fgrep "commit.author" | gron --ungron
[
  {
    "commit": {
      "author": {
        "date": "2016-07-02T10:51:21Z",
        "email": "[email protected]",
        "name": "Tom Hudson"
      }
    }
  }
]

Disclaimer: the GitHub API has fantastic documentation, but it makes for a good example.

Installation

gron has no runtime dependencies. You can just download a binary for Linux, Mac, Windows or FreeBSD and run it. Put the binary in your $PATH (e.g. in /usr/local/bin) to make it easy to use:

▶ tar xzf gron-linux-amd64-0.1.5.tgz
▶ sudo mv gron /usr/local/bin/

If you're a Mac user you can also install gron via brew:

▶ brew install gron

Or if you're a Go user you can use go get (if you're using Go 1.7 or newer):

▶ go get -u github.com/tomnomnom/gron

It's recommended that you alias ungron or norg (or both!) to gron --ungron. Put something like this in your shell profile (e.g. in ~/.bashrc):

alias norg="gron --ungron"
alias ungron="gron --ungron"

Or you could create a shell script in your $PATH named ungron or norg to affect all users:

gron --ungron "$@"

Usage

Get JSON from a file:

▶ gron testdata/two.json 
json = {};
json.contact = {};
json.contact.email = "[email protected]";
json.contact.twitter = "@TomNomNom";
json.github = "https://github.com/tomnomnom/";
json.likes = [];
json.likes[0] = "code";
json.likes[1] = "cheese";
json.likes[2] = "meat";
json.name = "Tom";

From a URL:

▶ gron http://headers.jsontest.com/
json = {};
json.Host = "headers.jsontest.com";
json["User-Agent"] = "gron/0.1";
json["X-Cloud-Trace-Context"] = "6917a823919477919dbc1523584ba25d/11970839830843610056";

Or from stdin:

▶ curl -s http://headers.jsontest.com/ | gron
json = {};
json.Accept = "*/*";
json.Host = "headers.jsontest.com";
json["User-Agent"] = "curl/7.43.0";
json["X-Cloud-Trace-Context"] = "c70f7bf26661c67d0b9f2cde6f295319/13941186890243645147";

Grep for something and easily see the path to it:

▶ gron testdata/two.json | grep twitter
json.contact.twitter = "@TomNomNom";

gron makes diffing JSON easy too:

▶ diff <(gron two.json) <(gron two-b.json)
3c3
< json.contact.email = "[email protected]";
---
> json.contact.email = "[email protected]";

The output of gron is valid JavaScript:

▶ gron testdata/two.json > tmp.js
▶ echo "console.log(json);" >> tmp.js
▶ nodejs tmp.js
{ contact: { email: '[email protected]', twitter: '@TomNomNom' },
  github: 'https://github.com/tomnomnom/',
  likes: [ 'code', 'cheese', 'meat' ],
  name: 'Tom' }

It's also possible to obtain the gron output as JSON stream via the --json switch:

▶ curl -s http://headers.jsontest.com/ | gron --json
[[],{}]
[["Accept"],"*/*"]
[["Host"],"headers.jsontest.com"]
[["User-Agent"],"curl/7.43.0"]
[["X-Cloud-Trace-Context"],"c70f7bf26661c67d0b9f2cde6f295319/13941186890243645147"]

ungronning

gron can also turn its output back into JSON:

▶ gron testdata/two.json | gron -u
{
  "contact": {
    "email": "[email protected]",
    "twitter": "@TomNomNom"
  },
  "github": "https://github.com/tomnomnom/",
  "likes": [
    "code",
    "cheese",
    "meat"
  ],
  "name": "Tom"
}

This means you use can use gron with grep and other tools to modify JSON:

▶ gron testdata/two.json | grep likes | gron --ungron
{
  "likes": [
    "code",
    "cheese",
    "meat"
  ]
}

or

▶ gron --json testdata/two.json | grep likes | gron  --json --ungron
{
  "likes": [
    "code",
    "cheese",
    "meat"
  ]
}

To preserve array keys, arrays are padded with null when values are missing:

▶ gron testdata/two.json | grep likes | grep -v cheese
json.likes = [];
json.likes[0] = "code";
json.likes[2] = "meat";
▶ gron testdata/two.json | grep likes | grep -v cheese | gron --ungron
{
  "likes": [
    "code",
    null,
    "meat"
  ]
}

If you get creative you can do some pretty neat tricks with gron, and then ungron the output back into JSON.

Get Help

▶ gron --help
Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable

Usage:
  gron [OPTIONS] [FILE|URL|-]

Options:
  -u, --ungron     Reverse the operation (turn assignments back into JSON)
  -c, --colorize   Colorize output (default on tty)
  -m, --monochrome Monochrome (don't colorize output)
  -s, --stream     Treat each line of input as a separate JSON object
  -k, --insecure   Disable certificate validation
  -j, --json       Represent gron data as JSON stream
      --no-sort    Don't sort output (faster)
      --version    Print version information

Exit Codes:
  0	OK
  1	Failed to open file
  2	Failed to read input
  3	Failed to form statements
  4	Failed to fetch URL
  5	Failed to parse statements
  6	Failed to encode JSON

Examples:
  gron /tmp/apiresponse.json
  gron http://jsonplaceholder.typicode.com/users/1 
  curl -s http://jsonplaceholder.typicode.com/users/1 | gron
  gron http://jsonplaceholder.typicode.com/users/1 | grep company | gron --ungron

FAQ

Wasn't this written in PHP before?

Yes it was! The original version is preserved here for posterity.

Why the change to Go?

Mostly to remove PHP as a dependency. There's a lot of people who work with JSON who don't have PHP installed.

Why shouldn't I just use jq?

jq is awesome, and a lot more powerful than gron, but with that power comes complexity. gron aims to make it easier to use the tools you already know, like grep and sed.

gron's primary purpose is to make it easy to find the path to a value in a deeply nested JSON blob when you don't already know the structure; much of jq's power is unlocked only once you know that structure.

Owner
Tom Hudson
Open-source tool maker, trainer, talker, fixer, eater, not really a sheep. He/him.
Tom Hudson
Comments
  • Please do not change output strings

    Please do not change output strings

    Please consider the following JSON:

    {
      "dependencies": {
        "ssb-client": "http://localhost:8989/blobs/get/&EAaUpI+wrJM5/ly1RqZW0GAEF4PmCAmABBj7e6UIrL0=.sha256",
        "ssb-mentions": "http://localhost:8989/blobs/get/&GjuxknqKwJqHznKueFNCyIh52v1woz5PB41vqmoHfyM=.sha256"
      }
    }
    

    Seemingly, I can gron and ungron this to achieve an identical output:

    $ gron < test.json
    json = {};
    json.dependencies = {};
    json.dependencies["ssb-client"] = "http://localhost:8989/blobs/get/&EAaUpI+wrJM5/ly1RqZW0GAEF4PmCAmABBj7e6UIrL0=.sha256";
    json.dependencies["ssb-mentions"] = "http://localhost:8989/blobs/get/&GjuxknqKwJqHznKueFNCyIh52v1woz5PB41vqmoHfyM=.sha256";
    $ gron < test.json | ungron
    {
      "dependencies": {
        "ssb-client": "http://localhost:8989/blobs/get/&EAaUpI+wrJM5/ly1RqZW0GAEF4PmCAmABBj7e6UIrL0=.sha256",
        "ssb-mentions": "http://localhost:8989/blobs/get/&GjuxknqKwJqHznKueFNCyIh52v1woz5PB41vqmoHfyM=.sha256"
      }
    }
    

    However, if stdout is not a TTY, what you get is something entirely different:

    $ gron < test.json | ungron | cat   # same thing happens if you redirect to a file
    {
      "dependencies": {
        "ssb-client": "http://localhost:8989/blobs/get/\u0026EAaUpI+wrJM5/ly1RqZW0GAEF4PmCAmABBj7e6UIrL0=.sha256",
        "ssb-mentions": "http://localhost:8989/blobs/get/\u0026GjuxknqKwJqHznKueFNCyIh52v1woz5PB41vqmoHfyM=.sha256"
      }
    }
    

    IMHO, gron should make identical output no matter what. Ideally, gron shouldn't try to outsmart the user and start interpreting string values or displaying them differently (even if the meaning is the same). At least provide a commandline switch so that the original strings are preserved.

    Cheers.

  • Adds JSON encoded data format

    Adds JSON encoded data format

    Introducing the -j, --json switch:

    > gron -j <<<  '{"a":{"b":["c"]}}'  | tee out.jgron          
    [[],{}]                 
    [["a"],{}]              
    [["a","b"],[]]          
    [["a","b",0],"c"] 
    > cat out.jgron  | gron -j -u                                            
    {                       
      "a": {                
        "b": [              
           "c"              
        ]                   
      }                     
    }                       
    
  • doesn't read stdin on Cygwin

    doesn't read stdin on Cygwin

    I got https://github.com/tomnomnom/gron/releases/download/v0.5.1/gron-windows-amd64-0.5.1.zip.

    • works ok from cmd (though need to specify -m to avoid the colors, or use a better terminal like conemu)
    • when I run from mintty & bash, doesn't read stdin:
    $ gron http://jsonplaceholder.typicode.com/users/1
    # works ok
    $ curl -s http://jsonplaceholder.typicode.com/users/1 | gron -
    # nothing happens
    $ uname
    CYGWIN_NT-6.1 
    
  • Better handling of big json files

    Better handling of big json files

    Currently running gron on large json files is very slow. For example a 40MB file takes over a minute:

    > time gron big.json > foo
    
    real    1m28.850s
    user    1m37.038s
    sys 0m2.333s
    

    My guess is it's in the sorting phase. Would it possible to avoid sorting all together? Maybe doing a streaming decode of the json would be helpful too.

    At the very least it should be possible to disable sorting via command line option.

  • preserving JSON order

    preserving JSON order

    Nice tool, really... But I was surprised that the --no-sort option doesn't seem to preserve the order of the keys in the input file. When I generate JSON files, I generally specify my own custom order. Working on a JSON file where, for instance, the first name always precedes the family name, makes a lot of things easier to check or modify inside a text editor.

    Is it possible to make --no-sort preserve the original order? Ideally, ungroning would keep this order too.

    Thanks!

  • gronning APIs where an authentication token is needed

    gronning APIs where an authentication token is needed

    Dear Tom,

    Many thanks for this very useful package which I already sent to people around as am sure they will find it extremely useful. Would there be any way of trying this for APIs where authentication is needed? I tried for example and I get this message:

    json = {}; json.detail = "Authentication credentials were not provided.";

    Best wishes, Dimitris

  • Sorting results

    Sorting results

    When you need to compare two files (or parts of them) without caring about the order of values within an object, it's common to pipe the result of gron through sort. However, this is incorrect in cases where some values can span multiple lines.

    For example:

    json.foo = "foo";
    json.bar = "lorem ipsum dolor
    sit amet consequetur
    adipiscing elit";
    

    These lines would be sorted on the command line like so:

    adipiscing elit";
    json.bar = "lorem ipsum dolor
    json.foo = "foo";
    sit amet consequetur
    

    This is obviously incorrect. The sorted output we want is:

    json.bar = "lorem ipsum dolor
    sit amet consequetur
    adipiscing elit";
    json.foo = "foo";
    

    It would be helpful if gron had an option to reliably sort the values as it outputs them, such as a -s --sort flag.

  • Ungron to ignore lines saying --

    Ungron to ignore lines saying --

    Grep can search for lines immediately preceding or following the matched line, using grep -A, grep -B or grep -C. However the output of these includes separator lines that read --. This output currently produces an error when you try to ungron the result.

    Since grep is a primary use for gron, I believe it would be a useful enhancement for it to accept a common output of grep. It doesn't need to do anything with the lines, only match and exclude them.

    For example:

    $ gron file.json | grep -A 1 'ktoe per year'
    
    json.resources.geothermal.production.units = "ktoe per year";
    json.resources.geothermal.production.value = 2007.738525390625;
    --
    json.resources.hydropower.production.units = "ktoe per year";
    json.resources.hydropower.production.value = 9038.80078125;
    --
    json.resources.wind.production.units = "ktoe per year";
    json.resources.wind.production.value = 381.5000305175781;
    
  • gron parses differently when key has non-alphanum char

    gron parses differently when key has non-alphanum char

    Example(note '-' in the second example): `

    echo '{"foo_bar":0}' |gron json = {}; json.foo_bar = 0;

    echo '{"foo-bar":0}' |gron json = {}; json["foo-bar"] = 0; `

  •  gron won't connect to insecure https endpoints

    gron won't connect to insecure https endpoints

    I'm unable to connect to https endpoints with self signed certificates due to the requirement to validate the server certificate with the default transport for net/http clients.

    The ability to connect to insecure endpoints would be helpful, even if arguably not a good idea.

  • Can't ungron strings containing both escapes and semi-colons

    Can't ungron strings containing both escapes and semi-colons

    I was playing around with your tool on the output of gmail json, gron works fine, but I get an error "cannot parse input" if I try and pipe it back into ungron.

    Narrowing it down, the problem seems to be reproducible with this example:

    $ echo 'json.payload.headers[4].value = "from o1.email.codeship.io (o1.email.codeship.io. [192.254.119.116])        by mx.google.com with ESMTPS id d79si3761733ioj.86.2015.10.09.12.02.54        for \[email protected]\u003e        (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);        Fri, 09 Oct 2015 12:02:54 -0700 (PDT)";' | gron -u
    Fatal (failed to parse input statements)
    

    A little bit of digging reveals a minimal test case:

    echo 'json.value = "\u003c ;"' | ./gron -u
    

    It seems to be a combination of the character escape and the semi-colon in the string.

    Let me know if I can be more helpful.

  • Output format

    Output format

    This is a feature request for output format configuration.

    I would like to remove ending ";" from lines and also remove spaces before and after "=" so instead of this:

    json.message.chat.id = 7403466;

    I got this

    json.message.chat.id=7403466

    I think this way will be a lot easier to parse results:

    cat test.json | grep "json.message.chat.id" | cut -d"=" -f2

    instead of

    cat test.json | grep "json.message.chat.id" | cut -d"=" -f2 | cut -d" " -f2- | tr -d";"

  • Ungron doesn't respect --no-sort option

    Ungron doesn't respect --no-sort option

    When using the --ungron option I'd expect the --no-sort option to take effect too, but unfortunately it's being ignored.

    Example:

    $ echo '{"z": "first", "a": "last"}' | gron --no-sort | gron --no-sort --ungron
    {
      "a": "last",
      "z": "first"
    }
    

    Maybe related to #102 ?

  • --no-sort option is unstable

    --no-sort option is unstable

    For a simple JSON doc

    {"z": "first", "a": "last"}
    

    gron --no-sort keeps producing wrong results at around 12% rate.

    Tried it with:

    $ for i in $( seq 1000 ); do echo '{"z": "first", "a": "last"}' | gron --no-sort | column -x; done | sort | uniq -c
     125 json = {};		json.a = "last";	json.z = "first";
     875 json = {};		json.z = "first";	json.a = "last";
    

    Tried it with:

    $ gron --version
    gron version dev
    
    $ brew info gron
    gron: stable 0.7.1 (bottled), HEAD
    Make JSON greppable
    https://github.com/tomnomnom/gron
    /usr/local/Cellar/gron/0.7.1 (4 files, 5MB) *
      Poured from bottle on 2022-06-29 at 13:56:51
    From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gron.rb
    License: MIT
    ==> Dependencies
    Build: go ✘
    ==> Options
    --HEAD
    	Install HEAD version
    ==> Analytics
    install: 878 (30 days), 2,899 (90 days), 5,560 (365 days)
    install-on-request: 876 (30 days), 2,899 (90 days), 5,561 (365 days)
    build-error: 0 (30 days)
    
    $ brew list gron
    /usr/local/Cellar/gron/0.7.1/bin/gron
    
  • Add proxy capabilities

    Add proxy capabilities

    This PR adds support for using a proxy when calling gron <url>. It allows to configure a proxy through the environment variables http_proxy and https_proxy and also respects values in the no_proxy environment variables. Users can always overwrite environment variables by using the two new cli arguments -x/--proxy or --noproxy to overwrite the environment variables (e.g., to disable the proxy). The behavior is similar to curl's behavior.

    This PR fixes #89.

    It's currently unclear to me if we should add some docs to this - either directly in the Readme or maybe in the advanced section.

    Please note: In difference to the behavior of curl, I don't have an option to configure an ALL_PROXY environment variable. Also I don't support an asterisk symbol in the no_proxy environment variable to deactivate the proxy, simply because in this case http_proxy=""/https_proxy="" or gron --proxy "" <url> could be used instead.

Related tags
Fluent API to make it easier to create Json objects.

Jsongo Fluent API to make it easier to create Json objects. Install go get github.com/ricardolonga/jsongo Usage To create this: { "name":"Ricar

Nov 7, 2022
Gron transforms JSON into discrete assignments to make it easier to grep

gron Make JSON greppable! gron transforms JSON into discrete assignments to make it easier to grep for what you want and see the absolute 'path' to it

Nov 4, 2021
Get JSON values quickly - JSON parser for Go
Get JSON values quickly - JSON parser for Go

get json values quickly GJSON is a Go package that provides a fast and simple way to get values from a json document. It has features such as one line

Dec 28, 2022
JSON diff library for Go based on RFC6902 (JSON Patch)

jsondiff jsondiff is a Go package for computing the diff between two JSON documents as a series of RFC6902 (JSON Patch) operations, which is particula

Dec 4, 2022
Fast JSON encoder/decoder compatible with encoding/json for Go
Fast JSON encoder/decoder compatible with encoding/json for Go

Fast JSON encoder/decoder compatible with encoding/json for Go

Jan 6, 2023
Package json implements encoding and decoding of JSON as defined in RFC 7159

Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions

Jun 26, 2022
Json-go - CLI to convert JSON to go and vice versa
Json-go - CLI to convert JSON to go and vice versa

Json To Go Struct CLI Install Go version 1.17 go install github.com/samit22/js

Jul 29, 2022
JSON Spanner - A Go package that provides a fast and simple way to filter or transform a json document

JSON SPANNER JSON Spanner is a Go package that provides a fast and simple way to

Sep 14, 2022
Abstract JSON for golang with JSONPath support

Abstract JSON Abstract JSON is a small golang package provides a parser for JSON with support of JSONPath, in case when you are not sure in its struct

Jan 5, 2023
Fast JSON parser and validator for Go. No custom structs, no code generation, no reflection

fastjson - fast JSON parser and validator for Go Features Fast. As usual, up to 15x faster than the standard encoding/json. See benchmarks. Parses arb

Jan 5, 2023
Small utility to create JSON objects
Small utility to create JSON objects

gjo Small utility to create JSON objects. This was inspired by jpmens/jo. Support OS Mac Linux Windows Requirements Go 1.1.14~ Git Installtion Build $

Dec 8, 2022
A Go package for handling common HTTP JSON responses.

go-respond A Go package for handling common HTTP JSON responses. Installation go get github.com/nicklaw5/go-respond Usage The goal of go-respond is to

Sep 26, 2022
JSON query in Golang

gojq JSON query in Golang. Install go get -u github.com/elgs/gojq This library serves three purposes: makes parsing JSON configuration file much easie

Dec 28, 2022
Automatically generate Go (golang) struct definitions from example JSON

gojson gojson generates go struct definitions from json or yaml documents. Example $ curl -s https://api.github.com/repos/chimeracoder/gojson | gojson

Jan 1, 2023
A JSON diff utility

JayDiff A JSON diff utility. Install Downloading the compiled binary Download the latest version of the binary: releases extract the archive and place

Dec 11, 2022
Fast and flexible JSON encoder for Go
Fast and flexible JSON encoder for Go

Jettison Jettison is a fast and flexible JSON encoder for the Go programming language, inspired by bet365/jingo, with a richer features set, aiming at

Dec 21, 2022
Create go type representation from json

json2go Package json2go provides utilities for creating go type representation from json inputs. Json2go can be used in various ways: CLI tool Web pag

Dec 26, 2022
Console JSON formatter with query feature
Console JSON formatter with query feature

Console JSON formatter with query feature. Install: $ go get github.com/miolini/jsonf Usage: Usage of jsonf: -c=true: colorize output -d=false: de

Dec 4, 2022
Arbitrary transformations of JSON in Golang

kazaam Description Kazaam was created with the goal of supporting easy and fast transformations of JSON data with Golang. This functionality provides

Dec 18, 2022