Bash sort array according to length of elements

arraybashshell-scriptsort

Given an array of strings, I would like to sort the array according to the length of each element.

For example…

    array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
    )

Should sort to…

    "the longest string in the list"
    "also a medium string"
    "medium string"
    "middle string"
    "short string"
    "tiny string"

(As a bonus, it would be nice if the list sorted strings of the same length, alphabetically. In the above example medium string was sorted before middle string even though they are the same length. But that's not a "hard" requirement, if it over complicates the solution).

It is OK if the array is sorted in-place (i.e. "array" is modified) or if a new sorted array is created.

Best Answer

If the strings don't contain newlines, the following should work. It sorts the indices of the array by the length, using the strings themselves as the secondary sort criterion.

#!/bin/bash
array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
)
expected=(
    "the longest string in the list"
    "also a medium string"
    "medium string"
    "middle string"
    "short string"
    "tiny string"
)

indexes=( $(
    for i in "${!array[@]}" ; do
        printf '%s %s %s\n' $i "${#array[i]}" "${array[i]}"
    done | sort -nrk2,2 -rk3 | cut -f1 -d' '
))

for i in "${indexes[@]}" ; do
    sorted+=("${array[i]}")
done

diff <(echo "${expected[@]}") \
     <(echo "${sorted[@]}")

Note that moving to a real programming language can greatly simplify the solution, e.g. in Perl, you can just

sort { length $b <=> length $a or $a cmp $b } @array
Related Question