Linux CLI 70 🐧 Arrays in shell scripts
#!/bin/bash
my_array=(value1 value2 value3)
my_array2=("value with space" "another value")
my_array3=()
echo ${my_array[0]}
index=1
echo ${my_array[index]}
echo ${#my_array[@]}
echo ${#my_array}
for element in "${my_array[@]}"; do
echo "$element"
done
my_array+=("new element")
my_array[3]="fourth element"
echo "${my_array[@]:1:2}"
if [ ${#my_array[@]} -eq 0 ]; then
echo "Array is empty"
fi
declare -A my_assoc_array
my_assoc_array["key1"]="value1"
echo ${my_assoc_array["key1"]}
Arrays let you store multiple values under a single variable name. Instead of juggling file1, file2, file3, you have one array files with three elements. Bash arrays are zero-indexed, flexible, and — with associative arrays — can even be keyed by strings.
Key point: Bash has indexed arrays (numbered slots) and associative arrays (named keys). Indexed arrays are declared with (), associative arrays with declare -A. Both need ${array[@]} with quotes for correct iteration.
a – Arrays in shell scripts Part 1
Arrays are used to store multiple values under a single variable name. They’re zero-indexed and declared with ().
Key facts:
- Use quotes to preserve spaces and avoid word splitting
- Use
${array[@]}in loops for correct iteration - Associative arrays (with
declare -A) allow key-value mapping - Bash does not support native multi-dimensional arrays, but can simulate them
Declaring arrays:
Arrays in bash are declared using parentheses and space-separated values:
my_array=(value1 value2 value3)
An empty array:
my_array3=()
An array with values containing spaces:
my_array2=("value with space" "another value")
Quoting elements with spaces keeps them as single elements. Without quotes, they’d be split into separate elements.
# ❌ Without quotes — becomes 4 elements
$ arr=(value with space)
$ echo ${#arr[@]}
[ 3 ]
# ✅ With quotes — stays as 1 element
$ arr=("value with space")
$ echo ${#arr[@]}
[ 1 ]
More ways to declare:
# Indexed array with explicit indices
$ arr=([0]="a" [1]="b" [2]="c")
# Sparse array (skipping indices)
$ arr=([0]="zero" [5]="five" [10]="ten")
$ echo ${#arr[@]}
[ 3 ] # only 3 elements despite high indices
# From a command's output
$ files=($(ls *.txt))
$ files=(*.txt) # better — handles spaces via glob
# From a range
$ nums=({1..10})
$ echo ${#nums[@]}
[ 10 ]
# Copy an array
$ original=(a b c)
$ copy=("${original[@]}")
Reading array elements:
$ arr=(apple banana cherry)
$ echo ${arr[0]}
[ apple ]
$ echo ${arr[1]}
[ banana ]
$ echo ${arr[-1]}
[ cherry ] # last element (bash 4.3+)
Accessing an element whose index is in a variable:
$ index=1
$ echo ${arr[index]}
[ banana ]
No $ needed inside [...] — the arithmetic context expands it.
The whole array:
$ echo ${arr[@]}
[ apple banana cherry ]
$ echo ${arr[*]}
[ apple banana cherry ]
Both print the same here. The difference shows up when you quote them:
$ arr=("hello world" "goodbye moon")
$ for x in "${arr[*]}"; do echo "[$x]"; done
[ [hello world goodbye moon] ]
$ for x in "${arr[@]}"; do echo "[$x]"; done
[ [hello world] ]
[ [goodbye moon] ]
| Form | Quoted | Result |
|---|---|---|
${arr[*]} | "${arr[*]}" | All elements as one string |
${arr[@]} | "${arr[@]}" | Each element as separate word |
Rule of thumb: Use
"${arr[@]}"almost always. Use"${arr[*]}"only when you specifically want to join elements with the first character ofIFS(usually a space).
Array length:
$ arr=(apple banana cherry)
$ echo ${#arr[@]}
[ 3 ]
$ echo ${#arr[*]}
[ 3 ]
Both give the number of elements. But ${#arr[0]} gives the length of element 0:
$ arr=("hello" "hi" "hey")
$ echo ${#arr[0]}
[ 5 ] # length of "hello"
$ echo ${#arr[1]}
[ 2 ] # length of "hi"
What about ${#arr} without an index? It gives the length of element 0 — usually not what you want.
$ arr=(apple banana cherry)
$ echo ${#arr}
[ 5 ] # length of "apple" (element 0)
$ echo ${#arr[@]}
[ 3 ] # number of elements ✅
Tip: Always use
${#arr[@]}for element count. Avoid${#arr}— it’s ambiguous.
Iterating over arrays:
for element in "${my_array[@]}"; do
echo "$element"
done
Quotes around ${my_array[@]} preserve spaces and prevent word splitting.
$ arr=("hello world" "goodbye moon")
$ for x in "${arr[@]}"; do echo "→ $x"; done
[ → hello world ]
[ → goodbye moon ]
Without quotes, spaces inside elements would split them:
$ for x in ${arr[@]}; do echo "→ $x"; done
[ → hello ]
[ → world ]
[ → goodbye ]
[ → moon ]
# ❌ wrong
Iterating with indices:
$ arr=(apple banana cherry)
$ for i in "${!arr[@]}"; do
> echo "$i: ${arr[$i]}"
> done
[ 0: apple ]
[ 1: banana ]
[ 2: cherry ]
${!arr[@]} gives all the indices of the array.
C-style iteration:
$ arr=(apple banana cherry)
$ for ((i=0; i<${#arr[@]}; i++)); do
> echo "$i: ${arr[$i]}"
> done
[ 0: apple ]
[ 1: banana ]
[ 2: cherry ]
Iterating over a sparse array:
$ arr=([0]="zero" [5]="five" [10]="ten")
$ for i in "${!arr[@]}"; do
> echo "$i: ${arr[$i]}"
> done
[ 0: zero ]
[ 5: five ]
[ 10: ten ]
C-style iteration would miss the gaps.
b – Arrays in shell scripts Part 2
Accessing array elements:
Use ${array[index]}:
echo ${my_array[0]} # element 0
echo ${my_array[index]} # element using a variable index
Negative indices (bash 4.3+):
$ arr=(a b c d e)
$ echo ${arr[-1]}
[ e ]
$ echo ${arr[-2]}
[ d ]
Iterating over arrays:
Use a for loop to process each element:
for element in "${my_array[@]}"; do
echo "$element"
done
Use quotes around ${my_array[@]} to preserve spaces and prevent word splitting.
${my_array[*]} vs ${my_array[@]}:
| Form | Behavior |
|---|---|
${arr[*]} | Joins elements into a single string (useful for passing to commands) |
${arr[@]} | Expands each element as a separate word |
$ arr=("one two" "three four")
# [*] joins — one big string
$ printf "[%s]\n" "${arr[*]}"
[ [one two three four] ]
# [@] preserves — each element separate
$ printf "[%s]\n" "${arr[@]}"
[ [one two] ]
[ [three four] ]
Passing array elements to a command:
$ files=("my file.txt" "your file.txt")
$ cat "${files[@]}"
# cat sees two arguments: "my file.txt" and "your file.txt"
$ cat "${files[*]}"
# cat sees one argument: "my file.txt your file.txt"
Use "${files[@]}" for individual files; "${files[*]}" when you specifically want them joined.
Unsetting array elements:
$ arr=(a b c d)
$ unset arr[1]
$ echo ${arr[@]}
[ a c d ] # element 1 is gone
$ echo ${!arr[@]}
[ 0 2 3 ] # indices are now sparse
Note: unset arr[1] doesn’t reindex the array — the remaining elements keep their original indices.
Clearing the whole array:
$ unset arr
$ echo ${#arr[@]}
[ 0 ]
Copying an array:
$ original=(a b c)
$ copy=("${original[@]}")
$ echo ${copy[@]}
[ a b c ]
Without the quotes and [@], you’d copy only the first element:
$ copy=$original
$ echo ${copy[@]}
[ a ] # ❌ only first element copied
Sorting array elements:
$ arr=(cherry apple banana)
$ sorted=($(printf "%s\n" "${arr[@]}" | sort))
$ echo ${sorted[@]}
[ apple banana cherry ]
Finding an element:
$ arr=(apple banana cherry)
$ needle="banana"
$ for x in "${arr[@]}"; do
> if [ "$x" = "$needle" ]; then
> echo "found"
> break
> fi
> done
[ found ]
c – Arrays in shell scripts Part 3
Appending elements:
my_array+=("new element")
The += operator adds to the end of the array.
$ arr=(a b c)
$ arr+=("d")
$ echo ${arr[@]}
[ a b c d ]
You can append multiple elements at once:
$ arr+=(e f g)
$ echo ${arr[@]}
[ a b c d e f g ]
Assigning specific indices:
my_array[3]="fourth element"
This sets or replaces the element at index 3. If index 3 doesn’t exist, it’s created — leaving any gaps as empty.
$ arr=(a b c)
$ arr[5]="sixth"
$ echo ${arr[@]}
[ a b c sixth ]
$ echo ${!arr[@]}
[ 0 1 2 5 ]
Array length:
echo ${#my_array[@]} # number of elements
$ arr=(a b c d e)
$ echo ${#arr[@]}
[ 5 ]
${#my_array} gives the length of element 0 — not what you usually want.
$ arr=("hello" "hi")
$ echo ${#arr}
[ 5 ] # length of "hello"
$ echo ${#arr[@]}
[ 2 ] # ✅ number of elements
Slicing arrays:
Use ${array[@]:offset:number} to extract a subset:
$ arr=(a b c d e)
$ echo "${arr[@]:1:2}"
[ b c ] # from index 1, take 2 elements
$ echo "${arr[@]:2}"
[ c d e ] # from index 2, take all
$ echo "${arr[@]:0:3}"
[ a b c ] # first 3
$ echo "${arr[@]: -2}"
[ d e ] # last 2 (space needed before -2)
Check if array is empty:
if [ ${#my_array[@]} -eq 0 ]; then
echo "Array is empty"
fi
Or with [[ ]]:
if [[ ${#my_array[@]} -eq 0 ]]; then
echo "Array is empty"
fi
Or use the ${arr[@]:-} idiom:
if [ -z "${arr[@]:-}" ]; then
echo "empty or unset"
fi
Associative arrays:
declare -A my_assoc_array
my_assoc_array["key1"]="value1"
echo ${my_assoc_array["key1"]}
Associative arrays use strings as keys instead of numbers. You must declare them with declare -A.
$ declare -A user
$ user[name]="Alice"
$ user[age]=30
$ user[city]="Paris"
$ echo ${user[name]}
[ Alice ]
$ echo ${user[age]}
[ 30 ]
$ echo ${user[city]}
[ Paris ]
Iterating associative arrays:
$ for key in "${!user[@]}"; do
> echo "$key: ${user[$key]}"
> done
[ name: Alice ]
[ age: 30 ]
[ city: Paris ]
${!user[@]} gives the keys; ${user[$key]} gives the value.
Checking if a key exists:
$ if [[ -v user[name] ]]; then
> echo "key exists"
> fi
[ key exists ]
Or with the older form:
$ if [ "${user[name]+exists}" ]; then
> echo "key exists"
> fi
Deleting keys:
$ unset 'user[age]'
$ echo ${!user[@]}
[ name city ]
Declaring and initializing in one line:
$ declare -A color=([red]="#FF0000" [green]="#00FF00" [blue]="#0000FF")
$ echo ${color[red]}
[ #FF0000 ]
Multi-dimensional arrays — simulated:
Bash has no native 2D arrays. You can simulate them with a naming convention:
$ declare -A matrix
$ matrix[0,0]=1
$ matrix[0,1]=2
$ matrix[1,0]=3
$ matrix[1,1]=4
$ for i in 0 1; do
> for j in 0 1; do
> printf "%s " "${matrix[$i,$j]}"
> done
> echo
> done
[ 1 2 ]
[ 3 4 ]
The key "$i,$j" is a string like "0,1" — the comma is just a separator you pick.
Alternative — array of arrays via indirect expansion:
$ row0=(1 2 3)
$ row1=(4 5 6)
$ rows=(row0 row1)
$ for r in "${rows[@]}"; do
> eval "row=(\"\${$r[@]}\")"
> echo "${row[@]}"
> done
[ 1 2 3 ]
[ 4 5 6 ]
This uses eval and indirection. It works but is fragile — for real multi-dimensional data, consider a different language or format.
More practical uses:
# Store command output in an array
$ users=($(cut -d: -f1 /etc/passwd))
$ echo ${#users[@]}
[ 45 ]
# Read lines into an array (preserves spaces)
$ readarray -t lines < file.txt
$ echo "${lines[0]}"
# Read a file into an array
$ mapfile -t lines < file.txt
# Build a CSV
$ fields=("name" "age" "city")
$ IFS=,; echo "${fields[*]}"
[ name,age,city ]
# Split a string into an array
$ IFS=, read -ra parts <<< "a,b,c,d"
$ echo ${#parts[@]}
[ 4 ]
# Join an array into a string
$ arr=(a b c)
$ IFS=,; echo "${arr[*]}"
[ a,b,c ]
Array operations summary:
| Operation | Syntax |
|---|---|
| Declare | arr=(a b c) |
| Declare empty | arr=() |
| Declare associative | declare -A map |
| Access element | ${arr[0]} |
| Access all | ${arr[@]} |
| Access indices | ${!arr[@]} |
| Count | ${#arr[@]} |
| Length of element | ${#arr[0]} |
| Append | arr+=(x) |
| Assign index | arr[3]=x |
| Slice | ${arr[@]:1:3} |
| Iterate | for x in "${arr[@]}" |
| Unset element | unset arr[1] |
| Unset all | unset arr |
Complete Example Session
# ============================================
# PART 1: DECLARING ARRAYS
# ============================================
$ my_array=(value1 value2 value3)
$ my_array2=("value with space" "another value")
$ my_array3=()
$ echo ${#my_array[@]}
[ 3 ]
$ echo ${#my_array2[@]}
[ 2 ]
$ echo ${#my_array3[@]}
[ 0 ]
# ============================================
# PART 2: ACCESSING ELEMENTS
# ============================================
$ echo ${my_array[0]}
[ value1 ]
$ index=1
$ echo ${my_array[index]}
[ value2 ]
$ echo ${my_array[-1]}
[ value3 ]
# ============================================
# PART 3: LENGTH
# ============================================
$ echo ${#my_array[@]}
[ 3 ]
$ echo ${#my_array}
[ 6 ] # length of "value1"
# ============================================
# PART 4: ITERATION
# ============================================
$ for element in "${my_array[@]}"; do
> echo "$element"
> done
[ value1 ]
[ value2 ]
[ value3 ]
$ for i in "${!my_array[@]}"; do
> echo "$i: ${my_array[$i]}"
> done
[ 0: value1 ]
[ 1: value2 ]
[ 2: value3 ]
# ============================================
# PART 5: APPEND AND ASSIGN
# ============================================
$ my_array+=("new element")
$ echo ${my_array[@]}
[ value1 value2 value3 new element ]
$ my_array[3]="fourth element"
$ echo ${my_array[@]}
[ value1 value2 value3 fourth element ]
# ============================================
# PART 6: SLICING
# ============================================
$ echo "${my_array[@]:1:2}"
[ value2 value3 ]
$ echo "${my_array[@]:2}"
[ value3 fourth element ]
$ echo "${my_array[@]: -2}"
[ value3 fourth element ]
# ============================================
# PART 7: EMPTY CHECK
# ============================================
$ arr=()
$ if [ ${#arr[@]} -eq 0 ]; then
> echo "Array is empty"
> fi
[ Array is empty ]
# ============================================
# PART 8: WITH SPACES
# ============================================
$ arr=("hello world" "goodbye moon")
$ for x in "${arr[@]}"; do echo "[$x]"; done
[ [hello world] ]
[ [goodbye moon] ]
$ for x in "${arr[*]}"; do echo "[$x]"; done
[ [hello world goodbye moon] ]
$ for x in ${arr[@]}; do echo "[$x]"; done
[ [hello] ]
[ [world] ]
[ [goodbye] ]
[ [moon] ]
# ❌ word splitting
# ============================================
# PART 9: ASSOCIATIVE ARRAYS
# ============================================
$ declare -A my_assoc_array
$ my_assoc_array["key1"]="value1"
$ my_assoc_array["key2"]="value2"
$ echo ${my_assoc_array["key1"]}
[ value1 ]
$ for key in "${!my_assoc_array[@]}"; do
> echo "$key: ${my_assoc_array[$key]}"
> done
[ key1: value1 ]
[ key2: value2 ]
# ============================================
# PART 10: SPARSE ARRAYS
# ============================================
$ arr=([0]="a" [5]="b" [10]="c")
$ echo ${#arr[@]}
[ 3 ]
$ echo ${!arr[@]}
[ 0 5 10 ]
$ for i in "${!arr[@]}"; do
> echo "$i: ${arr[$i]}"
> done
[ 0: a ]
[ 5: b ]
[ 10: c ]
# ============================================
# PART 11: COPY ARRAY
# ============================================
$ original=(a b c)
$ copy=("${original[@]}")
$ echo ${copy[@]}
[ a b c ]
$ wrong=$original
$ echo ${wrong[@]}
[ a ] # only first element
# ============================================
# PART 12: SORT ARRAY
# ============================================
$ arr=(cherry apple banana)
$ sorted=($(printf "%s\n" "${arr[@]}" | sort))
$ echo ${sorted[@]}
[ apple banana cherry ]
# ============================================
# PART 13: READ FILE INTO ARRAY
# ============================================
$ printf "line one\nline two\nline three\n" > file.txt
$ readarray -t lines < file.txt
$ echo ${#lines[@]}
[ 3 ]
$ echo "${lines[1]}"
[ line two ]
# ============================================
# PART 14: SPLIT STRING INTO ARRAY
# ============================================
$ IFS=, read -ra parts <<< "a,b,c,d"
$ echo ${#parts[@]}
[ 4 ]
$ echo "${parts[2]}"
[ c ]
# ============================================
# PART 15: JOIN ARRAY INTO STRING
# ============================================
$ arr=(a b c)
$ IFS=,; echo "${arr[*]}"
[ a,b,c ]
# ============================================
# PART 16: CHECK KEY IN ASSOC ARRAY
# ============================================
$ declare -A user
$ user[name]="Alice"
$ if [[ -v user[name] ]]; then
> echo "name exists"
> fi
[ name exists ]
# ============================================
# PART 17: UNIQUE ELEMENTS
# ============================================
$ arr=(a b a c b d)
$ unique=($(printf "%s\n" "${arr[@]}" | sort -u))
$ echo ${unique[@]}
[ a b c d ]
# ============================================
# PART 18: 2D SIMULATION
# ============================================
$ declare -A matrix
$ matrix[0,0]=1
$ matrix[0,1]=2
$ matrix[1,0]=3
$ matrix[1,1]=4
$ for i in 0 1; do
> for j in 0 1; do
> printf "%s " "${matrix[$i,$j]}"
> done
> echo
> done
[ 1 2 ]
[ 3 4 ]
# ============================================
# PART 19: FULL SCRIPT
# ============================================
$ cat > arrays.sh << 'EOF'
#!/bin/bash
my_array=(value1 value2 value3)
my_array2=("value with space" "another value")
my_array3=()
echo ${my_array[0]}
index=1
echo ${my_array[index]}
echo ${#my_array[@]}
echo ${#my_array}
for element in "${my_array[@]}"; do
echo "$element"
done
my_array+=("new element")
my_array[3]="fourth element"
echo "${my_array[@]:1:2}"
if [ ${#my_array[@]} -eq 0 ]; then
echo "Array is empty"
fi
declare -A my_assoc_array
my_assoc_array["key1"]="value1"
echo ${my_assoc_array["key1"]}
EOF
$ chmod +x arrays.sh
$ ./arrays.sh
[ value1 ]
[ value2 ]
[ 3 ]
[ 6 ]
[ value1 ]
[ value2 ]
[ value3 ]
[ value2 value3 ]
[ value1 ]
Quick Reference
Declaring Arrays
| Command | Meaning |
|---|---|
arr=(a b c) | Indexed array |
arr=() | Empty array |
arr=("a b" "c d") | With spaces (quoted) |
arr=([0]="a" [5]="b") | With explicit indices |
arr=({1..10}) | From a range |
arr=(*.txt) | From a glob |
arr=($(ls)) | From a command ⚠️ |
declare -A map | Associative array |
Accessing
| Syntax | Meaning |
|---|---|
${arr[0]} | Element at index 0 |
${arr[-1]} | Last element (bash 4.3+) |
${arr[@]} | All elements |
${arr[*]} | All as one string |
${!arr[@]} | All indices / keys |
${#arr[@]} | Number of elements |
${#arr[0]} | Length of element 0 |
Modifying
| Syntax | Meaning |
|---|---|
arr+=(x) | Append |
arr[3]=x | Set index 3 |
unset arr[1] | Delete element 1 |
unset arr | Delete entire array |
Slicing
| Syntax | Meaning |
|---|---|
${arr[@]:1:2} | 2 elements from index 1 |
${arr[@]:2} | All from index 2 |
${arr[@]: -2} | Last 2 |
${arr[@]:0:3} | First 3 |
Iteration
| Syntax | Meaning |
|---|---|
for x in "${arr[@]}" | Values |
for i in "${!arr[@]}" | Indices |
for ((i=0;i<${#arr[@]};i++)) | C-style |
Associative Arrays
| Syntax | Meaning |
|---|---|
declare -A map | Declare |
map[key]=value | Set |
${map[key]} | Get |
${!map[@]} | All keys |
${#map[@]} | Count |
[[ -v map[key] ]] | Check key exists |
unset 'map[key]' | Delete key |
Reading Files
| Command | Meaning |
|---|---|
readarray -t arr < file | File into array |
mapfile -t arr < file | Same |
IFS=, read -ra arr <<< "a,b" | Split string |
${arr[*]} vs ${arr[@]}
| Form | Unquoted | Quoted |
|---|---|---|
[*] | Splits on IFS | One string |
[@] | Splits on IFS | Separate words |
Best Practices
✅ Do This:
# Quote array expansions
for x in "${arr[@]}"; do ...; done # ✅
# Use ${#arr[@]} for count
echo ${#arr[@]} # ✅
# Copy with quotes and [@]
copy=("${original[@]}") # ✅
# Use declare -A for associative
declare -A map # ✅
# Initialize associative in one line
declare -A color=([red]="#F00") # ✅
# Use readarray for files
readarray -t lines < file.txt # ✅
# Split strings with IFS
IFS=, read -ra parts <<< "$csv" # ✅
# Use += to append
arr+=("new") # ✅
# Check key exists in assoc
[[ -v map[key] ]] # ✅
# Use globs, not ls
files=(*.txt) # ✅
❌ Don’t Do This:
# Don't iterate unquoted
for x in ${arr[@]}; do ...; done # ❌ word splitting
# Don't use ${#arr} for count
echo ${#arr} # ❌ length of element 0
# Don't assign array as scalar
copy=$original # ❌ only first element
# Don't use () for assoc
map=([key]="value") # ❌ indexed, not assoc
declare -A map=([key]="value") # ✅
# Don't use ls for file arrays
files=($(ls *.txt)) # ⚠️ breaks on spaces
files=(*.txt) # ✅
# Don't forget declare -A
map[key]=value # ❌ may be treated as index
# Don't use commas in keys
map[a,b]=1 # ⚠️ just a string key
# Don't forget quotes when slicing
echo ${arr[@]:1:2} # ⚠️ word splitting
echo "${arr[@]:1:2}" # ✅
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
Unquoted ${arr[@]} | Word splitting | Quote it |
${#arr} for count | Length of element 0 | Use ${#arr[@]} |
copy=$arr | Only first element | copy=("${arr[@]}") |
(*.txt) from ls | Breaks on spaces | arr=(*.txt) |
No declare -A | Not associative | Declare first |
| Commas in assoc keys | Just part of key | That’s fine — it’s a string |
| Missing quotes in slice | Word splitting | Quote: "${arr[@]:1:2}" |
Sparse indices with for ((i=0;...)) | Skips gaps | Use ${!arr[@]} |
Real-World Examples
1. Basic Array
#!/bin/bash
my_array=(value1 value2 value3)
echo ${my_array[0]}
[ value1 ]
2. Array with Spaces
#!/bin/bash
my_array2=("value with space" "another value")
echo "${my_array2[0]}"
[ value with space ]
3. Access with Variable Index
#!/bin/bash
my_array=(a b c)
index=1
echo ${my_array[index]}
[ b ]
4. Array Length
#!/bin/bash
my_array=(a b c d e)
echo ${#my_array[@]}
[ 5 ]
5. Iterate Values
#!/bin/bash
my_array=(one two three)
for element in "${my_array[@]}"; do
echo "$element"
done
[ one ]
[ two ]
[ three ]
6. Iterate Indices
#!/bin/bash
my_array=(one two three)
for i in "${!my_array[@]}"; do
echo "$i: ${my_array[$i]}"
done
[ 0: one ]
[ 1: two ]
[ 2: three ]
7. Append Element
#!/bin/bash
my_array=(a b c)
my_array+=("new element")
echo ${my_array[@]}
[ a b c new element ]
8. Assign by Index
#!/bin/bash
my_array=(a b c)
my_array[3]="fourth element"
echo ${my_array[@]}
[ a b c fourth element ]
9. Slice
#!/bin/bash
my_array=(a b c d e)
echo "${my_array[@]:1:2}"
[ b c ]
10. Check Empty
#!/bin/bash
my_array=()
if [ ${#my_array[@]} -eq 0 ]; then
echo "Array is empty"
fi
[ Array is empty ]
11. Associative Array
#!/bin/bash
declare -A my_assoc_array
my_assoc_array["key1"]="value1"
echo ${my_assoc_array["key1"]}
[ value1 ]
12. User Info
#!/bin/bash
declare -A user
user[name]="Alice"
user[age]=30
user[city]="Paris"
for key in "${!user[@]}"; do
echo "$key: ${user[$key]}"
done
[ name: Alice ]
[ age: 30 ]
[ city: Paris ]
13. File Array
#!/bin/bash
files=(*.txt)
for f in "${files[@]}"; do
echo "Processing: $f"
done
14. Command Output
#!/bin/bash
users=($(cut -d: -f1 /etc/passwd))
echo "User count: ${#users[@]}"
[ User count: 45 ]
15. Read File into Array
#!/bin/bash
readarray -t lines < file.txt
echo "Lines: ${#lines[@]}"
echo "First: ${lines[0]}"
16. Split CSV
#!/bin/bash
IFS=, read -ra fields <<< "name,age,city"
echo "${fields[1]}"
[ age ]
17. Join Array
#!/bin/bash
arr=(a b c)
IFS=,; echo "${arr[*]}"
[ a,b,c ]
18. Sort Array
#!/bin/bash
arr=(cherry apple banana)
sorted=($(printf "%s\n" "${arr[@]}" | sort))
echo ${sorted[@]}
[ apple banana cherry ]
19. Unique Elements
#!/bin/bash
arr=(a b a c b d)
unique=($(printf "%s\n" "${arr[@]}" | sort -u))
echo ${unique[@]}
[ a b c d ]
20. Full Script
#!/bin/bash
my_array=(value1 value2 value3)
my_array2=("value with space" "another value")
my_array3=()
echo ${my_array[0]}
index=1
echo ${my_array[index]}
echo ${#my_array[@]}
echo ${#my_array}
for element in "${my_array[@]}"; do
echo "$element"
done
my_array+=("new element")
my_array[3]="fourth element"
echo "${my_array[@]:1:2}"
if [ ${#my_array[@]} -eq 0 ]; then
echo "Array is empty"
fi
declare -A my_assoc_array
my_assoc_array["key1"]="value1"
echo ${my_assoc_array["key1"]}
Visual: Indexed vs Associative
┌──────────────────────────────────────────────┐
│ Indexed array │
│ │
│ arr=(apple banana cherry) │
│ │
│ ┌─────┬────────┬────────┐ │
│ │ 0 │ 1 │ 2 │ │
│ ├─────┼────────┼────────┤ │
│ │apple│ banana │ cherry │ │
│ └─────┴────────┴────────┘ │
│ │
│ Access: ${arr[0]} │
│ Count: ${#arr[@]} → 3 │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Associative array │
│ │
│ declare -A user │
│ user[name]=Alice │
│ user[age]=30 │
│ │
│ ┌───────┬────────┐ │
│ │ name │ Alice │ │
│ │ age │ 30 │ │
│ └───────┴────────┘ │
│ │
│ Access: ${user[name]} │
│ Keys: ${!user[@]} → name age │
│ Count: ${#user[@]} → 2 │
│ │
└──────────────────────────────────────────────┘
Visual: [*] vs [@]
┌──────────────────────────────────────────────┐
│ arr=("hello world" "goodbye moon") │
│ │
│ "${arr[*]}" → one string: │
│ [ "hello world goodbye moon" ] │
│ │
│ "${arr[@]}" → separate words: │
│ [ "hello world" ] [ "goodbye moon" ] │
│ │
│ Use [@] in loops. Use [*] for joining. │
│ │
└──────────────────────────────────────────────┘
Summary
| Operation | Syntax | Example |
|---|---|---|
| Declare | arr=(a b c) | fruits=(apple banana) |
| Empty | arr=() | arr=() |
| Assoc | declare -A map | declare -A user |
| Element | ${arr[0]} | ${fruits[0]} |
| Last | ${arr[-1]} | ${fruits[-1]} |
| All | ${arr[@]} | "${arr[@]}" |
| All as one | ${arr[*]} | "${arr[*]}" |
| Indices | ${!arr[@]} | ${!arr[@]} |
| Count | ${#arr[@]} | ${#arr[@]} |
| Length of element | ${#arr[0]} | ${#arr[0]} |
| Append | arr+=(x) | arr+=("new") |
| Set index | arr[3]=x | arr[3]="d" |
| Slice | ${arr[@]:1:2} | "${arr[@]:1:2}" |
| Iterate values | for x in "${arr[@]}" | |
| Iterate indices | for i in "${!arr[@]}" | |
| Delete element | unset arr[1] | |
| Delete all | unset arr | |
| Read file | readarray -t arr < file | |
| Split string | IFS=, read -ra arr <<< str | |
| Join | IFS=,; echo "${arr[*]}" |
Key takeaways:
- Bash arrays store multiple values under one name — zero-indexed by default
- Declare with
arr=(a b c)— quote elements with spaces - Access with
${arr[index]}— negative indices work in bash 4.3+ - Count with
${#arr[@]}— never${#arr}(that’s element 0’s length) - Iterate with
"${arr[@]}"— always quote ${arr[@]}gives separate words;${arr[*]}joins into one string- Append with
arr+=(x); assign by index witharr[3]=x - Slice with
${arr[@]:offset:length} - Associative arrays use
declare -Aand string keys - Check keys with
[[ -v map[key] ]] - Read files with
readarray -t arr < file - Split strings with
IFS=, read -ra arr <<< "$str" - Bash has no 2D arrays — simulate with composite keys like
[i,j] - Always quote array expansions — unquoted breaks on spaces
- Use globs (
arr=(*.txt)) rather than$(ls)— handles spaces correctly
Remember: Arrays are how you handle lists in bash. Declare them with (), access with ${arr[i]}, count with ${#arr[@]}, and iterate with "${arr[@]}". Use associative arrays (declare -A) when you need named keys. And quote everything — unquoted array expansion is the single most common array bug.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!