Як Uniq недостатньо унікальний, що існує також uniq -unique?


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робить прапор. Будь-яка порада?


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 Я час від часу хотів вміти зберігати перший екземпляр будь-якого рядка, не переставляючи їх, і писав сценарії для цього.
Випадково832

1
@hvd: якщо у вашій версії uniqвідбувається нормалізація та порівняння, так. Але навіть тоді це лише місцевий розгляд - ви знаєте, де в відсортованому виході з'явиться рядок, і вам просто потрібно вибрати, який із кількох суміжних рядків зберегти. Якщо введення не сортоване, то рішення впливає на всю операцію уніфікації, наприклад, якщо ви збираєтеся зберегти останній дублікат, ви нічого не можете вивести, поки не прочитаєте останній рядок введення ...
Стів Джессоп

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варіант зробити uniqне друкувати повторні рядки.

Більшість uniqреалізацій використовували порівняння байтів, тоді як GNU uniqвикористовував порядок порівняння для фільтрації дублюваних рядків. Таким чином, це може призвести до помилкового результату в деяких локалях, наприклад в en_US.UTF-8locale:

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

і не -uдав вам рядків:

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

Тому вам слід встановити локаль для Cпорівняння байтів:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②

3
Зауважте, що тут неправильно не так багато uniq(хоча, мабуть, наміром POSIX було те, що він повинен робити порівняння байтів замість порівняння strcoll (), як у sort -u), як ті локалі, які помилково have сортують те саме, що ②. Принаймні 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

sort / uniq: все чітко

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

приємні чіткі приклади :)
Мадівад
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.