gslewis.id.au:~
The Bedlington Ape

Another bash array primer

I imagine most people who have tried more than once to use arrays in bash have written up some syntax notes to refer back to when they inevitably forget how to use them. These are mine.

Tip
Find the Arrays section in the bash man page by searching for ^\s{3}Arrays. That is, the start of the line, followed by 3 spaces, followed by "Arrays". This assumes less or similar is your man pager,

Creating arrays

declare -a MY_ARRAY

Declare an empty global indexed array (zero-based).

declare -A MY_ARRAY

Declare an empty global associative array.

You do not need to declare indexed arrays before use. You do need to declare associative arrays before use. You can still assign to an undeclared "associative" array without error but it is actually an indexed array and all your string keys will be intepreted as index zero.

You can use local instead of declare to create local arrays within functions using the same -a and -A options. However, if you use declare inside a function, it will create a locally-scoped array anyway, unless you use the -g option (declare in global scope).

If you do not declare an indexed array inside a function and just create it by assigning a value, it will be a global array, same as if you assign to a non-array variable inside a function without using local.

Syntax & examples
# Set value at index
MY_ARRAY[0]="first"

# Get value at index 0
echo ${MY_ARRAY[0]}
> first

# Get the length of the value at index 0 (number of characters)
echo ${#MY_ARRAY[0]}
> 5

# Set mapped value using "key" string
declare -A MY_ARRAY
MY_ARRAY[key]="value"

# Get value at key
echo ${MY_ARRAY[key]}
> value

# Create indexed array with initial values, indices assigned from 0
MY_ARRAY=(aaa bbb ccc)

# Create indexed array with initial values, specify indices
MY_ARRAY=([0]=aaa [2]=ccc [3]=ddd)

# Create associative array with initial values using [key]=value format
declare -A MY_ARRAY
MY_ARRAY=([key1]=value1 [key2]=value2 [key3]=value3)

# Create associative array with initial values using alternating keys and
# values
declare -A MY_ARRAY
MY_ARRAY=(key1 value1 key2 value2 key3 value3)

# Create _and_ do initial assignment to associative array
declare -A MY_ARRAY=(key1 value1 key2 value2 key3 value3)

For associative arrays, you do not need to quote the key string between the square brackets, which act as double quotes.

Array size, index and value lists

Use a subscript of @ or * to list all elements of the array. The choice of which to use only matters if used within double quotes.

Syntax & examples
MY_ARRAY=(aaa bbb ccc)

# Get the array size
echo ${#MY_ARRAY[@]}
> 3

# Get the array values as a list
echo ${MY_ARRAY[@]}
> aaa bbb ccc

# Get the array subscripts (indices or keys) as a list
echo ${!MY_ARRAY[@]}
> 0 1 2
  • For an indexed array, the subscript list (indices) will be sorted.

  • For an associative array, the subscript list (keys) is not guaranteed to be sorted or in order of assignment.

  • The order of the value list and the subscript list will be the same. That is, the first value in the value list corresponds to the first subscript in the subscript list, and so on.

Negative indices

For indexed arrays, negative indices count back from the end of the array so -1 references the last element, -2 the second last element, and so on.

# Get the last element
MY_ARRAY=(aaa bbb ccc)
echo ${MY_ARRAY[-1]}
> ccc

You can replace existing values using negative indices.

# Replace the last element
MY_ARRAY=(aaa bbb ccc)
MY_ARRAY[-1]='ddd'
echo ${MY_ARRAY[@]}
> aaa bbb ddd

Deleting

To delete an array or its elements, use unset.

  • Delete an entire array: unset MY_ARRAY

  • Delete an element of an array: unset MY_ARRAY[0]

  • For an indexed array, unsetting an index will leave a gap in the index sequence.

Example
MY_ARRAY=(aaa bbb ccc)

# Array length
echo ${#MY_ARRAY[@]}
> 3

# Delete 2nd element
unset MY_ARRAY[1]

# List values
echo ${MY_ARRAY[@]}
> aaa ccc

# List indices
echo ${!MY_ARRAY[@]}
> 0 2

# Array length after delete
echo ${#MY_ARRAY[@]}
> 2

Read input into an array

read -a

Read a line of text into an array, each word is an array element.

mapfile or readarray

Read all lines from a file into an array, each line is an array element.

When reading lines with read -a, words are separated according to the IFS value, which defaults to whitespace.

while read -a MY_ARRAY; do
    echo ${MY_ARRAY[@]}
done < my_data.txt

When reading a file with mapfile or readarray (same thing), there are various options to limit number of lines read, skip lines from start, use an alternate delimiter, etc. See help mapfile for info.

mapfile MY_LINES < my_data.txt

You cannot create an associative array using read, mapfile or readarray, only an indexed array.