Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
150 lines (132 sloc) 5.77 KB

Advanced Usage

Although gron's primary purpose is API discovery, when combined with other tools like grep it can do some interesting things.

As an exercise, let's try to mimick some of the examples from the jq tutorial.

Disclaimer: munging data on the command line with gron can be useful, but using tools like grep and sed to manipulate the data is error-prone and shouldn't be relied on in scripts.

Get the last 5 commits from the gron repo:

▶ gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=5"
json = [];
json[0] = {};
json[0].author = {};
json[0].author.avatar_url = "https://avatars.githubusercontent.com/u/58276?v=3";
json[0].author.events_url = "https://api.github.com/users/tomnomnom/events{/privacy}";
...
json[4].parents[0].html_url = "https://github.com/tomnomnom/gron/commit/cbcad2299e55c28a9922776e58b2a0b5a0f05016";
json[4].parents[0].sha = "cbcad2299e55c28a9922776e58b2a0b5a0f05016";
json[4].parents[0].url = "https://api.github.com/repos/tomnomnom/gron/commits/cbcad2299e55c28a9922776e58b2a0b5a0f05016";
json[4].sha = "91b204972e63a1166c9d148fbbfd839f8697f91b";
json[4].url = "https://api.github.com/repos/tomnomnom/gron/commits/91b204972e63a1166c9d148fbbfd839f8697f91b";

To make the rest of this a little more readable, let's add an alias for that:

▶ alias ggh='gron "https://api.github.com/repos/tomnomnom/gron/commits?per_page=5"'

Extract just the first commit using fgrep "json[0]":

▶ ggh | fgrep "json[0]"
json[0] = {};
json[0].author = {};
json[0].author.avatar_url = "https://avatars.githubusercontent.com/u/58276?v=3";
json[0].author.events_url = "https://api.github.com/users/tomnomnom/events{/privacy}";
json[0].author.followers_url = "https://api.github.com/users/tomnomnom/followers";
...
json[0].parents[0].html_url = "https://github.com/tomnomnom/gron/commit/48aba5325ece087ae24ab72684851cbe77ce8311";
json[0].parents[0].sha = "48aba5325ece087ae24ab72684851cbe77ce8311";
json[0].parents[0].url = "https://api.github.com/repos/tomnomnom/gron/commits/48aba5325ece087ae24ab72684851cbe77ce8311";
json[0].sha = "7da81e29c27241c0a5c2e5d083ddebcfcc525908";
json[0].url = "https://api.github.com/repos/tomnomnom/gron/commits/7da81e29c27241c0a5c2e5d083ddebcfcc525908";

Get just the committer's name and the commit message using egrep "(committer.name|commit.message)":

▶ ggh | fgrep "json[0]" | egrep "(committer.name|commit.message)"
json[0].commit.committer.name = "Tom Hudson";
json[0].commit.message = "Adds 0.1.7 to changelog";

Turn the result back into JSON using gron --ungron:

▶ ggh | fgrep "json[0]" | egrep "(committer.name|commit.message)" | gron --ungron
[
  {
    "commit": {
      "committer": {
        "name": "Tom Hudson"
      },
      "message": "Adds 0.1.7 to changelog"
    }
  }
]

gron preserves the location of values in the JSON, but you can use sed to remove keys from the path:

▶ ggh | fgrep "json[0]" | egrep "(committer.name|commit.message)" | sed -r "s/(commit|committer)\.//g"
json[0].name = "Tom Hudson";
json[0].message = "Adds 0.1.7 to changelog"

With those keys removed, the result is a 'flattened' object, which looks much cleaner when turned back into JSON with gron --ungron:

▶ ggh | fgrep "json[0]" | egrep "(committer.name|commit.message)" | sed -r "s/(commit|committer)\.//g" | gron --ungron
[
  {
    "message": "Adds 0.1.7 to changelog",
    "name": "Tom Hudson"
  }
]

Removing the fgrep "json[0]" from the pipeline means we do the same for all commits:

▶ ggh | egrep "(committer.name|commit.message)" | sed -r "s/(commit|committer)\.//g" | gron --ungron
[
  {
    "message": "Adds 0.1.7 to changelog",
    "name": "Tom Hudson"
  },
  {
    "message": "Refactors natural sort to actualy work + be more readable",
    "name": "Tom Hudson"
  },
...

To include the html_url key for each commit's parents, all we need to do is add parents.*html_url into our call to egrep:

▶ ggh | egrep "(committer.name|commit.message|parents.*html_url)" | sed -r "s/(commit|committer)\.//g"
json[0].name = "Tom Hudson";
json[0].message = "Adds 0.1.7 to changelog";
json[0].parents[0].html_url = "https://github.com/tomnomnom/gron/commit/48aba5325ece087ae24ab72684851cbe77ce8311";
json[1].name = "Tom Hudson";
json[1].message = "Refactors natural sort to actualy work + be more readable";
json[1].parents[0].html_url = "https://github.com/tomnomnom/gron/commit/3eca8bf5e07151f077cebf0d942c1fa8bc51e8f2";
...

To make the structure more like that in the final example in the jq tutorial, we can use sed -r "s/\.html_url//" to remove the .html_url part of the path:

▶ ggh | egrep "(committer.name|commit.message|parents.*html_url)" | sed -r "s/(commit|committer)\.//g" | sed -r "s/\.html_url//"
json[0].name = "Tom Hudson";
json[0].message = "Adds 0.1.7 to changelog";
json[0].parents[0] = "https://github.com/tomnomnom/gron/commit/48aba5325ece087ae24ab72684851cbe77ce8311";
json[1].name = "Tom Hudson";
json[1].message = "Refactors natural sort to actualy work + be more readable";
json[1].parents[0] = "https://github.com/tomnomnom/gron/commit/3eca8bf5e07151f077cebf0d942c1fa8bc51e8f2";
...

And, of course, the statements can be turned back into JSON with gron --ungron:

▶ ggh | egrep "(committer.name|commit.message|parents.*html_url)" | sed -r "s/(commit|committer)\.//g" | sed -r "s/\.html_url//" | gron --ungron
[
  {
    "message": "Adds 0.1.7 to changelog",
    "name": "Tom Hudson",
    "parents": [
      "https://github.com/tomnomnom/gron/commit/48aba5325ece087ae24ab72684851cbe77ce8311"
    ]
  },
  {
    "message": "Refactors natural sort to actualy work + be more readable",
    "name": "Tom Hudson",
    "parents": [
      "https://github.com/tomnomnom/gron/commit/3eca8bf5e07151f077cebf0d942c1fa8bc51e8f2"
    ]
  },
...