Bash Arrays: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
No edit summary
 
(106 intermediate revisions by the same user not shown)
Line 1: Line 1:
=External=
=External=


* https://www.gnu.org/software/bash/manual/html_node/Arrays.html
* https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays
* https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays


Line 16: Line 17:
==Indexed Arrays Overview==
==Indexed Arrays Overview==


bash indexed arrays are 0-based and unidimensional. No explicit declaration is necessary if at least one element is [[Bash_Arrays#Assign_Individual_Elements|initialized]] as described below:
bash indexed arrays are 0-based and unidimensional. No explicit declaration is necessary if at least one element is [[Bash_Arrays#Assign_Individual_Elements|initialized]] as described below.
 
Indexed arrays behave as '''local''' variables: an array declared in a function will be accessible to the declaring function and all functions invoked from the declaring function after declaration, but not to callers of the declaring function. In other words, indexed arrays are accessible only in the declaring scope and sub-scopes.


==Indexed Arrays Declaration==
==Indexed Arrays Declaration==
Line 22: Line 25:
Arrays do not need explicit declarations, they will be automatically declared upon the first assignment of any of their elements:
Arrays do not need explicit declarations, they will be automatically declared upon the first assignment of any of their elements:


my_array_var[0]="something"
<syntaxhighlight lang='bash'>
 
my_array_var[0]="something"
</syntaxhighlight>
They can be explicitly declared, though:
They can be explicitly declared, though:
<syntaxhighlight lang='bash'>
declare -a my_array_var
</syntaxhighlight>
Previously declared arrays can be listed with:
<syntaxhighlight lang='bash'>
declare -a
</syntaxhighlight>
Whether a specific array was declared can be checked as follows:
<syntaxhighlight lang='bash'>
if declare -a | grep -q my_array_var; then
  # 'my_array_var' was declared
  ...
else
  # 'my_array_var' was not declared
  ...
fi
</syntaxhighlight>


declare -a my_array_var
Negation also works:
<syntaxhighlight lang='bash'>
if ! declare -a | grep -q my_array_var; then
  # 'my_array_var' was not declared
  ...
else
  # 'my_array_var' was declared 
  ...
fi
</syntaxhighlight>


Previously declared arrays can be listed with:
<span id='Automatic_Declaration'></span>An indexed array is automatically declared if it is [[#Entire_Indexed_Array|assigned using this syntax]]:
 
<syntaxhighlight lang='bash'>
declare -a
my_array_var=("a" "b" "c")
</syntaxhighlight>


An array variable can be "undeclared" with the "unset" builtin.
An array variable can be "undeclared" with the "unset" [[Bash_Concepts#Builtin|builtin]].


  unset my_array_var
  unset my_array_var
Line 41: Line 72:


A subscript of "*" or "@" also removes the entire array.
A subscript of "*" or "@" also removes the entire array.
==Indexed Array Declaration Test==
This sequence tests whether a variable was declared as an indexed array. The test does not tell whether the indexed array was actually allocated.
<syntaxhighlight lang='bash'>
declare -a | grep -q "declare -a my_array" && \
echo "'my_array' was declared as indexed array" || \
echo "'my_array' was not declared as indexed array"
</syntaxhighlight>
==Indexed Array Allocation Test==
This sequence tests whether an indexed array was actually allocated (can be empty) and associated with the variable.
<syntaxhighlight lang='bash'>
[[ -v my_array[@] ]] && \
  echo "there is an array associated with 'my_array'" || \
  echo "there is NO array associated with 'my_array'"
</syntaxhighlight>
The above detects allocation in both following cases:
<syntaxhighlight lang='bash'>
my_array[0]=
my_array[0]="a"
</syntaxhighlight>
Also see: {{Internal|Bash_test#-v|-v}}


==Indexed Arrays Assignment==
==Indexed Arrays Assignment==
Line 54: Line 113:
The (''value'' ...) or ([''index'']=''value'' ...) syntax can be used to initialize an entire array. The values must be separated by space:
The (''value'' ...) or ([''index'']=''value'' ...) syntax can be used to initialize an entire array. The values must be separated by space:


a=("X" "Y" "Z")
<syntaxhighlight lang='bash'>
a=("X" "Y" "Z")
</syntaxhighlight>


If we want initialize only specific elements, we can use this syntax:
If we want initialize only specific elements, we can use this syntax:


a=([0]="X" [4]="Y" [8]="Z")
<syntaxhighlight lang='bash'>
a=([0]="X" [4]="Y" [8]="Z")
</syntaxhighlight>


==Indexed Arrays Reference==
Arrays initialized this way are [[#Automatic_Declaration|automatically declared]].


===Reference Individual Indexed Array Elements===
===Append Array Elements===
 
Use the <code>+=</code> operator:
 
<syntaxhighlight lang='bash'>
declare -a my_array
my_array+=(a)
my_array+=(b)
my_array+=(c)
</syntaxhighlight>
===Prepend Array Elements===
 
<syntaxhighlight lang='bash'>
declare -a my_array
my_array+=(b)
 
# this is how you prepend
my_array=("a" "${my_array[@]}")
</syntaxhighlight>
 
===Load an Array from a Space-Separated List===
 
Method 1 - use a 'for' iterator:
 
<syntaxhighlight lang='bash'>
local space_separated_list="a b c d"
   
declare -a my_array
 
for i in ${space_separated_list}; do
    my_array+=(${i})
done
 
echo "length: ${#my_array[@]}"
echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}
echo ${my_array[3]}
</syntaxhighlight>
 
 
Method 2 - use [[Bash_read#Array_Assignment|read]]:
 
(note that this can be used for other separators as well, by setting IFS)
 
<syntaxhighlight lang='bash'>
local space_separated_list="a b c d"
   
read -r -a my_array <<< "${space_separated_list}"
 
echo "length: ${#my_array[@]}"
echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}
echo ${my_array[3]}
</syntaxhighlight>
 
==Load an Array from Command-Line Positional Arguments==
 
<syntaxhighlight lang='bash'>
declare -a my_array
my_array=("$@")
</syntaxhighlight>
 
===Read the Content of a File into An Indexed Array===
 
Each line will be assigned to an element of the array:
 
<syntaxhighlight lang='bash'>
readarray < ./somefile.txt -t my_array_var
</syntaxhighlight>
 
'''It DOES NOT split the file by lines!''' Only the first line will be loaded into the array, where each space separated element will be assigned to an array element:
 
<syntaxhighlight lang='bash'>
declare -a VALUES
read -r -a VALUES < ./file.txt
</syntaxhighlight>
 
===Assign Words Read from stdin to an Indexed Array===
 
Assing words read from stdin to an array:
 
{{Internal|Bash_read#Array_Assignment|read -a}}
 
==Indexed Array Access==
===Dereference the Array Variable===
 
Dereferencing the array variable returns the value of the first element of the array. For
<syntaxhighlight lang='bash'>
declare -a VALUES
VALUES=("A" "B" "C")
echo ${VALUES}
</syntaxhighlight>
produces "A".
 
===<span id='Indexed_Arrays_Reference'></span>Indexed Arrays Access by Index===
 
====Reference Individual Indexed Array Elements====


Element arrays can be referenced with ${''var-name''[''index'']} notation:
Element arrays can be referenced with ${''var-name''[''index'']} notation:
Line 70: Line 231:
If the array variable [[bash Parameters and Variables#Undeclared_Variable|was not previously declared]], or if the specific element [[bash Parameters and Variables#Uninitialized_Variable|was not initialized]], a reference attempt will return the blank string.
If the array variable [[bash Parameters and Variables#Undeclared_Variable|was not previously declared]], or if the specific element [[bash Parameters and Variables#Uninitialized_Variable|was not initialized]], a reference attempt will return the blank string.


===Reference All Indexed Array Elements===
====<span id='Reference_All_Indexed_Array_Elements'></span>Get All Indexed Array Elements====


If '@' or '*' is used as subscript, the following expressions expand to all members of the array:
If <code>"@"</code> or <code>*</code> is used as subscript, the following expressions expand to all members of the array:


${var_name[@]}
<syntaxhighlight lang='bash'>
${var_name[*]}
${some_array[*]}
"${some_array[@]}"
</syntaxhighlight>
The difference between <code>*</code> and <code>"@"</code> relative to any array elements, in general, is described here: {{Internal|bash * and @ Relative to Array Elements#Overview|<tt>*</tt> and <tt>@</tt> Relative to Array Elements}}


===Reference a Sub-Array===
====Reference a Sub-Array====


A contiguous sub-array can be referenced as follows:
A contiguous sub-array can be referenced as follows:
Line 88: Line 252:


returns all elements of the array starting with the index 'from' up to index 'to'.
returns all elements of the array starting with the index 'from' up to index 'to'.
===Indirect Variable Access for Indexed Arrays===
It is possible to use [[Bash_Parameter_and_Variable_Expansion#Indirect_Variable_Access_for_Indexed_Arrays|variable indirection]] with indexed array variables. Knowing the name of the array variable, the values corresponding to a certain index can be accessed as follows:
<syntaxhighlight lang='bash'>
declare -a VALUES
VALUES=("A" "B" "C")
</syntaxhighlight>
The value of the first element of the array is displayed as follows:
<syntaxhighlight lang='bash'>
name="VALUES[0]"
echo ${!name}
</syntaxhighlight>
The value of the second element of the array is displayed as follows:
<syntaxhighlight lang='bash'>
name="VALUES[1]"
echo ${!name}
</syntaxhighlight>
====Passing the Name of an Indexed Array as Argument to a Function====
<font color=darkkhaki>
Does not work, the values can be accessed inside the function, but the changes do not surface outside the function.
</font>
It is possible to declare an indexed array outside a function, then pass the '''name''' of the array to the function, which then can refer the underlying array and use it: access it and mutate it. This is an effective way of "pass by reference".
Example:
<syntaxhighlight lang='bash'>
declare -a SOME_ARRAY
function array_manipulator() {
  local array_name=$1
  array=${!array_name}
  array+=(a)
}
array_manipulator SOME_ARRAY
echo ${SOME_ARRAY[0]}} # unfortunately, it does not displays "a"
</syntaxhighlight>


==Length of an Indexed Array==
==Length of an Indexed Array==
 
<syntaxhighlight lang='bash'>
${#var_name[@]}
${#var_name[@]}
${#var_name[*]}
${#var_name[*]}
</syntaxhighlight>


{{Warn|If the array is sparse, this does not return the index of last element plus one, but just the number of non-empty elements.}}
{{Warn|If the array is sparse, this does not return the index of last element plus one, but just the number of non-empty elements.}}
Line 100: Line 311:
===Using the Indexed Array Elements===
===Using the Indexed Array Elements===


for i in ${array_var[@]}; do
<syntaxhighlight lang='bash'>
    ...
for i in "${array_var[@]}"; do
done
  echo "${i}"
done
</syntaxhighlight>
 
====Iterate Over the Argument List====
 
<syntaxhighlight lang='bash'>
args=("$@")
for arg in ${args[@]}; do
  echo "${arg}"
done
</syntaxhighlight>
or
<syntaxhighlight lang='bash'>
for arg in "$@"; do
  echo "${arg}"
done
</syntaxhighlight>


===Using the Index===
===Using the Index===


i=0
<syntaxhighlight lang='bash'>
while [[ ${i} < ${#array_var[@]} ]]; do
i=0
  echo ${array_var[$i]}
while [[ ${i} < ${#array_var[@]} ]]; do
  ((i++))
  echo ${array_var[${i}]}
done
  ((i++))
 
done
</syntaxhighlight>
Note that this does not work when the array is sparse, because ${#array_var[@]} only returns the number of non-empty elements, and not the array length.
Note that this does not work when the array is sparse, because ${#array_var[@]} only returns the number of non-empty elements, and not the array length.


==Clear an Indexed Array==
==Clear an Indexed Array==


Note that re-declared an indexed array does not clear it. To be cleared, the array needs to be unset and redeclared.
Note that re-declaring an indexed array does not clear it. To be cleared, the array needs to be unset and redeclared.


<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
Line 125: Line 354:
</syntaxhighlight>
</syntaxhighlight>


==Indexed Array Use Cases==
=Associative Arrays=


===Read the Content of a File into An Indexed Array===
==Associative Array Overview==
 
Associative arrays can be used to implement sets and maps in bash. The most common usage as set is to insert elements whose subscript is identical with the value.
 
==Associative Array Declaration==
 
{{Warn|Associative arrays '''must''' be explicitly declare before initialization, otherwise unexpected behavior may occur. For example, if multiple assignments are declared, only the last one is reflected in the state of the array. This is different from the behavior of the indexed arrays, which can be used without explicit declaration.}}
<syntaxhighlight lang='bash'>
declare -A some_assoc_array
</syntaxhighlight>
This command does not create the associative array immediately, it just sets an attribute on the name <code>some_assoc_array</code> which allows assignments to the name as an associative array. The array does not exist until the first assignment. The fact that a specific array was declared can be tested by executing <code>declare -A</code> and grepping the result, as shown [[#Associative_Array_Declaration_Test|below]].
 
All previously declared (and not yet unset) associative arrays can be listed with:
<syntaxhighlight lang='bash'>
declare -A
</syntaxhighlight>


Each line will be assigned to an element of the array:
An associative array variable can be "undeclared" with the <code>unset</code> [[Bash_Concepts#Builtin|builtin]].
<syntaxhighlight lang='bash'>
unset some_assoc_array
</syntaxhighlight>


readarray < ./somefile.txt -t my_array_var
==Associative Array Declaration Test==


===Assign Words Read from stdin to an Indexed Array===
This sequence tests whether a variable was declared as an associative array. The test does not tell whether the associative array was actually allocated.


Assing words read from stdin to an array:
<syntaxhighlight lang='bash'>
declare -A | grep -q "declare -A some_assoc_array" && \
echo "'some_assoc_array' was declared as associative array" || \
echo "'some_assoc_array' was not declared as associative array"
</syntaxhighlight>


{{Internal|Bash_read#Array_Assignment|read -a}}
==Associative Array Allocation Test==
<font color=darkkhaki>
This sequence tests whether an associative array was actually allocated (can be empty) and associated with the variable.


===Iterate Over the Argument List===
<syntaxhighlight lang='bash'>
[[ -v some_assoc_array[@] ]] && \
  echo "there is an array associated with 'some_assoc_array'" || \
  echo "there is NO array associated with 'some_assoc_array'"
</syntaxhighlight>


args=("$@")
The above detects allocation in both following cases:
for arg in ${args[@]}; do
  ...
done


=Associative Arrays=
<syntaxhighlight lang='bash'>
some_assoc_array["a"]=
some_assoc_array["a"]="b"
</syntaxhighlight>
</font>
Also see: {{Internal|Bash_test#-v|bash <tt>test</tt> <tt>-v</tt>}}


==Associative Array Overview==
==Associative Array Assignment==


Associative arrays can be used to implement sets and maps in bash. The most common usage as set is to insert elements whose subscript is identical with the value.
===Assign Individual Associative Array Elements===


==Associative Array Declaration==
Individual elements are initialized by using <code>assoc_array_var_name[key]=value</code> notation:


{{Warn|Associative arrays '''must''' be explicitly declare before initialization, otherwise unexpected behavior may occur. For example, if multiple assignments are declared, only the last one is reflected in the state of the array. This is different from the behavior of the indexed arrays, which can be used without explicit declaration.}}
<syntaxhighlight lang='bash'>
a["color"]="blue"
</syntaxhighlight>


declare -A my_assoc_array
The associative array variable must be declared with <code>declare -A</code> in advance, otherwise only the last assignment is reflected in the state of the array.


Previously declared associative arrays can be listed with:
===Entire Associative Array===
The <code>([key_1]=value_1 [key_2]=value_2 ...)</code> syntax can be used to initialize an entire array. The values must be separated by space:
<syntaxhighlight lang='bash'>
a=(["color]="red" ["size"]="small")
</syntaxhighlight>


declare -A
==Associative Array Key Existence==


An associative array variable can be "undeclared" with the "unset" builtin.
The existence of a specific key in an associative array (whether it has a value associated with it or not) can be tested with:


unset my_assoc_array
<syntaxhighlight lang='bash'>
declare -A A


==Associative Array Assignment==
[[ ${A["some-key"]+nonemptystring} ]] && echo "'some-key' exists" || echo "'some-key' does not exist"


===Assign Individual Associative Array Elements===
</syntaxhighlight>


Individual elements are initialized by using ${''var-name''[''key'']}=''value'' notation:
The key is identified to exist even if it has an empty value. In the following cases, the key is identified as existent:


a["color"]="blue"
<syntaxhighlight lang='bash'>
A["some-key"]=
A["some-key"]=""
A["some-key"]="something"
</syntaxhighlight>


The associative array variable must be declared with -A before, otherwise only the last assignment is reflected in the state of the array.
This should work for both associative arrays and indexed arrays.


===Entire Associative Array===
More general:


The (["key"]="value" ...) syntax can be used to initialize an entire array. The values must be separated by space:
<syntaxhighlight lang='bash'>
declare -A A
key="somekey"
A[${key}]="somevalue"


a=(["color]="red" ["size"]="small")
[[ ${A[${key}]+nonemptystring} ]] && echo "'${key}' exists" || echo "'${key}' does not exist"
</syntaxhighlight>


==Associative Array Reference==
==<span id='Associative_Array_Reference'></span>Associative Array Access==


===Reference Individual Associative Array Elements===
===Reference Individual Associative Array Elements===


Element arrays can be referenced with ${''var-name''[''key'']} notation:
Element arrays can be referenced with <code>${assoc_array_var_name[key]}</code> notation:


echo ${a["color"]}
<syntaxhighlight lang='bash'>
echo ${some_assoc_array["color"]}
</syntaxhighlight>


If the array variable [[bash Parameters and Variables#Undeclared_Variable|was not previously declared]], or if the specific element [[bash Parameters and Variables#Uninitialized_Variable|was not initialized]], a reference attempt will return the blank string.
If the array variable [[bash Parameters and Variables#Undeclared_Variable|was not previously declared]], or if the specific element [[bash Parameters and Variables#Uninitialized_Variable|was not initialized]], a reference attempt will return the blank string.
Line 194: Line 470:
===Get All Associative Array Keys===
===Get All Associative Array Keys===


The keys are accessed with:
All keys are returned with:
${!array_var_name[@]}
<syntaxhighlight lang='bash'>
${!some_assoc_array[*]}
</syntaxhighlight>
or
<syntaxhighlight lang='bash'>
"${!some_assoc_array[@]}"
</syntaxhighlight>
 
The difference between <code>!some_assoc_array[*]</code> and <code>"${!some_assoc_array[@]}"</code> shows in the case the key contain spaces. In the former situation, the keys that contain spaces are tokenized into individual non-space-containing strings. In the later situation, the keys that contain spaces are handled as individual strings that contain spaces.
 
The difference between <code>*</code> and <code>@</code> relative to any array elements, in general, is described here: {{Internal|bash * and @ Relative to Array Elements#Overview|<tt>*</tt> and <tt>@</tt> Relative to Array Elements}}


===Get All Associative Array Values===
===Get All Associative Array Values===


If '@' or '*' is used as subscript, the following expressions expand to all values maintained in the array:
If <code>"@"</code> or <code>*</code> is used as subscript, the following expressions expand to all values maintained in the array:


${array_var_name[@]}
<syntaxhighlight lang='bash'>
${array_var_name[*]}
${array_var_name[@]}
${array_var_name[*]}
</syntaxhighlight>
The difference between <code>*</code> and <code>"@"</code> relative to any array elements, in general, is described here: {{Internal|bash * and @ Relative to Array Elements#Overview|<tt>*</tt> and <tt>@</tt> Relative to Array Elements}}


===Iterate over Key/Values of an Associative Array===
===Iterate over Key/Values of an Associative Array===


<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
for i in "${!array_var_name[@]}" do
for k in "${!array_var_name[@]}"; do
     echo "key: ${i}"
     echo "key: ${k}"
     echo "value: ${array_var_name[${i}]}"
     echo "value: ${array_var_name[${k}]}"
done
done
</syntaxhighlight >
</syntaxhighlight >
{{Warn|Enclose ${!array_var_name[@]} in double quotes.}}
===Indirect Variable Access for Associative Arrays===
It is possible to use [[Bash_Parameter_and_Variable_Expansion#Indirect_Variable_Access_for_Associative_Arrays|variable indirection]] with associative array variables. Knowing the name of the associative array variable, the values corresponding to a certain key can be accessed as follows:
<syntaxhighlight lang='bash'>
declare -A VALUES
VALUES["color"]="red"
</syntaxhighlight>
The value associated with the "color" key is displayed as follows:
<syntaxhighlight lang='bash'>
name="VALUES[\"color\"]"
echo ${!name}
</syntaxhighlight>
The value associated with the "color" key can be modified as follows:
<syntaxhighlight lang='bash'>
name="VALUES[\"color\"]"
eval "${name}=blue"
</syntaxhighlight>
This will produce:
<syntaxhighlight lang='bash'>
echo ${VALUES["color"]}
blue
</syntaxhighlight>
Also see: {{Internal|Bash eval|eval}}


==Size==
==Size==
Line 217: Line 536:
  ${#var_name[@]}
  ${#var_name[@]}
  ${#var_name[*]}
  ${#var_name[*]}
==Clear the Array==
To clear an individual element of the array, use:
unset array_name[subscript]
<syntaxhighlight lang='bash'>
declare -a a
a["color"]="blue"
unset a["color"]
</syntaxhighlight>
To clear the entire array, but not discard the variable, iterate over the array and unset each element:
<syntaxhighlight lang='bash'>
for k in "${!array_var_name[@]}"; do
  unset array_var_name[${k}]
done
</syntaxhighlight>
{{Warn|Enclose ${!array_var_name[@]} in double quotes.}}
==Associative Array Patterns==
* [[Bash Return Multiple Values from a Function using an Associative Array|Return Multiple Values from a Function using an Associative Array]]

Latest revision as of 19:15, 1 April 2024

External

Internal

Indexed Arrays

External

Indexed Arrays Overview

bash indexed arrays are 0-based and unidimensional. No explicit declaration is necessary if at least one element is initialized as described below.

Indexed arrays behave as local variables: an array declared in a function will be accessible to the declaring function and all functions invoked from the declaring function after declaration, but not to callers of the declaring function. In other words, indexed arrays are accessible only in the declaring scope and sub-scopes.

Indexed Arrays Declaration

Arrays do not need explicit declarations, they will be automatically declared upon the first assignment of any of their elements:

my_array_var[0]="something"

They can be explicitly declared, though:

declare -a my_array_var

Previously declared arrays can be listed with:

declare -a

Whether a specific array was declared can be checked as follows:

if declare -a | grep -q my_array_var; then
   # 'my_array_var' was declared
   ...
else
   # 'my_array_var' was not declared
   ...
fi

Negation also works:

if ! declare -a | grep -q my_array_var; then
   # 'my_array_var' was not declared
   ...
else
   # 'my_array_var' was declared   
   ...
fi

An indexed array is automatically declared if it is assigned using this syntax:

my_array_var=("a" "b" "c")

An array variable can be "undeclared" with the "unset" builtin.

unset my_array_var

Individual array elements can also be unset:

unset my_array_var[subscript] 

A subscript of "*" or "@" also removes the entire array.

Indexed Array Declaration Test

This sequence tests whether a variable was declared as an indexed array. The test does not tell whether the indexed array was actually allocated.

declare -a | grep -q "declare -a my_array" && \
 echo "'my_array' was declared as indexed array" || \
 echo "'my_array' was not declared as indexed array"

Indexed Array Allocation Test

This sequence tests whether an indexed array was actually allocated (can be empty) and associated with the variable.

[[ -v my_array[@] ]] && \
  echo "there is an array associated with 'my_array'" || \
  echo "there is NO array associated with 'my_array'"

The above detects allocation in both following cases:

my_array[0]=
my_array[0]="a"

Also see:

-v

Indexed Arrays Assignment

Assign Indexed Array Individual Elements

Individual elements are initialized by using ${var-name[index]}=value notation:

a[0]="something"

Entire Indexed Array

The (value ...) or ([index]=value ...) syntax can be used to initialize an entire array. The values must be separated by space:

a=("X" "Y" "Z")

If we want initialize only specific elements, we can use this syntax:

a=([0]="X" [4]="Y" [8]="Z")

Arrays initialized this way are automatically declared.

Append Array Elements

Use the += operator:

declare -a my_array
my_array+=(a)
my_array+=(b)
my_array+=(c)

Prepend Array Elements

declare -a my_array
my_array+=(b)

# this is how you prepend
my_array=("a" "${my_array[@]}")

Load an Array from a Space-Separated List

Method 1 - use a 'for' iterator:

local space_separated_list="a b c d"
    
declare -a my_array

for i in ${space_separated_list}; do
    my_array+=(${i})
done

echo "length: ${#my_array[@]}"
echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}
echo ${my_array[3]}


Method 2 - use read:

(note that this can be used for other separators as well, by setting IFS)

local space_separated_list="a b c d"
    
read -r -a my_array <<< "${space_separated_list}"

echo "length: ${#my_array[@]}"
echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}
echo ${my_array[3]}

Load an Array from Command-Line Positional Arguments

declare -a my_array
my_array=("$@")

Read the Content of a File into An Indexed Array

Each line will be assigned to an element of the array:

readarray < ./somefile.txt -t my_array_var

It DOES NOT split the file by lines! Only the first line will be loaded into the array, where each space separated element will be assigned to an array element:

declare -a VALUES
read -r -a VALUES < ./file.txt

Assign Words Read from stdin to an Indexed Array

Assing words read from stdin to an array:

read -a

Indexed Array Access

Dereference the Array Variable

Dereferencing the array variable returns the value of the first element of the array. For

declare -a VALUES
VALUES=("A" "B" "C")
echo ${VALUES}

produces "A".

Indexed Arrays Access by Index

Reference Individual Indexed Array Elements

Element arrays can be referenced with ${var-name[index]} notation:

echo ${a[0]}

If the array variable was not previously declared, or if the specific element was not initialized, a reference attempt will return the blank string.

Get All Indexed Array Elements

If "@" or * is used as subscript, the following expressions expand to all members of the array:

${some_array[*]}
"${some_array[@]}"

The difference between * and "@" relative to any array elements, in general, is described here:

* and @ Relative to Array Elements

Reference a Sub-Array

A contiguous sub-array can be referenced as follows:

${var_name[@]:from}

returns all elements of the array starting with the index 'from'.

${var_name[@]:from:to}

returns all elements of the array starting with the index 'from' up to index 'to'.

Indirect Variable Access for Indexed Arrays

It is possible to use variable indirection with indexed array variables. Knowing the name of the array variable, the values corresponding to a certain index can be accessed as follows:

declare -a VALUES
VALUES=("A" "B" "C")

The value of the first element of the array is displayed as follows:

name="VALUES[0]"
echo ${!name}

The value of the second element of the array is displayed as follows:

name="VALUES[1]"
echo ${!name}

Passing the Name of an Indexed Array as Argument to a Function

Does not work, the values can be accessed inside the function, but the changes do not surface outside the function.

It is possible to declare an indexed array outside a function, then pass the name of the array to the function, which then can refer the underlying array and use it: access it and mutate it. This is an effective way of "pass by reference".

Example:

declare -a SOME_ARRAY

function array_manipulator() {
  local array_name=$1
  array=${!array_name}
  array+=(a)
}

array_manipulator SOME_ARRAY

echo ${SOME_ARRAY[0]}} # unfortunately, it does not displays "a"

Length of an Indexed Array

${#var_name[@]}
${#var_name[*]}

If the array is sparse, this does not return the index of last element plus one, but just the number of non-empty elements.

Iterate over an Indexed Array

Using the Indexed Array Elements

for i in "${array_var[@]}"; do
   echo "${i}"
done

Iterate Over the Argument List

args=("$@")
for arg in ${args[@]}; do
  echo "${arg}"
done

or

for arg in "$@"; do
   echo "${arg}"
done

Using the Index

i=0
while [[ ${i} < ${#array_var[@]} ]]; do
  echo ${array_var[${i}]}
  ((i++))
done

Note that this does not work when the array is sparse, because ${#array_var[@]} only returns the number of non-empty elements, and not the array length.

Clear an Indexed Array

Note that re-declaring an indexed array does not clear it. To be cleared, the array needs to be unset and redeclared.

declare -a A
...
unset A
declare -a A

Associative Arrays

Associative Array Overview

Associative arrays can be used to implement sets and maps in bash. The most common usage as set is to insert elements whose subscript is identical with the value.

Associative Array Declaration


Associative arrays must be explicitly declare before initialization, otherwise unexpected behavior may occur. For example, if multiple assignments are declared, only the last one is reflected in the state of the array. This is different from the behavior of the indexed arrays, which can be used without explicit declaration.

declare -A some_assoc_array

This command does not create the associative array immediately, it just sets an attribute on the name some_assoc_array which allows assignments to the name as an associative array. The array does not exist until the first assignment. The fact that a specific array was declared can be tested by executing declare -A and grepping the result, as shown below.

All previously declared (and not yet unset) associative arrays can be listed with:

declare -A

An associative array variable can be "undeclared" with the unset builtin.

unset some_assoc_array

Associative Array Declaration Test

This sequence tests whether a variable was declared as an associative array. The test does not tell whether the associative array was actually allocated.

declare -A | grep -q "declare -A some_assoc_array" && \
 echo "'some_assoc_array' was declared as associative array" || \
 echo "'some_assoc_array' was not declared as associative array"

Associative Array Allocation Test

This sequence tests whether an associative array was actually allocated (can be empty) and associated with the variable.

[[ -v some_assoc_array[@] ]] && \
  echo "there is an array associated with 'some_assoc_array'" || \
  echo "there is NO array associated with 'some_assoc_array'"

The above detects allocation in both following cases:

some_assoc_array["a"]=
some_assoc_array["a"]="b"

Also see:

bash test -v

Associative Array Assignment

Assign Individual Associative Array Elements

Individual elements are initialized by using assoc_array_var_name[key]=value notation:

a["color"]="blue"

The associative array variable must be declared with declare -A in advance, otherwise only the last assignment is reflected in the state of the array.

Entire Associative Array

The ([key_1]=value_1 [key_2]=value_2 ...) syntax can be used to initialize an entire array. The values must be separated by space:

a=(["color]="red" ["size"]="small")

Associative Array Key Existence

The existence of a specific key in an associative array (whether it has a value associated with it or not) can be tested with:

declare -A A

[[ ${A["some-key"]+nonemptystring} ]] && echo "'some-key' exists" || echo "'some-key' does not exist"

The key is identified to exist even if it has an empty value. In the following cases, the key is identified as existent:

A["some-key"]=
A["some-key"]=""
A["some-key"]="something"

This should work for both associative arrays and indexed arrays.

More general:

declare -A A
key="somekey"
A[${key}]="somevalue"

[[ ${A[${key}]+nonemptystring} ]] && echo "'${key}' exists" || echo "'${key}' does not exist"

Associative Array Access

Reference Individual Associative Array Elements

Element arrays can be referenced with ${assoc_array_var_name[key]} notation:

echo ${some_assoc_array["color"]}

If the array variable was not previously declared, or if the specific element was not initialized, a reference attempt will return the blank string.

Get All Associative Array Keys

All keys are returned with:

${!some_assoc_array[*]}

or

"${!some_assoc_array[@]}"

The difference between !some_assoc_array[*] and "${!some_assoc_array[@]}" shows in the case the key contain spaces. In the former situation, the keys that contain spaces are tokenized into individual non-space-containing strings. In the later situation, the keys that contain spaces are handled as individual strings that contain spaces.

The difference between * and @ relative to any array elements, in general, is described here:

* and @ Relative to Array Elements

Get All Associative Array Values

If "@" or * is used as subscript, the following expressions expand to all values maintained in the array:

${array_var_name[@]}
${array_var_name[*]}

The difference between * and "@" relative to any array elements, in general, is described here:

* and @ Relative to Array Elements

Iterate over Key/Values of an Associative Array

for k in "${!array_var_name[@]}"; do
    echo "key: ${k}"
    echo "value: ${array_var_name[${k}]}"
done

Enclose ${!array_var_name[@]} in double quotes.

Indirect Variable Access for Associative Arrays

It is possible to use variable indirection with associative array variables. Knowing the name of the associative array variable, the values corresponding to a certain key can be accessed as follows:

declare -A VALUES
VALUES["color"]="red"

The value associated with the "color" key is displayed as follows:

name="VALUES[\"color\"]"
echo ${!name}

The value associated with the "color" key can be modified as follows:

name="VALUES[\"color\"]"
eval "${name}=blue"

This will produce:

echo ${VALUES["color"]}
blue

Also see:

eval

Size

${#var_name[@]}
${#var_name[*]}

Clear the Array

To clear an individual element of the array, use:

unset array_name[subscript]
declare -a a
a["color"]="blue"
unset a["color"]

To clear the entire array, but not discard the variable, iterate over the array and unset each element:

for k in "${!array_var_name[@]}"; do
   unset array_var_name[${k}]
done

Enclose ${!array_var_name[@]} in double quotes.

Associative Array Patterns