将最后一个参数传递给shell脚本

$1是第一个参数 $@是它们的全部

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

152035 次浏览
#! /bin/sh


next=$1
while [ -n "${next}" ] ; do
last=$next
shift
next=$1
done


echo $last

如果你使用的是Bash >= 3.0

echo ${BASH_ARGV[0]}
shift `expr $# - 1`
echo "$1"

这将参数移位为参数的数量减1,并返回第一个(也是唯一一个)剩余的参数,这将是最后一个参数。

我只在bash中测试,但它应该也能在sh和ksh中工作。

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

#!/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子句轻松地调整这种行为。

使用结合长度的索引:

echo ${@:${#@}}

注意,这是bash专用的。

使用eval的解决方案:

last=$(eval "echo \$$#")


echo $last

这是一个小hack:

for last; do true; done
echo $last

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

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

这是bash独有的:

echo "${@: -1}"

对于bash 3.0或更高版本,最简单的答案是

_last=${!#}       # *indirect reference* to the $# variable
# or
_last=$BASH_ARGV  # official built-in (but takes more typing :)

就是这样。

$ cat lastarg
#!/bin/bash
# echo the last arg given:
_last=${!#}
echo $_last
_last=$BASH_ARGV
echo $_last
for x; do
echo $x
done

输出是:

$ lastarg 1 2 3 4 "5 6 7"
5 6 7
5 6 7
1
2
3
4
5 6 7

在将最后一个参数与所有前一个参数分开时发现了这个。 虽然有些答案确实得到了最后一个参数,但如果你还需要所有其他参数,它们就没有多大帮助了。

heads=${@:1:$#-1}
tail=${@:$#}

注意,这是bash专用的。

这适用于所有posix兼容的shell:

eval last=\${$#}

来源:http://www.faqs.org/faqs/unix-faq/faq/part2/section-12.html

$ set quick brown fox jumps


$ echo ${*: -1:1} # last argument
jumps


$ echo ${*: -1} # or simply
jumps


$ echo ${*: -2:1} # next to last
fox

空格是必要的,这样它就不会被解释为默认值

注意,这是bash专用的。

在阅读了上面的答案后,我写了一个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

以下是我的解决方案:

  • 相当可移植(所有POSIX sh, bash, ksh, zsh)应该工作
  • 不移位原始参数(移位副本)。
  • 不使用邪恶的 eval
  • 不是遍历整个列表
  • 不使用外部工具

代码:

ntharg() {
shift $1
printf '%s\n' "$1"
}
LAST_ARG=`ntharg $# "$@"`

下面将在不改变当前环境的情况下将LAST设置为最后一个参数:

LAST=$({
shift $(($#-1))
echo $1
})
echo $LAST

如果其他参数不再需要并且可以被转移,则可以简化为:

shift $(($#-1))
echo $1

出于便携性的考虑:

shift $(($#-1));

可替换为:

shift `expr $# - 1`

也将$()替换为反引号,我们得到:

LAST=`{
shift \`expr $# - 1\`
echo $1
}`
echo $LAST

尝试下面的脚本找到最后一个参数

 # cat arguments.sh
#!/bin/bash
if [ $# -eq 0 ]
then
echo "No Arguments supplied"
else
echo $* > .ags
sed -e 's/ /\n/g' .ags | tac | head -n1 > .ga
echo "Last Argument is: `cat .ga`"
fi

输出:

 # ./arguments.sh
No Arguments supplied


# ./arguments.sh testing for the last argument value
Last Argument is: value

谢谢。

tcsh:

set X = `echo $* | awk -F " " '{print $NF}'`
somecommand "$X"

我很确定这将是一个可移植的解决方案,除了作业。

echo $argv[$#argv]

现在我只需要添加一些文字,因为我的回答太短了。我需要添加更多的文字来编辑。

有一种更简洁的方法可以做到这一点。bash脚本的参数可以放入数组中,这使得元素的处理更加简单。下面的脚本将始终打印传递给脚本的最后一个参数。

  argArray=( "$@" )                        # Add all script arguments to argArray
arrayLength=${#argArray[@]}              # Get the length of the array
lastArg=$((arrayLength - 1))             # Arrays are zero based, so last arg is -1
echo ${argArray[$lastArg]}

样例输出

$ ./lastarg.sh 1 2 buckle my shoe
shoe

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

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

注意,这是bash专用的。

编辑:根据@f-hauri的注释删除了不必要的$(( ))

这是复制函数的一部分:

eval echo $(echo '$'"$#")

要在脚本中使用,请这样做:

a=$(eval echo $(echo '$'"$#"))

解释(最嵌套的先):

  1. $(echo '$'"$#")返回$[nr],其中[nr]是参数的个数。例如,字符串$123(未展开)。
  2. echo $123返回第123个参数的值。
  3. eval只是将$123扩展为参数的值,例如last_arg。它被解释为一个字符串并返回。

从2015年年中开始使用Bash。

下面的方法对你有用。

  • @是参数数组。
  • :表示at
  • $#是参数数组的长度。

所以结果是最后一个元素:

${@:$#}

例子:

function afunction{
echo ${@:$#}
}
afunction -d -o local 50
#Outputs 50

注意,这是bash专用的。

使用参数展开(删除匹配的开头):

args="$@"
last=${args##* }

也很容易把所有的都放在最后:

prelast=${args% *}

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

最可移植的解决方案,甚至更老的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

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

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

至于“倒数第二”:

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

对于bash这样的评论建议非常优雅:

echo "${@:$#}"

禁用shellcheck,使用:

echo ${*:$#}

作为奖励,两者都可以在zsh中工作。

要返回最近使用的命令的最后一个参数,请使用特殊形参:

$_

在这个实例中,如果在调用另一个命令之前在脚本中使用它,那么它将工作。

只需使用!$即可。

$ mkdir folder
$ cd !$ # will run: cd folder
$ echo "${*: -1}"

这将打印最后一个参数

GNU bash版本>= 3.0:

num=$#                 # get number of arguments
echo "${!num}"         # print last argument