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
andsed
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"
]
},
...