Quelle est la difference entre “sort -u” et “sort | uniq ”?

120

Partout où je vois quelqu'un qui a besoin d'une liste unique et triée, il le fait toujours sort | uniq. Je n'ai jamais vu d'exemples où quelqu'un utilise à la sort -uplace. Pourquoi pas? Quelle est la différence et pourquoi est-il préférable d'utiliser uniq plutôt que le drapeau unique pour trier?

Benubird
la source

Réponses:

120

sort | uniqexistait auparavant sort -uet est compatible avec un plus grand nombre de systèmes, bien que presque tous les systèmes modernes prennent en charge -u- c’est POSIX. Il est la plupart du temps un retour à l'époque où sort -un'existaient pas (et les gens tendent à ne pas changer leurs méthodes si la façon dont ils savent continue à travailler, il suffit de regarder par ifconfigrapport à l' ipadoption).

Les deux ont probablement été fusionnés, car la suppression des doublons dans un fichier nécessite un tri (au moins, dans le cas standard), et constitue un cas d'utilisation extrêmement courant. Il est également plus rapide en interne car il permet de réaliser les deux opérations en même temps (et du fait qu’il n’exige pas d’IPC entre uniqet sort). Surtout si le fichier est volumineux, vous sort -uutiliserez probablement moins de fichiers intermédiaires pour trier les données.

Sur mon système, j'obtiens régulièrement des résultats comme celui-ci:

$ 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

Il masque également ne pas le code de retour sort, qui peut être important (dans des coquilles modernes , il existe des moyens pour obtenir, par exemple, bashl » $PIPESTATUSensemble, mais ce ne fut pas toujours vrai).

Chris Down
la source
31
J'ai tendance à utiliser sort | uniqparce que 9 fois sur 10, je suis en train de faire piping uniq -c.
Plutor
5
Notez que cela sort -ufaisait partie de la 7e édition d'UNIX, vers 1979. Les versions de sortsans support pour -usont vraiment archaïques - ou ont été écrites sans tenir compte du standard de facto avant le standard de jure de POSIX. Voir aussi Stack Overflow Sort & uniq dans le shell Linux à partir de 2010.
Jonathan Leffler
3
+1 à cause de ip. Nous sommes en 2016 et cette publication en 2013, mais je ne connais que la ipcommande maintenant.
Départ
4
+1 pour "9 fois sur 10, je suis effectivement en train de uniq -c" (et peut-être encore une fois sort -nr | head). Je me demandais à quoi équivaut sort | uniqdans Vim quand j'ai découvert que Vim avait le :sort ucommandement. Et TIL sort -uexiste aussi.
Zhuoyun Wei
Notez qu'il ya une différence lors de l' utilisation par sort -n | uniqrapport sort -n -u. Par exemple, les espaces de début et de fin seront considérés comme des doublons, sort -n -umais pas par les précédents! echo -e 'test \n test' | sort -n -uretourne test, mais echo -e 'test \n test' | sort -n | uniqretourne les deux lignes.
mxmlnkn
46

Une différence réside dans le uniqnombre d'options supplémentaires utiles, telles que le saut de champs pour la comparaison et le comptage du nombre de répétitions d'une valeur. sortLe -udrapeau de n'implémente que les fonctionnalités de la uniqcommande sans fioritures .

CLF
la source
3
+0,49 pour une réponse utile, mais je dirais: "Le résultat de sort -une peut pas être uniqutilisé pour utiliser certaines des options utiles de ce dernier, telles que le saut de champs pour la comparaison et le comptage du nombre de répétitions."
l0b0
15
+1 pour compenser les opposants car "il n'y a aucun moyen de le faire directement à partir d'une sorte" répond bien à la question ...
Izkata
42

Avec les normes sorts et uniqs compatibles avec POSIX (GNU uniqn’est actuellement pas conforme à cet égard), il existe une différence en sortutilisant l’algorithme de classement des paramètres régionaux pour comparer les chaînes (généralement utilisé strcoll()pour comparer les chaînes) tout en uniqvérifiant l’identité en valeur des octets (généralement utilisée strcmp()). .

Cela compte pour au moins deux raisons.

  • Dans certains paramètres régionaux, en particulier sur les systèmes GNU, différents caractères trient de la même manière. Par exemple, dans les paramètres régionaux en_US.UTF-8 sur un système GNU, tous les caractères ①②③④⑤⑥⑦⑧⑨⑩ ... et beaucoup d'autres sont identiques, car leur ordre de tri n'est pas défini. Les chiffres arabes 0123456789 sont du même ordre que leurs homologues indiens de l’indien arabe oriental (٠١٢٣٤٥٦٧٨٩).

    Car sort -u, ① trie la même chose que et 0123, pareil que ٠١٢٣, sort -un'en retiendrait qu'un, alors que pour uniq(pas GNU uniqqui utilise strcoll()(sauf avec -i)), ① est différent de et 0123, différent de, donc uniqconsidérerait tout 4 unique.

  • strcollpeut uniquement comparer des chaînes de caractères valides (le comportement n'est pas défini selon POSIX lorsque l'entrée contient des séquences d'octets qui ne forment pas des caractères valides), alors strcmp()que les caractères sont indifférents, car ils ne font que comparer octet par octet. C'est donc une autre raison pour laquelle sort -uvous ne pouvez pas vous donner toutes les lignes uniques si certaines ne forment pas un texte valide. sort|uniq, bien que non spécifiée pour la saisie non textuelle, est plus susceptible de vous donner des lignes uniques pour cette raison.

À côté de ces subtilités, une chose qui n’a pas été remarquée jusqu’à présent est que la uniqligne entière est comparée lexicalement, tandis que sortla -ucomparaison de est basée sur la spécification de tri donnée sur la ligne de commande.

$ 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
Stéphane Chazelas
la source
9

Je préfère utiliser sort | uniqparce que lorsque j'essaie d'utiliser l' -uoption (éliminer les doublons) pour supprimer les doublons impliquant des chaînes de casse mixtes, il n'est pas facile de comprendre le résultat.

Remarque: avant de pouvoir exécuter les exemples ci-dessous, vous devez simuler la séquence de classement C standard en procédant comme suit:

LC_ALL=C
export LC_ALL

Par exemple, si je veux trier un fichier et supprimer les doublons, tout en maintenant les différentes cas de chaînes distinctes.

$ 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?)

Cette confusion est résolue en n'utilisant pas l' -uoption de suppression des doublons. L'utilisation uniqest plus prévisible. La première ci-dessous trie et ignore le cas, puis le passe à uniqpour supprimer les doublons.

$ sort -f short | uniq
Apple
apple
Pear
pear
Jerry Marbas
la source
2
-uoption de sortsortie du premier d'une exécution égale (voir la page de manuel). Ainsi sort -fu, la première occurrence de chaque ligne unique insensible à la casse est prise en compte. La logique sortutilisée pour supprimer les doublons est prévisible.
pallxk
3

Une autre différence que j'ai constatée aujourd'hui concerne le tri basé sur un délimètre où sort -ul'indicateur unique s'applique uniquement à la colonne avec laquelle vous triez.

$ 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
Stefanos Chrs
la source
Ceci est mentionné dans une réponse de Stéphane Chazelas mais j'aime bien votre exemple alors +1
roaima
Merci d'avoir signalé @roaima, la réponse à cette question n'était pas très claire
Stefanos Chrs le