Reputation: 9752
I can access all element of an array like so:
echo ${myarray[@]}
and the number of elements:
echo ${#myarray[@]}
and I can get the nth element by doing:
echo ${myarray[@]:(-1)}
however I try the following to get the n-1th array element:
echo ${myarray[@]:(-2)}
but I end up with the last two elements. How do I only obtain the last but one element?
Upvotes: 1
Views: 2678
Reputation: 77079
My version of bash appears to support negative indices directly:
$ echo $BASH_VERSION
4.3.33(1)-release
$ x=( {0..100} )
$ echo "${x[-45]}"
56
The feature was added to bash-4.3-alpha. See the change log, section 3x under 4.3-alpha.
I commented in Gordon Davisson's answer that if the subtractor is larger than the array you'll get an error. That appears to be true of negative indices in Bash 4.3 as well:
$ myarray=( {0..100} )
$ echo "${myarray[-104]}"
-bash: myarray: bad array subscript
This is incongruous with normal bash sparse arrays, for which any positive index is valid. It may not be set, but there's no error:
$ echo "${myarray[500]}"
(no output)
On the other hand, negative slicing does not suffer from this:
$ echo "${myarray[@]: -500:1}"
(no output; no error)
Upvotes: 1
Reputation: 125748
You can also do math in the index part of a standard array reference:
$ myarray=( {0..100} )
$ echo "${myarray[ ${#myarray[@]} - 2 ]}"
99
or, a little more clearly:
$ myarray=( {0..100} )
$ myarray_len="${#myarray[@]}"
$ echo "${myarray[ myarray_len - 2 ]}"
99
BTW, please make a habit of double-quoting all variable references (e.g. echo "${myarray[@]}"
instead of echo ${myarray[@]}
). There are some situations where it's safe to omit the quotes, but also lots where it isn't, and figuring out when it's safe to leave them off is more work than it's worth. Just quote 'em all, unless there's a specific reason not to.
Upvotes: 1
Reputation: 74595
You can add another colon, and specify the length of your slice:
echo "${myarray[@]: -2: 1}"
For example (although I'm ashamed to show my vintage version of bash on this machine...):
$ echo "$BASH_VERSION"
3.1.20(4)-release
$ a=( 1 2 3 )
$ echo ${a[@]: -2: 1}
2
Upvotes: 9