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 subscriptFix
#!/usr/bin/env bash
arr=(a b c)
echo "${arr[0]}" # a
declare -A map
map[foo]=bar
echo "${map[foo]}" # barExplanation
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.