1. Introduction

Bash arrays can store multiple values in a single variable, providing an efficient way to organize data. Further, reading the last element of an array is a common practice. For example, in the Linux operating system, we might want to read the last entry from the system log files to monitor recent system activities.

In general, there are two types of arrays: indexed and associative. Index arrays enable us to access elements using numerical indices starting from 0 (zero-based). On the other hand, we can access associative arrays using keys.

In this tutorial, we’ll focus on indexed arrays since determining the last element of associative arrays can be more complex as it relies on the specific implementation.

In particular, *we’ll discuss several methods to read the last element of an array such as standard array indexing, negative array indexing, array slicing, a while loop, the awk, and the sed commands*.

2. Understanding the Scenario

If we know the array length, we can easily read the last element by providing its index. Since the indexed arrays use zero-based indexing, the index of the last element will always be array_length – 1.

For example, if we have an array with five elements, the index of the last element would be 4:

$ my_array=(one two three four five)
$ last_element=${my_array[4]}
$ echo "The 5th element is: "${last_element}""
The 5th element is: five

In this Bash code, we initialized a variable my_array with five elements. Next, we read the last element using index 4 (actually the fifth, starting from 0). Additionally, the $() operator denotes command substitution, which in this case stores the last index value in the variable last_element. Lastly, we use the echo command to confirm that we’ve read the last element correctly.

However, accessing the last element can become fairly challenging if the array length is unknown. So, let’s see some comprehensive solutions to the problem.

3. Using Array Indexing

As we saw, array indexing can access the individual elements of an array by specifying their unique index number:

$ my_array=(one two three four five)
$ array_size=${#my_array[@]}
$ last_index=$(( array_size-1))
$ last_element=${my_array[$last_index]}
$ echo "The last element is: $last_element"
The last element is: five

Here, my_array[@] refers to all elements of my_array, and # returns the array length. As array indices are zero-based, subtracting 1 from the array size gives the index of the last element.

Hence, ${my_array[$last_index]} retrieves the value of the last element of the array and stores it into a new variable last_element.

4. Using Negative Array Indexing

Negative array indexing reads array elements from the end instead of the beginning:

$ my_array=(one two three four five) 
$ last_element=${my_array[-1]}
$ echo "The last element is: $last_element"
The last array element is: five

Using the -1 index gets the last array element by starting from the array end in reverse.

Critically, while negative array indexing is supported in popular shells like Bash, compatibility issues might occur especially when working on older or alternate versions. So, it’s advisable to check the compatibility when implementing this method.

5. Using Array Slicing

Array slicing is useful for extracting a specific element or group of elements from an array.

While there are more complex variants, one syntax involves first specifying an array that is to be expanded, followed by a colon, and then the starting index of the substring:

$ my_array=(one two three four five)
$ last_element="${my_array[@]: -1}"
$ echo "The last element is: $last_element"

Here, ${my_array[@]} expands to all elements of my_array, essentially representing its entire content. The colon (:) followed by -1 is a substring expansion which indicates that the substring should start from the last element of the expanded content and continue to the end. In other words, we slice the array from its last element to the end.

6. Using a while Loop

A while loop enables repeated execution of a task until it meets a desired condition:

$ my_array=(one two three four five)
$ while [ ${#my_array[@]} -gt 1 ]; do
    my_array=("${my_array[@]:1}")
done
$ last_element=${my_array[0]}
$ echo "The last element is: $last_element"

The condition ${#my_array[@]} -gt 1 keeps executing until the elements in my_array are greater than 1. Next, ${my_array[@]:1} slices the array on each iteration and stores the updated elements again in my_array. When the while loop control statement becomes false, we’re left with only the last element which we can read using ${my_array[0]}.

Caution is needed as this while loop recursively deletes the first element of the array until we’ve only the last element left. So, we should copy the array beforehand, as the rest of the original array will be deleted. To avoid losing the integrity of the array, the original array can be copied to a different variable.

7. Using the awk Command

The main uses of the awk command are pattern matching, data extraction, and manipulation.

In our case, we use the awk command to read the last element of the array by first converting the entire array into a single string and then extracting the last field of that string:

$ my_array=(one two three four five)
$ last_element=$(echo "${my_array[@]}" | awk '{print $NF}')
$ echo "The last element is: $last_element"

Within the command substitution syntax, we first print the entire array. Next, we use the pipe (|) operator to pass the output on its left side as an input to the awk command on its right side. AWK then treats the data as a string separated by spaces.

Finally, the expression ‘{print $NF}’ retrieves the last field of the string, which corresponds to the last element of the array, and then prints it.

Importantly, there are no spaces within these elements. However, if spaces were present, the output may not be as expected:

$ my_array=("Hello World", "abc 123", "Welcome to Baeldung")
$ last_element=$(echo "${my_array[@]}" | awk '{print $NF}')
$ echo "The last element is: $last_element"
The last element is: Baeldung

Here, the last element of an array is “Welcome to Baeldung” but the output shows only its last word.

In such cases, we can modify the field separator according to the array and amend the code.

8. Using the sed Command

The sed command which stands for stream editor, is useful for processing and altering textual data. Thus, it can perform various text transformations.

So, we can use sed to filter out the last element of the array by first turning it into text:

$ my_array=(one two three four five)
$ last_element=$(echo "${my_array[@]}" | sed 's/.* \([^ ]*\)$/\1/')
$ echo "Last element: $last_element"

Here, ${my_array[*]} concatenates all elements of my_array as a single string with spaces between them, and echo prints this string. Next, the sed command uses this string as an input provided by the | operator. Lastly, the ‘s/.* \([^ ]*\)$/\1/’) expression locates the last space in the string and extracts the word after it.

Similar to awk, because the sed command treats the entire array as a string, we need to ensure there are no spaces between the elements to get the desired results. Otherwise, we’d need to modify the regular expression accordingly.

9. Conclusion

In this article, we discussed standard array and negative array indexing, array slicing, and while loops, as well as the awk and sed commands to read the last element of an indexed array.

While all methods can read the last element, negative array indexing usually provides a better and more concise solution by effectively reading the array’s elements in reverse order.