$1是第一个参数。 $@是全部。

如何找到传递给shell的最后一个参数 脚本?


当前回答

只需使用!$。

$ mkdir folder
$ cd !$ # will run: cd folder

其他回答

这是一个小hack:

for last; do true; done
echo $last

这也是非常可移植的(同样,应该与bash、ksh和sh一起工作),并且它不改变参数,这可能很好。

它利用了这样一个事实:如果你不告诉它循环什么,for会隐式地遍历参数,而且for循环变量没有作用域:它们保持它们设置的最后一个值。

从最古老的解决方案到最新的解决方案:

最可移植的解决方案,甚至更老的sh(适用于空格和glob字符)(没有循环,更快):

eval printf "'%s\n'" "\"\${$#}\""

从bash 2.01版开始

$ set -- The quick brown fox jumps over the lazy dog

$ printf '%s\n'     "${!#}     ${@:(-1)} ${@: -1} ${@:~0} ${!#}"
dog     dog dog dog dog

对于ksh, zsh和bash:

$ printf '%s\n' "${@: -1}    ${@:~0}"     # the space beetwen `:`
                                          # and `-1` is a must.
dog   dog

至于“倒数第二”:

$ printf '%s\n' "${@:~1:1}"
lazy

使用printf解决以破折号(如-n)开头的参数的任何问题。

对于所有shell和旧的sh(使用空格和glob字符)是:

$ set -- The quick brown fox jumps over the lazy dog "the * last argument"

$ eval printf "'%s\n'" "\"\${$#}\""
The last * argument

或者,如果你想设置最后一个变量:

$ eval last=\${$#}; printf '%s\n' "$last"
The last * argument

至于“倒数第二”:

$ eval printf "'%s\n'" "\"\${$(($#-1))}\""
dog

在阅读了上面的答案后,我写了一个Q&D shell脚本(应该在sh和bash上工作)在PGM.cpp上运行g++以生成可执行的图像PGM。它假设命令行上的最后一个参数是文件名(.cpp是可选的),所有其他参数都是选项。

#!/bin/sh
if [ $# -lt 1 ]
then
    echo "Usage: `basename $0` [opt] pgm runs g++ to compile pgm[.cpp] into pgm"
    exit 2
fi
OPT=
PGM=
# PGM is the last argument, all others are considered options
for F; do OPT="$OPT $PGM"; PGM=$F; done
DIR=`dirname $PGM`
PGM=`basename $PGM .cpp`
# put -o first so it can be overridden by -o specified in OPT
set -x
g++ -o $DIR/$PGM $OPT $DIR/$PGM.cpp

如果你想以一种非破坏性的方式来做,一种方法是将所有的参数传递给一个函数,并返回最后一个:

#!/bin/bash

last() {
        if [[ $# -ne 0 ]] ; then
            shift $(expr $# - 1)
            echo "$1"
        #else
            #do something when no arguments
        fi
}

lastvar=$(last "$@")
echo $lastvar
echo "$@"

pax> ./qq.sh 1 2 3 a b
b
1 2 3 a b

如果你实际上不关心保留其他参数,你不需要在函数中使用它,但我很难想出一种情况,你永远不会想要保留其他参数,除非它们已经被处理了,在这种情况下,我会使用process/shift/process/shift/…顺序处理它们的方法。

我假设你想保留它们因为你没有遵循顺序法。此方法还处理没有参数的情况,返回""。您可以通过插入注释掉的else子句轻松地调整这种行为。

我发现@AgileZebra的答案(加上@starfry的评论)最有用,但它将头设置为一个标量。数组可能更有用:

heads=( "${@: 1: $# - 1}" )
tail=${@:${#@}}

注意,这是bash专用的。

编辑:根据@f-hauri的评论删除了不必要的$(())。