1# gron 2[![Build Status](https://travis-ci.org/tomnomnom/gron.svg?branch=master)](https://travis-ci.org/tomnomnom/gron) 3 4Make JSON greppable! 5 6gron transforms JSON into discrete assignments to make it easier to `grep` for what you want and see the absolute 'path' to it. 7It eases the exploration of APIs that return large blobs of JSON but have terrible documentation. 8 9<pre> 10▶ <b>gron</b> "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | fgrep "commit.author" 11json[0].commit.author = {}; 12json[0].commit.author.date = "2016-07-02T10:51:21Z"; 13json[0].commit.author.email = "mail@tomnomnom.com"; 14json[0].commit.author.name = "Tom Hudson"; 15</pre> 16 17gron can work backwards too, enabling you to turn your filtered data back into JSON: 18<pre> 19▶ gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=1" | fgrep "commit.author" | <b>gron --ungron</b> 20[ 21 { 22 "commit": { 23 "author": { 24 "date": "2016-07-02T10:51:21Z", 25 "email": "mail@tomnomnom.com", 26 "name": "Tom Hudson" 27 } 28 } 29 } 30] 31</pre> 32 33> Disclaimer: the GitHub API has fantastic documentation, but it makes for a good example. 34 35## Installation 36 37gron has no runtime dependencies. You can just [download a binary for Linux, Mac, Windows or FreeBSD and run it](https://github.com/tomnomnom/gron/releases). 38Put the binary in your `$PATH` (e.g. in `/usr/local/bin`) to make it easy to use: 39``` 40▶ tar xzf gron-linux-amd64-0.1.5.tgz 41▶ sudo mv gron /usr/local/bin/ 42``` 43 44If you're a Mac user you can also [install gron via brew](http://braumeister.org/formula/gron): 45``` 46▶ brew install gron 47``` 48 49Or if you're a Go user you can use `go get` (if you're using Go 1.7 or newer): 50 51``` 52▶ go get -u github.com/tomnomnom/gron 53``` 54 55It'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`): 56``` 57alias norg="gron --ungron" 58alias ungron="gron --ungron" 59``` 60Or you could create a shell script in your $PATH named `ungron` or `norg` to affect all users: 61``` 62gron --ungron "$@" 63``` 64 65## Usage 66 67Get JSON from a file: 68 69``` 70▶ gron testdata/two.json 71json = {}; 72json.contact = {}; 73json.contact.email = "mail@tomnomnom.com"; 74json.contact.twitter = "@TomNomNom"; 75json.github = "https://github.com/tomnomnom/"; 76json.likes = []; 77json.likes[0] = "code"; 78json.likes[1] = "cheese"; 79json.likes[2] = "meat"; 80json.name = "Tom"; 81``` 82 83From a URL: 84 85``` 86▶ gron http://headers.jsontest.com/ 87json = {}; 88json.Host = "headers.jsontest.com"; 89json["User-Agent"] = "gron/0.1"; 90json["X-Cloud-Trace-Context"] = "6917a823919477919dbc1523584ba25d/11970839830843610056"; 91``` 92 93Or from `stdin`: 94 95``` 96▶ curl -s http://headers.jsontest.com/ | gron 97json = {}; 98json.Accept = "*/*"; 99json.Host = "headers.jsontest.com"; 100json["User-Agent"] = "curl/7.43.0"; 101json["X-Cloud-Trace-Context"] = "c70f7bf26661c67d0b9f2cde6f295319/13941186890243645147"; 102``` 103 104Grep for something and easily see the path to it: 105 106``` 107▶ gron testdata/two.json | grep twitter 108json.contact.twitter = "@TomNomNom"; 109``` 110 111gron makes diffing JSON easy too: 112 113``` 114▶ diff <(gron two.json) <(gron two-b.json) 1153c3 116< json.contact.email = "mail@tomnomnom.com"; 117--- 118> json.contact.email = "contact@tomnomnom.com"; 119``` 120 121The output of `gron` is valid JavaScript: 122 123``` 124▶ gron testdata/two.json > tmp.js 125▶ echo "console.log(json);" >> tmp.js 126▶ nodejs tmp.js 127{ contact: { email: 'mail@tomnomnom.com', twitter: '@TomNomNom' }, 128 github: 'https://github.com/tomnomnom/', 129 likes: [ 'code', 'cheese', 'meat' ], 130 name: 'Tom' } 131``` 132 133It's also possible to obtain the `gron` output as JSON stream via 134the `--json` switch: 135 136``` 137▶ curl -s http://headers.jsontest.com/ | gron --json 138[[],{}] 139[["Accept"],"*/*"] 140[["Host"],"headers.jsontest.com"] 141[["User-Agent"],"curl/7.43.0"] 142[["X-Cloud-Trace-Context"],"c70f7bf26661c67d0b9f2cde6f295319/13941186890243645147"] 143``` 144 145## ungronning 146gron can also turn its output back into JSON: 147``` 148▶ gron testdata/two.json | gron -u 149{ 150 "contact": { 151 "email": "mail@tomnomnom.com", 152 "twitter": "@TomNomNom" 153 }, 154 "github": "https://github.com/tomnomnom/", 155 "likes": [ 156 "code", 157 "cheese", 158 "meat" 159 ], 160 "name": "Tom" 161} 162``` 163 164This means you use can use gron with `grep` and other tools to modify JSON: 165``` 166▶ gron testdata/two.json | grep likes | gron --ungron 167{ 168 "likes": [ 169 "code", 170 "cheese", 171 "meat" 172 ] 173} 174``` 175 176or 177 178 179``` 180▶ gron --json testdata/two.json | grep likes | gron --json --ungron 181{ 182 "likes": [ 183 "code", 184 "cheese", 185 "meat" 186 ] 187} 188``` 189 190To preserve array keys, arrays are padded with `null` when values are missing: 191``` 192▶ gron testdata/two.json | grep likes | grep -v cheese 193json.likes = []; 194json.likes[0] = "code"; 195json.likes[2] = "meat"; 196▶ gron testdata/two.json | grep likes | grep -v cheese | gron --ungron 197{ 198 "likes": [ 199 "code", 200 null, 201 "meat" 202 ] 203} 204``` 205 206If you get creative you can do [some pretty neat tricks with gron](ADVANCED.mkd), and 207then ungron the output back into JSON. 208 209## Get Help 210 211``` 212▶ gron --help 213Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable 214 215Usage: 216 gron [OPTIONS] [FILE|URL|-] 217 218Options: 219 -u, --ungron Reverse the operation (turn assignments back into JSON) 220 -c, --colorize Colorize output (default on tty) 221 -m, --monochrome Monochrome (don't colorize output) 222 -s, --stream Treat each line of input as a separate JSON object 223 -k, --insecure Disable certificate validation 224 -j, --json Represent gron data as JSON stream 225 --no-sort Don't sort output (faster) 226 --version Print version information 227 228Exit Codes: 229 0 OK 230 1 Failed to open file 231 2 Failed to read input 232 3 Failed to form statements 233 4 Failed to fetch URL 234 5 Failed to parse statements 235 6 Failed to encode JSON 236 237Examples: 238 gron /tmp/apiresponse.json 239 gron http://jsonplaceholder.typicode.com/users/1 240 curl -s http://jsonplaceholder.typicode.com/users/1 | gron 241 gron http://jsonplaceholder.typicode.com/users/1 | grep company | gron --ungron 242``` 243 244## FAQ 245### Wasn't this written in PHP before? 246Yes it was! The original version is [preserved here for posterity](https://github.com/tomnomnom/gron/blob/master/original-gron.php). 247 248### Why the change to Go? 249Mostly to remove PHP as a dependency. There's a lot of people who work with JSON who don't have PHP installed. 250 251### Why shouldn't I just use jq? 252[jq](https://stedolan.github.io/jq/) is *awesome*, and a lot more powerful than gron, but with that power comes 253complexity. gron aims to make it easier to use the tools you already know, like `grep` and `sed`. 254 255gron's primary purpose is to make it easy to find the path to a value in a deeply nested JSON blob 256when you don't already know the structure; much of jq's power is unlocked only once you know that structure. 257