views:

873

answers:

12

$1 is the first argument.
$@ is all of them.

How can I find the last argument passed to a shell script?

+1  A: 
#! /bin/sh

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

echo $last
Craig Trader
This will fail if an argument is the empty string, but will work in 99.9% of the cases.
Thomas
A: 

At least in bash, $# returns the number of arguements passed to the shell script, so you can use this to find out how many and then do $15 (or whatever) to get the last one.

However, if you want access to all arguements one at a time, I like this construct:

for var in "$@"
do
    echo "$var"
done
bdk
The trick is how to do the $15 (or whatever) programatically. Looping over $@ looks like a good idea. Just remember the last value and you're done.
Thomas
+1  A: 

If you are using Bash >= 3.0

echo ${BASH_ARGV[0]}
dusan
+1  A: 
shift `expr $# - 1`
echo "$1"

This shifts the arguments by the number of arguments minus 1, and returns the first (and only) remaining argument, which will be the last one.

I only tested in bash, but it should work in sh and ksh as well.

Laurence Gonsalves
+2  A: 

If you want to do it in a non-destructive way, one way is to pass all the arguments to a function and return the last one:

#!/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

If you don't actually care about keeping the other arguments, you don't need it in a function but I have a hard time thinking of a situation where you would never want to keep the other arguments unless they've already been processed, in which case I'd use the process/shift/process/shift/... method of sequentially processing them.

I'm assuming here that you want to keep them because you haven't followed the sequential method. This method also handles the case where there's no arguments, returning "". You could easily adjust that behavior by inserting the commented-out else clause.

paxdiablo
+2  A: 

Use indexing combined with length of:

echo ${@:${#@}}
Mark Byers
Only works in Bash, but a good answer
Craig Trader
+2  A: 

A solution using eval:

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

echo $last
Mikael S
+8  A: 

This is a bit of a hack:

for last; do true; done
echo $last

This one is also pretty portable (again, should work with bash, ksh and sh) and it doesn't shift the arguments, which could be nice.

It uses the fact that for implicitly loops over the arguments if you don't tell it what to loop over, and the fact that for loop variables aren't scoped: they keep the last value they were set to.

Laurence Gonsalves
A: 

just google it http://www.google.com/search?rlz=1C1GGLS%5FenIL307IL307&sourceid=chrome&ie=UTF-8&q=unix+shell+print+last+argument

I liked this one:

echo $@ | awk '{ print $NF }'

Here is how it works:

#cat > t
echo $@ | awk '{ print $NF }'
#bash t a b c
c
#
Moisei
You'll need to use quotes: `"$@"`
glenn jackman
+3  A: 

This is Bash-only:

echo "${@: -1}"
Dennis Williamson
A: 

$_ works perfectly for ksh shell.

Sachin Chourasiya
+1  A: 

The simplest answer for bash 3.0 or greater is

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

That's it.

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

Output is:

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