【问题标题】:How to pass a raw string to a variable in Zsh?如何将原始字符串传递给 Zsh 中的变量?
【发布时间】:2020-08-21 22:41:20
【问题描述】:

我需要从带有jqgrep 的JSON 文件中获取与“版本”键关联的值,无论前者是否未安装。我正在使用 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)

由于 Z Shell 中没有原始字符串机制之类的东西,我如何通过不转义单引号(即')等字符来正确解析正则表达式?

是否可以进行参数扩展?我尝试了这些都是徒劳的:

  • P 标志(即 espace 序列替换)
  • g:c(带有连接选项的进程转义序列)
  • e 标志(执行单字外壳扩展)

还是使用通配符?或者可能带有子字符串修饰符?

编辑: 你让我今天一整天都感觉很好。感谢 user1934428 和 chepner 的好意。

【问题讨论】:

  • 当你用set -x 运行它时,你应该看到dpkg|grep 产生了什么。顺便说一句,虽然可能与问题无关,但您可以更轻松地将测试编写为if dpkg -s jq | grep -qF 'install ok installed'; then ....。实际上,你只需要知道 grep 是否找到了模式;无需使用[[ ... ]] 并测试字符串是否存在。

标签: regex zsh glob anonymous-function rawstring


【解决方案1】:

zsh 默认情况下不会对参数扩展执行分词(并且依赖它无论如何都容易出错),因此您将 single 参数 jq -r .master.version 传递给您的匿名函数,而不是 3 个参数 jq-r.master.version。请改用数组。

#!/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[@]}"

此外,使用whence 来查看jq 是否可用更简单,而不是专门检查它是否使用dpkg 安装。

if whence jq > /dev/null; then
  API=(jq -r '.master.version')
else
  API=(grep -Po '(?<="version": "\)\[\^"]*')
fi

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-16
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多