I would like to make a small jq
-like function that does get-or-default-if-not-present similar to Python's dict.get(key, default)
. This is the desired behavior:
% echo '{"nested": {"key": "value", "tricky": null}}' > file.json
% my-jq nested.key \"default\" file.json
"value"
% my-jq nested.tricky \"default\" file.json
null
% my-jq nested.dne \"default\" file.json
"default"
I have tried playing with this answer to a similar question but it doesn't work for nested keys. Does anyone have a suggestion?
function my-jq () {
jq --arg key "$1" --arg default "$2" \
'if has($key) then .[$key] else $default | fromjson end' "$3"
}
CodePudding user response:
You can't use a dotted path as a sequence of keys. You can turn such a path into a valid path for use with the getpath
function, however. (There may be a cleaner, more robust way to do this.) The //
operator provides for an alternate value should the left-hand side produce false
or null
.
$ jq 'getpath($key | ltrimstr(".") | split(".")) // $default' file.json --arg key .nested.key --arg default foobar
"value"
$ jq 'getpath($key | ltrimstr(".") | split(".")) // $default' file.json --arg key .nested.dne --arg default foobar
"foobar"
$key | ltrimstr(".") | split(".")
first gets rid of the leading .
, then splits the remaining string on the remaining .
to produce a list of separate keys. getpath
produces a filter using that list of keys; getpath(["nested", "key"])
is equivalent (AFAIK) to .nested.key
.
CodePudding user response:
Your requirements go against JSON's grain a bit, but here is one possible solution, or the basis of a family of solutions.
This particular solution assumes that the path is given in array form:
function my-jq () {
jq -c --argjson key "$1" --arg default "$2" '
first(tostream | select(length == 2 and .[0] == $key)) // null
| if . then .[1] else $default end
'
}
Examples:
echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","key"]' haha
"value"
echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","nokey"]' haha
"haha"
echo '{"nested": {"key": "value", "tricky": null}}' | my-jq2 '["nested","tricky"]' haha
null