Arrays
Use Bash indexed arrays and associative arrays — creating, expanding, slicing, looping, and understanding when arrays beat space-separated strings.
- Create and access indexed arrays with arr=(...) and ${arr[@]}
- Use ${#arr[@]} for length and array slices
- Create associative arrays with declare -A and access by key
- Loop over array keys and values
- Explain why arrays are safer than space-separated strings
Beginner Bash stores lists in variables as space-separated strings. That works until a value contains a space — then word splitting silently corrupts the data. Arrays are the proper solution: each element is a discrete, quoted value, and the shell never splits on spaces within an element.
Indexed arrays
Create an indexed array with the =() syntax:
fruits=("apple" "banana" "cherry plum")Access elements with ${arr[n]}, expand all with ${arr[@]}, and get the count with ${#arr[@]}:
echo "${fruits[0]}" # apple
echo "${fruits[2]}" # cherry plum (the space is preserved)
echo "${#fruits[@]}" # 3
# All elements — always quote to preserve spaces
for f in "${fruits[@]}"; do
echo "$f"
doneAppend to an array:
fruits+=("date" "elderberry")
echo "${#fruits[@]}" # 5Assign or overwrite a specific index:
fruits[1]="blueberry"
echo "${fruits[1]}" # blueberryUnset a specific element:
unset 'fruits[2]'
# The array is now sparse — index 2 is gone, indices 0,1,3,4 remain
echo "${!fruits[@]}" # 0 1 3 4 (the existing indices)Array slices
${arr[@]:start:length} returns a sub-array:
nums=(10 20 30 40 50)
echo "${nums[@]:1:3}" # 20 30 40 (starting at index 1, length 3)
echo "${nums[@]:2}" # 30 40 50 (from index 2 to end)This mirrors Python's list[1:4] — a useful mental bridge.
Printing indices
${!arr[@]} gives you the indices (keys), not the values:
for i in "${!fruits[@]}"; do
echo "fruits[$i] = ${fruits[$i]}"
doneWhy [@] and not [*]? Both expand all elements, but "${arr[@]}" (quoted, with @) preserves each element as a separate word. "${arr[*]}" joins all elements with the first character of IFS (usually a space) into a single string. For loops and function calls, always use "${arr[@]}".
Associative arrays
Declare an associative array with declare -A. Keys are arbitrary strings:
declare -A config
config["host"]="localhost"
config["port"]="5432"
config["user"]="admin"
echo "${config["host"]}" # localhost
echo "${#config[@]}" # 3 (number of keys)Iterate over key-value pairs:
for key in "${!config[@]}"; do
echo "$key = ${config[$key]}"
doneAssociative arrays require Bash 4+. macOS ships with Bash 3.2 (due to licence reasons), which does not support declare -A. Check with bash --version. If you need to support macOS users with the system Bash, use a flat string encoding or require Homebrew Bash 5.
Check your understanding
- 1.arr=("file one" "file two"). Which expansion passes both elements correctly to a command that expects two arguments?
- 2.What must you do before using an associative array in Bash?
- 3.After unset arr[1] on a 5-element array, ${#arr[@]} returns 4.
Do it yourself
# Indexed array: files with spaces
declare -a myfiles=("/tmp/file one.txt" "/tmp/file two.txt")
for f in "${myfiles[@]}"; do echo "File: $f"; done
# Slice
nums=(10 20 30 40 50 60)
echo "Middle three: ${nums[@]:1:3}"
# Associative array: simple config store
declare -A cfg
cfg[host]="localhost"
cfg[port]="8080"
for k in "${!cfg[@]}"; do echo "$k=${cfg[$k]}"; done
# Append and check length
myfiles+=("/tmp/file three.txt")
echo "Now ${#myfiles[@]} files"Where to go next
Arrays give you proper data structures in the shell. The next lesson — Parameter expansion — shows the full set of ${...} forms for defaults, string manipulation, prefix/suffix stripping, and case conversion.