Skip to main content

Bash Arrays - Indexed and Associative Arrays Complete Guide

• 8 min read
bash arrays data structures loop iteration

Quick Answer: What Are Bash Arrays?

Bash arrays store multiple values in a single variable. Create an indexed array with array=(val1 val2 val3), then access elements with ${array[0]}. For key-value pairs, use associative arrays: declare -A map; map[key]=value.

Quick Comparison: Array Storage Methods

MethodBest ForComplexityUse Case
Indexed arraysOrdered listsSimpleProcessing files, usernames, items
Associative arraysKey-value pairsModerateConfiguration, lookups, dictionaries
Array slicingPartial extractionSimpleWorking with subsets
String splittingParsing inputSimpleBreaking apart delimited data

Bottom line: Use indexed arrays for lists, associative arrays for key-value data.


Arrays are essential for storing multiple values in Bash. This guide covers indexed arrays and associative arrays with practical examples for real-world scripting.

Table of Contents

  1. Indexed Arrays
  2. Associative Arrays
  3. Array Operations
  4. Looping Through Arrays
  5. Array Functions
  6. Best Practices
  7. Frequently Asked Questions

Indexed Arrays

Indexed arrays store values in a numbered list, starting from position 0. This is the most common array type in Bash and works perfectly for ordered data.

Creating Indexed Arrays

There are three ways to create indexed arrays, each useful in different situations:

# Method 1: Space-separated values (most common)
fruits=(apple banana orange)

# Method 2: Separate assignments
colors[0]="red"
colors[1]="green"
colors[2]="blue"

# Method 3: Using declare (explicit)
declare -a numbers=(1 2 3 4 5)

Method 1 is the cleanest and most readable. When you write fruits=(apple banana orange), Bash automatically creates an array with three elements. Method 2 is useful when you’re building an array dynamically. Method 3 makes it explicit that you’re creating an array, which can be useful for code clarity.

Accessing Elements

Retrieve elements using the array name and the index in square brackets. Remember that numbering starts at 0, not 1—that catches a lot of beginners.

fruits=(apple banana orange)

echo ${fruits[0]}       # Output: apple
echo ${fruits[1]}       # Output: banana
echo ${fruits[2]}       # Output: orange
echo ${fruits[-1]}      # Output: orange (last element, Bash 4.3+)

The ${fruits[0]} syntax retrieves the first element. Use negative indices (like [-1]) to access from the end—this requires Bash 4.3 or later. The braces are important when accessing array elements; without them, Bash might misinterpret your intentions.

Array Length

To find how many elements your array contains, use the # operator with [@] to reference all elements. This is essential when you need to loop through an array or check if it has items.

