opscape

Text processing

sort

Sort lines of text alphabetically, numerically, by version or by chosen fields; also merge and de-duplicate.

sort [OPTION...] [FILE...]

15 of 15 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: sort(1)

sort reads all its input, sorts the lines and prints them. By default it compares whole lines as text, using the collation rules of the current locale. Options change how lines compare (-n numbers, -h sizes like 2K, -V version strings, -f ignore case, -r reverse) and what is compared (-k picks a field, -t sets the field separator).

The key option deserves care. -k 2 means "from field 2 to the end of the line", not "field 2"; write -k 2,2 to compare only that field, and put the type letter on the key itself (-k 4,4n) when different keys need different rules. Without -t, fields are separated by the transition from blanks to non-blanks, and the leading blanks belong to the field.

The locale matters more than people expect. In C or C.UTF-8 (what these examples use) lines are compared by byte or code point, so all capital letters sort before all lower-case ones. In a locale such as en_US.UTF-8 the comparison is dictionary-like: case is only a tie-breaker and punctuation is mostly ignored, so the same file sorts differently on a desktop and in a cron job or container. Scripts that need a stable order should set LC_ALL=C.

Examples

Sort lines alphabetically

sort data/fruits.txt
explain
output
apple
apple
apple
banana
banana
cherry
cherry
date
elderberry
fig

Lines are compared as text and duplicates are kept, so apple appears three times.

Sort numbers by value

sort data/numbers.txt | paste -s -d ' '
sort -n data/numbers.txt | paste -s -d ' '
output
100 19 21 3 3 42 58 64 7 7
3 3 7 7 19 21 42 58 64 100

As text, 100 comes before 19 because 1 < 9 at the second character. -n compares numeric values, giving 3 3 7 7 19 ... 100. (paste only puts the results on one line.)

Largest first

sort -nr data/numbers.txt | head -n 3
explain
output
100
64
58

-r reverses the order, so with -n the biggest numbers come first: the top three are 100, 64 and 58.

Sort and remove duplicates

sort -u data/fruits.txt
explain
output
apple
banana
cherry
date
elderberry
fig

-u prints only the first of each run of equal lines, the same result as sort | uniq.

Sort a CSV by one column

tail -n +2 data/sales.csv | sort -t , -k 4,4n | head -n 4
explain
output
2026-03-06,west,gadget,1,19.99
2026-03-05,west,gizmo,2,12.00
2026-03-01,south,gadget,3,19.99
2026-03-04,east,gadget,4,19.99

-t , splits fields on commas and -k 4,4n sorts numerically on the fourth field only (units). The header is skipped first with tail so it does not get sorted into the data.

Sort by several keys

tail -n +2 data/sales.csv | sort -t , -k 3,3 -k 4,4nr
explain
output
2026-03-05,south,gadget,6,19.99
2026-03-04,east,gadget,4,19.99
2026-03-01,south,gadget,3,19.99
2026-03-06,west,gadget,1,19.99
2026-03-06,east,gizmo,8,12.00
2026-03-02,north,gizmo,5,12.00
2026-03-05,west,gizmo,2,12.00
2026-03-03,west,widget,20,4.50
2026-03-04,north,widget,15,4.50
2026-03-01,north,widget,12,4.50
2026-03-03,south,widget,9,4.50
2026-03-02,east,widget,7,4.50

The first key groups rows by product name; within each product, the second key orders rows by units, numerically and in reverse. The r and n apply only to the key they are attached to.

Trap: -k 2 runs to the end of the line

printf 'a 1 z\nb 1 y\nc 0 x\n' | sort -k 2
echo ---
printf 'a 1 z\nb 1 y\nc 0 x\n' | sort -k 2,2
output
c 0 x
b 1 y
a 1 z
---
c 0 x
a 1 z
b 1 y

With -k 2 the keys are 1 z, 1 y and 0 x: the third column takes part, so b 1 y sorts before a 1 z. With -k 2,2 the key is the second field alone; a and b tie on it, and the tie is broken by comparing the whole lines, so a 1 z comes first.

Keep the original order for ties

printf 'b 2\na 2\nc 1\n' | sort -s -k 2,2n
explain
output
c 1
b 2
a 2

-s (stable) disables the last-resort whole-line comparison, so b 2 stays ahead of a 2 as in the input. Without -s, a 2 would come first.

One line per key value

tail -n +2 data/sales.csv | sort -t , -k 2,2 -u
explain
output
2026-03-02,east,widget,7,4.50
2026-03-01,north,widget,12,4.50
2026-03-01,south,gadget,3,19.99
2026-03-03,west,widget,20,4.50

With -u and a key, lines count as duplicates when their keys are equal, so you get the first line (in input order) for each region and the rest are dropped.

