我经常需要弹出 bash 函数或脚本的最后一个位置参数。
我所说的“pop”的意思是:“将其从位置参数列表中删除,并(可选)将其分配给变量。”
考虑到我需要此操作的频率,我有点惊讶的是,我发现的最好的结果是下面的示例所示:
foo () {
local argv=( "$@" )
local last=${argv[$(( ${#argv[@]} - 1 ))]}
argv=( ${argv[@]:0:$(( ${#argv[@]} - 1 ))} )
echo "last: $last"
echo "rest: ${argv[@]}"
}
换句话说,一部由数千名演员组成的史诗级制作......
有没有更简单、更容易阅读的东西?
答案1
您可以使用(bash 4.2或更高版本)访问最后一个元素,并使用内置函数(bash 4.3或更高版本)${argv[-1]}
将其从数组中删除:unset
last=${argv[-1]}
unset 'argv[-1]'
周围的引号argv[-1]
是必需的,就像[...]
全局运算符一样,因此argv[-1]
未加引号的可以扩展到argv-
和/或如果这些文件存在于当前目录中(或者如果它们没有启用/argv1
则什么也没有或导致错误)。nullglob
failglob
答案2
这个怎么样:
foo () {
local last="${!#}"
local argv=("${@:1:$#-1}")
echo "last: $last"
echo "rest: ${argv[@]}"
}
答案3
您可以稍微简化一下以使其更容易阅读,但基本方法保持不变(如果您有不支持的 Bash 版本,这可能很有用卡西莫多的奉献):
foo () {
local argv=( "$@" )
local last="${argv[$# - 1]}"
argv=( "${argv[@]:0:$# - 1}" )
echo "last: $last"
echo "rest: ${argv[@]}"
}
我承认这样使用有点厚颜无耻$#
,但它具有与${#argv[@]}
在这个具体的例子中并且代码更加简洁。
答案4
对于更简单的等价于bxm 的回答, 使用set
:
pop() {
last="${!#}" # see man bash, search for "indirect expansion"
set -- "${@:1:$#-1}"
printf 'not last: %s\n' "$@"
printf 'last: %s\n' "${last}"
}
pop 1 2 3 4
# prints:
# not last: 1
# not last: 2
# not last: 3
# last: 4
这里,${!#}
是一个间接参数扩展(在 中搜索“间接扩展”)man bash
,并将set -- ARGS...
参数($1
等)的新值设置为给定的 args。
值得注意的是,${!#}
数组切片是 bashisms,但set --
可以移植到任何 POSIX shell。