Linux Basic — Sorting Arrays
Sorting Arrays
Bash has no native sort() for arrays. The idiomatic pattern is “pipe the elements through sort, then capture them back with mapfile.” It’s a one-liner once you’ve seen it.
The Base Pattern
arr=(cherry apple banana)
mapfile -t sorted < <(printf '%s\n' "${arr[@]}" | sort)
echo "${sorted[@]}"
# apple banana cherry
Breakdown:
printf '%s\n' "${arr[@]}"— one element per line (%s\nrepeats for every arg)| sort— sort the linesmapfile -t sorted < <(…)— read each line back into thesortedarray (-tstrips the trailing\n)
mapfile is much safer than sorted=( $(…) ), which would re-split on whitespace.
Sort Flavours
sort has the variety you need built in:
| Flag | Meaning |
|---|---|
| (none) | alphabetical (LC_COLLATE) |
-r |
reverse |
-n |
numeric |
-h |
human-numeric (1K, 2M, 3G) |
-V |
version sort (1.2, 1.10) |
-f |
case-insensitive |
-u |
unique (dedupe) |
-t SEP -k N |
sort by column N split on SEP |
Examples:
arr=(b c A B a)
mapfile -t sorted < <(printf '%s\n' "${arr[@]}" | sort)
mapfile -t sorted_ci < <(printf '%s\n' "${arr[@]}" | sort -f)
mapfile -t reverse < <(printf '%s\n' "${arr[@]}" | sort -r)
echo "default: ${sorted[*]}" # default: A B a b c
echo "ci: ${sorted_ci[*]}" # ci: a A b B c
echo "reverse: ${reverse[*]}" # reverse: c b a B A
Numeric:
nums=(10 2 33 4 100)
mapfile -t s < <(printf '%s\n' "${nums[@]}" | sort -n)
echo "${s[@]}" # 2 4 10 33 100
Version-aware (perfect for tag/release lists):
versions=(v1.10 v1.2 v1.9 v2.0)
mapfile -t s < <(printf '%s\n' "${versions[@]}" | sort -V)
echo "${s[@]}" # v1.2 v1.9 v1.10 v2.0
Deduplicate — sort -u
items=(apple banana apple cherry banana)
mapfile -t unique < <(printf '%s\n' "${items[@]}" | sort -u)
echo "${unique[@]}" # apple banana cherry
sort -u is the simplest dedupe — it also sorts. For “dedupe while preserving order” use an associative-array-as-set:
declare -A seen
ordered=()
for x in "${items[@]}"; do
if [[ ! -v seen[$x] ]]; then
seen[$x]=1
ordered+=("$x")
fi
done
echo "${ordered[@]}" # apple banana cherry (first-seen order)
Sort an Associative Array
You can sort by keys or by values.
By key (alphabetical)
declare -A cfg=([host]=example.com [port]=8080 [debug]=true)
for k in $(printf '%s\n' "${!cfg[@]}" | sort); do
printf '%-8s = %s\n' "$k" "${cfg[$k]}"
done
# debug = true
# host = example.com
# port = 8080
By value (e.g. counters, descending)
declare -A count=([apple]=3 [banana]=2 [cherry]=1)
for line in $(
for k in "${!count[@]}"; do
printf '%d %s\n' "${count[$k]}" "$k"
done | sort -rn
); do
echo "$line"
done
# 3 apple
# 2 banana
# 1 cherry
A cleaner version using mapfile:
mapfile -t lines < <(
for k in "${!count[@]}"; do
printf '%d %s\n' "${count[$k]}" "$k"
done | sort -rn
)
printf '%s\n' "${lines[@]}"
Reverse an Array (No Sort)
arr=(a b c d)
# Method 1 — loop backwards
rev=()
for ((i=${#arr[@]}-1; i>=0; i--)); do
rev+=("${arr[i]}")
done
echo "${rev[@]}" # d c b a
# Method 2 — tac (line-oriented; needs printf one-per-line)
mapfile -t rev < <(printf '%s\n' "${arr[@]}" | tac)
On macOS tac isn’t installed; use tail -r or stick with method 1.
Sort by a Computed Key
If you have rich elements (e.g. lines) and want to sort by a derived field:
items=(
"alice 42"
"bob 17"
"carol 99"
"dan 5"
)
mapfile -t by_age < <(printf '%s\n' "${items[@]}" | sort -k2 -n)
printf '%s\n' "${by_age[@]}"
# dan 5
# bob 17
# alice 42
# carol 99
-k2 -n says “sort by column 2 numerically.” sort is far more powerful than people realise.
Stable Sort
sort is stable by default — equal keys keep their original order. If you want to be explicit, pass -s. Important when you sort by one field and don’t want secondary fields shuffled.
sort -s -k2 -n # stable numeric sort by field 2
Common Mistakes
| ❌ Wrong | ✅ Right | Issue |
|---|---|---|
sorted=( $(printf '%s\n' "${arr[@]}" \| sort) ) |
mapfile -t sorted < <(printf '%s\n' "${arr[@]}" \| sort) |
command sub splits on whitespace |
echo "${arr[@]}" \| sort |
printf '%s\n' "${arr[@]}" \| sort |
echo joins with spaces — one line, can’t sort |
sort on versions |
sort -V |
1.10 sorts before 1.2 lexically |
| Manual dedup loop without an assoc array | sort -u for sort+dedupe, or assoc-set for stable order |
hand-coded dedup is O(n²) |
Forgetting -n on numeric |
sort -n |
10 sorts before 2 lexically |
Next → Array vs String