Bash Arrays
Creating Arrays
The most common way to define an array in bash is with the simple a=() syntax. This can be done on a single line, or it can be split over multiple lines.
one_line=(foo bar baz)
multi_line=(
foo
bar
baz
)Bash also allows you to define elements at specific indexes. You are not required to define the indexes in order. You can leave gaps to create a sparse array which can be useful if you need to insert items in between the initial items later on.
using_indexes=([0]=foo [1]=bar [2]=baz)
sparse_array=([0]=foo [20]=bar [30]=baz)You can also create an array by splitting data with IFS. IFS, or Internal Field Separator, tells bash what characters should be used to split up a string. We can change it to our delimiter and use it along with read to split a string into an array.
IFS=. read -ra dot_delimited <<< "foo.bar.baz"
IFS=, read -ra comma_delimited <<< "foo,bar,baz"
IFS=" " read -ra space_delimited <<< "foo bar baz"Editing Arrays
When adding to an array, you can append data to the end of the array or you can set values at specific indexes.
array+=(foo)
array[10]=fooIf you need to delete something from an array, you can use unset. Note that the reference to the array should be quoted to prevent bash from treating the square brackets as a glob pattern.
unset 'array[2]'Expanding Arrays
Here is a basic overview of the different ways to expand arrays:
"$array" # If you expand like a variable, you get the first element
"${array[@]}" # Expand all individual elements of the array
"${array[*]}" # Combine the array elements into a single string
"${array[0]}" # Get the array element at a specific index
"${!array[@]}" # Expand the indexes of the elements in the array
"${#array[@]}" # Get the length of the array
"${#array[1]}" # Get the length of a specific element in the array
# Get the array elements starting at index 1
# array=(foo bar baz) would become (bar baz)
"${array[@]:1}"
# Get the last 2 elements of the array.
# The space is required in front of a negative value.
# array=(foo bar baz) would become (bar baz)
"${array[@]: -2}"
# Get the first 2 elements of the array.
# array=(foo bar baz) would become (foo bar)
"${array[@]:0:2}"
# Get a slice of the array containing 2 elements, starting at index 3
# array=(a b c d e f) would become (d e)
"${array[@]:3:2}"The [*] syntax is a bit special. While it does combine the elements of the array into a single string, you can actually control the character that’s used to combine them using bash’s IFS variable. The first character of IFS is what will be used to combine the elements. The default value of IFS is a space, tab, and newline.
:::caution
Internal Bash variables like IFS should be always be changed in a subshell rather than the main shell process when possible. A lot of commands rely on IFS to determine how they behave, and changing it in the main shell can cause weird and unexpected behavior. In the example below, the ( ) subshell syntax is used for this.
:::
# The default value of IFS is space, tab, and newline so by default this will
# combine with a space. By overriding IFS, we can change the character used
# to combine the elements.
words=(foo bar baz)
echo "${words[*]}" # foo bar baz
(IFS=,; echo "${words[*]}") # foo,bar,baz
# Being able to change the character can make it much easier to see the
# individual elements when they contain spaces.
names=("John Doe" "Jane Doe")
echo "${names[*]}" # John Doe Jane Doe
(IFS=,; echo "${names[*]}") # John Doe,Jane DoeSafe Expansion With set -u or set -o nounset
In versions of Bash before 4.4, expanding an empty array is considered the same as expanding an unset variable. If you have set -u or set -o nounset (same thing) set, this will cause the script to exit.
In cases where the array may be empty, you can expand it like below to prevent the script from exiting if it is empty:
# Expanding the individual elements
"${args[@]+"${args[@]}"}"
# Expanding as a single string
"${args[*]+${args[*]}}"This uses Bash’s Use Alternate Value form of parameter expansion. The left side of the plus sign will test to see if the array is set. If it is unset, it will be replaced with nothing. If it is set, then it will be replaced with whatever is on the right side of the plus sign (the array expansion).
An example use case of this is a function where the caller may or may not provide additional arguments for a wrapped command:
set -u
curl_wrapper() {
# First argument is always the URL
local url="$1"
# Everything after that can be an additional argument to pass to curl
local curl_args=("${@:2}")
# Safely expand the array so it works whether or not the caller provided additional arguments
curl --fail --silent "$url" "${curl_args[@]+"${curl_args[@]}"}"
}