Is there a way of reading the last element of an array with bash?

If I have an array with 5 elements, for example:

[a][b][c][d][e]

Using echo ${myarray[4]} I can see what it holds.

But what if I didn’t know the number of elements in a given array? Is there a way of reading the last element of an unknown length array? i.e. The first element reading from the right to the left for any array?

I would like to know how to do this in bash.

Asked By: 3kstc

||

Modern bash (v4.1 or better)

You can read the last element at index -1:

$ a=(a b c d e f)
$ echo ${a[-1]}
f

Support for accessing numerically-indexed arrays from the end using negative indexes started with bash version 4.1-alpha.

Older bash (v4.0 or earlier)

You must get the array length from ${#a[@]} and then subtract one to get the last element:

$ echo ${a[${#a[@]}-1]}
f

Since bash treats array subscripts as an arithmetic expression, there is no need for additional notation, such as $((...)), to force arithmetic evaluation.

Answered By: John1024

As of bash 4.2, you can just use a negative index ${myarray[-1]} to get the last element. You can do the same thing for the second-last, and so on; in Bash:

If the subscript used to reference an element of an indexed array
evaluates to a number less than zero, it is interpreted as relative to
one greater than the maximum index of the array, so negative indices
count back from the end of the array, and an index of -1 refers to the
last element.

The same also works for assignment. When it says "expression" it really means an expression; you can write in any arithmetic expression there to compute the index, including one that computes using the length of the array ${#myarray[@]} explicitly like ${myarray[${#myarray[@]} - 1]} for earlier versions.

Answered By: Michael Homer

bash array assignment, reference, unsetting with negative index were only added in bash 4.3. With older version of bash, you can use expression in index array[${#array[@]-1}]

Another way, also work with older version of bash (bash 3.0 or better):

$ a=('[a]' '[b]' '[c]' '[d]' '[e]')
$ printf %s\n "${a[@]:(-1)}"
[e]

or:

$ printf %s\n "${a[@]: -1}"
[e]

Using negative offset, you need to separate : with - to avoid being confused with the :- expansion.

Answered By: cuonglm

Also you can do this:

$ a=(a b c d e f)
$ echo ${a[$(expr ${#a[@]} - 1)]}

Result:

$ f

What you’re doing is getting all the count of elements in the array and subtract -1 due you’re getting all the elements, not starting from the array index that is 0.

Answered By: Javier Salas

array

The oldest alternative(s) in bash (Since bash 3.0+) are:

$ a=(aa bb cc dd ee)
$ echo "${a[@]:(-1)}   ${a[@]: -1}   ${a[@]:(~0)}   ${a[@]:~0}"
ee   ee   ee   ee

The space is required to avoid the interpretation of : followed by a minus - as the expansion of "${var:-abc}" (Use Default Values).

The ~ is an arithmetic bitwise negation (equivalent to one’s complement or flip all bits). From man bash:

ARITHMETIC EVALUATION

      ! ~         logical and bitwise negation  

Since bash-4.2+ also:

$ echo "${a[-1]}   ${a[(~0)]}"
ee   ee

Since bash 5.0+ also:

$ echo "${a[~0]}"
ee

For all bash versions (older bash):

$ echo "${a[   ${#a[@]}-1   ]}"    # spaces added **only** for readability
ee

@

For positional arguments (since bash 2.01):

$ set aa bb cc dd ee
$ echo "${@:(-1)} ${@:~0} ${@: -1} ${@:$#}   ${!#}"
ee ee ee   ee

A portable solution for all shells is to use eval:

eval printf '"%sn"' "${$#}"
Answered By: user232326
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.