В чем разница между «sort -u» и «sort | уник»?

120

Везде, где я вижу, кто-то должен получить отсортированный, уникальный список, к которому они всегда обращаются sort | uniq. Я никогда не видел примеров, где кто-то использует sort -uвместо этого. Почему нет? В чем разница, и почему для сортировки лучше использовать uniq, чем уникальный флаг?

Benubird
источник

Ответы:

120

sort | uniqсуществовал ранее sort -uи совместим с более широким спектром систем, хотя почти все современные системы поддерживают -uего - это POSIX. В основном это возврат к тем временам, когда sort -uих не было (и люди не склонны менять свои методы, если способ, который они знают, продолжает работать, просто посмотрите ifconfigпротив ipпринятия).

Вероятно, они были объединены, поскольку удаление дубликатов в файле требует сортировки (по крайней мере, в стандартном случае) и является чрезвычайно распространенным вариантом использования сортировки. Это также быстрее внутри благодаря возможности выполнять обе операции одновременно (и из-за того, что не требуется IPC между uniqи sort). Особенно, если файл большой, sort -uвероятно , будет использовать меньше промежуточных файлов для сортировки данных.

В моей системе я последовательно получаю такие результаты:

$ dd if=/dev/urandom of=/dev/shm/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.95208 s, 11.7 MB/s
$ time sort -u /dev/shm/file >/dev/null

real        0m0.500s
user        0m0.767s
sys         0m0.167s
$ time sort /dev/shm/file | uniq >/dev/null

real        0m0.772s
user        0m1.137s
sys         0m0.273s

Он также не скрывает код возврата sort, который может быть важным (в современных оболочках есть способы , чтобы получить это, например, bash«s $PIPESTATUSмассив, но это не всегда верно).

Крис Даун
источник
31
Я склонен использовать, sort | uniqпотому что 9 раз из 10, я на самом деле обожаю uniq -c.
Plutor
5
Обратите внимание, что это sort -uбыло частью 7-го издания UNIX, около 1979 года. Версии sortбез поддержки -uдействительно архаичны - или были написаны без учета стандарта де-факто до стандарта де-юре POSIX. См. Также Переполнение стека Sort & uniq в оболочке Linux с 2010 года.
Джонатан Леффлер
3
+1 из-за ip. Это 2016 год, а этот пост в 2013 году, но я знаю только о ipкоманде сейчас.
августа
4
+1 за «9 раз из 10, я на самом деле пипец к uniq -c» (и, возможно, пайпинг еще раз к sort -nr | head). Мне было интересно, что является эквивалентом sort | uniqв Vim, когда я узнал, что у Vim есть :sort uкоманда. И TIL также sort -uсуществует.
Чжуоюнь Вэй
Обратите внимание, что есть разница при использовании sort -n | uniqпротив sort -n -u. Например, конечные и ведущие пробелы будут рассматриваться как дубликаты, sort -n -uно не первыми! echo -e 'test \n test' | sort -n -uвозвращает test, но echo -e 'test \n test' | sort -n | uniqвозвращает обе строки.
mxmlnkn
46

Одно из отличий состоит в том, что у uniqнего есть ряд полезных дополнительных опций, таких как пропуск полей для сравнения и подсчет количества повторений значения. sort«ы -uфлаг реализует только функциональность неукрашенной uniqкоманды.

CLF
источник
3
+0,49 за полезный ответ, но я бы сказал что-то вроде «Вывод sort -uне может быть передан для uniqиспользования некоторых полезных опций последнего, таких как пропуск полей для сравнения и подсчет количества повторений».
10
15
+1, чтобы компенсировать скептиков, потому что «нет способа сделать это напрямую из сортировки» действительно отвечает на вопрос ...
Izkata
42

С POSIX-совместимыми sorts и uniqs (GNU uniqв настоящее время не совместим в этом отношении), есть различие в том, что sortиспользуется алгоритм сортировки локали для сравнения строк (обычно используется strcoll()для сравнения строк) при uniqпроверке идентичности байтового значения (обычно используется strcmp()) ,