fruits=(apple banana orange)
echo ${#fruits[@]}      # Output: 3 (number of elements)
echo ${#fruits[*]}      # Output: 3 (alternative)
echo ${#fruits[0]}      # Output: 5 (length of first element "apple")

Notice the difference: ${#fruits[@]} gives you the count of elements, while ${#fruits[0]} gives you the length of the first element’s string. The [@] syntax means “all elements” and is the standard way to get array length.

Adding Elements

To add elements to an existing array, use the += operator with another array in parentheses. This appends new elements to the end.

fruits=(apple banana)
fruits+=(orange)        # Append to array
echo ${fruits[@]}       # Output: apple banana orange

This is the idiomatic way to extend arrays. You can also add single elements by assigning directly to a new index: fruits[3]="grape", but the += syntax is cleaner for multiple additions.

Array Slicing

Extract a portion of an array using the syntax ${array[@]:start:length}. This is useful when you need to work with a subset of elements without modifying the original array.

array=(a b c d e f)
echo ${array[@]:0:3}    # Output: a b c (first 3 elements)
echo ${array[@]:2:2}    # Output: c d (2 elements starting at index 2)

The first number is the starting index (0-based), and the second is how many elements to extract. This pattern is perfect for pagination or processing array subsets.


Associative Arrays

Associative arrays work like dictionaries or hash maps—they store values paired with keys instead of numeric indices. This is perfect for storing configuration, metadata, or any data where you want to look up values by name rather than position. Note: Associative arrays require Bash 4 or later.

Creating Associative Arrays

You must declare an associative array before using it, unlike indexed arrays which can be created on the fly.

# Declare associative array
declare -A person

# Add elements
person[name]="John"
person[age]="30"
person[city]="New York"

The declare -A tells Bash you’re creating an associative array. Then you assign values using descriptive keys instead of numbers. This makes your code much more readable than something like array[0]="John" and array[1]="30".

Accessing Elements

Retrieve values from an associative array the same way you would from an indexed array—using square brackets with the key name.

declare -A person=(
  [name]="John"
  [age]="30"
  [city]="New York"
)

echo ${person[name]}    # Output: John
echo ${person[age]}     # Output: 30

The key difference is that you’re using meaningful labels (name, age) instead of numbers. This makes the code far more maintainable because anyone reading it immediately understands what each value represents.

Array Keys and Values

Sometimes you need to iterate over all keys or values in an associative array. The ! prefix gives you the keys, while [@] alone gives you the values.

declare -A config=(
  [host]="localhost"
  [port]="8080"
  [debug]="true"
)

# Get all keys
echo ${!config[@]}      # Output: host port debug

# Get all values
echo ${config[@]}       # Output: localhost 8080 true

This is essential when you’re looping through a configuration array or exporting all settings. The ${!array[@]} syntax extracts just the keys, which you can then use to look up values in a loop.

Check if Key Exists

Before accessing a key in an associative array, you might want to verify it exists. Use the -v test to check if a key is set.

declare -A user=([name]="Alice")

if [[ -v user[name] ]]; then
  echo "Key exists"
fi

This prevents errors from trying to access non-existent keys. The -v operator checks if a variable is set, and it works with array elements too.

When to Use Indexed vs Associative Arrays

Use indexed arrays when:

  • You have an ordered list of items
  • You’re processing multiple files, users, or similar items
  • Position in the list matters
  • You need simple, fast iteration

Use associative arrays when:

  • You want to access values by meaningful names (not numbers)
  • You’re storing configuration settings or metadata
  • Keys are more important than order
  • You’re building a dictionary or lookup table

Array Operations

Remove Elements

To delete an element from an array, use the unset command. However, this leaves a gap in the indices—the array becomes “sparse.” If you need to compact the array, you can reassign it to itself.

array=(a b c d e)

# Remove element at index 2
unset array[2]
echo ${array[@]}        # Output: a b d e (sparse array)

# Reindex array (removes gaps)
array=(${array[@]})
echo ${array[@]}        # Output: a b d e (normal array)

The first approach is faster if you don’t mind gaps. The second approach creates a clean, reindexed array if you need contiguous indices.

Find Element

To search for a specific value in an array, loop through the indices and compare. This is straightforward but useful when you need to know where something is.

array=(apple banana orange)

for i in "${!array[@]}"; do
  if [[ ${array[$i]} = "banana" ]]; then
    echo "Found at index $i"
  fi
done

The ${!array[@]} gives you all the indices, which you can then use to check each value. This pattern is essential when you need to find positions or verify that an item exists.

Reverse Array

To reverse an array, loop through it backwards (from the last index to the first) and collect the elements into a new array.

array=(1 2 3 4 5)
reverse=($(for ((i=${#array[@]}-1; i>=0; i--)); do echo ${array[$i]}; done))
echo ${reverse[@]}      # Output: 5 4 3 2 1

This creates a new array with elements in reverse order. You could also use tac (reverse of cat) with the array as input, but the loop approach is portable and clear.


Looping Through Arrays

Iterating through arrays is one of the most common operations. Bash offers several ways to loop, each useful in different situations.

For Loop (Values)

The simplest loop iterates through each value in the array. Each iteration gets one element assigned to a variable.

fruits=(apple banana orange)

for fruit in "${fruits[@]}"; do
  echo "Fruit: $fruit"
done

Use "${fruits[@]}" with quotes to preserve values that contain spaces. Without quotes, any spaces in array elements would cause them to be split into multiple loop iterations.

For Loop with Index

When you need to know the position of each element as well as its value, use the index loop. This is useful when you need both the index and the value, or when you’re working with associative array keys.

fruits=(apple banana orange)

for i in "${!fruits[@]}"; do
  echo "[$i] = ${fruits[$i]}"
done

# Output:
# [0] = apple
# [1] = banana
# [2] = orange

The "${!fruits[@]}" syntax (with the !) gives you the indices instead of the values. This is essential when you need to track positions or when working with sparse arrays.

While Loop

A while loop with a counter is useful when you need more control over iteration, such as skipping elements or exiting early.

array=(1 2 3 4 5)
i=0

while [[ $i -lt ${#array[@]} ]]; do
  echo ${array[$i]}
  ((i++))
done

This approach is less common than for loops for simple array iteration, but it’s powerful when you need conditional logic or want to modify the counter in complex ways.


Array Functions

Join Array Elements

Converting an array to a single string with a delimiter is useful for creating CSV output or logging comma-separated values. Use the IFS (Internal Field Separator) variable to control the joining character.

array=(one two three)
IFS=','
echo "${array[*]}"      # Output: one,two,three

The ${array[*]} syntax (without the @) uses the first character of IFS as a delimiter between elements. This is perfect for creating CSV lines or comma-separated output.

Count Occurrences

To count how many times a specific value appears in an array, loop through and increment a counter when you find a match.

array=(a b c a b a)
target="a"
count=0

for element in "${array[@]}"; do
  [[ $element = $target ]] && ((count++))
done

echo "Count: $count"    # Output: Count: 3

The && operator runs the counter increment only if the condition is true. This is a compact way to count matches without using if statements.

Remove Duplicates

When you have an array with repeated values and need to keep only unique items, use an associative array to track what you’ve already seen.

array=(apple banana apple orange banana)
declare -A seen
result=()

for item in "${array[@]}"; do
  if [[ ! -v seen[$item] ]]; then
    result+=("$item")
    seen[$item]=1
  fi
done

echo ${result[@]}       # Output: apple banana orange

This approach is efficient: use the associative array seen as a lookup table to check if you’ve already processed an item. If not, add it to the result array and mark it as seen. This preserves order while eliminating duplicates.


Quick Reference

# Create indexed array
array=(item1 item2 item3)

# Access element
echo ${array[0]}        # First element
echo ${array[-1]}       # Last element (Bash 4.3+)

# Array length
echo ${#array[@]}

# Loop through values
for item in "${array[@]}"; do echo "$item"; done

# Loop with indices
for i in "${!array[@]}"; do echo "$i: ${array[$i]}"; done

# Create associative array
declare -A map
map[key]="value"

# Access value
echo ${map[key]}

# Get all keys
echo ${!map[@]}

# Join array
IFS=',' echo "${array[*]}"

Best Practices

1. Quote Array Expansions

# Good
for item in "${array[@]}"; do
  echo "$item"
done

# Bad (fails with spaces)
for item in ${array[@]}; do
  echo "$item"
done

2. Use Descriptive Names

# Good
user_names=(alice bob charlie)
config_values=(localhost 8080 true)

# Poor
a=(alice bob charlie)
b=(localhost 8080 true)

3. Validate Array Access

array=(1 2 3)

if [[ ${#array[@]} -gt 0 ]]; then
  echo "Array has elements"
fi

4. Use Associative Arrays for Key-Value

# Good (clear intent)
declare -A settings=(
  [timeout]=30
  [retries]=3
)

# Poor (confusing)
settings=(timeout 30 retries 3)

Frequently Asked Questions

Q: What’s the difference between $@ and $*?

A: For arrays: ${array[@]} is like $@ (each element separate), ${array[*]} is like $* (concatenated).

Q: Can I have multidimensional arrays?

A: Not directly. Use associative arrays with composite keys: array["row:col"]=value.

Q: How do I copy an array?

A: copy=("${original[@]}") - Use quotes to preserve elements.

Q: Are sparse arrays supported?

A: Yes, after unset array[2], the array keeps its indices but skips deleted elements.


Next Steps

Explore related topics: