Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 33

Bash Arrays: Indexed & Associative

Recommended resources

Hello! Welcome to your next lesson in the "Advanced Bash Scripting" module.

In our last session, we mastered manipulating individual strings using Bash's powerful parameter expansion. This is a crucial skill for performance, as it avoids creating new processes for simple text operations. Today, we'll build on that foundation to handle collections of data.

Your learning outcome for this lesson is to use indexed and associative arrays to manage collections of data in Bash scripts. This will enable you to move beyond simple variables and structure your script's data in a more organized and powerful way, which is essential for managing lists of servers, configuration settings, or processing structured data.

1. Indexed Arrays: The Ordered List

The most common type of array is an indexed array, which is essentially an ordered list of strings. Each item, or "element," is accessed by a numeric index, starting at 0. This is perfect for when you have a list of items and the order matters, or you just need to loop through a collection.

Arrays in Bash Shell Scripting Example
A simple visual representation of an indexed array, showing how string values are mapped to numeric indices starting from 0.

Declaration and Initialization

You can create an indexed array in a few ways. The most common is using parentheses ().




# An array of server hostnames
servers=("web-01" "app-01" "db-01" "db-02")




# You can also declare an empty array and add to it
files=()
files+=("/etc/hosts")
files+=("/etc/resolv.conf")

Accessing and Iterating

Accessing elements uses a syntax that builds on the parameter expansion we learned previously. The real power comes from how you expand the array to access its elements, especially when iterating.

Let's watch a video that covers the fundamentals of declaring, accessing, and iterating over indexed arrays. Pay close attention to the distinction between * and @ when expanding an array—it's a critical detail for writing robust scripts.

Arrays in Bash Explained in 7 Minutes! - Indexed, Associative, and Nested / Multi-Dimensional

The video 'Arrays in Bash Explained in 7 Minutes!' by You Suck at Programming provides a fantastic and concise introduction to indexed arrays.

Watch the first part of the video, from 00:00 to 04:37. Focus on: How to declare and initialize an array. How to access elements by index (e.g., ${servers[0]}). The difference between "${array[*]}" (one string) and "${array[@]}" (multiple elements), and why the latter is almost always what you want.

As the video highlighted, "${array[@]}" is your go-to for safely handling elements, especially those containing spaces.

Here's the summary of key operations for indexed arrays:

  • Access an element: ${array[index]}
  • Access all elements (correctly): "${array[@]}"
  • Get the array length: ${#array[@]}
  • Get all indices: ${!array[@]}
  • Append an element: array+=("new_element")
  • Remove an element: unset array[index] (Note: this leaves a "hole" in the array, it doesn't re-index the subsequent elements).

For a more detailed written reference with code examples for each of these operations, you can consult the following guide.

How to Handle Arrays in Bash Scripts

The article 'How to Handle Arrays in Bash Scripts' on OneUptime serves as an excellent reference guide.

Skim through the sections 'Indexed Arrays', 'Accessing Array Elements', and 'Modifying Arrays'. You don't need to memorize everything, but be aware of the different ways you can declare, access, and modify these arrays.

Practical Use Case: Building Dynamic Commands

As a DevOps engineer, you often need to construct commands with a variable number of arguments. Arrays are perfect for this. Instead of messy string concatenation, you can build a clean list of arguments.

Using Indexed and Associative Arrays in Bash

The article 'Using Indexed and Associative Arrays in Bash' on belief-driven-design.com has a great, practical example of this.

Read the sub-section titled '(Indexed) Building Commands'. It shows how to build an ffmpeg command dynamically. This pattern is directly applicable to tools you use, like kubectl, terraform, or aws CLI.


2. Associative Arrays: Key-Value Stores

Associative arrays work like dictionaries in Python or hashmaps in other languages. They store data in key-value pairs, where the key is a string. This is incredibly useful for storing configuration data or mapping one piece of information to another.

Important Note: Associative arrays were introduced in Bash version 4.0. While this is standard on most modern Linux systems, macOS ships with an older version of Bash by default. You can check your version with bash --version.

Declaration and Initialization

Unlike indexed arrays, you must explicitly declare an associative array using declare -A.




# Declare an associative array to store container image info
declare -A image_info




# Assign key-value pairs
image_info[name]="nginx"
image_info[version]="1.21"
image_info[registry]="docker.io"




# Or declare and initialize at once
declare -A user_roles=( [alice]="admin" [bob]="developer" [charlie]="guest" )

Accessing and Iterating

Accessing values is done via the key. The most common task is to loop through the keys to process each key-value pair.

Iterating Through a Bash Associative Array
This terminal output demonstrates the standard loop for an associative array: iterating through the keys (`!capitals[@]`) to access both the key (`country`) and its corresponding value (`capitals[\$country]`).

Let's watch a video that walks through these concepts.

Associative Arrays in Bash (AKA Key-Value Dictionaries)

The video 'Associative Arrays in Bash' by Nick Janetakis focuses entirely on this array type and includes a fantastic real-world example relevant to your work with Kubernetes.

Watch the following segments: 00:00 - 01:52: Introduction and how to declare/initialize an associative array. 01:52 - 02:53: How to access values using keys. 07:01 - 09:53: Iterating over keys and values, and the important point that the order is not guaranteed. 11:57 - 14:38: A practical example using an associative array to manage Helm chart repositories. This demonstrates how arrays can reduce duplication in your scripts.

Key takeaways on associative arrays:

  • Declaration: declare -A my_map is mandatory.
  • Access a value: ${my_map[key]}
  • Get all values: "${my_map[@]}"
  • Get all keys: "${!my_map[@]}" (This is what you'll use most often for iteration).
  • Get the count: ${#my_map[@]}
  • Check if a key exists: [[ -v my_map[key] ]]

Practical Use Case: Log Analysis

Associative arrays excel at counting occurrences. For instance, you could parse a log file and count how many times each IP address appears or how many ERROR vs. INFO messages there are.

The OneUptime article we looked at earlier has a superb example of this.

How to Handle Arrays in Bash Scripts

Let's revisit the OneUptime article for a final practical example.

Read the 'Log Analyzer' example. It shows how to use while read to process a log file line-by-line and use two associative arrays to count log levels and IP address frequencies.


Conclusion

You've now seen how to go from working with single variables to managing structured collections of data using both indexed and associative arrays. This is a significant step toward writing more sophisticated and organized automation scripts.

Key Takeaways:

  • Indexed Arrays are for ordered lists of items, accessed by number. Use them for lists of files, servers, or arguments.
  • Associative Arrays are for unordered key-value pairs, accessed by string keys. Use them for configuration, mapping data, or counting items.
  • Always quote your expansions! "${my_array[@]}" is the safe and correct way to expand an array into its elements.
  • Master the key syntax:
    • declare -A for associative arrays.
    • ${#array[@]} for length.
    • "${!array[@]}" to get all keys/indices, which is essential for iteration.

Preview of the Next Lesson:
As your scripts become more complex with loops and arrays, the chances of introducing bugs increase. How do you find them? In our next lesson, we will cover how to debug Bash scripts effectively using set -x, trap, and the shellcheck linter. This will give you the tools to diagnose and fix issues with confidence.