README.mkd
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