如何获取 /bin/sh 函数的最后一个参数

如何获取 /bin/sh 函数的最后一个参数

有什么更好的实施方法print_last_arg

#!/bin/sh

print_last_arg () {
    eval "echo \${$#}"  # this hurts
}

print_last_arg foo bar baz
# baz

(如果是这样的话,我#!/usr/bin/zsh就会#!/bin/sh知道该怎么做。我的问题是找到一种合理的方法来实现这一点#!/bin/sh。)

编辑:上面只是一个愚蠢的例子。我的目标不是打印最后一个参数,而是有一种方法来引用 shell 函数中的最后一个参数。


编辑2:对于这样一个措辞不明确的问题,我深表歉意。 我希望这次能做对。

如果这是/bin/zsh代替的话/bin/sh,我可以写这样的东西

#!/bin/zsh

print_last_arg () {
    local last_arg=$argv[$#]
    echo $last_arg
}

表达方式$argv[$#]是我在第一次编辑中描述的示例一种在 shell 函数中引用最后一个参数的方法

因此,我真的应该这样写我原来的例子:

print_last_arg () {
    local last_arg=$(eval "echo \${$#}")   # but this hurts even more
    echo $last_arg
}

...为了明确我所追求的是放在作业右侧的不那么可怕的东西。

但请注意,在所有示例中,都会访问最后一个参数非破坏性地。 IOW,访问最后一个参数不会影响整个位置参数。

答案1

给出开篇文章的示例(不带空格的位置参数):

print_last_arg foo bar baz

对于默认的IFS=' \t\n',怎么样:

args="$*" && printf '%s\n' "${args##* }"

为了更安全地扩展"$*",请设置 IFS (根据@StéphaneChazelas):

( IFS=' ' args="$*" && printf '%s\n' "${args##* }" )

但是如果你的位置参数可以包含空格,上面的方法将会失败。在这种情况下,请改用:

for a in "$@"; do : ; done && printf '%s\n' "$a"

请注意,这些技术避免使用eval并且没有副作用。

测试于shellcheck.net

答案2

虽然这个问题已经有两年多了,但我想我会分享一个更紧凑的选择。

print_last_arg () {
    echo "${@:${#@}:${#@}}"
}

让我们运行一下

print_last_arg foo bar baz
baz

重击shell参数扩展

编辑

甚至更简洁: echo "${@: -1}"

(注意空间)

来源

在 macOS 10.12.6 上进行了测试,但还应该返回大多数可用 *nix 风格的最后一个参数...

伤害少得多¯\_(ツ)_/¯

答案3

这是一个简单的方法:

print_last_arg () {
  if [ "$#" -gt 0 ]
  then
    s=$(( $# - 1 ))
  else
    s=0
  fi
  shift "$s"
  echo "$1"
}

(根据 @cuonglm 的观点进行更新,即原始版本在不传递任何参数时失败;这现在回显空行 -else如果需要,请更改子句中的行为)

答案4

这应该适用于任何符合 POSIX 标准的 shell,也适用于 POSIX 之前的遗留 Solaris Bourne shell:

do=;for do do :;done;printf "%s\n" "$do"

这是一个基于相同方法的函数:

print_last_arg()
  if [ "$*" ]; then
    for do do :;done
    printf "%s\n" "$do"
  else
    echo
  fi

PS:别告诉我我忘记了函数体周围的大括号;-)

相关内容