1. Overview

In this tutorial, we’ll learn how to sort arrays in Bash. We’ll begin by sorting an array of integers and floats. Then, we’ll move on to sort strings.

Finally, we’ll discuss how to sort an array that contains both numbers and strings.

2. Bash

In Bash, there is no magic built-in that can sort arrays for us. However, we can use sort to carry out the sorting.

2.1. Numbers Array

For our example, we’ll sort an array that contains even numbers:

even=( 4 14 8 32 66 12 2 90 )

Now, we numerically sort this array with sort:

IFS=$'\n' sorted=($(sort -n <<<"${even[*]}"))

Let’s break this down:

  • IFS=$’\n’ sets the Internal Field Separator to a newline, which allows us to correctly split the elements in the array
  • ${even[*]} expands the elements to a single string, separated by IFS
  • <<< is a “here-string” that passes the expanded array as input to sort
  • sort -n performs a numeric sort on the elements of the expanded array
  • sorted is a variable where the sorted contents will be stored

Here’s our complete script:

#!/bin/bash

even=(4 14 8 32 66 12 2 90)
IFS=$'\n' sorted=($(sort -n <<<"${even[*]}"))
unset IFS

for value in "${sorted[@]}"; do
  echo "$value"
done

Let’s take it for a test run:

$ ./sort.sh
2
4
8
12
14
32
66
90

Similarly, if we have an array that contains floating point numbers, the script works just as well:

#!/bin/bash
floating=(7.99 11.23 12.113 66.2435 12.12291 2.41 90.0)
...

Let’s test it out:

$ ./sort
2.41
7.99
11.23
12.113
12.12291
66.2435
90.0

2.2. Strings Array

This is all good, but what about the lexicographic (string) sort? Well, in that case, we need another approach.

Let’s say we have the following array:

fruits=("banana" "cherry" "apple" "date" "grape")

We’ll read the contents of the array, sort them, and read them into a new array fruits_sorted:

readarray -td '' fruits_sorted < <(printf '%s\0' "${fruits[@]}" | sort -z)

Let’s break this down:

  • readarray is a Bash-specific command to read a file or an input into an array variable:
    • -t trims the leading and trailing whitespaces from each line
    • -d sets the delimiter to  (null character), which reads and splits the input on null characters
    • fruits_sorted is the variable, which will contain the sorted contents
  • < feeds the sorted array into the fruits_sorted array
  • printf ‘%s\0’ “${fruits[@]} formats the elements of the array with a null delimiter (\0), which combines the contents of the array separated by \0 character
  • sort -z sorts the null-delimited string

Combining all these, we have a complete script that sorts the array and prints out the contents of the sorted array:

#!/bin/bash

fruits=("banana" "cherry" "apple" "date" "grape")
readarray -td '' fruits_sorted < <(printf '%s\0' "${fruits[@]}" | sort -z)

for fruit in "${fruits_sorted[@]}"; do
  echo "$fruit"
done

Now, let’s run this:

$ ./sort
apple
banana
cherry
date
grape

2.3. Generic Sort

In some cases, we have arrays that contain both numbers and strings. In that case, we’ll need to use the -n option with sort:

#!/bin/bash

fruits=( "banana" 30 12 199 "apple" "cherry" "date" "grape" )
readarray -td '' fruits_sorted < <(printf '%s\0' "${fruits[@]}" | sort -z -n)
...

Let’s run this:

$ ./sort.sh
apple
banana
cherry
date
grape
12
30
199

In addition, we can reverse the sort by passing the -r option to sort:

$ ./reverse_sort.sh
199
30
12
grape
date
cherry
banana
apple

3. Conclusion

In this article, we explored sorting arrays in Bash. We learned to sort number arrays as well as string arrays. Finally, we also discussed how to sort an array that contains numbers as well as strings.