如何弹出 bash 函数或脚本的最后一个位置参数?

如何弹出 bash 函数或脚本的最后一个位置参数?

我经常需要弹出 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则什么也没有或导致错误)。nullglobfailglob

答案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。

相关内容