I have read/been told that in Bash (4+ in my case) that all parameter expansion functions that are available on strings are available on arrays. Today I was trying to setup a function similar to an array pop. I used something similar to the following syntax:

declare -a arr=( 0 1 2 3 4 5 )
arr=( ${arr[@]:0:(-1)} )

Unexpectedly Bash complained with:

-bash: (-1): substring expression < 0

When I do this with a string the syntax works as expected. For example:

var="see spot run"
echo "$var"
  see spot ru

I know that for the array I could do this instead (and I tested that it works):

declare -a arr=( 0 1 2 3 4 5 )
arr=( ${arr[@]:0:((${#arr[@]}-1))} )
echo ${arr[@]}
    0 1 2 3 4

The questions is if all string parameter expansions work on arrays why doesn't the (-1) syntax work as I expect? Am I just over looking something simple here or is there something deeper at play I am missing?


1 Answer 1


The answer to this question seems to be that NOT ALL string parameter expansions work on arrays. After reviewing the comments and reading the Bash Reference Manual (link provided by don_crissti, thanks) there is a caveat for negative indexing on substring expansion. As noted in the Bash manual (Shell Parameter Expansion):


This is referred to as Substring Expansion. It expands to up to length characters of the value of parameter starting at the character specified by offset. If parameter is @, an indexed array subscripted by @ or *, or an associative array name, the results differ as described below.


If parameter is an indexed array name subscripted by @ or *, the result is the length members of the array beginning with ${parameter[offset]}. A negative offset is taken relative to one greater than the maximum index of the specified array. It is an expansion error if length evaluates to a number less than zero.

As pointed out by don_crissti, the length evaluation that is done here is not in reference to the length of the string/substring but rather evaluation performed during the assignment of the length attribute. As in don_crissti's example:

printf %s\\n "${arr[@]:3:(a+1)}"

If the arithmetic evaluation portion of the length assignment (a+1) were to result in a negative value or, as in my case, the value itself were statically passed as a negative number it is an expansion error. That being said both of the following would result in an expansion error:

declare -a arr=( 0 1 2 3 4 5 )
# length evaluates to (-1)
printf %s\\n "${arr[@]:3:(a-3)}"
  -bash: (a-3): substring expression < 0

# or length is assigned as (-1)
arr=( ${arr[@]:0:(-1)} )
  -bash: (-1): substring expression < 0

Per the Bash manual, this is the expected behavior in both cases.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .