Arrays¶
Arrays let you store and manipulate collections of values. Bash supports indexed (numeric) and associative (key-value) arrays.
Indexed Arrays¶
Creating Arrays¶
# Direct assignment
fruits=("apple" "banana" "cherry")
# Index assignment
colors[0]="red"
colors[1]="green"
colors[2]="blue"
# From command output
files=($(ls *.txt))
# Empty array
empty=()
Accessing Elements¶
fruits=("apple" "banana" "cherry")
echo "${fruits[0]}" # apple (first element)
echo "${fruits[1]}" # banana
echo "${fruits[-1]}" # cherry (last element, bash 4.3+)
echo "${fruits[@]}" # All elements: apple banana cherry
echo "${fruits[*]}" # All as single string
Braces Required
Always use braces for array access:
Array Length¶
fruits=("apple" "banana" "cherry")
echo "${#fruits[@]}" # 3 (number of elements)
echo "${#fruits[0]}" # 5 (length of first element)
Array Indices¶
Iterating¶
fruits=("apple" "banana" "cherry")
# Iterate over values
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
# Iterate with indices
for i in "${!fruits[@]}"; do
echo "$i: ${fruits[$i]}"
done
Output:
Modifying Arrays¶
Adding Elements¶
fruits=("apple" "banana")
# Append
fruits+=("cherry")
# Append multiple
fruits+=("date" "elderberry")
# Insert at index
fruits[5]="fig" # Sparse array - index 3,4 are unset
echo "${fruits[@]}"
# apple banana cherry date elderberry fig
Removing Elements¶
fruits=("apple" "banana" "cherry")
# Remove by index
unset fruits[1]
echo "${fruits[@]}" # apple cherry
# Note: doesn't reindex - index 1 is now empty
echo "${!fruits[@]}" # 0 2
Replacing Elements¶
fruits=("apple" "banana" "cherry")
fruits[1]="blueberry"
echo "${fruits[@]}" # apple blueberry cherry
Array Slice¶
arr=(a b c d e f)
echo "${arr[@]:2:3}" # c d e (from index 2, length 3)
echo "${arr[@]:2}" # c d e f (from index 2 to end)
echo "${arr[@]::3}" # a b c (first 3 elements)
Copying Arrays¶
Associative Arrays¶
Associative arrays use strings as keys. Requires Bash 4.0+.
Creating¶
# Must declare first
declare -A user
user[name]="Alice"
user[age]=30
user[email]="alice@example.com"
# Or inline
declare -A person=(
[name]="Bob"
[age]=25
[city]="NYC"
)
Accessing¶
declare -A user=([name]="Alice" [age]=30)
echo "${user[name]}" # Alice
echo "${user[@]}" # All values
echo "${!user[@]}" # All keys: name age
echo "${#user[@]}" # Number of elements: 2
Iterating¶
declare -A user=([name]="Alice" [age]=30 [city]="NYC")
# Iterate over keys
for key in "${!user[@]}"; do
echo "$key: ${user[$key]}"
done
Checking Key Exists¶
declare -A user=([name]="Alice")
if [[ -v user[name] ]]; then
echo "Name is set"
fi
if [[ -v user[age] ]]; then
echo "Age is set"
else
echo "Age is not set"
fi
Common Patterns¶
Array from String¶
With custom delimiter:
Array to String¶
With custom delimiter:
Or use printf:
arr=("one" "two" "three")
printf -v str '%s,' "${arr[@]}"
str="${str%,}" # Remove trailing comma
echo "$str" # one,two,three
Check if Array Contains Value¶
arr=("apple" "banana" "cherry")
contains() {
local item="$1"
shift
local arr=("$@")
for elem in "${arr[@]}"; do
[[ "$elem" == "$item" ]] && return 0
done
return 1
}
if contains "banana" "${arr[@]}"; then
echo "Found banana"
fi
Using pattern matching:
Remove Duplicates¶
arr=("a" "b" "a" "c" "b")
declare -A seen
unique=()
for item in "${arr[@]}"; do
if [[ ! -v seen[$item] ]]; then
seen[$item]=1
unique+=("$item")
fi
done
echo "${unique[@]}" # a b c
Sort Array¶
arr=("banana" "apple" "cherry")
# Using printf and sort
IFS=$'\n' sorted=($(printf '%s\n' "${arr[@]}" | sort))
echo "${sorted[@]}" # apple banana cherry
# Numeric sort
nums=(10 2 30 1)
IFS=$'\n' sorted=($(printf '%s\n' "${nums[@]}" | sort -n))
echo "${sorted[@]}" # 1 2 10 30
Reverse Array¶
arr=("a" "b" "c" "d")
reversed=()
for ((i=${#arr[@]}-1; i>=0; i--)); do
reversed+=("${arr[$i]}")
done
echo "${reversed[@]}" # d c b a
Filter Array¶
arr=(1 2 3 4 5 6 7 8 9 10)
evens=()
for num in "${arr[@]}"; do
((num % 2 == 0)) && evens+=("$num")
done
echo "${evens[@]}" # 2 4 6 8 10
Map Function Over Array¶
arr=(1 2 3 4 5)
doubled=()
for num in "${arr[@]}"; do
doubled+=($((num * 2)))
done
echo "${doubled[@]}" # 2 4 6 8 10
Reading File into Array¶
Using mapfile (Bash 4+)¶
Options:
-t- Remove trailing newlines-n count- Read at most count lines-s skip- Skip first skip lines
Using While Loop¶
Passing Arrays to Functions¶
By Value (Copy)¶
process_array() {
local arr=("$@")
for item in "${arr[@]}"; do
echo "Item: $item"
done
}
fruits=("apple" "banana" "cherry")
process_array "${fruits[@]}"
By Reference (Bash 4.3+)¶
process_array() {
local -n arr=$1 # nameref
for item in "${arr[@]}"; do
echo "Item: $item"
done
}
fruits=("apple" "banana" "cherry")
process_array fruits # Pass array name, not contents
Stack and Queue¶
Stack (LIFO)¶
stack=()
push() { stack+=("$1"); }
pop() {
local top="${stack[-1]}"
unset 'stack[-1]'
echo "$top"
}
push "a"
push "b"
push "c"
echo $(pop) # c
echo $(pop) # b
Queue (FIFO)¶
queue=()
enqueue() { queue+=("$1"); }
dequeue() {
local front="${queue[0]}"
queue=("${queue[@]:1}")
echo "$front"
}
enqueue "a"
enqueue "b"
enqueue "c"
echo $(dequeue) # a
echo $(dequeue) # b
Try It¶
-
Basic array operations:
-
Iterate with index:
-
Associative array:
-
Array from command:
Summary¶
| Operation | Indexed Array | Associative Array |
|---|---|---|
| Declare | arr=() | declare -A arr |
| Assign | arr[0]="val" | arr[key]="val" |
| Access | ${arr[0]} | ${arr[key]} |
| All values | ${arr[@]} | ${arr[@]} |
| All keys | ${!arr[@]} | ${!arr[@]} |
| Length | ${#arr[@]} | ${#arr[@]} |
| Append | arr+=("val") | arr[key]="val" |
| Delete | unset arr[0] | unset arr[key] |
Best practices:
- Always quote:
"${arr[@]}" - Use
declare -Afor associative arrays - Check existence with
[[ -v arr[key] ]] - Use
mapfile -tto read files - Associative arrays require Bash 4.0+