如何将原始字符串传递给 Zsh 中的变量?
How to pass a raw string to a variable in Zsh?
我需要使用 jq
或 grep
从 JSON 文件中获取与 "version" 键关联的值,无论前者是否未安装。我正在使用 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}
以上脚本returns出现如下错误(调试模式下):
+(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)
您可以看到命令未找到,因为正则表达式已被空格序列字符解释(即 '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标志(即空格序列替换)
- g:c(处理带串联选项的转义序列)
- e 标志(执行单字shell展开)
或使用 globbing 限定词?或者可能使用子字符串修饰符?
编辑:
你让我今天一整天都感觉很好。感谢 user1934428 和 chepner 的好意。
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
我需要使用 jq
或 grep
从 JSON 文件中获取与 "version" 键关联的值,无论前者是否未安装。我正在使用 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}
以上脚本returns出现如下错误(调试模式下):
+(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)
您可以看到命令未找到,因为正则表达式已被空格序列字符解释(即 '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标志(即空格序列替换)
- g:c(处理带串联选项的转义序列)
- e 标志(执行单字shell展开)
或使用 globbing 限定词?或者可能使用子字符串修饰符?
编辑: 你让我今天一整天都感觉很好。感谢 user1934428 和 chepner 的好意。
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