Sort human-readable sizes

printf '10K\n2M\n512\n1G\n3K\n' | sort -h
explain
output
512
3K
10K
2M
1G

-h understands the K, M, G suffixes that du -h and ls -lh print, so 512 < 3K < 10K < 2M < 1G.

Sort version numbers

printf 'v2.10\nv2.9\nv2.4.1\nv10\n' | sort -V
explain
output
v2.4.1
v2.9
v2.10
v10

-V compares runs of digits as numbers, so v2.9 comes before v2.10 and v10 is last. Plain sort would put v10 first.

Upper and lower case in the C locale

printf 'banana\nApple\napple\nBanana\n' | sort
echo ---
printf 'banana\nApple\napple\nBanana\n' | sort -f
output
Apple
Banana
apple
banana
---
Apple
apple
Banana
banana

In C.UTF-8 every capital letter sorts before every lower-case one, so Apple and Banana come first. -f folds case for the comparison and keeps the words together. In an en_US.UTF-8 session the first command would already interleave them.

Check whether a file is already sorted

sort -c data/fruits.txt
explain
outputexit 1
sort: data/fruits.txt:2: disorder: apple

-c sorts nothing; it reports the first line out of order and exits with 1. Use -C to get only the exit status, for a script's if.

Sort a file in place

sort -n -o data/numbers.txt data/numbers.txt
head -n 3 data/numbers.txt
output
3
3
7

-o names the output file, and unlike > data/numbers.txt it is safe even when it is also the input, because sort reads everything before it opens the output.

Trap: the decimal separator depends on the locale

printf '1,5\n1.25\n1.5\n' | sort -n
explain
output
1,5
1.25
1.5

In this locale the decimal point is ., so 1,5 is read as 1 (the number stops at the comma) and sorts first. In a German or French locale, where the comma is the decimal separator, the order would change. Set LC_ALL=C for data with dots.

Common pitfalls

  • sort file > file empties the file before sort reads it. Use sort -o file file.

  • -k 2 means field 2 to the end of the line. Use -k 2,2 for exactly one field, and -k 2,2n for a numeric field.

  • Sorting differs between locales: C puts Z before a, en_US.UTF-8 mixes cases and ignores most punctuation. Tools that rely on sort order (join, comm, uniq) must run in the same locale as the sort that fed them; export LC_ALL=C in scripts avoids surprises.

  • Forgetting -n when sorting numbers gives 10 before 9. For du -h output use -h, not -n, or 2M sorts below 10K.

  • sort -u and sort | uniq agree on whole lines, but with -f or -k, -u compares only the key and may drop lines that differ elsewhere.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • -h (human sizes) and -V (versions) are available in GNU sort and in recent macOS/FreeBSD sort, but not in older BSD versions or busybox builds; check your system's man page.

  • --parallel, -S buffer sizes and --debug are GNU options. sort --debug is the fastest way to see which part of each line a -k actually compares.

Options worth knowing

A selection, described in our own words. For the full list, see sort(1) or sort --help.

OptionWhat it does
-n, --numeric-sortCompare by numeric value.
-h, --human-numeric-sortCompare sizes with suffixes like 2K, 1G.
-V, --version-sortCompare version numbers naturally, so 2.9 < 2.10.
-g, --general-numeric-sortCompare as floating-point numbers, including exponents like 1e3; slower than -n.
-r, --reverseReverse the result of comparisons.
-f, --ignore-caseFold lower case to upper case when comparing.
-d, --dictionary-orderConsider only blanks and letters and digits.
-b, --ignore-leading-blanksIgnore leading blanks in keys.
-M, --month-sortCompare month abbreviations, JAN < FEB < ... < DEC.
-k, --key KEYDEFSort on a key such as 2,2 or 4,4n; repeat for secondary keys.
-t, --field-separator SEPUse SEP as the field separator instead of blank-to-non-blank transitions.
-u, --uniqueOutput only the first of each group of equal lines or keys.
-s, --stableKeep lines with equal keys in their input order.
-c, --checkCheck whether the input is sorted and report the first disorder.
-CLike -c but silent; only the exit status reports.
-o, --output FILEWrite the result to FILE, which may be one of the inputs.
-m, --mergeMerge already sorted files without re-sorting.
-R, --random-sortShuffle, but keep identical lines together.
-z, --zero-terminatedLines end with NUL instead of newline.
-S, --buffer-size SIZEUse SIZE of memory for sorting, e.g. 50% or 1G.
-T, --temporary-directory DIRPut temporary files for large sorts in DIR.
--parallel NSort with up to N threads.
--debugAnnotate the parts of each line used for comparison.

Related