Applies to: Bash 4 and later on Linux (examples tested with Bash 5.1); macOS ships Bash 3.2, which has no associative arrays
Arrays let a Bash script keep a list of values, such as server names, files or ports, and loop over them. Bash has indexed arrays (numbered from 0) and associative arrays (with text keys). Every example below was run in Bash 5.1.
Indexed arrays
servers=(web1 web2 "db 1")
echo "${servers[0]}" # web1
echo "${#servers[@]}" # 3 (number of elements)
servers+=(cache1) # append
for s in "${servers[@]}"; do
echo "- $s"
done
Always write "${servers[@]}" with quotes: then db 1 stays one element instead of being split in two.
Indexes, slices and removing elements
echo "${!servers[@]}" # 0 1 2 3 (the indexes)
echo "${servers[@]:1:2}" # web2 db 1 (2 elements from index 1)
echo "${servers[-1]}" # the last element
unset "servers[1]" # remove web2
After unset, the other elements keep their indexes (there is a gap at 1), and the count drops to 3.
Associative arrays (key and value)
declare -A port=([ssh]=22 [https]=443)
port[mysql]=3306
for k in "${!port[@]}"; do
echo "$k=${port[$k]}"
done
[[ -v port[ssh] ]] && echo "ssh key exists"
declare -A is required. Associative arrays have no fixed order; pipe the loop through sort if you need one.
Fill an array from a command or a file
mapfile -t lines < /etc/hosts # one element per line
mapfile -t users < <(cut -d: -f1 /etc/passwd)
IFS=, read -ra parts <<< "x,y,z" # split a string on commas
echo "${parts[1]}" # y
A practical example
#!/usr/bin/env bash
sites=(example.com example.net example.org)
for site in "${sites[@]}"; do
code=$(curl -s -o /dev/null -w "%{http_code}" "https://$site/")
echo "$site $code"
done
Related: Bash functions.