sort
Sort lines: alphabetically, numerically, or by field
sort orders the lines of a file or stream and writes the result to stdout. On its own that
sounds trivial, but two things trip people up constantly: the default order is lexicographic,
not numeric, and sort compares whole lines unless you tell it which field to look at.
Plain sort on a file of numbers puts 10 before 2, because it's comparing the characters
'1' and '2', not the values ten and two. -n switches to numeric comparison; -h does the
same but also understands K/M/G suffixes, which is what you want when sorting du -h or
ls -lh output.
For anything with columns (CSV, ps output, du output) -k picks which
field to sort by instead of the whole line: -k2 sorts by the second field, -t, changes the
field separator from whitespace to a comma. Combine -k with -n or -h to sort a specific
numeric column correctly instead of falling back to lexicographic order on it by accident.
-u deduplicates while sorting (cheaper than piping to uniq separately when you don't need the
unsorted order preserved). -r reverses whatever order you asked for. -c checks whether a file
is already sorted without printing anything, useful in scripts as a precondition check.
Case matters too: default comparison is case-sensitive, so every uppercase letter sorts before
every lowercase one in the ASCII table, so Cherry lands before apple. -f folds case before
comparing, which is almost always what you want for sorting words a human will read.
Sample files used on this page
Every example below was run against these files. Recreate them to follow along.
wordlist.txt duplicates and mixed case, to show what -u and -f do
banana
apple
Cherry
apple
date
banana
apple
Elderberry
cherry
numbers.txt deliberately ordered so lexicographic and numeric sorting disagree
10
2
33
4
scores.txt three whitespace-separated fields; the score is field 3
Team Alpha 89
Team Beta 42
Team Gamma 100
Team Delta 7
sizes.txt human-readable sizes in field 2, spanning bytes to gigabytes
report.txt 1.2K
access.log 890
photos.tar.gz 4.3G
backup.sql 128M
notes.txt 340
users.csv comma-separated, with a header row that must stay on top
name,age,department
Alice,34,Engineering
Bob,29,Sales
Carol,41,Engineering
Dave,25,Marketing
Erin,38,Sales
Frank,31,Engineering
people.csv two records per department, for the stable-sort and dedupe-by-field examples
Carol,Eng
Bob,Sales
Alice,Eng
Dave,Sales
access.log standard combined log format: IP is field 1, status field 8, bytes field 9
203.0.113.5 - - [13/Aug/2026:09:12:01] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:12:03] "GET /style.css HTTP/1.1" 200 231
198.51.100.7 - - [13/Aug/2026:09:14:22] "GET /index.html HTTP/1.1" 200 512
198.51.100.7 - - [13/Aug/2026:09:14:25] "GET /missing.html HTTP/1.1" 404 162
203.0.113.5 - - [13/Aug/2026:09:15:47] "GET /index.html HTTP/1.1" 200 512
192.0.2.44 - - [13/Aug/2026:09:16:03] "POST /login HTTP/1.1" 302 0
192.0.2.44 - - [13/Aug/2026:09:16:04] "GET /dashboard HTTP/1.1" 200 4021
198.51.100.7 - - [13/Aug/2026:09:18:51] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:19:10] "GET /api/status HTTP/1.1" 500 89
192.0.2.44 - - [13/Aug/2026:09:20:33] "GET /dashboard HTTP/1.1" 200 4021
data.txt fixed 1-character prefix then a 3-letter code, for the -k1.2,1.4 example
xAAAy
xCCCa
xBBBz
setA.txt / setB.txt two overlapping sets, for the comm example - b and a are in both
==> setA.txt <==
a
c
b
==> setB.txt <==
b
d
a
Default order: lexicographic, not numeric
With no flags, sort compares lines character by character. That's exactly what you want for words, and almost never what you want for numbers.
Sort lines of text alphabetically
sort wordlist.txt
Default comparison, case-sensitive. Every uppercase letter sorts before every lowercase one in ASCII.
Show output
Cherry
Elderberry
apple
apple
apple
banana
banana
cherry
date
Fold case before comparing
sort -f wordlist.txt
-f (--ignore-case) compares case-insensitively, so Cherry and cherry sort next to each other instead of at opposite ends of the file.
Show output
apple
apple
apple
banana
banana
Cherry
cherry
date
Elderberry
Watch plain numbers sort wrong without -n
sort numbers.txt
10 comes before 2 here because '1' is a smaller character than '2' - sort has no idea these are meant to be numbers.
Show output
10
2
33
4
Sort those same numbers correctly
sort -n numbers.txt
-n switches to numeric comparison. Same input, correct order.
Show output
2
4
10
33
Numeric sort handles negative numbers correctly too
printf -- '-5\n3\n-10\n0\n' | sort -n
Negative values sort by actual magnitude, not by the position of the minus sign character.
Show output
-10
-5
0
3
Numeric and human-readable sorting
-n for plain numbers, -h when the numbers carry K/M/G suffixes, -V for version-style strings, -M for month names.
Sort du or ls -h output by actual size
sort -k2 -h sizes.txt
-h understands K/M/G suffixes as multipliers, so 890 < 1.2K < 128M < 4.3G comes out in the order a human expects.
Show output
notes.txt 340
access.log 890
report.txt 1.2K
backup.sql 128M
photos.tar.gz 4.3G
The mistake: -h without picking the size field
sort -h sizes.txt
Without -k2, sort -h compares from the start of each line - the filename - which isn't a number at all, so this silently falls back to sorting alphabetically by filename instead of by size. Verified: this produces access.log, backup.sql, notes.txt, photos.tar.gz, report.txt - alphabetical order, not size order.
Sort filenames with embedded numbers correctly
printf 'file10.txt\nfile2.txt\nfile1.txt\n' | sort -V
-V (version sort) treats digit runs as numbers, so file2.txt sorts before file10.txt instead of after it - the opposite of what plain sort would do.
Show output
file1.txt
file2.txt
file10.txt
Sort by month name
printf 'Mar 3\nJan 1\nFeb 2\n' | sort -M
-M recognises the first three letters of month names (Jan, Feb, Mar...) and sorts chronologically instead of alphabetically.
Show output
Jan 1
Feb 2
Mar 3
Sorting by field with -k
-k N sorts by the Nth field instead of the whole line. -t changes what counts as a field separator.
Sort a scoreboard by score
sort -k3 -n scores.txt
-k3 picks the third whitespace-separated field; -n makes that comparison numeric.
Show output
Team Delta 7
Team Beta 42
Team Alpha 89
Team Gamma 100
Same scoreboard, highest first
sort -k3 -rn scores.txt
-r reverses whatever order the rest of the flags produce - combine it with -n rather than trying to sort ascending and pipe through tac.
Show output
Team Gamma 100
Team Alpha 89
Team Beta 42
Team Delta 7
Sort CSV data by a numeric column
(head -1 users.csv; tail -n +2 users.csv | sort -t, -k2 -n)
-t, treats a comma as the field separator instead of whitespace. Keeping the header out of the sort with head/tail is the standard trick for not sorting it into the middle of the data.
Show output
name,age,department
Dave,25,Marketing
Bob,29,Sales
Frank,31,Engineering
Alice,34,Engineering
Erin,38,Sales
Carol,41,Engineering
Sort by one field, then break ties with another
(head -1 users.csv; tail -n +2 users.csv | sort -t, -k3,3 -k2,2n)
The -k options apply in order: group by department (field 3) first, then sort each group by age (field 2) numerically. -k3,3 means 'field 3 to field 3' - without the end bound, -k3 alone would sort by field 3 through the end of the line.
Show output
name,age,department
Frank,31,Engineering
Alice,34,Engineering
Carol,41,Engineering
Dave,25,Marketing
Bob,29,Sales
Erin,38,Sales
Ignore leading whitespace when comparing
printf ' banana\napple\n cherry\n' | sort -b
-b (--ignore-leading-blanks) skips indentation before comparing, so inconsistently-indented input still sorts by content.
Show output
apple
banana
cherry
Deduplicating, reversing, and combining sorted files
Sort and deduplicate in one pass
sort -u wordlist.txt
-u drops duplicate lines after sorting - cheaper than sort | uniq when you don't need the two steps separately, and it needs the file sorted anyway.
Show output
Cherry
Elderberry
apple
banana
cherry
date
The same thing, long-form flag
sort --unique wordlist.txt
--unique is the exact same flag as -u - useful to know when reading someone else's script that spells it out.
Sort a file in place safely
sort -u -o wordlist.txt wordlist.txt
-o lets the output filename be the same as the input - sort reads the whole file into memory before opening the output, so this doesn't truncate the input out from under itself the way sort wordlist.txt > wordlist.txt would. It prints nothing: the result goes to the file.
Reverse the sort order
sort -r wordlist.txt
-r reverses the final order, applied after any other comparison flags.
Show output
date
cherry
banana
banana
apple
apple
apple
Elderberry
Cherry
Merge two files that are already sorted
sort -m -n numbers-sorted.txt other-sorted.txt
-m merges pre-sorted inputs without re-sorting each one from scratch - much cheaper than cat-ing them together and sorting the result, on large files.
Show output
1
2
4
5
10
33
50
Checking and writing sorted output
Check whether a file is already sorted
sort -c numbers.txt
-c prints nothing and exits 0 if the file is already in sorted order for the comparison rules given - here, default lexicographic order, under which 10, 2, 33, 4 happens to already qualify.
Check with the comparison rule that actually matches the data
sort -cn numbers.txt
Same file, checked numerically instead: reports exactly where it breaks. This is the check a file of numbers needs - -c alone checked the wrong thing.
Show output
sort: numbers.txt:2: disorder: 2
Write sorted output to a new file
sort -o wordlist-sorted.txt wordlist.txt
-o is the safe way to 'sort in place' - sort > wordlist.txt would truncate the file before reading it, destroying the input. -o opens the output only after reading the input fully, so input and output can even be the same filename.
Sort output from another command
find . -maxdepth 1 -name 'numbers*' | sort
sort reads stdin when no filename is given, same as most Unix text tools - the standard way to get find's arbitrary directory-walk order into something predictable.
Show output
./numbers-pair.txt
./numbers-sci.txt
./numbers-sorted.txt
./numbers.txt
Sort NUL-separated input safely
find . -maxdepth 1 -name '*.txt' -print0 | sort -z
-z reads and writes NUL-terminated records instead of newline-terminated ones - the correct pairing with find -print0 and xargs -0 for filenames that might contain newlines.
Force byte-order sorting regardless of locale
LC_ALL=C sort wordlist.txt
Sort order can change between locales (some locales fold case or ignore punctuation differently by default). LC_ALL=C forces plain byte-value comparison - the reproducible choice for scripts, even on a system whose default locale sorts differently.
Show output
Cherry
Elderberry
apple
apple
apple
banana
banana
cherry
date
More field-sorting patterns
-k accepts a lot more than a bare field number: character ranges within a field, colon or tab separators, stability guarantees.
Sort colon-separated data, the /etc/passwd shape
sort -t: -k3 -n /etc/passwd | head -3
-t: splits on colons; -k3 -n sorts by the numeric UID field. The same shape works for any colon-delimited system file.
Show output
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
Sort on part of a field, not the whole thing
sort -k1.2,1.4 data.txt
1.2,1.4 means field 1, characters 2 through 4 - sorts on a slice inside a field rather than the field boundary. Here it sorts by the 3-letter code embedded after a fixed 1-character prefix.
Show output
xAAAy
xBBBz
xCCCa
Keep equal-key rows in their original relative order
sort -s -t, -k2,2 people.csv
Default sort doesn't guarantee what happens to rows that compare equal - -s (--stable) guarantees ties keep their original relative order, which matters when you sort by one field but still care about a secondary implicit order.
Show output
Carol,Eng
Alice,Eng
Bob,Sales
Dave,Sales
Sort a tab-separated file
sort -t$'\t' -k2 data.tsv
$'\t' is bash's way of writing a literal tab in a single-quoted-feeling argument - plain -t ' ' works too but is easy to mistype invisibly.
Show output
b a
a z
General numeric sort handles scientific notation
sort -g numbers-sci.txt
-n treats anything it can't parse as zero; -g (--general-numeric-sort) additionally understands scientific notation like 1e2, at some extra performance cost. Use -n unless you specifically have exponents in the data.
Show output
3
2.5e1
1e2
Deduplicate by one field, keeping one row per key
sort -t, -k2,2 -u people.csv
-u after a -k range dedupes on just that field, not the whole line - one row per distinct field-2 value survives (whichever sorts first once the rest of the line is compared as the tiebreak).
Show output
Carol,Eng
Bob,Sales
Multiple -k options without explicit end bounds
printf 'b 2 x\na 2 y\nc 1 z\n' | sort -k2 -k1
Without a comma, each -k extends to the end of the line, so the second -k1 only breaks ties left over after the first key already covered everything from field 2 onward. For precise multi-column sorts, always give explicit N,N ranges instead.
Show output
c 1 z
b 2 x
a 2 y
See exactly what sort is comparing and why
sort -n --debug numbers-pair.txt
--debug annotates the comparison it performed under each line - invaluable when a sort order looks wrong and you can't tell whether it's reading the field, locale, or numeric parsing you expect.
Show output
sort: text ordering performed using simple byte comparison
sort: numbers use '.' as a decimal point in this locale
2
_
_
10
__
__
Sorting real log and system data
Applying -k to data you didn't design yourself - a web server access log with quoted fields.
Group log entries by HTTP status code
sort -k8 -n access.log
Field 8 in a standard combined log line is the status code - the quoted request eats fields 5–7, so counting whitespace-separated fields by hand, rather than by meaning, is what finds it.
Show output
192.0.2.44 - - [13/Aug/2026:09:16:04] "GET /dashboard HTTP/1.1" 200 4021
192.0.2.44 - - [13/Aug/2026:09:20:33] "GET /dashboard HTTP/1.1" 200 4021
198.51.100.7 - - [13/Aug/2026:09:14:22] "GET /index.html HTTP/1.1" 200 512
198.51.100.7 - - [13/Aug/2026:09:18:51] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:12:01] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:12:03] "GET /style.css HTTP/1.1" 200 231
203.0.113.5 - - [13/Aug/2026:09:15:47] "GET /index.html HTTP/1.1" 200 512
192.0.2.44 - - [13/Aug/2026:09:16:03] "POST /login HTTP/1.1" 302 0
198.51.100.7 - - [13/Aug/2026:09:14:25] "GET /missing.html HTTP/1.1" 404 162
203.0.113.5 - - [13/Aug/2026:09:19:10] "GET /api/status HTTP/1.1" 500 89
Find the biggest responses a server sent
sort -k9 -rn access.log | head -n 3
Field 9 is response size in bytes. Combining -r, -n, and head is the standard 'top N' shape for any sortable log column.
Show output
192.0.2.44 - - [13/Aug/2026:09:20:33] "GET /dashboard HTTP/1.1" 200 4021
192.0.2.44 - - [13/Aug/2026:09:16:04] "GET /dashboard HTTP/1.1" 200 4021
203.0.113.5 - - [13/Aug/2026:09:15:47] "GET /index.html HTTP/1.1" 200 512
Sort IPv4 addresses in actual numeric order
sort -t. -k1,1n -k2,2n -k3,3n -k4,4n access.log
Chaining a numeric -k per octet is the fix for plain sort, which compares addresses as text and puts 10.x ahead of 9.x.
Combining sort with other commands
Sort multiple files as one combined stream
sort numbers.txt scores.txt
Multiple filename arguments are read as one concatenated input and sorted together, not sorted separately one after another.
Find the largest directories, biggest first
du -sh */ | sort -rh
du -sh */ prints one human-readable size per top-level directory; piping through sort -rh orders them biggest first. See find the largest files for the file-level version of this pattern.
Show output
2.0M archive/
504K photos/
56K docs/
Rank files by line count
wc -l *.txt | sort -rn | head -5
wc -l prints a count-then-filename line per file plus a total; sort -rn puts the biggest counts first, total included since it's just another number in the stream.
Show output
92 total
40 report.txt
9 wordlist.txt
9 wordlist-sorted.txt
5 sizes.txt
Count how often each line appears
sort wordlist.txt | uniq -c | sort -rn
The classic frequency-count pipeline: sort groups identical lines together so uniq -c can count them, then a second sort orders by that count. See the uniq page for -c and its other counting flags.
Show output
3 apple
2 banana
1 date
1 cherry
1 Elderberry
1 Cherry
Preview sorted output while also saving it
sort numbers.txt -n | tee numbers-sorted-final.txt | head -n 2
tee writes the full sorted stream to a file and still passes it through to head, so you can sanity-check the first few lines without a second pass over the data.
Show output
2
4
Read from a heredoc instead of a file
sort <<EOF
zebra
apple
mango
EOF
sort reads stdin exactly the same whether it's piped, redirected from a file, or fed by a heredoc - useful when the data to sort is generated inline in a script.
Show output
apple
mango
zebra
Confirm sort -u and sort | uniq agree
diff <(sort -u wordlist.txt) <(sort wordlist.txt | uniq)
No output and exit 0 means the two files are identical - confirms -u is a safe shortcut for sort | uniq when you don't need the two steps split apart in a pipeline.
Get the smallest value in a list
sort -n numbers.txt | head -n 1
sort plus head -n 1 is the standard shell idiom for a minimum - there's no separate 'min' utility.
Show output
2
Get the largest value in a list
sort -rn numbers.txt | head -n 1
Same idiom reversed: sort descending, take the first line, for a maximum instead.
Show output
33
Count how many distinct values there are
sort -u wordlist.txt | wc -l
Sort down to unique lines, then count them - the fastest way to answer 'how many different values' without writing a script.
Show output
6
Compare two sorted sets to see what's only in one
comm -3 <(sort setA.txt) <(sort setB.txt)
comm isn't sort, but it requires sorted input to work correctly - a common reason to run sort even when the sorted order itself isn't what you want to keep. -3 suppresses lines common to both, leaving only what's unique to each side.
Show output
c
d
Performance and large-file options
Flags that matter once a file is too big to sort comfortably in memory.
Use multiple CPU cores for the sort
sort --parallel=2 -n numbers.txt
--parallel caps how many sort threads run at once - helps on large files, does nothing measurable on a file this small.
Show output
2
4
10
33
Set how much memory sort is allowed to use
sort -S 1K -n numbers.txt
-S bounds sort's in-memory buffer; once a sort exceeds it, sort spills to temporary files on disk and merges them instead of holding everything in RAM at once. Same correct result either way.
Show output
2
4
10
33
Compress the temporary files a large external sort spills to disk
sort --compress-program=gzip -n numbers.txt
Only matters once a sort is big enough to spill to disk (see -S above) - compressing those temporary files trades CPU time for disk I/O on genuinely large sorts.
Show output
2
4
10
33