|

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] ]
FormQuotedResult
${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 of IFS (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[@]}:

FormBehavior
${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:

OperationSyntax
Declarearr=(a b c)
Declare emptyarr=()
Declare associativedeclare -A map
Access element${arr[0]}
Access all${arr[@]}
Access indices${!arr[@]}
Count${#arr[@]}
Length of element${#arr[0]}
Appendarr+=(x)
Assign indexarr[3]=x
Slice${arr[@]:1:3}
Iteratefor x in "${arr[@]}"
Unset elementunset arr[1]
Unset allunset 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

CommandMeaning
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 mapAssociative array

Accessing

SyntaxMeaning
${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

SyntaxMeaning
arr+=(x)Append
arr[3]=xSet index 3
unset arr[1]Delete element 1
unset arrDelete entire array

Slicing

SyntaxMeaning
${arr[@]:1:2}2 elements from index 1
${arr[@]:2}All from index 2
${arr[@]: -2}Last 2
${arr[@]:0:3}First 3

Iteration

SyntaxMeaning
for x in "${arr[@]}"Values
for i in "${!arr[@]}"Indices
for ((i=0;i<${#arr[@]};i++))C-style

Associative Arrays

SyntaxMeaning
declare -A mapDeclare
map[key]=valueSet
${map[key]}Get
${!map[@]}All keys
${#map[@]}Count
[[ -v map[key] ]]Check key exists
unset 'map[key]'Delete key

Reading Files

CommandMeaning
readarray -t arr < fileFile into array
mapfile -t arr < fileSame
IFS=, read -ra arr <<< "a,b"Split string

${arr[*]} vs ${arr[@]}

FormUnquotedQuoted
[*]Splits on IFSOne string
[@]Splits on IFSSeparate 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

PitfallProblemSolution
Unquoted ${arr[@]}Word splittingQuote it
${#arr} for countLength of element 0Use ${#arr[@]}
copy=$arrOnly first elementcopy=("${arr[@]}")
(*.txt) from lsBreaks on spacesarr=(*.txt)
No declare -ANot associativeDeclare first
Commas in assoc keysJust part of keyThat’s fine — it’s a string
Missing quotes in sliceWord splittingQuote: "${arr[@]:1:2}"
Sparse indices with for ((i=0;...))Skips gapsUse ${!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

OperationSyntaxExample
Declarearr=(a b c)fruits=(apple banana)
Emptyarr=()arr=()
Assocdeclare -A mapdeclare -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]}
Appendarr+=(x)arr+=("new")
Set indexarr[3]=xarr[3]="d"
Slice${arr[@]:1:2}"${arr[@]:1:2}"
Iterate valuesfor x in "${arr[@]}"
Iterate indicesfor i in "${!arr[@]}"
Delete elementunset arr[1]
Delete allunset arr
Read filereadarray -t arr < file
Split stringIFS=, read -ra arr <<< str
JoinIFS=,; 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 with arr[3]=x
  • Slice with ${arr[@]:offset:length}
  • Associative arrays use declare -A and 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!