opscape

Text processing

uniq

Collapse or report repeated adjacent lines; with sort, count how often each line occurs.

uniq [OPTION...] [INPUT [OUTPUT]]

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

uniq removes adjacent duplicate lines: when the same line appears several times in a row, it is printed once. Lines that repeat further apart are not touched, which is why uniq is almost always used after sort, which brings equal lines together.

Its options turn it into a small reporting tool: -c prefixes each line with how many times it occurred, -d prints only lines that were repeated, -u only lines that were not. The pipeline sort | uniq -c | sort -rn (a frequency table, most common first) is one of the most useful one-liners in the shell, for log analysis in particular.

uniq can compare only part of each line: -f N skips the first N fields, -s N skips N characters and -w N compares at most N characters. It cannot pick a field in the middle; for that, extract the field with cut or awk first, or use sort -u -k.

Examples

Only adjacent duplicates are removed

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

Nothing changes: no two equal lines are next to each other in fruits.txt, so uniq keeps all ten. This is the most common surprise with uniq.

Remove all duplicates

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

After sorting, equal lines are adjacent and uniq reduces each group to one line. sort -u does the same in one step.

Count occurrences

sort data/fruits.txt | uniq -c
explain
output
      3 apple
      2 banana
      2 cherry
      1 date
      1 elderberry
      1 fig

-c puts the size of each group in front of the line: apple occurs 3 times, date once.

Most frequent first

cut -d ' ' -f 3 logs/app.log | sort | uniq -c | sort -rn
explain
output
      6 INFO
      4 WARN
      2 ERROR

The classic frequency table: extract the log level, group equal levels, count them, then sort the counts numerically in reverse. The log has 6 INFO, 4 WARN and 2 ERROR lines.

Top clients in an access log

awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -n 3
explain
output
      5 192.0.2.10
      4 203.0.113.42
      4 198.51.100.7

The same pattern on the client IP field answers "who is hitting the server most?"; head keeps the top three.

Show only the repeated lines

sort data/fruits.txt | uniq -d
explain
output
apple
banana
cherry

-d prints one copy of each line that occurs more than once: the fruits that were listed twice or more.

Show only the lines that are not repeated

sort data/fruits.txt | uniq -u
explain
output
date
elderberry
fig

-u is the opposite of -d: date, elderberry and fig occur exactly once.

Print every copy of the duplicates

sort data/fruits.txt | uniq -D
explain
output
apple
apple
apple
banana
banana
cherry
cherry

-D keeps all lines that belong to a repeated group and drops the singles, useful to inspect what the duplicates look like.

Separate groups with a blank line

sort data/fruits.txt | uniq --group | head -n 8
explain
output
apple
apple
apple

banana
banana

cherry

--group prints every line and puts an empty line between groups of equal lines.

Ignore case when comparing

printf 'Apple\napple\nAPPLE\nbanana\n' | uniq -i -c
explain
output
      3 Apple
      1 banana

-i treats the three spellings as one group; the first spelling seen, Apple, is the one printed.

Compare from a later field on

printf '08:01 disk full\n08:02 disk full\n08:05 backup done\n' | uniq -f 1 -c
explain
output
      2 08:01 disk full
      1 08:05 backup done

-f 1 skips the first field (the timestamp) when comparing, so two consecutive "disk full" messages at different times count as repeats. The first line of each group is printed.

Compare only the first characters

printf 'web01 up\nweb02 up\ndb01 up\n' | uniq -w 3 -c
explain
output
      2 web01 up
      1 db01 up

-w 3 compares only the first three characters, so web01 and web02 form one group, and db01 another.

Trap: invisible differences break grouping

printf 'error \nerror\n' | uniq -c | cat -A
explain
output
      1 error $
      1 error$

The first line has a trailing space, so the lines differ and both are counted once. cat -A reveals it (error $). Trailing blanks and CRLF line endings are the usual culprits.

Common pitfalls

  • uniq only collapses adjacent equal lines. Sort first, or use sort -u, or awk '!seen[$0]++' to remove duplicates while keeping the original order.

  • sort and uniq must agree on what equal means: sorting with -f and then running uniq without -i leaves Apple and apple as separate lines.

  • The second file argument is an output file: uniq a.txt b.txt overwrites b.txt. It does not compare two files; use comm or diff for that.

  • uniq -c pads counts with leading spaces. To use them in a script, split with awk rather than cut -d ' '.

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).

  • -D, --group, -w and -z are GNU extensions. BSD/macOS uniq has -c, -d, -u, -i, -f and -s.

Options worth knowing

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

OptionWhat it does
-c, --countPrefix each line with the number of times it occurred.
-d, --repeatedPrint only lines that are repeated, one copy each.
-u, --uniquePrint only lines that are not repeated.
-DPrint all copies of repeated lines.
--all-repeated[=METHOD]Like -D, optionally separating groups: none, prepend or separate.
--group[=METHOD]Print all lines, separating groups with an empty line: separate, prepend, append or both.
-i, --ignore-caseIgnore differences in case when comparing.
-f, --skip-fields NSkip the first N fields before comparing.
-s, --skip-chars NSkip the first N characters before comparing.
-w, --check-chars NCompare no more than N characters.
-z, --zero-terminatedLines end with NUL instead of newline.

Related