Skip to content

Instantly share code, notes, and snippets.

@flisboac
Last active April 20, 2023 03:02
Show Gist options
  • Save flisboac/d1613d4f02644525a58cf8baab901c0f to your computer and use it in GitHub Desktop.
Save flisboac/d1613d4f02644525a58cf8baab901c0f to your computer and use it in GitHub Desktop.
Various slow-ish portable Shell utilities for JSON values (all depending on `jq`)
#!/bin/sh
##
# Sets properties in a JSON object.
#
# Properties are given in the format `KEY[:TYPE]=VALUE`, as a var-arg argument to the function.
# `TYPE` is optional; if not provided, the value will be simply serialized to string, regardless
# of its format. But if a type is informed, some conversion and validation occurs prior to
# assignment. Type names are case insensitive. Accepted types:
#
# - `boolean` (aliases: `bool`);
# - `integer` (aliases: `int`);
# - `number` (aliases: `num`);
# - `array`;
# - `object` (aliases: `obj`);
# - `json`.
#
# No variable substitution is performed on `VALUE`, but you can use the shell's own
# interpolation to your advantage.
#
# Examples:
# $ util_JsonObject_set {} \
# appName="${APP_NAME}" \
# debug:bool="${APP_DEBUG:-"$([ "${ENV}"!="prod" ]; echo "$?")"}" \
# timeout:int="${APP_TIMEOUT:-120}"
#
# @usage $0 OBJ [ASSIGN...]
# @param OBJ The object to which properties will be added.
# @param ASSIGN The property assignment to perform.
#
util_JsonObject_set() (
set -e
local __obj="${1}"; shift
local __name_type
local __name
local __type
local __value
if [ "${__obj}"=="-" ]; then
__obj="$(cat)"
fi
while [ "$#" -gt 0 ]; do
__name_type="${1%%=*}"
__value="${1#*=}"
__name="$(printf '%s\n' "$__name_type" | cut -d: -f1)"
__type="$(printf '%s\n' "$__name_type" | cut -d: -f2 -s | tr '[:upper:]' '[:lower:]')"
shift
printf '** %s: %s = %s\n' "$__name" "$__type" "$__value"
__name="$(printf '%s\n' "$__name" | jq -R --indent 0 ". | tostring")"
if [ -z "$__type" ]; then
__value="$(printf '%s' "$__value" | jq --indent 0 -R ". | tostring")" ;;
else
case "$__type" in
int|integer)
__value="$(printf '%s' "$__value" | jq --indent 0 -R '. | tonumber | floor')" ;;
num|number)
__value="$(printf '%s' "$__value" | jq --indent 0 -R '. | tonumber')" ;;
bool|boolean)
__value="$(printf '%s' "$__value" | jq --indent 0 -R '. | if test("false|f|no|n|off|0";"i") then false elif test("true|t|yes|y|on|1";"i") then true else error("value is not boolean-like") end')" ;;
array)
__value="$(printf '%s' "$__value" | jq --indent 0 '. | if type=="array" then . else error("value should be an array") end')" ;;
obj|object)
__value="$(printf '%s' "$__value" | jq --indent 0 '. | if type=="object" then . else error("value should be an object") end')" ;;
json)
__value="$(printf '%s' "$__value" | jq --indent 0 '.')" ;;
*)
printf 'Unknown declared type "%s" in property "%s".\n' "$__type" "$__name" ;;
esac
fi
__obj="$(printf '%s\n' "${__obj}" | jq "$(printf '. += {%s: %s}' "${__name}" "${__value}")")"
done
printf '%s\n' "${__obj}"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment