Text processing
sort
Sort lines of text alphabetically, numerically, by version or by chosen fields; also merge and de-duplicate.
sort [OPTION...] [FILE...]
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
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 ' '
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
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
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
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
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
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
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
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
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
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
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
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
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
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 > fileempties the file beforesortreads it. Usesort -o file file.-k 2means field 2 to the end of the line. Use-k 2,2for exactly one field, and-k 2,2nfor a numeric field.Sorting differs between locales:
CputsZbeforea,en_US.UTF-8mixes cases and ignores most punctuation. Tools that rely on sort order (join,comm,uniq) must run in the same locale as thesortthat fed them;export LC_ALL=Cin scripts avoids surprises.Forgetting
-nwhen sorting numbers gives10before9. Fordu -houtput use-h, not-n, or2Msorts below10K.sort -uandsort | uniqagree on whole lines, but with-for-k,-ucompares 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,-Sbuffer sizes and--debugare GNU options.sort --debugis the fastest way to see which part of each line a-kactually compares.
Options worth knowing
A selection, described in our own words. For the full list, see sort(1) or sort --help.
| Option | What it does |
|---|---|
-n, --numeric-sort | Compare by numeric value. |
-h, --human-numeric-sort | Compare sizes with suffixes like 2K, 1G. |
-V, --version-sort | Compare version numbers naturally, so 2.9 < 2.10. |
-g, --general-numeric-sort | Compare as floating-point numbers, including exponents like 1e3; slower than -n. |
-r, --reverse | Reverse the result of comparisons. |
-f, --ignore-case | Fold lower case to upper case when comparing. |
-d, --dictionary-order | Consider only blanks and letters and digits. |
-b, --ignore-leading-blanks | Ignore leading blanks in keys. |
-M, --month-sort | Compare month abbreviations, JAN < FEB < ... < DEC. |
-k, --key KEYDEF | Sort on a key such as 2,2 or 4,4n; repeat for secondary keys. |
-t, --field-separator SEP | Use SEP as the field separator instead of blank-to-non-blank transitions. |
-u, --unique | Output only the first of each group of equal lines or keys. |
-s, --stable | Keep lines with equal keys in their input order. |
-c, --check | Check whether the input is sorted and report the first disorder. |
-C | Like -c but silent; only the exit status reports. |
-o, --output FILE | Write the result to FILE, which may be one of the inputs. |
-m, --merge | Merge already sorted files without re-sorting. |
-R, --random-sort | Shuffle, but keep identical lines together. |
-z, --zero-terminated | Lines end with NUL instead of newline. |
-S, --buffer-size SIZE | Use SIZE of memory for sorting, e.g. 50% or 1G. |
-T, --temporary-directory DIR | Put temporary files for large sorts in DIR. |
--parallel N | Sort with up to N threads. |
--debug | Annotate the parts of each line used for comparison. |
Related
uniqCollapse or report repeated adjacent lines; with sort, count how often each line occurs.commCompare two sorted files line by line and show lines unique to each and lines in both.joinJoin lines of two sorted files that share a key field, like a database join on text files.shufShuffle lines into random order, or pick random lines, numbers or words.cutPrint selected fields, characters or bytes from each line, such as columns of a CSV or TSV file.tacPrint files with their lines in reverse order, last line first.- Pipes and pipelinesHow cmd1 | cmd2 connects processes, which exit status a pipeline returns, PIPESTATUS, pipefail, SIGPIPE, and why variables set in a piped loop vanish.