Bash has two types of arrays: one-dimensional indexed and associative array. declare -a
creates a one-dimensional array. To mimic a 2-D array, you need an associative array. Therefore, replace:
declare -a outages
with:
declare -A outages
With that one change:
$ bash test.sh
outages[1,12] = -1
outages[2,12] = -1
outages[3,12] = -1
outages[4,12] = -1
outages[5,12] = -1
outages[6,12] = 1000
outages[7,12] = -1
outages[8,12] = -1
outages[9,12] = -1
outages[10,12] = -1
outages[11,12] = -1
outages[12,12] =
(Note that outages[12,12]
is never set because the loop is limited by month<12
.)
What happens when you provide a 2-D subscript to a 1-D array
As in the original code, let's declare a 1-D array and try to use it as a 2-D array and see what happens:
$ declare -a outages
$ outages[1,2]=-1
This looks like it made a successful assignment to a 2-D array. But, that is not what happened. To see what really happened, use declare -p
:
$ declare -p outages
declare -a outages='([2]="-1")'
We can see that element 2
was assigned a value, not element 1,2
. The reason is that subscripts of 1-D arrays are treated as arithmetic expressions. Under the rules of arithmetic evaluation, anything before a comma is discarded.
One can see this by looking directly at an arithmetic expression:
$ echo $((1,2))
2
Everything before the ,
is discarded. That is why setting outages[6,12]=1000
had the effect of setting all your other ,12
elements to 1000.
Documentation
From the section of man bash
entitled "ARITHMETIC EVALUATION":
The operators and their precedence, associativity, and values
are the same as in the C language.
One needs to refer to C language documentation, such as here, to find out what the comma operator actually does.
Simulating 2-D array with bash 3.x
There are some hacks to shoehorn 2-D-like features into bash 3.x's 1-D arrays. See, for example, here or here. In this case, however, your subscripts are numeric and simpler approaches are possible. Let's update the code like this:
$ cat test2.sh
declare -a outages
function init_array () {
for (( month=1; month<=12; month++)) do
outages[$month+100*12]=-1
done
outages[6+100*12]=1000 # this is setting all elements to 1000, instead of just 1.
}
function print_array () {
for ((i=1;i<=12;i++)) do
echo "outages[$i,12] = ${outages[$i+100*12]}"
done
}
init_array
print_array
The code runs as you want:
$ bash test2.sh
outages[1,12] = -1
outages[2,12] = -1
outages[3,12] = -1
outages[4,12] = -1
outages[5,12] = -1
outages[6,12] = 1000
outages[7,12] = -1
outages[8,12] = -1
outages[9,12] = -1
outages[10,12] = -1
outages[11,12] = -1
outages[12,12] = -1
We can see what the array outages
looks like to bash with declare -p
:
$ declare -p outages
declare -a outages='([1201]="-1" [1202]="-1" [1203]="-1" [1204]="-1" [1205]="-1" [1206]="1000" [1207]="-1" [1208]="-1" [1209]="-1" [1210]="-1" [1211]="-1" [1212]="-1")'