1

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?

3 Answers 3

9

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
Sign up to request clarification or add additional context in comments.

3 Comments

you're on fire today Tom
Impressive. Even Yosemite has 3.2.57, and Apple is notorious for its archaic shells.
@kojiro I'm using git bash on windows (I know, I know...)
1

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.

2 Comments

FWIW, since the index field is always arithmetic context, you can also describe how to calculate the index in the assignment. E.g. index="${#myarray[@]} - 2"; echo "${myarray[index]}". Opinions may differ as to whether this is more or less readable or intuitive.
Oh, I might also add that the one downside to this approach is that it doesn't inherently protect against an overflow. If the amount subtracted from the index is larger than the size of the array (and your bash doesn't support negative indices) then you will get an error. More arithmetic could prevent this, but it starts to get cumbersome.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.