Как уникальна уникальность uniq, что существует и уникальная уникальность?

35

Вот команды для случайного файла из pastebin :

wget -qO - http://pastebin.com/0cSPs9LR | wc -l
350
wget -qO - http://pastebin.com/0cSPs9LR | sort -u | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq -u | wc -l
258

Страницы руководства не ясно о том, что -uделает флаг. Любой совет?

enfascination
источник
4
Попробуйте сортировать | uniq -d | wc -l, и вы можете заметить разницу. :)
Stoeff

Ответы:

42

Укороченная версия:

  • uniq, без -u, делает каждую строку вывода уникальной.
  • uniq -uпечатает только каждую уникальную строку из ввода .

Чуть более длинная версия:

uniqпредназначен для работы с файлами с дублированными строками, и только тогда, когда эти строки появляются последовательно во входных данных. Таким образом, для своих целей уникальная строка - это строка, которая не дублируется сразу.

( uniqимеет очень ограниченную кратковременную память; он никогда не будет помнить, появилась ли ранее строка на входе, если это не была непосредственно предыдущая строка - вот почему uniqочень часто в паре с sort.)

Когда встречается повторяющиеся строки, uniqбез -uаргумента печатается одна копия этой строки. (Это делает каждую строку вывода уникальной ).

С -uаргументом он печатает ноль копий этой строки - серии дубликатов просто исключаются из вывода.

Ян Клелланд
источник
1
Мне бы очень хотелось, чтобы была возможность не требовать сортировки. Но это потребовало бы сохранения всего файла в памяти (или выполнения большого количества операций учета с хэшами и смещениями, если источником является обычный файл)
Random832
3
@ Random832: и для этого потребуется решить, какой из дупсов оставить (первым, последним, что-то еще, настраиваемым), и это решение повлияет на алгоритм в глобальном масштабе. Хлопот.
Стив Джессоп
1
@ Random832: если речь идет только о количестве символов для ввода, вы можете использовать sort -uвместо sort | uniq.
Оливер
@oliver Я иногда хотел иметь возможность сохранить первый экземпляр любой строки, не переставляя их, и написать сценарии для этого.
Random832
1
@hvd: если ваша версия uniqвыполняет нормализацию и сопоставление, да. Но даже тогда это только локальное соображение - вы знаете, где в отсортированном выводе появится строка, и вам просто нужно выбрать, какую из нескольких соседних строк сохранить. Если входные данные не отсортированы, то решение влияет на всю операцию uniqifying, например, если вы собираетесь сохранить последний дубликат, вы ничего не сможете вывести, пока не прочитаете последнюю строку ввода ...
Стив Джессоп
53

uniqс -uпропускает любые строки, которые имеют дубликаты. Таким образом:

$ printf "%s\n" 1 1 2 3 | uniq
1
2
3
$ printf "%s\n" 1 1 2 3 | uniq -u
2
3

Обычно uniqпечатает строки не более одного раза (при условии отсортированного ввода). Эта опция на самом деле печатает строки, которые действительно уникальны (не появившись снова).

Мур
источник
11
То есть, uniqможет быть вызван distinct, поскольку он печатает все отдельные строки, тогда как uniq -uпечатает все уникальные строки.
Стив Джессоп
Это не совсем уникально с GNU uniqв некоторых локалях.
cuonglm
Должно быть, я прочитал принятый ответ несколько раз, но он не просочился. Ваш пример и параграф после него проясняют его (и, возвращаясь и перечитывая принятый ответ, я тоже это получаю) :)
Мадивад
18

Спецификация uniq POSIX описала это ясно:

-u
    Suppress the writing of lines that are repeated in the input.

-uопция make uniqне печатать повторяющиеся строки.

В большинстве uniqреализаций использовалось сравнение байтов, а в GNU uniqиспользовался порядок сортировки для фильтрации дублированных строк. Таким образом, он может давать неправильный результат в некоторых локалях, например в en_US.UTF-8локали:

$ printf '%b\n' '\U2460' '\U2461' | uniq
①

и не -uдал вам никаких строк:

$ printf '%b\n' '\U2460' '\U2461' | uniq -u
<blank>

Таким образом, вы должны установить locale Cдля получения байтового сравнения:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②
cuonglm
источник
3
Обратите внимание, что здесь неправильно не так много uniq(хотя очевидно, что цель POSIX состояла в том, чтобы он выполнял сравнение байтов вместо strcoll (), как в sort -u), в отличие от тех локалей, которые ошибочно имеют «сортировку, такую ​​же как». По крайней мере, GNU uniqсоответствует sort -u.
Стефан Шазелас
@ StéphaneChazelas - где в спецификации это становится очевидным?
mikeserv
О том, что uniqтребуется сделать memcmp / strcmp, а не strcoll, для меня это не очень очевидно, но для Джеффа . Для локалей GNU, имеющих «сортировку так же, как», это явно ошибка, поскольку нет причины, по которой они должны сортировать то же самое. Это разрешено POSIX, но есть некоторые изменения .
Стефан Шазелас
8

обычный:

echo "a b a b c c c" | tr ' ' '\n'
a
b
a
b
c
c
c

uniq: нет двух последовательных повторяющихся строк

echo "a b a b c c c" | tr ' ' '\n' | uniq
a
b
a
b
c

отсортированный

echo "a b a b c c c" | tr ' ' '\n' | sort
a
a
b
b
c
c
c

sort -u: нет двух повторяющихся строк

echo "a b a b c c c" | tr ' ' '\n' | sort -u
a
b
c

сортировка / уникальность: все различно

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq
a
b
c

считает различные случаи

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq -c
2 a
2 b
3 c

только строки, которые не повторяются (не отсортированы первыми)

echo "a b a b c c c" | tr ' ' '\n' | uniq -u
a
b
a
b

только строки, которые не повторяются (после сортировки)

echo "a b a b c c c Z" | tr ' ' '\n' | sort | uniq -u
Z

uniq -d: печатать только повторяющиеся строки, по одной для каждой группы

echo "a b a b c c c" | tr ' ' '\n' | uniq -d
c

.. посчитал

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c
jmullee
источник
хорошие наглядные примеры :)
Мадивад