Quelle est la différence entre "sort -u" et "sort | uniq "?

Partout où je vois quelqu'un qui a besoin d'get une list sortingée, unique, ils ont toujours tendance à sort | uniq sort | uniq . Je n'ai jamais vu d'exemples où quelqu'un utilise sort -u place. Pourquoi pas? Quelle est la différence, et pourquoi est-il préférable d'utiliser uniq que le drapeau unique pour sortinger?

sort | uniq sort | uniq existait avant le sort -u , et 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. C'est surtout un return aux jours où le sort -u n'existait pas (et les gens n'ont pas tendance à changer leurs methods si la façon dont ils savent continuer à fonctionner, il suffit de regarder ifconfig vs adoption ip ).

Les deux ont probablement été fusionnés, car la suppression des duplicates dans un file nécessite un sorting (au less, dans le cas standard) et est un cas d'utilisation extrêmement courant. Il est également plus rapide en interne en raison de la possibilité de faire les deux opérations en même time (et parce qu'il ne nécessite pas d'IPC entre uniq et sort ). Surtout si le file est volumineux, sort -u utilisera probablement less de files intermédiaires pour sortinger datatables.

Sur mon système, je reçois 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) copyd, 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 ne masque pas non plus le code de return, ce qui peut être important (dans les shells modernes, il existe des moyens d'get ceci, par exemple, le tableau $PIPESTATUS , mais ce n'était pas toujours vrai).

La seule différence est que uniq dispose d'un certain nombre 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. sort indicateur -u sort -u que la fonctionnalité de la command uniq sans fioritures.

Avec les sort et uniq s conforms à POSIX (GNU uniq n'est actuellement pas compatible à cet égard), il y a une différence dans ce sort qui utilise l'algorithm de collationnement des parameters régionaux pour comparer les strings (en général, strcoll() pour comparer les strings) -value identity (utilisera typiquement strcmp() ).

Cela count pour au less deux raisons.

  • Dans certains environnements, en particulier sur les systèmes GNU, il existe différents caractères qui sont identiques. Par exemple, dans les parameters régionaux en_US.UTF-8 sur un système GNU, tous les caractères ①②③④⑤⑥⑦⑧⑨⑩ … et bien d'autres sont identiques car leur ordre de sorting n'est pas défini. Les numbers arabes 0123456789 sont les mêmes que leurs homologues arabes orientaux (0123456789).

    Pour sort -u , ① sortinge la même chose que ② et 0123 la même chose que 0123 pour que sort -u ne retienne qu'un seul de chacun, alors que pour uniq (pas GNU uniq qui utilise strcoll() (sauf avec -i )), ① est différent de ② et 0123 différent de 0123, donc uniq considérerait les 4 uniques.

  • strcoll ne peut comparer que des strings de caractères valides (le comportement est indéfini selon POSIX lorsque l'input a des séquences d'octets qui ne forment pas de caractères valides) alors que strcmp() ne se soucie pas des caractères puisqu'il ne fait que des octets Comparaison. C'est donc une autre raison pour laquelle le sort -u ne peut pas vous donner toutes les lignes uniques si certains d'entre eux ne forment pas un text valide. sort|uniq , même s'il n'est toujours pas spécifié sur les inputs non textuelles, dans la pratique est plus susceptible de vous donner des lignes uniques pour cette raison.

A côté de ces subtilités, une chose qui n'a pas été notée jusqu'ici est que uniq compare la ligne entière lexicalement, tandis que la méthode de sort -u compare en fonction de la spécification de sorting donnée sur la command line.

 $ printf '%s\n' 'ab' 'ac' | sort -uk 1,1 ab $ printf '%s\n' 'ab' 'ac' | sort -k 1,1 | uniq ab ac $ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq 0 -0 +0 00 $ printf '%s\n' 0 -0 +0 00 '' | sort -nu 0 

Je préfère utiliser le sort | uniq sort | uniq parce que lorsque j'essaie d'utiliser l'option -u (éliminer les duplicates) pour supprimer les duplicates impliquant des strings de cas mixtes, ce n'est pas si facile de comprendre le résultat.

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

 LC_ALL=C export LC_ALL 

Par exemple, si je veux sortinger un file et supprimer les duplicates, tout en gardant les différents cas de strings distincts.

 $ 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(ie, why did it remove pear instead of Pear?) 

Cette confusion est résolue en n'utilisant pas l'option -u pour supprimer les duplicates. Utiliser uniq est plus prévisible. Le premier ci-dessous sortinge et ignore le cas et le transmet ensuite à uniq pour supprimer les duplicates.

 $ sort -f short | uniq Apple apple Pear pear 

Une autre différence que j'ai découvert aujourd'hui est lors du sorting basé sur un délimiteur où sort -u applique le drapeau unique uniquement sur la colonne avec laquelle vous sortingez.

 $ 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 
 $ cat need2sort pma2005 PMA2005 pma2005 $ LC_CTYPE="C" sort -fu need2sort pma2005 $ LC_CTYPE="C" sort -f need2sort | uniq PMA2005 pma2005