0

我需要从 JSON 文件中获取与“版本”键关联的值jqgrep无论前者是否未安装。我正在使用 Zsh 5.7.1。

JSON文件看起来像这样;

{
    "version": "1.7.0+01e7dgc6",
    "date": "2020-04-06",
}

因此,预期的结果是:

1.7.0+01e7dgc6

这是我的带有条件测试的脚本,它提供了一个正则表达式,该正则表达式又被传递给匿名函数的位置参数:

#!/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}

上面的脚本返回以下错误(在调试模式下):

+(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)

您可以看到该命令未找到,因为正则表达式已被 espace 序列字符解释(即'jq -r '\''.master.version'\')。这就是为什么我需要原始字符串将正则表达式正确解析为位置参数的原因。

当测试失败时,同样的错误肯定会上升:

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:

  • P flag (i.e. espace sequence replacement)
  • g:c (process escape sequence with concatenation option)
  • e flag (performs single word shell expansion)

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.

4

1 回答 1

0

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
于 2020-05-08T12:16:14.053 回答