readarray -t array < <(
for str in "${array[@]}"; do
printf '%d\t%s\n' "${#str}" "$str"
done | sort -k 1,1nr -k 2 | cut -f 2- )
This reads the values of the sorted array from a process substitution.
The process substitution contains a loop. The loop output each element of the array prepended by the element's length and a tab character in-between.
The output of the loop is sorted numerically from largest to smallest (and alphabetically if the lengths are the same; use -k 2r in place of -k 2 to reverse the alphabetical order) and the result of that is sent to cut which deletes the column with the string lengths.
Sort test script followed by a test run:
array=(
"tiny string"
"the longest string in the list"
"middle string"
"medium string"
"also a medium string"
"short string"
)
readarray -t array < <(
for str in "${array[@]}"; do
printf '%d\t%s\n' "${#str}" "$str"
done | sort -k 1,1nr -k 2 | cut -f 2- )
printf '%s\n' "${array[@]}"
$ bash script.sh
the longest string in the list
also a medium string
medium string
middle string
short string
tiny string
This assumes that the strings do not contain newlines. On GNU systems with a recent bash, you can support embedded newlines in the data by using the nul-character as the record separator instead of newline:
readarray -d $'\0''' -t array < <(
for str in "${array[@]}"; do
printf '%d\t%s\0' "${#str}" "$str"
done | sort -z -k 1,1nr -k 2 | cut -z -f 2- )
Here, the data is printed with trailing \0 in the loop instead of newlines, the sort and cut reads nul-delimited lines through their -z GNU options and readarray finally reads the nul-delimited data with -d $'\0'''.