Remove last argument from argument list of shell script (bash)

I have used this bash one-liner before

set -- "${@:1:$(($#-1))}"

It sets the argument list to the current argument list, less the last argument.


How it works:

  • $# is the number of arguments
  • $((...)) is an arithmetic expression, so $(($#-1)) is one less than the number of arguments.
  • ${variable:position:count} is a substring expression: it extracts count characters from variable starting at position. In the special case where variable is @, which means the argument list, it extracts count arguments from the list beginning at position. Here, position is 1 for the first argument and count is one less than the number of arguments worked out previously.
  • set -- arg1...argn sets the argument list to the given arguments

So the end result is that the argument list is replaced with a new list, where the new list is the original list except for the last argument.


You can also get all but the last argument with

"${@:0:$#}"

which, honestly, is a little sketchy, since it seems to be (ab)using the fact that arguments are numbered starting with 1, not 0.

Update: This only works due to a bug (fixed in 4.1.2 at the latest) in handling $@. It works in version 3.2.


Assuming that you already have an array, you can say:

unset "array[${#array[@]}-1]"

For example, if your script contains:

array=( "$@" )
unset "array[${#array[@]}-1]"    # Removes last element -- also see: help unset
for i in "${array[@]}"; do
  echo "$i"
done

invoking it with: bash scriptname foo bar baz produces:

foo
bar