137 votes

Supprimer les lignes en double sans trier

J'ai un utilitaire script en Python :

#!/usr/bin/env python
import sys
unique_lines = []
duplicate_lines = []
for line in sys.stdin:
  if line in unique_lines:
    duplicate_lines.append(line)
  else:
    unique_lines.append(line)
    sys.stdout.write(line)
# optionally do something with duplicate_lines

Cette simple fonctionnalité ( uniq sans avoir besoin de trier d'abord, ordre stable) doit être disponible comme un simple utilitaire UNIX, n'est-ce pas ? Peut-être une combinaison de filtres dans un tuyau ?

Motif de la demande : j'ai besoin de cette fonctionnalité sur un système sur lequel je ne peux pas exécuter Python depuis n'importe où.

335voto

Michael Hoffman Points 8557

Le blog sur le scriptage UNIX Bash suggère :

awk '!x[$0]++'

Cette commande indique à awk les lignes à imprimer. La variable $0 contient le contenu entier d'une ligne et les crochets permettent d'accéder au tableau. Ainsi, pour chaque ligne du fichier, le nœud du tableau x est incrémenté et la ligne est imprimée si le contenu de ce nœud n'était pas ( ! ) précédemment défini.

85voto

DigitalTrauma Points 6235

Une réponse tardive - je viens de tomber sur un double de ceci - mais cela vaut peut-être la peine d'être ajouté...

Le principe qui sous-tend la réponse de @1_CR peut être écrit de manière plus concise, à l'aide des éléments suivants cat -n au lieu de awk pour ajouter des numéros de ligne :

cat -n file_name | sort -uk2 | sort -n | cut -f2-
  • Utilisez cat -n pour faire précéder les numéros de ligne
  • Utilisez sort -u supprimer les données dupliquées ( -k2 dit 'commencer au champ 2 pour la clé de tri')
  • Utilisez sort -n pour trier par le numéro ajouté au préalable
  • Utilisez cut pour supprimer la numérotation des lignes ( -f2- dit 'select field 2 till end')

8voto

Azi Points 2421

Pour supprimer les doublons de 2 fichiers :

awk '!a[$0]++' file1.csv file2.csv

5voto

1_CR Points 11848

La solution proposée par Michael Hoffman ci-dessus est courte et efficace. Pour les fichiers plus volumineux, une approche de transformation schwartzienne impliquant l'ajout d'un champ d'indexation à l'aide d'awk, suivi de plusieurs tours de tri et d'uniq, implique une charge mémoire moindre. L'extrait suivant fonctionne en bash

awk '{print(NR"\t"$0)}' file_name | sort -t$'\t' -k2,2 | uniq --skip-fields 1 | sort -k1,1 -t$'\t' | cut -f2 -d$'\t'

4voto

Shou Ya Points 633

Vous pouvez maintenant découvrir ce petit outil écrit en Rust : uq .

Il effectue un filtrage d'unicité sans avoir à trier l'entrée au préalable, et peut donc s'appliquer à un flux continu.

Cet outil présente deux avantages par rapport à la solution awk, qui a été plébiscitée, et aux autres solutions basées sur le shell :

  1. uq se souvient de l'occurrence des lignes en utilisant leurs valeurs de hachage, de sorte qu'il n'utilise pas autant de mémoire lorsque les lignes sont longues.
  2. uq peut maintenir l'utilisation de la mémoire constante en fixant une limite au nombre d'entrées à stocker (lorsque la limite est atteinte, il y a un drapeau pour contrôler si l'on doit passer outre ou mourir), tandis que la fonction awk pourrait se heurter à des problèmes d'erreurs de manipulation lorsqu'il y a trop de lignes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X