Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash arrays and negative subscripts, yes or no?

The GNU bash manual tells me

An indexed array is created automatically if any variable is assigned to using the syntax

name[subscript]=value

The subscript is treated as an arithmetic expression that must evaluate to a number. If subscript evaluates to a number less than zero, it is used as an offset from one greater than the array’s maximum index (so a subcript of -1 refers to the last element of the array).

So I figure I will give it a try and get the following result:

$ muh=(1 4 'a' 'bleh' 2)
$ echo $muh
1
$ echo ${muh[*]}
1 4 a bleh 2    # so far so good so now I'll try a negative ...
$ echo ${muh[-1]}
-bash: muh: bad array subscript  # didn't go as planned!

Did I do something wrong, or is the website wrong, or is gnu bash that different from the bash I am running under CentOS? Thanks!

like image 421
bob.sacamento Avatar asked Apr 19 '13 16:04

bob.sacamento


4 Answers

If you just want the last element

$ echo ${muh[*]: -1}
2

If you want next to last element

$ echo ${muh[*]: -2:1}
bleh
like image 182
2 revs Avatar answered Sep 20 '22 19:09

2 revs


According to Greg Wooledge's wiki, (which links to the bash changelog) the negative index syntax was added to bash in version 4.2 alpha.

like image 36
kojiro Avatar answered Sep 21 '22 19:09

kojiro


If you do man bash the section on arrays does not list this behavior. It might be something new (gnu?) in bash.

Fails for me in CentOS 6.3 (bash 4.1.2)

like image 3
stark Avatar answered Sep 24 '22 19:09

stark


Bash beore 4.2 (like the default one on Macs these days) doesn't support negative subscripts. Apart from the "substring expansion" used in the accepted answer, a possibly cleaner workaround is to count the desired index from the array start within the brackets:

$ array=(one two three)
$ echo "${array[${#array[@]}-1]}"
three

With this approach, you can pack other parameter expansion operations into the term, e.g. "remove matching prefix pattern" th:

$ echo "${array[${#array[@]}-1]#th}"
ree
like image 3
tlwhitec Avatar answered Sep 20 '22 19:09

tlwhitec