function tail() {
shift 1
echo $@
}
% tail one two three
two three
我怎样才能写出这个简单函数的反函数?
我想实现
% init one two three
one two
并获取变量中除最后一个参数之外的所有参数$@
,因此该函数可以写成
function init() {
# ???
echo $@
}
我已经尝试过unset '@[-1]'
,,unset '[@:-1]'
来自https://unix.stackexchange.com/a/611717/696135,但这些不起作用
我已经尝试过set -- "${@:1:$(($#-1))}"
,,来自https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bashunset "@[${#@[@]}-1]"
,但这些不起作用set -- "${@:1:$#-1}"
不起作用的脚本示例:
function init() {
set -- ${@:1:$#-1}
echo $@
}
init one two three
shift -p
将删除最后一个数组元素,如下所示man zshbuiltins
:您想要的
init
功能可以是:正如@Gairfowl 在评论中所说,
zsh
你应该这样做:删除最后一个参数(用空列表替换它)。
甚至
甚至:
有时可能比
shift
(本身是 的缩写shift 1
,本身是 的缩写,后者是 zsh 特有的) 更可取,因为如果没有元素shift 1 argv
它不会抱怨。$argv
请注意您的:
应该写成:
或者与 Korn 兼容:
如果要点是打印剩余参数,则用空格分隔并用换行符结尾。
如果没有引号,空参数将被跳过;如果没有
-
,则第一个以 开头的参数将无法正常工作;-
如果没有-E
/-r
,则包含反斜杠的参数将无法正常工作。为了您的
init
:尽管你也可以这样做:
Zsh 最近还添加了
${array:offset:length}
数组切片的替代形式以兼容 ksh93,因此与 ksh93 兼容的变体可以是:#
请注意,在 zsh 中(除非在 sh 或 ksh 模拟中),如果没有 which,则括号$#-1
将被视为参数${#-}1
的长度$-
(使用 csh 样式的$#param
运算符),后跟 1.${@:1:$# - 1}
也可以。zsh
也支持${var:offset:-length}
à la bash,因此您也可以使用print -r -- "${@:1:-1}"
。请注意,如果参数列表为空,则会报告错误,与 ksh93 或 bash 中相同。
${@:1:#-1}
在 的当前版本中也可以使用zsh
,就像echo $(( # ))
输出与 相同echo $(( $# ))
,但我会避免这样做,因为它没有记录,并且#
在算术表达式的几个运算符中使用。特别是$(( #var ))
,扩展为 中第一个字符的字符值$var
(类似于$(( '$var' ))
ksh 中的 ),因此有人可能会认为$(( #- ))
应该扩展为 中第一个字符的字符值$-
。unset 'array[i]'
在 zsh 中确实可以与 ksh 兼容,但在 ksh 中,数组不是真正的数组,而更像是关联数组,其键限制为正整数,而在 zsh 中,它们与所有其他非 Korn 类 shell 一样是普通数组,因此要模拟 ksh 行为unset 'array[i]'
不会取消设置元素(这对于普通数组没有意义),而是将其设置为空字符串,即使这是数组中的最后一个元素。在
zsh
:$a[4]
仍然是4
,未设置的元素已被替换为空字符串。与具有特殊数组设计的 ksh93 或 bash 相比:
那(以及数组索引从 0 而不是 1 开始的事实)是为什么在 ksh 及其克隆(例如 bash)中,位置参数不能映射到数组(像大多数其他 shell 一样,例如 csh、fish、rc、zsh)的原因之一,并且我怀疑
unset 'argv[i]'
在 zsh 中除了最后一个元素之外都不能这样做(尽管它仍然不会取消设置它,而是用空字符串替换)可能与 ksh 兼容性有关。(如果
,last
省略,则与 相同array[first,first]
)本身就是一个数组切片赋值,类似于您可以使用perl
其函数splice
实现的功能,例如,它不仅限于取消设置最后一个元素(如perl
)pop
,您还可以执行以下操作:array[1,0]=(new elements)
在前面插入元素(perl
例如unshift
)array[3,5]=()
删除中间的元素。array+=(more)
或者array[3]+=(more)
在末尾或者给定索引之后插入元素。与 perl 版本相比,缺少的是在删除元素时检索这些元素的能力。
例如,
perl
要@last2 = splice @array, -2
弹出最后两个元素,@last2
必须写成:(如果没有需要保留的空元素,last2=( "${(A@)array[-2,-1]}" ); array[-2,-1]=()
则可以缩短为)。last2=( $array[-2,-1] ); array[-2,-1]=()
但我离题了……
¹ Beware
"$@[-2,-1]"
会扩展为一个空元素列表,而不是一个空列表。对于print -r --
在两种情况下打印空行而言,这没有区别,但在一般情况下,这可能是不可取的,可以使用 来解决"${(A)@[-2,-1]}"
。如果没有需要保留的空元素,$@[-2,-1]
(不带引号)就足够了。