Это важно как минимум по двум причинам.

  • В некоторых локалях, особенно в системах GNU, есть разные символы, которые сортируют одинаково. Например, в локали en_US.UTF-8 в системе GNU все символы ①②③④⑤⑥⑦⑧⑨⑩ ... и многие другие сортируют одинаково, поскольку их порядок сортировки не определен. Арабские цифры 0123456789 сортируются так же, как и их аналоги на восточном арабском языке (٠١٢٣٤٥٦٧٨٩).

    Для sort -u, ① сортирует так же, как ② и 0123, то же самое, что и ٠١٢٣, поэтому sort -uбудет сохранять только один из каждого, в то время как для uniq(не GNU, uniqкоторый использует strcoll()(кроме как с -i)), ① отличается от ② и 0123 отличается от ٠١٢٣, поэтому uniqбудет рассматривать все 4 уникальных.

  • strcollможет сравнивать только строки допустимых символов (поведение не определено в соответствии с POSIX, когда на входе есть последовательности байтов, которые не образуют допустимых символов), strcmp()но не заботится о символах, поскольку выполняет только побайтное сравнение. Так что это еще одна причина, почему вы sort -uможете не дать вам все уникальные строки, если некоторые из них не образуют корректный текст. sort|uniqхотя он не определен для нетекстового ввода, на практике с большей вероятностью по этой причине вы получите уникальные строки.

Помимо этих тонкостей, одна вещь , которую не было замечено до сих пор является то , что uniqсравнивает всю линию лексически, в то время как sort«s -uсопоставляются на основе спецификации сортировки , заданной в командной строке.

$ printf '%s\n' 'a b' 'a c' | sort -uk 1,1
a b
$ printf '%s\n' 'a b' 'a c' | sort -k 1,1 | uniq
a b
a c

$ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq
0
-0
+0
00

$ printf '%s\n' 0 -0 +0 00 '' | sort -nu
0
Стефан Шазелас
источник
9

Я предпочитаю использовать, sort | uniqпотому что, когда я пытаюсь использовать -uопцию (исключить дубликаты) для удаления дубликатов, включающих строки со смешанным регистром, не так просто понять результат.

Примечание: прежде чем вы сможете запустить приведенные ниже примеры, вам нужно смоделировать стандартную последовательность сортировки C, выполнив следующие действия:

LC_ALL=C
export LC_ALL

Например, если я хочу отсортировать файл и удалить дубликаты, в то же время сохраняя разные случаи строк различными.

$ cat short      #file to sort
Pear
Pear
apple
pear
Apple

$ sort short     #normal sort (in normal C collating sequence)
Apple            #the lower case words are at the end
Pear
Pear
apple
pear

$ sort -f short  #correctly sorts ignoring the C collating order
Apple            #but duplicates are still there
apple
Pear
Pear
pear

$ sort -fu short #By adding the -u option to remove duplicates it is 
apple            #difficult to ascertain the logic that sort uses to remove
Pear             #duplicates(i.e., why did it remove pear instead of Pear?)

Эта путаница -uустраняется, если не использовать опцию удаления дубликатов. Использование uniqболее предсказуемо. Нижеследующее сначала сортирует и игнорирует регистр, а затем передает его, uniqчтобы удалить дубликаты.

$ sort -f short | uniq
Apple
apple
Pear
pear
Джерри Марбас
источник
2
-uопция sortвывода первого из равного прогона (см. справочную страницу). Таким образом, sort -fuвыявляет первое вхождение каждой нечувствительной к регистру уникальной строки. Логика, которая sortиспользуется для удаления дубликатов, предсказуема.
pallxk
3

Еще одно отличие, которое я обнаружил сегодня, заключается в том, что при сортировке по разделителю sort -uприменяется уникальный флаг только для столбца, с которым вы сортируете.

$ cat input.csv
3,World,1
1,Hello,1
2,Hello,1

$ cat input.csv | sort -t',' -k2 -u
1,Hello,1
3,World,1

$ cat input.csv | sort -t',' -k2 | uniq
1,Hello,1
2,Hello,1
3,World,1
Стефанос Хрс
источник
Это упоминается в ответе Стефана Шазеля, но мне нравится ваш пример, поэтому +1
roaima
Спасибо за указание на @roaima, в этом ответе было не очень ясно
Stefanos Chrs