我正在研究 RBENV 代码库,我发现rbenv-init
文件第 116 行,创建一个包含switch
语句的函数。我的假设是,我们检查变量的值是否command
是(复数)变量中值数组的成员之一commands
。如果是,我们执行 switch 语句的分支 1。否则,我们执行分支 2。
我想写一个简单的脚本来检验我的假设,所以我写了以下内容:
#!/usr/bin/env fish
set command "foo"
switch $command
case ${argv[*]}
echo "command in args"
case "*"
echo "command not found"
end
但是,当我运行此脚本时,出现以下错误:
$ ./foo bar baz
./foo (line 6): ${ is not a valid variable in fish.
case ${argv[*]}
^
warning: Error while reading file ./foo
我原本期望对包含和argv
的数组进行求值,因为这是我向脚本提供的两个参数。我的语法与源代码中第 117 行的语法相匹配(即)。bar
baz
case ${commands[*]}
我执行脚本的 shell 是 zsh v5.8.1,但是我的 shebang 特别引用了“fish”shell,所以我认为我的 shell 并不重要。我安装了fish v3.5.1,fwiw。
答案1
其中的 bash 代码是:
commands=(`rbenv-commands --sh`)
这就是 split+glob 应用于 的输出rbenv-commands --sh
,并将生成的单词分配给 的元素$commands
bash
大批
case "$shell" in fish ) cat <<EOS function rbenv set command \$argv[1] set -e argv[1] switch "\$command" case ${commands[*]} rbenv "sh-\$command" \$argv|source case '*' command rbenv "\$command" \$argv end end EOS ;;
cat << EOS...
输出一些fish
代码,但由于EOS
未引用该代码,因此仍会执行扩展(通过 bash)。除非前面有反斜杠,否则$param
由 展开bash
。您会注意到大多数$
s 都以 为前缀\
,但不是${commands[*]}
(无论如何这是 Korn shell 语法,而不是 Fish 语法)。 bash 将其扩展为$commands
与第一个字符$IFS
(默认为空格)连接的数组元素。
因此该命令生成的 Fish 代码cat
类似于:
function rbenv
set command $argv[1]
set -e argv[1]
switch "$command"
case elements of the commands bash array
rbenv "sh-$command" $argv|source
case '*'
command rbenv "$command" $argv
end
end
要检查字符串是否在列表中,您可以使用fish
's contains
buitin:
set list foo bar baz
set string foo
if contains -- $string $list
echo $string is in the list
end
(如 zshif (( $list[(Ie)$string] ))
或非空列表if [[ $string = (${(~j[|])list}) ]]
)
您还可以这样做:
switch $string
case $list
echo $string matches at least one of the patterns in the list
end
(除非列表中的任何元素都不包含*
或?
字符,否则这是不一样的)
(这更像是zsh
's [[ $string = (${(j[|])~list}) ]]
(对于非空列表))。
还有:
if string match -q -- $pattern $list > /dev/null
echo at least one of the elements of the list matches $pattern
end
(比如zsh
)if (( $list[(I)$pattern] ))
。