Bash error: "bad array subscript"

Fix "bad array subscript" in Bash. Usually an associative array used with an integer index, or an indexed array with a string key.

Error String

bash: bad array subscript

Tldr

"bad array subscript" means you used an index type the array does not support. Indexed arrays (arr=(...)) take integer keys. Associative arrays (declare -A) take string keys. Mixing the two causes this error.

Cause

Bash has two array types: indexed (default, created with `arr=(a b c)`) and associative (created with `declare -A map`). Indexed arrays only accept integer indices like `${arr[0]}`. Associative arrays only accept string keys like `${map[key]}`. Passing a string key to an indexed array or an integer to an associative array triggers "bad array subscript".

Repro

#!/usr/bin/env bash
arr=(a b c)
echo "${arr[key]}"      # bad array subscript

declare -A map
map[foo]=bar
echo "${map[0]}"        # bad array subscript

Fix

#!/usr/bin/env bash
arr=(a b c)
echo "${arr[0]}"        # a

declare -A map
map[foo]=bar
echo "${map[foo]}"      # bar

Explanation

Check how the array was declared. If you see `declare -A`, use string keys. If it was declared with parentheses or no declare statement, use integer indices. Also watch for variables that accidentally hold the wrong type of value.

Faq

Q

Can I use a variable as an index?

A

Yes — `${arr[$i]}` works when `$i` is an integer. For associative arrays, `${map[$key]}` works when `$key` is a string.

Q

Why does ${arr[@]:0:1} work but ${arr[key]} fail?

A

The `:0:1` slice syntax operates on indexed arrays and expects numeric offsets. A bare `[key]` is treated as an array element lookup, and indexed arrays reject string keys.

Q

Why does my string key assign to index 0?

A

Without `declare -A` the array is indexed, and the key is evaluated as arithmetic — an unset name becomes 0.

Q

Are associative arrays available everywhere?

A

They need Bash 4.0+. macOS ships Bash 3.2, so scripts targeting it must avoid them.

Deep Dive

Heading

Indexed arrays need integer subscripts

Body

An indexed array subscript is evaluated as an arithmetic expression, so a non-numeric or empty value fails. Using a string key against an indexed array is the common mistake — associative arrays must be declared first with `declare -A map`, otherwise `map[name]=1` evaluates `name` as arithmetic and usually assigns index 0. A negative index counts from the end in Bash 4.3+, but only with a space: `${arr[-1]}` works, `${arr[ -1]}` is safest in older versions.

Heading

Bounds, sparseness and safe iteration

Body

Bash arrays are sparse: deleting an element with `unset arr[2]` leaves a hole, so `${#arr[@]}` is the element count, not the highest index. Iterate over values with `for v in "${arr[@]}"` or over real indices with `for i in "${!arr[@]}"`; never assume `0..count-1`. Always quote `"${arr[@]}"` so elements containing spaces stay separate, and remember that `${arr}` without a subscript refers to element 0 rather than the whole array.

Checklist

Declare associative arrays with `declare -A` before using string keys.

Iterate indices with `"${!arr[@]}"` rather than a counted loop.

Quote `"${arr[@]}"` in every expansion.

Check the subscript is a valid integer before indexing.