mxwcore-wotlk/deps/jsonpath/JSONPath.sh

857 lines
24 KiB
Bash

#!/usr/bin/env bash
# ---------------------------------------------------------------------------
# GLOBALS
# ---------------------------------------------------------------------------
DEBUG=0
INCLEMPTY=0
NOCASE=0
WHOLEWORD=0
FILE=
NO_HEAD=0
NORMALIZE_SOLIDUS=0
BRIEF=0
PASSTHROUGH=0
JSON=0
PRINT=1
MULTIPASS=0
FLATTEN=0
STDINFILE=/var/tmp/JSONPath.$$.stdin
STDINFILE2=/var/tmp/JSONPath.$$.stdin2
PASSFILE=/var/tmp/JSONPath.$$.pass1
declare -a INDEXMATCH_QUERY
# ---------------------------------------------------------------------------
main() {
# ---------------------------------------------------------------------------
# It all starts here
parse_options "$@"
trap cleanup EXIT
if [[ $QUERY == *'?(@'* ]]; then
# This will be a multipass query
[[ -n $FILE ]] && STDINFILE=$FILE
[[ -z $FILE ]] && cat >$STDINFILE
while true; do
tokenize_path
create_filter
cat "$STDINFILE" | tokenize | parse | filter | indexmatcher >$PASSFILE
[[ $MULTIPASS -eq 1 ]] && {
# replace filter expression with index sequence
SET=$(sed -rn 's/.*,([0-9]+)[],].*/\1/p' $PASSFILE | tr '\n' ,)
SET=${SET%,}
QUERY=$(echo $QUERY | sed "s/?(@[^)]\+)/$SET/")
[[ $DEBUG -eq 1 ]] && echo "QUERY=$QUERY"
reset
continue
}
cat $PASSFILE | flatten | json | brief
break
done
else
tokenize_path
create_filter
if [[ $PASSTHROUGH -eq 1 ]]; then
JSON=1
flatten | json
elif [[ -z $FILE ]]; then
tokenize | parse | filter | indexmatcher | flatten | json | brief
else
cat "$FILE" | tokenize | parse | filter | indexmatcher | flatten | \
json | brief
fi
fi
}
# ---------------------------------------------------------------------------
reset() {
# ---------------------------------------------------------------------------
# Reset some vars
declare -a INDEXMATCH_QUERY
PATHTOKENS=
FILTER=
OPERATOR=
RHS=
MULTIPASS=0
}
# ---------------------------------------------------------------------------
cleanup() {
# ---------------------------------------------------------------------------
[[ -e "$PASSFILE" ]] && rm -f "$PASSFILE"
[[ -e "$STDINFILE2" ]] && rm -f "$STDINFILE2"
[[ -z "$FILE" && -e "$STDINFILE" ]] && rm -f "$STDINFILE"
}
# ---------------------------------------------------------------------------
usage() {
# ---------------------------------------------------------------------------
echo
echo "Usage: JSONPath.sh [-b] [j] [-h] [-f FILE] [pattern]"
echo
echo "pattern - the JSONPath query. Defaults to '$.*' if not supplied."
#echo "-s - Remove escaping of the solidus symbol (straight slash)."
echo "-b - Brief. Only show values."
echo "-j - JSON ouput."
echo "-u - Strip unnecessary leading path elements."
echo "-i - Case insensitive."
echo "-p - Pass-through to the JSON parser."
echo "-w - Match whole words only (for filter script expression)."
echo "-f FILE - Read a FILE instead of stdin."
#echo "-n - No-head. Do not show nodes that have no path (lines that start with [])."
echo "-h - This help text."
echo
}
# ---------------------------------------------------------------------------
parse_options() {
# ---------------------------------------------------------------------------
set -- "$@"
local ARGN=$#
while [ "$ARGN" -ne 0 ]
do
case $1 in
-h) usage
exit 0
;;
-f) shift
FILE=$1
;;
-i) NOCASE=1
;;
-j) JSON=1
;;
-n) NO_HEAD=1
;;
-b) BRIEF=1
;;
-u) FLATTEN=1
;;
-p) PASSTHROUGH=1
;;
-w) WHOLEWORD=1
;;
-s) NORMALIZE_SOLIDUS=1
;;
?*) QUERY=$1
;;
esac
shift 1
ARGN=$((ARGN-1))
done
[[ -z $QUERY ]] && QUERY='$.*'
}
# ---------------------------------------------------------------------------
awk_egrep() {
# ---------------------------------------------------------------------------
local pattern_string=$1
gawk '{
while ($0) {
start=match($0, pattern);
token=substr($0, start, RLENGTH);
print token;
$0=substr($0, start+RLENGTH);
}
}' pattern="$pattern_string"
}
# ---------------------------------------------------------------------------
tokenize() {
# ---------------------------------------------------------------------------
# json parsing
local GREP
local ESCAPE
local CHAR
if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
then
GREP='egrep -ao --color=never'
else
GREP='egrep -ao'
fi
if echo "test string" | egrep -o "test" >/dev/null 2>&1
then
ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
CHAR='[^[:cntrl:]"\\]'
else
GREP=awk_egrep
ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
CHAR='[^[:cntrl:]"\\\\]'
fi
local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
local KEYWORD='null|false|true'
local SPACE='[[:space:]]+'
# Force zsh to expand $A into multiple words
local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')
if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
}
# ---------------------------------------------------------------------------
tokenize_path () {
# ---------------------------------------------------------------------------
local GREP
local ESCAPE
local CHAR
if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
then
GREP='egrep -ao --color=never'
else
GREP='egrep -ao'
fi
if echo "test string" | egrep -o "test" >/dev/null 2>&1
then
CHAR='[^[:cntrl:]"\\]'
else
GREP=awk_egrep
#CHAR='[^[:cntrl:]"\\\\]'
fi
local WILDCARD='\*'
local WORD='[ A-Za-z0-9_-]*'
local INDEX="\\[$WORD(:$WORD){0,2}\\]"
local INDEXALL="\\[\\*\\]"
local STRING="[\\\"'][^[:cntrl:]\\\"']*[\\\"']"
local SET="\\[($WORD|$STRING)(,($WORD|$STRING))*\\]"
local FILTER='\?\(@[^)]+'
local DEEPSCAN="\\.\\."
local SPACE='[[:space:]]+'
# Force zsh to expand $A into multiple words
local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')
if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
readarray -t PATHTOKENS < <( echo "$QUERY" | \
$GREP "$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|." | \
egrep -v "^$SPACE$|^\\.$|^\[$|^\]$|^'$|^\\\$$|^\)$")
[[ $DEBUG -eq 1 ]] && {
echo "egrep -o '$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|.'"
echo -n "TOKENISED QUERY="; echo "$QUERY" | \
$GREP "$INDEX|$STRING|$WORD|$WILDCARD|$FILTER|$DEEPSCAN|$SET|$INDEXALL|." | \
egrep -v "^$SPACE$|^\\.$|^\[$|^\]$|^'$|^\\\$$|^\)$"
}
if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
}
# ---------------------------------------------------------------------------
create_filter() {
# ---------------------------------------------------------------------------
# Creates the filter from the user's query.
# Filter works in a single pass through the data, unless a filter (script)
# expression is used, in which case two passes are required (MULTIPASS=1).
local len=${#PATHTOKENS[*]}
local -i i=0
local query="^\[" comma=
while [[ i -lt len ]]; do
case "${PATHTOKENS[i]}" in
'"') :
;;
'..') query+="$comma[^]]*"
comma=
;;
'[*]') query+="$comma[^,]*"
comma=","
;;
'*') query+="$comma(\"[^\"]*\"|[0-9]+[^],]*)"
comma=","
;;
'?(@'*) a=${PATHTOKENS[i]#?(@.}
elem="${a%%[<>=!]*}"
rhs="${a##*[<>=!]}"
a="${a#$elem}"
elem="${elem//./[\",.]+}" # Allows child node matching
operator="${a%$rhs}"
[[ -z $operator ]] && { operator="=="; rhs=; }
if [[ $rhs == *'"'* || $rhs == *"'"* ]]; then
case $operator in
'=='|'=') OPERATOR=
if [[ $elem == '?(@' ]]; then
# To allow search on @.property such as:
# $..book[?(@.title==".*Book 1.*")]
query+="$comma[0-9]+[],][[:space:]\"]*${rhs//\"/}"
else
# To allow search on @ (this node) such as:
# $..reviews[?(@==".*Fant.*")]
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*${rhs//\"/}"
fi
FILTER="$query"
;;
'>='|'>') OPERATOR=">"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
;;
'<='|'<') OPERATOR="<"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
;;
esac
else
case $operator in
'=='|'=') OPERATOR=
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*$rhs"
FILTER="$query"
;;
'>=') OPERATOR="-ge"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
;;
'>') OPERATOR="-gt"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
;;
'<=') OPERATOR="-le"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
;;
'<') OPERATOR="-lt"
RHS="$rhs"
query+="$comma[0-9]+,\"$elem\"[],][[:space:]\"]*"
FILTER="$query"
esac
fi
MULTIPASS=1
;;
"["*) if [[ ${PATHTOKENS[i]} =~ , ]]; then
a=${PATHTOKENS[i]#[}
a=${a%]}
if [[ $a =~ [[:alpha:]] ]]; then
# converts only one comma: s/("[^"]+),([^"]+")/\1`\2/g;s/"//g
#a=$(echo $a | sed 's/\([[:alpha:]]*\)/"\1"/g')
a=$(echo $a | sed -r "s/[\"']//g;s/([^,]*)/\"\1\"/g")
fi
query+="$comma(${a//,/|})"
elif [[ ${PATHTOKENS[i]} =~ : ]]; then
if ! [[ ${PATHTOKENS[i]} =~ [0-9][0-9] || ${PATHTOKENS[i]} =~ :] ]]
then
if [[ ${PATHTOKENS[i]#*:} =~ : ]]; then
INDEXMATCH_QUERY+=("${PATHTOKENS[i]}")
query+="$comma[^,]*"
else
# Index in the range of 0-9 can be handled by regex
query+="${comma}$(echo ${PATHTOKENS[i]} | \
awk '/:/ { a=substr($0,0,index($0,":")-1);
b=substr($0,index($0,":")+1,index($0,"]")-index($0,":")-1);
if(b>0) { print a ":" b-1 "]" };
if(b<=0) { print a ":]" } }' | \
sed 's/\([0-9]\):\([0-9]\)/\1-\2/;
s/\[:\([0-9]\)/[0-\1/;
s/\([0-9]\):\]/\1-9999999]/')"
fi
else
INDEXMATCH_QUERY+=("${PATHTOKENS[i]}")
query+="$comma[^,]*"
fi
else
a=${PATHTOKENS[i]#[}
a=${a%]}
if [[ $a =~ [[:alpha:]] ]]; then
a=$(echo $a | sed -r "s/[\"']//g;s/([^,]*)/\"\1\"/g")
else
[[ $i -gt 0 ]] && comma=","
fi
#idx=$(echo "${PATHTOKENS[i]}" | tr -d "[]")
query+="$comma$a"
fi
comma=","
;;
*) PATHTOKENS[i]=${PATHTOKENS[i]//\'/\"}
query+="$comma\"${PATHTOKENS[i]//\"/}\""
comma=","
;;
esac
i=i+1
done
[[ -z $FILTER ]] && FILTER="$query[],]"
[[ $DEBUG -eq 1 ]] && echo "FILTER=$FILTER"
}
# ---------------------------------------------------------------------------
parse_array () {
# ---------------------------------------------------------------------------
# json parsing
local index=0
local ary=''
read -r token
case "$token" in
']')
;;
*)
while :
do
parse_value "$1" "$index"
index=$((index+1))
ary="$ary""$value"
read -r token
case "$token" in
']') break ;;
',') ary="$ary," ;;
*) throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
esac
read -r token
done
;;
esac
value=
:
}
# ---------------------------------------------------------------------------
parse_object () {
# ---------------------------------------------------------------------------
# json parsing
local key
local obj=''
read -r token
case "$token" in
'}')
;;
*)
while :
do
case "$token" in
'"'*'"') key=$token ;;
*) throw "EXPECTED string GOT ${token:-EOF}" ;;
esac
read -r token
case "$token" in
':') ;;
*) throw "EXPECTED : GOT ${token:-EOF}" ;;
esac
read -r token
parse_value "$1" "$key"
obj="$obj$key:$value"
read -r token
case "$token" in
'}') break ;;
',') obj="$obj," ;;
*) throw "EXPECTED , or } GOT ${token:-EOF}" ;;
esac
read -r token
done
;;
esac
value=
:
}
# ---------------------------------------------------------------------------
parse_value () {
# ---------------------------------------------------------------------------
# json parsing
local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0
case "$token" in
'{') parse_object "$jpath" ;;
'[') parse_array "$jpath" ;;
# At this point, the only valid single-character tokens are digits.
''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
*) value=$token
# if asked, replace solidus ("\/") in json strings with normalized value: "/"
[ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g')
isleaf=1
[ "$value" = '""' ] && isempty=1
;;
esac
[[ -z INCLEMPTY ]] && [ "$value" = '' ] && return
[ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return
[ "$isleaf" -eq 1 ] && [ $isempty -eq 0 ] && print=1
[ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value"
:
}
# ---------------------------------------------------------------------------
flatten() {
# ---------------------------------------------------------------------------
# Take out
local path a prevpath pathlen
if [[ $FLATTEN -eq 1 ]]; then
cat >"$STDINFILE2"
highest=9999
while read line; do
a=${line#[};a=${a%%]*}
readarray -t path < <(grep -o "[^,]*"<<<"$a")
[[ -z $prevpath ]] && {
prevpath=("${path[@]}")
highest=$((${#path[*]}-1))
continue
}
pathlen=$((${#path[*]}-1))
for i in `seq 0 $pathlen`; do
[[ ${path[i]} != ${prevpath[i]} ]] && {
high=$i
break
}
done
[[ $high -lt $highest ]] && highest=$high
prevpath=("${path[@]}")
done <"$STDINFILE2"
if [[ $highest -gt 0 ]]; then
sed -r 's/\[(([0-9]+|"[^"]+")[],]){'$((highest))'}(.*)/[\3/' \
"$STDINFILE2"
else
cat "$STDINFILE2"
fi
else
cat
fi
}
# ---------------------------------------------------------------------------
indexmatcher() {
# ---------------------------------------------------------------------------
# For double digit or greater indexes match each line individually
# Single digit indexes are handled more efficiently by regex
local a b
[[ $DEBUG -eq 1 ]] && {
for i in `seq 0 $((${#INDEXMATCH_QUERY[*]}-1))`; do
echo "INDEXMATCH_QUERY[$i]=${INDEXMATCH_QUERY[i]}"
done
}
matched=1
step=
if [[ ${#INDEXMATCH_QUERY[*]} -gt 0 ]]; then
while read -r line; do
for i in `seq 0 $((${#INDEXMATCH_QUERY[*]}-1))`; do
[[ ${INDEXMATCH_QUERY[i]#*:} =~ : ]] && {
step=${INDEXMATCH_QUERY[i]##*:}
step=${step%]}
INDEXMATCH_QUERY[i]="${INDEXMATCH_QUERY[i]%:*}]"
}
q=${INDEXMATCH_QUERY[i]:1:-1} # <- strip '[' and ']'
a=${q%:*} # <- number before ':'
b=${q#*:} # <- number after ':'
[[ -z $b ]] && b=99999999999
readarray -t num < <( (grep -Eo ',[0-9]+[],]' | tr -d ,])<<<$line )
if [[ ${num[i]} -ge $a && ${num[i]} -lt $b && matched -eq 1 ]]; then
matched=1
[[ $i -eq $((${#INDEXMATCH_QUERY[*]}-1)) ]] && {
if [[ $step -gt 1 ]]; then
[[ $(((num[i]-a)%step)) -eq 0 ]] && {
[[ $DEBUG -eq 1 ]] && echo -n "($a,$b,${num[i]}) "
echo "$line"
}
else
[[ $DEBUG -eq 1 ]] && echo -n "($a,$b,${num[i]}) "
echo "$line"
fi
}
else
matched=0
continue
fi
done
matched=1
done
else
cat -
fi
}
# ---------------------------------------------------------------------------
brief() {
# ---------------------------------------------------------------------------
# Only show the value
if [[ $BRIEF -eq 1 ]]; then
sed 's/^[^\t]*\t//;s/^"//;s/"$//;'
else
cat
fi
}
# ---------------------------------------------------------------------------
json() {
# ---------------------------------------------------------------------------
# Turn output into JSON
local a tab=$(echo -e "\t")
local UP=1 DOWN=2 SAME=3
local prevpathlen=-1 prevpath=() path a
declare -a closers
if [[ $JSON -eq 0 ]]; then
cat -
else
while read -r line; do
a=${line#[};a=${a%%]*}
readarray -t path < <(grep -o "[^,]*"<<<"$a")
value=${line#*$tab}
# Not including the object itself (last item)
pathlen=$((${#path[*]}-1))
# General direction
direction=$SAME
[[ $pathlen -gt $prevpathlen ]] && direction=$DOWN
[[ $pathlen -lt $prevpathlen ]] && direction=$UP
# Handle jumps UP the tree (close previous paths)
[[ $prevpathlen != -1 ]] && {
for i in `seq 0 $((pathlen-1))`; do
[[ ${prevpath[i]} == ${path[i]} ]] && continue
[[ ${path[i]} != '"'* ]] && {
a=(${!arrays[*]})
[[ -n $a ]] && {
for k in `seq $((i+1)) ${a[-1]}`; do
arrays[k]=
done
}
a=(${!comma[*]})
[[ -n $a ]] && {
for k in `seq $((i+1)) ${a[-1]}`; do
comma[k]=
done
}
for j in `seq $((prevpathlen)) -1 $((i+2))`
do
arrays[j]=
[[ -n ${closers[j]} ]] && {
let indent=j*4
printf "\n%0${indent}s${closers[j]}" ""
unset closers[j]
comma[j]=
}
done
direction=$DOWN
break
}
direction=$DOWN
for j in `seq $((prevpathlen)) -1 $((i+1))`
do
arrays[j]=
[[ -n ${closers[j]} ]] && {
let indent=j*4
printf "\n%0${indent}s${closers[j]}" ""
unset closers[j]
comma[j]=
}
done
a=(${!arrays[*]})
[[ -n $a ]] && {
for k in `seq $i ${a[-1]}`; do
arrays[k]=
done
}
break
done
}
[[ $direction -eq $UP ]] && {
[[ $prevpathlen != -1 ]] && comma[prevpathlen]=
for i in `seq $((prevpathlen+1)) -1 $((pathlen+1))`
do
arrays[i]=
[[ -n ${closers[i]} ]] && {
let indent=i*4
printf "\n%0${indent}s${closers[i]}" ""
unset closers[i]
comma[i]=
}
done
a=(${!arrays[*]})
[[ -n $a ]] && {
for k in `seq $i ${a[-1]}`; do
arrays[k]=
done
}
}
# Opening braces (the path leading up to the key)
broken=
for i in `seq 0 $((pathlen-1))`; do
[[ -z $broken && ${prevpath[i]} == ${path[i]} ]] && continue
[[ -z $broken ]] && {
broken=$i
[[ $prevpathlen -ne -1 ]] && broken=$((i+1))
}
if [[ ${path[i]} == '"'* ]]; then
# Object
[[ $i -ge $broken ]] && {
let indent=i*4
printf "${comma[i]}%0${indent}s{\n" ""
closers[i]='}'
comma[i]=
}
let indent=(i+1)*4
printf "${comma[i]}%0${indent}s${path[i]}:\n" ""
comma[i]=",\n"
else
# Array
if [[ ${arrays[i]} != 1 ]]; then
let indent=i*4
printf "%0${indent}s" ""
echo "["
closers[i]=']'
arrays[i]=1
comma[i]=
else
let indent=(i+1)*4
printf "\n%0${indent}s${closers[i-1]}" ""
direction=$DOWN
comma[i+1]=",\n"
fi
fi
done
# keys & values
if [[ ${path[-1]} == '"'* ]]; then
# Object
[[ $direction -eq $DOWN ]] && {
let indent=pathlen*4
printf "${comma[pathlen]}%0${indent}s{\n" ""
closers[pathlen]='}'
comma[pathlen]=
}
let indent=(pathlen+1)*4
printf "${comma[pathlen]}%0${indent}s" ""
echo -n "${path[-1]}:$value"
comma[pathlen]=",\n"
else
# Array
[[ ${arrays[i]} != 1 ]] && {
let indent=(pathlen-0)*4
printf "%0${indent}s[\n" ""
closers[pathlen]=']'
comma[pathlen]=
arrays[i]=1
}
let indent=(pathlen+1)*4
printf "${comma[pathlen]}%0${indent}s" ""
echo -n "$value"
comma[pathlen]=",\n"
fi
prevpath=("${path[@]}")
prevpathlen=$pathlen
done
# closing braces
for i in `seq $((pathlen)) -1 0`
do
let indent=i*4
printf "\n%0${indent}s${closers[i]}" ""
done
echo
fi
}
# ---------------------------------------------------------------------------
filter() {
# ---------------------------------------------------------------------------
# Apply the query filter
local a tab=$(echo -e "\t") v
[[ $NOCASE -eq 1 ]] && opts+="-i"
[[ $WHOLEWORD -eq 1 ]] && opts+=" -w"
if [[ -z $OPERATOR ]]; then
egrep $opts "$FILTER"
else
egrep $opts "$FILTER" | \
while read line; do
v=${line#*$tab}
case $OPERATOR in
'-ge') if awk '{exit !($1>=$2)}'<<<"$v $RHS";then echo "$line"; fi
;;
'-gt') if awk '{exit !($1>$2) }'<<<"$v $RHS";then echo "$line"; fi
;;
'-le') if awk '{exit !($1<=$2) }'<<<"$v $RHS";then echo "$line"; fi
;;
'-lt') if awk '{exit !($1<$2) }'<<<"$v $RHS";then echo "$line"; fi
;;
'>') v=${v#\"};v=${v%\"}
RHS=${RHS#\"};RHS=${RHS%\"}
[[ "$v" > "$RHS" ]] && echo "$line"
;;
'<') v=${v#\"};v=${v%\"}
RHS=${RHS#\"};RHS=${RHS%\"}
[[ "$v" < "$RHS" ]] && echo "$line"
;;
esac
done #< <(egrep $opts "$FILTER")
fi
}
# ---------------------------------------------------------------------------
parse () {
# ---------------------------------------------------------------------------
# Parses json
read -r token
parse_value
read -r token
case "$token" in
'') ;;
*) throw "EXPECTED EOF GOT $token"
exit 1;;
esac
}
# ---------------------------------------------------------------------------
throw() {
# ---------------------------------------------------------------------------
echo "$*" >&2
exit 1
}
if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]);
then
main "$@"
fi
# vi: expandtab sw=2 ts=2