100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Bash

Arrays in Depth

A thorough look at Bash indexed arrays: declaration, expansion pitfalls, slicing, appending, iteration, and the differences between @ and * expansions that trip up even experienced scripters.

Advanced FundamentalsAdvanced10 min readJul 10, 2026
Analogies

Declaring and Populating Indexed Arrays

Bash indexed arrays are declared implicitly by assignment, e.g. fruits=(apple banana cherry), or explicitly with declare -a; indices are not required to be contiguous, so you can assign fruits[10]=mango and leave gaps, since Bash arrays are technically sparse. Elements are accessed with ${array[index]}, the full array with ${array[@]} or ${array[*]}, and new elements are appended safely with array+=(newitem) rather than manually tracking the next index.

🏏

Cricket analogy: A batting order lineup declared as batsmen=(Rohit Gill Kohli Rahul) mirrors an indexed array's initial population, and a sparse array with gaps is like a squad list where jersey numbers 4 and 18 are reserved but currently unassigned to any player.

bash
#!/usr/bin/env bash
set -euo pipefail

# Implicit declaration
fruits=(apple banana cherry)

# Explicit declaration
declare -a scores
scores=(90 85 78)

# Sparse assignment
fruits[10]="mango"

echo "${fruits[1]}"        # banana
echo "${#fruits[@]}"       # 4 (element COUNT, not highest index)
echo "${!fruits[@]}"       # 0 1 2 10  (the actual indices present)

# Safe append
fruits+=("dragonfruit")
echo "${fruits[@]}"

@ vs * Expansion and Word Splitting

"${array[@]}" expands each element as a separate, individually-quoted word — the only correct way to iterate over an array whose elements may contain spaces — whereas "${array[*]}" joins all elements into a single string separated by the first character of $IFS, which is almost never what you want in a for loop. Dropping the quotes on either form reintroduces word splitting and glob expansion on every element, defeating the purpose of using an array in the first place.

🏏

Cricket analogy: "${array[@]}" is like calling each fielder onto the ground individually by name for a team photo, each standing distinctly, while "${array[*]}" is like squeezing the whole team into one blurred group huddle where individual players are no longer distinguishable.

Always iterate with for item in "${array[@]}" (quoted, with @). Using "${array[*]}" in a for loop, or leaving either form unquoted, is one of the most common Bash array bugs — it silently breaks on elements containing spaces and can turn one array element into several loop iterations or vice versa.

Slicing, Deleting, and Common Operations

Array slicing with ${array[@]:offset:length} extracts a subset of elements starting at offset for length elements, mirroring substring slicing syntax on strings; unset array[index] removes a single element (leaving a gap in the indices, since arrays are sparse) while unset array removes the entire array. Passing an array to a function requires either using a nameref (local -n ref=$1) in Bash 4.3+ or explicitly re-expanding "$@" after positional-parameter assignment, since Bash cannot pass arrays by value as a single function argument the way scalar variables are passed.

🏏

Cricket analogy: ${array[@]:2:3} pulling three players starting from the third batting position mirrors slicing a specific stretch of the batting order for a middle-overs analysis, without touching the rest of the lineup.

bash
servers=(web1 web2 db1 db2 cache1 cache2)

# Slicing: offset:length
echo "${servers[@]:2:2}"    # db1 db2

# Removing one element (leaves a sparse gap)
unset 'servers[0]'
echo "${servers[@]}"        # web2 db1 db2 cache1 cache2

# Passing an array to a function via nameref (Bash 4.3+)
summarize() {
  local -n ref=$1
  echo "Count: ${#ref[@]}, First: ${ref[0]:-none}"
}
summarize servers
  • Bash indexed arrays are sparse: indices need not be contiguous, and ${#array[@]} counts elements present, not the highest index.
  • Declare arrays implicitly with name=(a b c) or explicitly with declare -a; append safely with array+=(item).
  • Always use "${array[@]}" (quoted, @) to iterate — it preserves each element as a separate word even with embedded spaces.
  • "${array[*]}" joins all elements into one string using $IFS's first character, which is rarely what you want.
  • ${array[@]:offset:length} slices a subrange of elements, mirroring string substring syntax.
  • unset 'array[i]' removes a single element and leaves a gap; unset array removes the whole array.
  • Pass arrays into functions using a nameref (local -n ref=$1) since Bash cannot pass arrays by value as a single argument.

Practice what you learned

Was this page helpful?

Topics covered

#Bash#AdvancedBashScriptingStudyNotes#DevOps#ArraysInDepth#Arrays#Depth#Declaring#Populating#DataStructures#StudyNotes#SkillVeris