Linux / Commande uniq : supprimer et compter les doublons adjacents

uniq réduit les lignes identiques consécutives à une seule ligne, ou indique combien de fois elles se répètent. Il ne regroupe pas les doublons séparés par une autre ligne. Pour dédupliquer l'ensemble d'un fichier, il faut généralement regrouper les valeurs avec un tri préalable, ce qui change leur ordre d'origine.

Décidez donc d'abord ce que représente un doublon : une répétition immédiate dans un journal, ou une valeur présente plusieurs fois dans l'ensemble des données. Le premier cas peut être traité directement par uniq ; le second demande un regroupement compatible avec la comparaison souhaitée.

Syntaxe et petit jeu de données

uniq [options] [entrée [sortie]]

Sans chemin d'entrée, uniq lit l'entrée standard. Sans chemin de sortie, il affiche le résultat sur la sortie standard. Consultez man uniq pour les options de votre implémentation. Pour essayer les commandes dans Bash sans toucher à vos documents :

uniq_lab=$(mktemp -d "$HOME/uniq-lab.XXXXXX")
cd -- "$uniq_lab"
printf 'apple\napple\nbanana\napple\n' > events.txt
printf 'apple\napple\nbanana\napple\n' > names.txt

Les deux fichiers contiennent les mêmes quatre lignes. La dernière occurrence de apple est séparée des deux premières par banana. Le répertoire créé par mktemp -d est propre à cet exercice ; notez son chemin pour retrouver les résultats. Vous pourrez le quitter avec cd "$HOME".

Réduire et compter les répétitions adjacentes

LC_ALL=C uniq events.txt

Résultat attendu :

apple
banana
apple

Les deux premières lignes ont été regroupées, mais la dernière demeure. Un comptage montre les trois groupes successifs :

LC_ALL=C uniq -c events.txt
      2 apple
      1 banana
      1 apple

Les espaces qui alignent le compteur peuvent varier selon l'implémentation. Le nombre indique la taille du groupe adjacent, pas le total de cette valeur dans tout le fichier. Vous pouvez reproduire le même exemple sans fichier :

printf 'apple\napple\nbanana\napple\n' | LC_ALL=C uniq -c

Regrouper les valeurs dans tout le fichier

Pour compter les occurrences globales, le tri des lignes avec sort place les valeurs identiques les unes à côté des autres. Appliquez la même locale aux deux commandes :

LC_ALL=C sort names.txt | LC_ALL=C uniq -c
      3 apple
      1 banana

LC_ALL=C devant la première commande ne définit pas automatiquement l'environnement de la seconde partie du tube. En le précisant deux fois, vous utilisez ici les mêmes règles de comparaison. Cette locale donne une comparaison reproductible selon la locale C ; elle n'est pas un classement linguistique français.

Si vous voulez simplement une ligne par valeur, sans compteur, utilisez :

LC_ALL=C sort names.txt | LC_ALL=C uniq

La sortie contient apple, puis banana. Pour une comparaison de lignes entières sans options particulières, sort -u répond aussi à ce besoin. Évitez toutefois d'assimiler toutes les combinaisons de sort et uniq : les clés ou la comparaison numérique de sort peuvent modifier la signification de l'égalité.

Le tri change l'ordre des événements. Ne l'appliquez pas à un journal si la chronologie doit être conservée. Pour retirer les doublons non adjacents tout en gardant la première apparition de chaque valeur, il faut un traitement qui mémorise les valeurs déjà vues ; uniq seul ne réalise pas cette opération.

Distinguer -d et -u

-d affiche une seule représentation de chaque groupe répété. -u ne garde que les groupes d'une seule ligne. Comparez les résultats sur le fichier non trié :

LC_ALL=C uniq -d events.txt
LC_ALL=C uniq -u events.txt

La première commande affiche apple, correspondant au groupe des deux premières lignes. La seconde affiche banana puis apple : la dernière occurrence d'apple forme un groupe isolé, même si cette valeur apparaît ailleurs.

Après regroupement par tri, les mêmes options ont une portée globale sur ces données :

LC_ALL=C sort names.txt | LC_ALL=C uniq -d
LC_ALL=C sort names.txt | LC_ALL=C uniq -u

La première commande affiche seulement apple. La seconde affiche seulement banana, seule valeur présente une fois dans le fichier. uniq -u ne signifie donc pas « une copie de toutes les valeurs différentes ». Pour ce dernier résultat, utilisez uniq sans -u après avoir regroupé les lignes.

Ignorer la casse ou certains champs

Avec -i, la comparaison ignore les différences de casse. L'option ne transforme pas le texte affiché en minuscules :

printf 'Apple\napple\nBANANA\n' | LC_ALL=C uniq -ic
      2 Apple
      1 BANANA

Les lignes à regrouper doivent toujours être adjacentes. Si un tri préalable doit ignorer la casse, utilisez également une comparaison compatible côté sort, plutôt que de supposer que toutes les variantes seront naturellement voisines.

-f N ignore les N premiers champs pendant la comparaison. Ces champs reposent sur les blancs et les séquences non blanches ; cette option ne définit pas un séparateur CSV. Exemple avec un numéro suivi d'un état :

printf '01 OK\n02 OK\n03 FAIL\n04 OK\n' | LC_ALL=C uniq -f 1
01 OK
03 FAIL
04 OK

Les deux premières lignes sont considérées comme égales après avoir ignoré le premier champ. La première ligne complète est conservée ; son numéro n'est pas supprimé de la sortie. Si les champs ignorés contiennent des données importantes, cette réduction peut perdre des enregistrements différents.

Options et enregistrement du résultat

Option Effet
-c Préfixer chaque groupe par son nombre de lignes.
-d Afficher seulement les groupes répétés, une fois par groupe.
-u Afficher seulement les groupes qui contiennent une ligne.
-i Ignorer la casse lors de la comparaison.
-f N Ignorer les N premiers champs pour comparer.

Choisissez un nouveau fichier de sortie pour conserver l'entrée :

LC_ALL=C uniq events.txt events-condensed.txt
cat events-condensed.txt
cat events.txt

Le fichier condensé comporte trois lignes ; l'original en conserve quatre. Le chemin de sortie doit être différent de l'entrée et ne pas désigner un document à conserver. Une redirection telle que uniq events.txt > events.txt peut vider la source avant sa lecture ; uniq ne propose pas l'option -o de sort pour ce cas.

Si des répétitions inattendues restent visibles, vérifiez le fait qu’elles soient adjacentes, les différences de casse et les espaces qui font partie des lignes. Les règles exactes de comparaison sont documentées dans le manuel officiel de GNU uniq.