Short answer: uniq removes duplicate lines, but only when the copies sit next to each other. Sort first: sort file | uniq prints every distinct line once, sort file | uniq -c counts them, and sort file | uniq -c | sort -nr | head ranks them. -d shows only repeated lines, -u only lines that occur once.
sort names.txt | uniq # each distinct line once
sort names.txt | uniq -c # with a count in front
sort names.txt | uniq -c | sort -nr # most frequent first
sort -u names.txt # same lines as sort | uniq, one commandEvery output on this page was produced in the C.UTF-8 locale on Debian 12.15 with GNU coreutils 9.1 (uniq, sort, cut) and GNU Awk 5.2.1, in a scratch directory on 21 and 22 October 2026, against small sample files including a 16-line nginx access log with documentation IP addresses. Ubuntu, Rocky Linux and AlmaLinux ship the same GNU uniq; the BSD uniq on macOS shares the core options but not every GNU long option, such as --group.
uniq cheat sheet
| Task | Command |
|---|---|
| Remove duplicate lines anywhere in a file | sort file | uniq |
| Count how often each line occurs | sort file | uniq -c |
| Top 10, most frequent first | sort file | uniq -c | sort -nr | head |
| Only lines that are repeated (one copy each) | sort file | uniq -d |
| Every copy of the repeated lines | sort file | uniq -D |
| Only lines that occur exactly once | sort file | uniq -u |
| Ignore upper and lower case | sort -f file | uniq -i |
| Ignore the first N fields (a timestamp, say) | uniq -f 1 file |
| Ignore the first N characters | uniq -s 9 file |
| Compare only the first N characters | uniq -w 10 file |
| Show groups separated by blank lines | sort file | uniq --group |
| Remove duplicates but keep the original order | awk '!seen[$0]++' file |
Why does uniq not remove all duplicates?
Because it never looks further back than the previous line. uniq reads its input once, compares each line with the one before it, and drops it when they match. That makes it fast and needs almost no memory on any file size, but a duplicate three lines further down survives. The man page says so in its last note: repeated lines are not detected unless they are adjacent.
$ cat fruits.txt
apple
apple
banana
apple
cherry
cherry
banana
kiwi
$ uniq fruits.txt
apple
banana
apple
cherry
banana
kiwi
$ sort fruits.txt | uniq
apple
banana
cherry
kiwiPlain uniq only merged the two runs (apple apple and cherry cherry). After sort puts equal lines next to each other, every duplicate goes. Skip the sort only when you want exactly that run behaviour, for example to collapse a log message that repeats many times in a row.
How do I count duplicate lines with uniq -c?
-c puts the number of occurrences in front of each line, right-aligned in a seven-character column. Pipe that into sort -nr (numeric, reversed) for a frequency list, and head to keep the top entries:
$ sort fruits.txt | uniq -c
3 apple
2 banana
2 cherry
1 kiwi
$ sort fruits.txt | uniq -c | sort -nr
3 apple
2 cherry
2 banana
1 kiwi
$ sort fruits.txt | uniq -c | sort -k1,1nr -k2
3 apple
2 banana
2 cherry
1 kiwiNote the tie: with plain sort -nr, lines with the same count come out in reverse alphabetical order, because -r also reverses the whole-line comparison sort falls back on. sort -k1,1nr -k2 sorts by count, highest first, and breaks ties alphabetically. Without the first sort, uniq -c counts runs, not totals: uniq -c fruits.txt reports apple twice, once with 2 and once with 1.
Show only repeated lines (-d, -D) or only unique ones (-u)
$ sort fruits.txt | uniq -d
apple
banana
cherry
$ sort fruits.txt | uniq -u
kiwi
$ sort fruits.txt | uniq -cd
3 apple
2 banana
2 cherry
$ sort fruits.txt | uniq -D
apple
apple
apple
banana
banana
cherry
cherry-dprints one copy of each line that appears more than once. Combined with-cit lists only the duplicates with their counts.-uis the opposite: only lines that appear exactly once. It does not mean “unique values” in the database sense; for that you want plainsort | uniq.-Dprints every copy of the repeated lines, and--all-repeated=separatedoes the same with a blank line between groups.--groupshows all lines, unique ones included, with a blank line between groups.
Ignore case with uniq -i (and why it needs sort -f)
-i treats Apple and apple as equal, but they still have to be adjacent. In the C and C.UTF-8 locales sort puts every capital letter before every small one, so the variants end up apart and uniq -i misses them. Sort with -f (fold case) so they line up:
$ cat case.txt
apple
Banana
APPLE
banana
Apple
$ sort case.txt | uniq -i
APPLE
Banana
apple
banana
$ sort -f case.txt | uniq -ic
3 APPLE
2 Banana
$ sort -fu case.txt
apple
Bananauniq keeps the first line of each group, so which spelling survives depends on the order sort produced. sort -fu gives the same set in one step, keeping whichever spelling came first in the input (here apple rather than APPLE).
Compare only part of a line: -f, -s and -w
Three options narrow what uniq compares. The printed line is always the whole first line of the group:
-f Nskips the first N fields. A field is a run of blanks followed by non-blank characters, souniqhas no option for another separator such as a comma.-s Nskips the first N characters (after any skipped fields).-w Ncompares no more than N characters.
$ cat app.log
09:15:01 disk /var 91% full
09:15:31 disk /var 91% full
09:16:01 disk /var 91% full
09:16:31 backup finished
09:17:01 disk /var 92% full
$ uniq -c -f 1 app.log
3 09:15:01 disk /var 91% full
1 09:16:31 backup finished
1 09:17:01 disk /var 92% full
$ uniq -c -w 10 days.log
2 2026-10-20T23:58:11 GET /
3 2026-10-21T00:00:02 GET /-f 1 ignored the timestamp and collapsed the repeated disk warning; uniq -s 9 gives the same result here, because the timestamp is exactly nine characters with its space. -w 10 compared only the date, which counts lines per day, but prints the first full line of each day. To print only the key, cut it out first: cut -c1-10 days.log | uniq -c. For a comma-separated file, pick the column with the cut command (cut -d, -f1) or deduplicate on a key with sort -t, -k1,1 -u, which keeps one whole line per key.
sort -u vs uniq: which one should I use?
| Need | Use | Why |
|---|---|---|
| Distinct lines, nothing else | sort -u file | One process, same result as sort | uniq |
| Counts per line | sort file | uniq -c | sort has no count option |
| Only duplicates or only singles | sort file | uniq -d | Also -u and -D; sort cannot do this |
| One line per key column | sort -t, -k1,1 -u file | uniq compares whole lines (or skips leading fields only) |
| Keep the original order | awk '!seen[$0]++' file | Prints each line the first time it appears |
| Collapse runs, keep later repeats | uniq file | The one case where unsorted input is what you want |
On a sample of one million random numbers, sort -u and sort | uniq both returned the same 50,000 lines. The awk command version keeps every distinct line in memory, which is fine for log keys and a poor idea for a multi-gigabyte file of mostly distinct lines; sort spills to temporary files instead.
Real example: top client IPs in an nginx access log
This is where uniq earns its place on a server. In nginx’s default combined log format, field 1 is the client address, field 7 the path and field 9 the status code. Take the field with awk, sort, count, sort by count:
$ awk '{print $1}' access.log | sort | uniq -c | sort -nr | head
8 203.0.113.7
4 198.51.100.23
2 2001:db8::42
2 192.0.2.10
$ awk '{print $9}' access.log | sort | uniq -c | sort -nr
8 200
7 404
1 502
$ awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -nr | head -n 3
2 /wp-login.php
1 /xmlrpc.php
1 /config.phpIn this sample one address sent half the requests, seven of them 404s for paths such as /wp-login.php, /.env and /backup.zip: that is a scanner, not a visitor. On a live server the log is root-only, so put sudo in front of the awk and point it at /var/log/nginx/access.log. Narrow it to a time window or a path with the grep command before counting, and for the number of distinct visitors rather than a list, end with wc -l: awk '{print $1}' access.log | sort -u | wc -l printed 4 here. The same pipeline shape works on any list: remote addresses from ss, repeated messages from journalctl -o cat, or the commands in your shell history.
Common problems and error messages
| Symptom | Cause | Fix |
|---|---|---|
| Duplicates still in the output | Input not sorted | sort file | uniq |
| Lines that look identical are not merged | Trailing spaces or Windows CRLF endings; check with cat -A | sed 's/[[:space:]]*$//' file | uniq |
| File is empty after sorting it | sort file > file truncates before sort reads | sort -u -o file file |
uniq: extra operand | A third file name; uniq takes INPUT and OUTPUT only | Concatenate first: cat a b | sort | uniq |
printing all duplicated lines and repeat counts is meaningless | -c combined with -D | Use -cd for counts of repeated lines |
--group is mutually exclusive with -c/-d/-D/-u | --group combined with a filter option | Use --all-repeated=separate instead |
Two more things catch people in scripts. A second file name is the output file, not another input: uniq in.txt out.txt writes to out.txt. And uniq exits with 0 whether or not it found duplicates, so test the output, not the exit status: [ -n "$(sort list | uniq -d)" ] && echo duplicates. For the other text tools in the same pipelines, the Linux commands cheat sheet has them on one page.
Frequently asked
Why does uniq not remove all duplicate lines?
uniq compares each line only with the line directly before it, so it removes duplicates only when they are adjacent. Sort the input first, as in sort file | uniq, or use sort -u, which prints the same distinct lines in one command.
How do I count how often each line occurs in Linux?
Sort the lines, then count them with uniq -c: sort file | uniq -c. Add | sort -nr to put the most frequent first and | head for the top ten. Without the first sort, uniq -c counts runs of adjacent lines, not totals, and the same line can appear several times with different counts.
What is the difference between uniq -d and uniq -u?
uniq -d prints one copy of every line that occurs more than once; uniq -u prints only the lines that occur exactly once. Both need sorted input to see all copies of a line. uniq -D prints every copy of the repeated lines instead of one.
Should I use sort -u or sort | uniq?
For distinct lines alone, sort -u is one process and gives the same result. Use sort | uniq when you need something only uniq does: counts with -c, only duplicates with -d, only single lines with -u, or grouping with --group.