I need to fetch the value associated with the "version" key from a JSON file with jq
or with grep
whether the former is not installed. I'm using Zsh 5.7.1.
The JSON file looks like that;
{
"version": "1.7.0+01e7dgc6",
"date": "2020-04-06",
}
Thereby, the expected result is:
1.7.0+01e7dgc6
Here is my script with a conditional test who feed a regular expression which in turn is passed to an anonymous function's positional argument:
#!/usr/bin/env zsh
# Fetch silently JSON latest numeroted version with `jq` if installed; fallback to `grep` otherwise.
set -x
if dpkg -s 'jq' | grep -qF 'install ok installed'; then
print "using jq"
API="jq -r '.master.version'"
else
print "falling back to grep"
API="grep -Po '(?<="version": "\)\[\^"]*'"
fi
function {
local JSON='path/to/URL/index.json'
curl -fsSL "$JSON" | $@
} ${API}
The above script returns the following error (in debug mode):
+(anon):2> curl -fsSL path/to/the/URL/index.json
+(anon):2> 'jq -r '\''.master.version'\'
(anon):2: command not found: 'jq -r '.master.version'
curl: (23) Failed writing body (0 != 9320)
You can see the command is not found because the regex has been interpreted by espace sequence characters (i.e. 'jq -r '\''.master.version'\'). That is why I need raw strings to parse correctly the regex into the positional argument.
The same error rises for sure when the test fails:
falling back to grep
+dpkg.zsh:9> API='grep -Po '\''(?<=version: )[^]*'\'
...
+(anon):2> 'grep -Po '\''(?<=version: )[^]*'\'
(anon):2: command not found: grep -Po '(?<=version: )[^]*'
curl: (23) Failed writing body (0 != 9320)
How can I correctly parse the regex by NOT escaping characters like the single quote (i.e. '
) as there is no such thing as a raw string mechanism within Z Shell?
Is it possible with parameter expansion? I tried those in vain:
or with globbing qualifiers? or perhaps with sub-string modifiers?
EDIT: You made my day. I'm grateful to both user1934428 and chepner for your kindness.
zsh
doesn't perform word-splitting on parameter expansions by default (and relying on it would be error-prone anyway), so you are passing the single argument jq -r .master.version
to your anonymous function, not 3 arguments jq
, -r
, and .master.version
. Use an array instead.
#!/usr/bin/env zsh
# Fetch silently JSON latest numeroted version with `jq` if installed; fallback to `grep` otherwise.
if dpkg -s 'jq' | grep -qF 'install ok installed'; then
print "using jq"
API=(jq -r '.master.version')
else
print "falling back to grep"
API=(grep -Po '(?<="version": "\)\[\^"]*')
fi
function {
local JSON='unified_resource_identifier/index.json'
curl -fsSL "$JSON" | "$@"
} $API # or "${API[@]}"
Further, it's simpler to use whence
to see if jq
is available at all, rather than checking if it was installed with dpkg
specifically.
if whence jq > /dev/null; then
API=(jq -r '.master.version')
else
API=(grep -Po '(?<="version": "\)\[\^"]*')
fi