Last active
June 21, 2024 05:45
-
-
Save mkfmnn/7b637aa0ec9b0422b3b75ec181a132fc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A basic re-implementation of gron in JQ | |
# Operates in a streaming manner, without having to read the entire input first or hold it in memory | |
# Try: cat big.json | while read; do printf '%s\n' "$REPLY"; sleep 0.1; done | jqgron | |
# Most operations are slower than gron, but `jqgron -u -j` is actually faster! | |
def topath: | |
map(if (tostring|test("\\A[[:alpha:]$_][[:alnum:]$_]*\\z")|not) | |
then "[\(tojson)]" else ".\(.)" end) | join(""); | |
def tojqpath: | |
topath | if .[0:1] == "[" then "." + . else . end; | |
def parsepath: if length == 0 then [] else | |
[capture("\\A(?:\\.(?<prop>[^.\\[]+)|\\[(?<field>(?:[^\"\\]]+|\"(?:[^\\\\\"]|\\\\.)+\"))\\])(?<rest>.*)\\z")] as $m | |
| if ($m|length) == 0 then error("unparsed input in path: \(.)") else $m[] end | |
| [(.prop // (.field|fromjson)), (.rest | parsepath[])] end; | |
def parsejqpath: | |
if . == "." then "" | |
elif .[0:2] == ".[" then .[1:] | |
elif .[0:1] == "." then . | |
else error("malformed path: \(.)") end | |
| parsepath; | |
def _addparents($path): | |
# expects input like {s:{}, e:[]} | |
(path[:-1]|tostring) as $pathstr | | |
if ($path|length == 0) or (.s|has($pathstr)) then . | |
else _addparents($path[:-1]) | .s[$pathstr] += 1 | .e += [$path] end; | |
# Converts a jq-style stream into a gron-style stream, with container openers | |
# and no container terminators | |
def prefixstream(i): | |
foreach (i | select(length == 2)) as $e ({s:{}} | |
; .e = [] | _addparents($e[0]) | |
; (.e[] | [.[0:-1], if (.[-1]|type) == "number" then [] else {} end]), $e); | |
# A simplified version of fromstream that doesn't require container terminators and that | |
# only outputs a single object | |
def fromstream2(i): | |
reduce i as $i (null; if $i|length == 2 then setpath($i[0]; $i[1]) else . end); | |
def gron(i): | |
prefixstream(i) | "json\(.[0]|topath) = \(.[1]|tojson);"; | |
def ungron(i): | |
fromstream2( | |
i | |
| capture("\\Ajson(?<path>(?:[^\"]|\"(?:[^\\\\\"]|\\\\.)+\")*) = (?<value>.*);\\z") | |
| [(.path|parsepath), (.value|fromjson)] | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
json= | |
ungron= | |
while getopts ju name | |
do | |
case $name in | |
j) json=1;; | |
u) ungron=1;; | |
?) printf "Usage: %s: [-j] [-u] [file]\n" $0 | |
exit 2;; | |
esac | |
done | |
shift $(($OPTIND - 1)) | |
if [ ! -z "$json" ]; then | |
if [ ! -z "$ungron" ]; then | |
exec jq -n $JQ_OPTS 'include "./gron";fromstream2(inputs)' "$@" | |
else | |
exec jq -cn --stream $JQ_OPTS 'include "./gron";prefixstream(inputs)' "$@" | |
fi | |
else | |
if [ ! -z "$ungron" ]; then | |
exec jq -nR $JQ_OPTS 'include "./gron";ungron(inputs)' "$@" | |
else | |
exec jq -rn --stream $JQ_OPTS 'include "./gron";gron(inputs)' "$@" | |
fi | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment