brucezepplin
brucezepplin

Reputation: 9752

access last but element of bash array

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

Answers (3)

kojiro
kojiro

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.

Edit: observations about negative indices

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)

Summary

  • The slice method is supported in old bash and immune to overflow errors, but cumbersome to read and write.
  • The negative index method is straightforward to read and write, but only supported in very recent bash versions and can error if the index is too negative.
  • The calculated index method is still fairly simple to read and will work in old bash versions, but can either error or give an unexpected answer if the negative value is too large.

Upvotes: 1

Gordon Davisson
Gordon Davisson

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

Tom Fenech
Tom Fenech

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

Related Questions