web-dev-qa-db-fra.com

Supprimer les lignes en double sans trier

J'ai un script utilitaire 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 fonctionnalité simple (uniq sans avoir besoin de trier d'abord, ordre stable) doit être disponible sous la forme d'un simple utilitaire UNIX, n'est-ce pas? Peut-être une combinaison de filtres dans un tuyau?

Raison de demander: besoin de cette fonctionnalité sur un système sur lequel je ne peux pas exécuter python de n'importe où

80
Robottinosino

Le blog UNIX Bash Scripting suggère :

awk '!x[$0]++'

Cette commande indique à awk les lignes à imprimer. La variable $0 contient l'intégralité du contenu d'une ligne et les crochets représentent un accès au tableau. Ainsi, pour chaque ligne du fichier, le noeud du tableau x est incrémenté et la ligne imprimée si le contenu de ce noeud n'était pas (!) défini auparavant.

202
Michael Hoffman

Une réponse tardive - je viens de tomber sur une copie de ceci - mais peut-être la peine d’ajouter ...

Le principe de la réponse de @ 1_CR peut être écrit de manière plus précise, en utilisant cat -n au lieu de awk pour ajouter des numéros de ligne:

cat -n file_name | sort -uk2 | sort -nk1 | cut -f2-
  • Utilisez cat -n pour ajouter des numéros de ligne
  • Utilisez sort -u supprimer les données en double
  • Utilisez sort -n pour trier par numéro ajouté
  • Utilisez cut pour supprimer la numérotation de ligne
46
Digital Trauma

La solution de Michael Hoffman ci-dessus est courte et douce. Pour les fichiers plus volumineux, une approche de transformation schwartzienne impliquant l'ajout d'un champ d'index à l'aide de awk suivi de plusieurs tours de tri et uniq implique moins de surcharge de mémoire. 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'
5
iruvar

Pour supprimer les doublons de 2 fichiers: 

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

Merci 1_CR! J'avais besoin d'un "uniq -u" (supprimer entièrement les doublons) plutôt que d'uniq (laisser 1 copie des doublons). Les solutions awk et Perl ne peuvent pas vraiment être modifiées pour ce faire, vous pouvez le faire! J'aurais peut-être aussi besoin de moins de mémoire, car je vais unifier environ 100 000 000 lignes 8). Juste au cas où quelqu'un d'autre en aurait besoin, je viens de mettre un "-u" dans la partie uniq de la commande:

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

la commande uniq fonctionne dans un alias même http://man7.org/linux/man-pages/man1/uniq.1.html

0
Master James

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

Il effectue le filtrage de l'unicité sans avoir à trier d'abord l'entrée, donc peut s'appliquer sur un flux continu.

0
Shou Ya

Je voulais juste supprimer tous les doublons sur les lignes suivantes, pas partout dans le fichier. Alors j'ai utilisé:

awk '{
  if ($0 != PREVLINE) print $0;
  PREVLINE=$0;
}'
0
speedolli