(注意:这个问题的动机只是为了提高我的bash
编程知识。)
我想知道bash
等价zsh
于 的表达式$@[2,$#]
,直接地寻址 shell 函数(或脚本)的命令行参数数组 ( $@
) 的范围。
(我在网上找到的所有解决范围的解决方案$@
都bash
可以描述为“间接寻址”,因为它们都需要首先分配$@
给中间变量。请参见下面的示例。)
为了具体起见:bash
以下zsh
测试函数的等价物是什么?
testfn () {
printf '>%s<\n' $@[2,$#]
}
% testfn a b c d
>b<
>c<
>d<
以下是我设法想出的最接近的;如上所述,它需要将 赋值$@
给中间变量:
testfn () {
holdargs=( $@ )
printf '>%s<\n' "${holdargs[@]:1}"
}
我对不需要中间变量的所有尝试都因错误而失败bad substitution
。
答案1
这对我有用:
testfn () {
printf '>%s<\n' "${@:2}"
}
例子:
$ testfn a b c d
>b<
>c<
>d<
$@ Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word.
查看位置参数部分Bash 黑客维基以及大量使用部分了解更多示例和详细信息。
一般情况下当你用双引号形式的时候是$@
这样的,"$@"
否则"${@:2}"
返回的结果将是双引号结果。
$@
可以使用以下符号访问数组元素:
"${@:START:COUNT}"
摘自“大量使用”部分
这将从 START 开始扩展 COUNT 个位置参数。 COUNT 可以省略 (${@:START}),在这种情况下,从 START 开始的所有位置参数都会展开。
空元素?
其他人指出上面的内容并不等效,因为它无法处理空元素。我使用的是 Bash 4.1.7,看起来确实如此。
例子:
$ testfn "" a "" c d e
>a<
><
>c<
>d<
>e<
$ testfn '' a '*' c d e
>a<
>*<
>c<
>d<
>e<
$ testfn "" a " " c d e
>a<
> <
>c<
>d<
>e<
答案2
在zsh
,
printf '<%s>\n' ${@[2,$#]}
与...一样
printf '<%s>\n' $@[2,-1]
打印非空位置元素 2 到最后一个。这与编写相同(如果 $# == 5):
printf '<%s>\n' $2 $3 $4 $5
所以:
$ set 1 2 '' '*' 5
$ printf '<%s>\n' $@[2,-1]
<2>
<*>
<5>
要获得 中的等价物bash
,您需要:
$ set 1 2 '' '*' 5
$ a=("$@")
$ IFS=; set -f
$ printf '<%s>\n' ${a[@]:1}
<2>
<*>
<5>
您需要一个中间数组,因为${@:2}
这样不行(至少在 4.2.45 中不行)。
当然,如果您想要除第一个元素之外的所有元素,无论它们是否为空,您都必须编写它:
$ printf '<%s>\n' "$@[2,-1]"
<2>
<>
<*>
<5>
在zsh
和
$ printf '<%s>\n' "${@:2}"
<2>
<>
<*>
<5>
在bash
。
请注意,zsh
最终包含了${array:first:n}
语法(仅当它不与 csh 样式修饰符冲突时),因此上面的 bash(实际上是 ksh)代码也可以在较新版本的zsh
.
${a[@]:1}
至于与 之间差异的原因${@:2}
,您必须记住,在 中,与or或bash
相反,但与复制其数组的位置一样,数组是稀疏的并且索引从 0 开始。zsh
csh
rc
ksh
bash
${a[@]:4:5}
返回索引大于或等于 4 的前 5 个元素。 第一个元素的$@
索引为 1 ( $1
),而定义为 的数组a=(...)
其元素设置为索引从 0 开始。
嗯,这并不完全正确。在bash
,中,"$@"
像 一样扩展"$1" "$2" "$3" "$4" "$5"
,而当且仅当 $# > 0 时,"${@:0:1}"
就像while (不带引号)一样,只有在未设置或非空时才像。这对我来说听起来像是错误。中的行为有所不同,但再次保持一致。"$0"
"$@"
"${@:1}"
$@
${@:1}
$IFS
ksh