Getting the last argument passed to a shell script

ShellArguments

Shell Problem Overview


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

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

Shell Solutions


Solution 1 - Shell

This is Bash-only:

echo "${@: -1}"

Solution 2 - Shell

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.

Solution 3 - Shell

$ set quick brown fox jumps

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

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

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

The space is necessary so that it doesn't get interpreted as a default value.

Note that this is bash-only.

Solution 4 - Shell

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

Solution 5 - Shell

The following will work for you.

  • @ is for array of arguments.
  • : means at
  • $# is the length of the array of arguments.

So the result is the last element:

${@:$#} 

Example:

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

Note that this is bash-only.

Solution 6 - Shell

Use indexing combined with length of:

echo ${@:${#@}} 

Note that this is bash-only.

Solution 7 - Shell

Found this when looking to separate the last argument from all the previous one(s). Whilst some of the answers do get the last argument, they're not much help if you need all the other args as well. This works much better:

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

Note that this is bash-only.

Solution 8 - Shell

This works in all POSIX-compatible shells:

eval last=\${$#}

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

Solution 9 - Shell

Here is mine solution:

  • pretty portable (all POSIX sh, bash, ksh, zsh) should work
  • does not shift original arguments (shifts a copy).
  • does not use evil eval
  • does not iterate through the whole list
  • does not use external tools

Code:

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

Solution 10 - Shell

From oldest to newer solutions:

The most portable solution, even older sh (works with spaces and glob characters) (no loop, faster):

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

Since version 2.01 of bash

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

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

For ksh, zsh and bash:

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

And for "next to last":

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

Using printf to workaround any issues with arguments that start with a dash (like -n).

For all shells and for older sh (works with spaces and glob characters) is:

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

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

Or, if you want to set a last var:

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

And for "next to last":

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

Solution 11 - Shell

If you are using Bash >= 3.0

echo ${BASH_ARGV[0]}

Solution 12 - Shell

For bash, this comment suggested the very elegant:

echo "${@:$#}"

To silence shellcheck, use:

echo ${*:$#}

As a bonus, both also work in zsh.

Solution 13 - Shell

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.

Solution 14 - Shell

I found @AgileZebra's answer (plus @starfry's comment) the most useful, but it sets heads to a scalar. An array is probably more useful:

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

Note that this is bash-only.

Edit: Removed unnecessary $(( )) according to @f-hauri's comment.

Solution 15 - Shell

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.

Solution 16 - Shell

A solution using eval:

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

echo $last

Solution 17 - Shell

For tcsh:

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

I'm quite sure this would be a portable solution, except for the assignment.

Solution 18 - Shell

After reading the answers above I wrote a Q&D shell script (should work on sh and bash) to run g++ on PGM.cpp to produce executable image PGM. It assumes that the last argument on the command line is the file name (.cpp is optional) and all other arguments are options.

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

Solution 19 - Shell

The following will set LAST to last argument without changing current environment:

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

If other arguments are no longer needed and can be shifted it can be simplified to:

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

For portability reasons following:

shift $(($#-1));

can be replaced with:

shift `expr $# - 1`

Replacing also $() with backquotes we get:

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

Solution 20 - Shell

echo $argv[$#argv]

Now I just need to add some text because my answer was too short to post. I need to add more text to edit.

Solution 21 - Shell

This is part of my copy function:

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

To use in scripts, do this:

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

Explanation (most nested first):

  1. $(echo '$'"$#") returns $[nr] where [nr] is the number of parameters. E.g. the string $123 (unexpanded).
  2. echo $123 returns the value of 123rd parameter, when evaluated.
  3. eval just expands $123 to the value of the parameter, e.g. last_arg. This is interpreted as a string and returned.

Works with Bash as of mid 2015.

Solution 22 - Shell

#! /bin/sh

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

echo $last

Solution 23 - Shell

Try the below script to find last argument

 # 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

Output:

 # ./arguments.sh
 No Arguments supplied

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

Thanks.

Solution 24 - Shell

There is a much more concise way to do this. Arguments to a bash script can be brought into an array, which makes dealing with the elements much simpler. The script below will always print the last argument passed to a script.

  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]}

Sample output

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

Solution 25 - Shell

Using parameter expansion (delete matched beginning):

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

It's also easy to get all before last:

prelast=${args% *}

Solution 26 - Shell

To return the last argument of the most recently used command use the special parameter:

$_

In this instance it will work if it is used within the script before another command has been invoked.

Solution 27 - Shell

$ echo "${*: -1}"

That will print the last argument

Solution 28 - Shell

With GNU bash version >= 3.0:

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

Solution 29 - Shell

Just use !$.

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomasView Question on Stackoverflow
Solution 1 - ShellDennis WilliamsonView Answer on Stackoverflow
Solution 2 - ShellLaurence GonsalvesView Answer on Stackoverflow
Solution 3 - ShellZomboView Answer on Stackoverflow
Solution 4 - ShellKevin LittleView Answer on Stackoverflow
Solution 5 - ShellTahsin TurkozView Answer on Stackoverflow
Solution 6 - ShellMark ByersView Answer on Stackoverflow
Solution 7 - ShellAgileZebraView Answer on Stackoverflow
Solution 8 - ShellpoiuzView Answer on Stackoverflow
Solution 9 - ShellMichał ŠrajerView Answer on Stackoverflow
Solution 10 - ShellIsaaCView Answer on Stackoverflow
Solution 11 - ShelldusanView Answer on Stackoverflow
Solution 12 - ShellTom HaleView Answer on Stackoverflow
Solution 13 - ShellLaurence GonsalvesView Answer on Stackoverflow
Solution 14 - ShellEndlosSchleifeView Answer on Stackoverflow
Solution 15 - ShellpaxdiabloView Answer on Stackoverflow
Solution 16 - ShellMikael SView Answer on Stackoverflow
Solution 17 - ShellPerfect64View Answer on Stackoverflow
Solution 18 - ShellDavid E.View Answer on Stackoverflow
Solution 19 - ShellPaweł NadolskiView Answer on Stackoverflow
Solution 20 - Shellfrank1rizzoView Answer on Stackoverflow
Solution 21 - ShellesavierView Answer on Stackoverflow
Solution 22 - ShellCraig TraderView Answer on Stackoverflow
Solution 23 - ShellRanjithkumar TView Answer on Stackoverflow
Solution 24 - ShelltekbotView Answer on Stackoverflow
Solution 25 - ShellJurijView Answer on Stackoverflow
Solution 26 - ShellThainView Answer on Stackoverflow
Solution 27 - ShellTruoc PhamView Answer on Stackoverflow
Solution 28 - ShellCyrusView Answer on Stackoverflow
Solution 29 - Shellr1ogaView Answer on Stackoverflow