Comment uniq n’est-il pas assez unique pour qu’il existe également uniq --unique?

35

Voici les commandes sur un fichier aléatoire de 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

Les pages de manuel ne disent pas clairement ce que fait le -udrapeau. Aucun conseil?

enfascination
la source
4
Essayez de trier | uniq -d | wc -l et vous remarquerez peut-être la différence. :)
Stoeff

Réponses:

42

Version courte:

  • uniqsans -u, rend chaque ligne de la sortie unique.
  • uniq -uimprime seulement chaque ligne unique de l’entrée .

Version légèrement plus longue:

uniqest destiné à traiter des fichiers dont les lignes sont dupliquées et uniquement lorsque ces lignes apparaissent successivement dans l'entrée. Ainsi, pour ses besoins, une ligne unique est une ligne qui n'est pas dupliquée immédiatement.

( uniqa une mémoire à court terme très limitée; il ne se souviendra jamais si une ligne est apparue plus tôt dans l'entrée, à moins que ce soit la ligne immédiatement précédente - c'est pourquoi il uniqest très souvent associé à sort.)

Lorsqu'il rencontre une série de lignes en double uniq, sans l' -uargument, en imprime une copie. (Chaque ligne de la sortie est unique ).

Avec l' -uargument, il n'imprime aucune copie de cette ligne. Les doublons sont simplement omis de la sortie.

Ian Clelland
la source
1
Je souhaite vraiment qu'il y avait une option pour ne pas exiger le tri. Mais il faudrait garder tout le fichier en mémoire (ou faire beaucoup de comptabilité avec des hachages et des décalages si la source est un fichier normal)
Aléatoire832
3
@ Random832: et il faudrait décider lequel des dupes à conserver (premier, dernier, quelque chose d'autre, configurable), et cette décision affecterait l'algorithme globalement. Tracas.
Steve Jessop
1
@ Random832: s'il ne s'agit que du nombre de caractères à saisir, vous pouvez utiliser à la sort -uplace sort | uniq.
oliver
@oliver J'ai parfois voulu avoir la possibilité de conserver la première instance d'une ligne sans la réorganiser, et d'écrire des scripts pour le faire.
hasard832
1
@hvd: si votre version de la uniqnormalisation et de la collationnement le fait, oui. Mais même dans ce cas, il s’agit uniquement d’une considération locale: vous savez où la ligne apparaîtra dans la sortie triée et vous n’avez plus qu’à sélectionner celle de plusieurs lignes adjacentes à conserver. Si l'entrée n'est pas triée, la décision affecte l'ensemble de l'opération d'unification. Par exemple, si vous souhaitez conserver la dernière copie, vous ne pouvez rien afficher tant que vous n'avez pas lu la dernière ligne de l'entrée ...
Steve Jessop
53

uniqavec -upasse toutes les lignes qui ont des doublons. Ainsi:

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

Habituellement, uniqimprime les lignes au plus une fois (en supposant que l’entrée soit triée). Cette option permet d’imprimer des lignes véritablement uniques (qui ne sont plus apparues).

muru
la source
11
C'est-à-dire que l'on uniqpourrait appeler distinct, car il imprime toutes les lignes distinctes, alors que uniq -utoutes les lignes uniques sont imprimées.
Steve Jessop
Ce n'est pas vraiment unique avec GNU uniqdans certaines langues.
jeudi
J'ai dû lire la réponse acceptée à plusieurs reprises, mais elle n'a pas été intégrée. Votre exemple et le paragraphe qui suit sont très clairs (et si vous relisez la réponse acceptée, je comprends cela) :)
Madivad
18

Uniq POSIX spec l'a décrit clairement:

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

-uoption make uniqpour ne pas imprimer les lignes répétées.

La plupart des uniqimplémentations utilisaient la comparaison d'octets, tandis que GNU uniqutilisait l'ordre de tri pour filtrer les lignes dupliquées. Donc, cela peut produire un résultat erroné dans certaines locales, exemple dans en_US.UTF-8locale:

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

et -une vous a pas donné de lignes:

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

Vous devez donc définir les paramètres régionaux sur Cpour obtenir la comparaison d'octets:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②
cuonglm
la source
3
Notez que ce qui ne va pas ici n’est pas aussi important uniq(bien qu’apparemment, l’intention de POSIX était de faire la comparaison entre octets au lieu de la comparaison avec strcoll () comme dans sort -u) comme les environnements locaux dans lesquels ① trie de manière identique le même que. Au moins, GNU uniqest compatible avec sort -u.
Stéphane Chazelas
@ StéphaneChazelas - Où dans la spécification cela est-il apparent?
mikeserv
À propos de l' uniqobligation de faire memcmp / strcmp plutôt que strcoll, ce n'est pas très évident pour moi, mais c'était pour Geoff . À propos des environnements locaux GNU ayant «triant la même chose que», il s'agit clairement d'un bogue, car il n'y a aucune raison pour qu'ils trient la même chose C'est autorisé par POSIX, mais des changements sont à venir .
Stéphane Chazelas
8

Ordinaire:

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

uniq: pas deux lignes répétées

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

triés

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

sort -u: pas deux lignes répétitives

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

sort / uniq: tous distincts

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

compte des occurrences distinctes

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

seulement les lignes qui ne sont pas répétées (non triées en premier)

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

seulement les lignes qui ne sont pas répétées (après le tri)

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

uniq -d: imprime uniquement les lignes en double, une pour chaque groupe

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

.. compté

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c
jmullee
la source
beaux exemples clairs :)
Madivad