If you’re working with a large amount of data in your Bash scripts, arrays will make your life a lot easier. Some people get intimidated by the syntax. But once learned, it will make your scripts more powerful, with fewer variables to think about.
Declaring an array
Arrays in Bash let you store multiple pieces of data in a single variable, much like a Python list. This makes them powerful tools for managing sets of related values such as filenames, usernames, configuration options, or command-line arguments.
Unlike many other programming languages, Bash doesn’t require you to declare an array type explicitly. You simply assign values using specific syntax, and Bash knows it’s an array. The declaration method varies depe…
If you’re working with a large amount of data in your Bash scripts, arrays will make your life a lot easier. Some people get intimidated by the syntax. But once learned, it will make your scripts more powerful, with fewer variables to think about.
Declaring an array
Arrays in Bash let you store multiple pieces of data in a single variable, much like a Python list. This makes them powerful tools for managing sets of related values such as filenames, usernames, configuration options, or command-line arguments.
Unlike many other programming languages, Bash doesn’t require you to declare an array type explicitly. You simply assign values using specific syntax, and Bash knows it’s an array. The declaration method varies depending on the array type (covered later.)
To declare an indexed array, which is the most common type of array, you simply type the name, an equal sign, and parentheses.
arr=()
That’s it. You just declared an empty array. You can see its elements using the echo command, like this:
echo $arr
Since there are no elements, you won’t see anything except a blank line. You can assign values to the array in the same line. To do that, type space-separated elements inside the parentheses.
fruits=("apple" "banana" "cherry")
Each space-separated value becomes an element of the array. You can verify it with:
echo "${fruits[@]}"
You can also declare an empty array and add elements later.
fruits=()fruits+=("apple")fruits+=("banana" "cherry")
Printing the array will display the newly added elements.
This approach is handy if you need to populate the array dynamically. You can also assign individual elements by index.
fruits[0]="apple"fruits[1]="banana"fruits[2]="cherry"
Another way you can declare an array is by using the declare built-in to explicitly define an indexed array.
declare -a colors=("red" "green" "blue")
This makes it clear to others that ‘colors’ is intended as an array, which can be useful in larger scripts. To confirm whether a Bash variable is an array (and what kind), use the declare -p command.
This is particularly useful when debugging scripts.
Looping through an array
Once you’ve declared an array, you’ll usually want to do something with its elements: print them, process them, or pass them to commands. In Bash, there are several ways to loop through arrays, and understanding these approaches is key to writing flexible, bug-free scripts.
The most common way to iterate through every element in an array is with a simple Bash for loop.
fruits=("apple" "banana" "cherry")for fruit in "${fruits[@]}"; do echo "I like $fruit"done
This is great for going through the values. But what if you need the indices too? For that, you can use a C-style for loop, like this:
for ((i=0; i<${#fruits[@]}; i++)); do echo "Fruit #$i is ${fruits[$i]}"done
This is ideal if you need both position and value. To get just the indices, you can use the special expansion ${!array[@]}, like this:
for index in "${!fruits[@]}"; do echo "Index $index = ${fruits[$index]}"done
This technique is also handy when the array isn’t sequential (for example, if some elements were removed). If your array comes from a command’s output, a while read loop can be more efficient or cleaner.
printf '%s\n' "${lines[@]}" | while read -r file; do echo "Processing $file"done
This approach is excellent when reading data dynamically from commands or files. Another cool trick is that you can traverse multiple arrays together. Here’s an example:
names=("Alice" "Bob" "Charlie")ages=(25 30 35)for ((i=0; i echo "${names[$i]} is ${ages[$i]} years old"done
When looping multiple arrays together, always ensure they have the same length.
Different types of arrays in Bash
Bash arrays come in a few varieties, and understanding their differences helps you choose the right tool for your script. Bash supports two main array types:
- Indexed arrays: standard lists indexed by numbers.
- Associative arrays: key-value pairs indexed by strings.
There’s also a special type worth noting called sparse arrays, where the numeric indices aren’t sequential. Let’s go through each type.
Indexed arrays
Indexed arrays are the most common type, perfect when you want to store ordered lists such as filenames, user IDs, or numbers. Each element is identified by an integer index starting at 0.
fruits=("apple" "banana" "cherry")echo "${fruits[0]}"echo "${fruits[1]}"
You can view all elements at once or check the number of elements:
echo "${fruits[@]}"echo "${#fruits[@]}"
Indexed arrays are useful when you have a list with a natural order, or you want to iterate through results from commands.
Associative arrays
Associative arrays act like dictionaries or hash maps in many other languages. They let you assign values to string keys instead of numeric indices.
declare -A capitals=( [France]="Paris" [Italy]="Rome" [Japan]="Tokyo")echo "${capitals[France]}"
You can loop through them easily:
for country in "${!capitals[@]}"; do echo "$country → ${capitals[$country]}"done
Note that the order of keys in associative arrays is undefined. If order matters, you’ll need to sort them manually. Associative arrays are useful when you need to map relationships or handle JSON format data.
Sparse arrays
Sparse arrays are a lesser-known but interesting feature. They’re indexed arrays with gaps in their numbering. You can assign elements to arbitrary indices. Bash doesn’t require them to be sequential.
numbers=()numbers[2]=200numbers[10]=1000numbers[42]=4200echo "${!numbers[@]}"
Accessing unset indices will return nothing:
echo "${numbers[5]}"
You can still loop through existing elements safely. If you have a large data set where not every index is used, or are working with results that naturally have “holes”, then the sparse feature can often be useful.
Accessing, modifying, and deleting array elements
Once you’ve declared and populated an array, the next step is to learn how to get values out, update them, and remove them when needed. Working with array elements in Bash is straightforward, but there are a few subtle behaviors worth remembering.
You can access an element by its index (for indexed arrays) or key (for associative arrays.) For indexed arrays:
fruits=("apple" "banana" "cherry")echo "${fruits[0]}"echo "${fruits[2]}"
For associative arrays:
declare -A capitals=( [France]="Paris" [Italy]="Rome" [Japan]="Tokyo")echo "${capitals[Japan]}"
In both cases, if the index or key doesn’t have a value, you get an empty string as an output. If you want to access all elements or indices at once, there are some special syntaxes. Here’s a cheatsheet you can follow.
| Expansion Syntax | Description |
|---|---|
| ${array[@]} | All values |
| ${!array[@]} | All indices or keys |
| ${#array[@]} | Number of elements |
| ${array[*]} | All values (merged into a string) |
Always quote your expansions: "${array[@]}". Unquoted expansions can break when elements contain spaces or wildcards.
To modify an array element, simply reassign it:
fruits[1]="blackberry"echo "${fruits[1]}"fruits[1]="blueberry"echo "${fruits[1]}"
You can also append new elements:
fruits+=("dragonfruit")
For associative arrays, you reassign values to keys.
capitals["France"]="Paris"echo "${capitals[France]}"capitals["France"]="Marseille"echo "${capitals[France]}"
Reassigning a value overwrites the old one, so be careful when performing it.
To delete an element, you can use the unset command. It can remove specific elements or the entire array.
unset 'fruits[1]'echo "${fruits[@]}"
To remove multiple elements:
unset 'fruits[0]' 'fruits[2]'
To delete the whole array, simply pass the array name:
unset fruits
The same is for associative arrays. Use the unset command and the key (instead of the index) to remove that element.
unset 'capitals[France]'
If you want to modify or remove multiple values, using a for loop to iterate through the array is a good idea.
Some advanced array tricks
By now, you know how to declare, loop through, and manipulate arrays. However, Bash can do a lot more with them. Let’s look at a few advanced array techniques that can make your scripts smarter and easier to maintain.
Slicing
You can extract subsets of arrays using slice syntax.
${array[@]:start:length}
Here, start refers to the first element in the slice, while length refers to how many elements you want to keep in the subset. Note that Bash arrays have 0-based indexing. Example:
numbers=(10 20 30 40 50)echo "${numbers[@]:1:3}"
We have the middle three elements since we sliced starting from index one. This is useful when you want to process a portion of the results from a command.
Copying and combining
Copying an array simply requires you to assign the array elements to another new array.
copy=("${fruits[@]}")
Bash copies arrays by value, not by reference. So, modifying ‘copy’ won’t affect the original.
To merge two or more arrays into one, you pass their elements to a new array using the expansion syntax.
numbers=(1 2 3)more_numbers=(4 5 6)combined=("${numbers[@]}" "${more_numbers[@]}")echo "${combined[@]}"
Sorting
Sorting an array means rearranging it in a specific order. This could be numerically or alphabetically (depending on the element type,) ascending or descending. Bash doesn’t have a built-in sort function, but it’s easy to achieve with command substitution and the sort command.
fruits=("banana" "apple" "cherry" "date")IFS=$'\n' sorted=($(sort unset IFSecho "${sorted[@]}"
Here, the sort command sorts the elements alphabetically. IFS=$'\n' ensures elements containing spaces aren’t split incorrectly. We store the sorted output into a new array.
Similarly, we can do reverse sorting as well.
IFS=$'\n' sorted=($(sort -r unset IFS
In the case of numerical data, you can use sort -n.
numbers=(42 5 19 100 3)IFS=$'\n' sorted_nums=($(sort -n unset IFSecho "${sorted_nums[@]}"
Removing duplicates
A classic problem. Remove any duplicate items in the array so that all remaining elements are unique. We can take help from the sort command again.
numbers=(1 2 2 3 4 3 5)unique=($(printf "%s\n" "${numbers[@]}" | sort -u))echo "${unique[@]}"
This approach works by printing all elements, sorting them, and removing duplicates with -u. However, this method is order-dependent. It sorts your array in the process. If you need to keep the original order, you’ll have to loop and track seen elements manually.
Filtering arrays
The last trick I’d like to cover is filtering elements from an array. We’ll do this using pattern matching and parameter expansion.
files=("data.txt" "image.png" "notes.txt" "script.sh")txt_files=()for f in "${files[@]}"; do [[ $f == *.txt ]] && txt_files+=("$f")doneecho "${txt_files[@]}"
This trick is simple but powerful when handling mixed file lists or datasets.
With that, you should have a good grasp on how to use arrays in Bash to manipulate your data. This will help you write better scripts. You can get started by going through some example Bash scripts.