mirror of https://github.com/lework/script
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
66 lines
1.8 KiB
66 lines
1.8 KiB
#!/bin/sh |
|
# A POSIX compatible JSON parser within 60 lines of code (without comments) |
|
# Usage example: |
|
# $ echo '{ "key1" : { "key2": {}, "key3": [null, true, false, "value"]}}' | ./poorjson.sh '"key1"' '"key3"' 3 |
|
# $ "value" |
|
# shellcheck disable=SC2015 |
|
|
|
__JNUM='\(-\?\(0\|[1-9][0-9]*\)\(\.[0-9]\+\)\?\([eE][+-]\?[0-9]\+\)\?\)' |
|
__JSTR='\("\([^[:cntrl:]"]\|\\["\\\/bfnrt]\|u[0-9]{4}\)*"\)' |
|
_TOKEN="" _TMP="" __JTOK="$__JSTR\|$__JNUM\|true\|false\|null\|[][}{,:]" |
|
|
|
_is_match() { [ "$1" = "$2" ] || [ "$1" = \* ] || [ "$1" = . ]; } |
|
_eof_error() { echo "Unexpected EOF after \"$_TOKEN\""; exit 1; } |
|
_token_error() { echo "Unexpected token \"$_TOKEN\""; exit 1; } |
|
_jread() { |
|
read -r _TOKEN || _eof_error |
|
[ "$1" = . ] && echo "$_TOKEN" |
|
} |
|
|
|
_jarr() { |
|
if _is_match "$1" 0; then _jval "$@"; else _jval; fi || { |
|
[ "$_TOKEN" = ']' ] && return || _token_error |
|
} |
|
while :; do |
|
_jread "$1"; |
|
case $_TOKEN in "]") return 0;; |
|
",") [ "$1" -ge 0 ] 2>/dev/null && _TMP=$(( $1 - 1)) && shift && set -- "$_TMP" "$@";; |
|
*) _token_error;; |
|
esac |
|
if _is_match "$1" 0; then _jval "$@"; else _jval; fi || _token_error |
|
done |
|
} |
|
|
|
_jobj() { |
|
_jread "$1"; [ "$_TOKEN" = "}" ] && return 0 |
|
while :; do |
|
_TMP=$_TOKEN |
|
case $_TMP in '"'*'"') |
|
_jread "$1" |
|
[ "$_TOKEN" = ":" ] || _token_error |
|
if _is_match "$1" "$_TMP"; then _jval "$@"; else _jval; fi || _token_error |
|
_jread "$1" |
|
[ "$_TOKEN" = "}" ] && return 0 |
|
[ "$_TOKEN" != "," ] && _token_error |
|
_jread "$1" |
|
continue |
|
;; |
|
esac |
|
_token_error |
|
done |
|
} |
|
|
|
_jval() { |
|
[ "$#" -eq 0 ] || [ "$*" = . ] || shift |
|
_jread "$1" |
|
case $_TOKEN in '{') _jobj "$@";; |
|
"[") _jarr "$@";; |
|
true|false|null|-*|[0-9]*|'"'*'"') [ "$1" = \* ] && echo "$_TOKEN"; :;; |
|
*) return 1;; |
|
esac |
|
} |
|
|
|
sed -e "s/\($__JTOK\)/\n\1\n/g" | sed -e "/^\s*$/d;/$__JTOK/!{q255};" | { _jval "" "$@" . && ! read -r; } || { |
|
echo "JSON string invalid." |
|
exit 1 |
|
}
|
|
|