Trouver des lignes en double dans un fichier et compter combien de fois chaque ligne a été dupliquée?

529

Supposons que j'ai un fichier similaire au suivant:

123 
123 
234 
234 
123 
345

Je voudrais savoir combien de fois '123' a été dupliqué, combien de fois '234' a été dupliqué, etc. Donc, idéalement, la sortie serait comme:

123  3 
234  2 
345  1
user839145
la source
4
Quelle langue souhaitez-vous utiliser?
VMAtm

Réponses:

791

En supposant qu'il y a un numéro par ligne:

sort <file> | uniq -c

Vous pouvez également utiliser l' --countindicateur le plus verbeux avec la version GNU, par exemple sous Linux:

sort <file> | uniq --count
wonk0
la source
3
C'est ce que je fais cependant, algorithmiquement, cela ne semble pas être l'approche la plus efficace (O (n log n) * avg_line_len où n est le nombre de lignes). Je travaille sur des fichiers de plusieurs gigaoctets, donc les performances sont un problème clé. Je me demande s'il existe un outil qui ne fait que compter en une seule passe en utilisant un arbre de préfixe (dans mon cas, les chaînes ont souvent des préfixes communs) ou similaire, qui devrait faire l'affaire dans O (n) * avg_line_len. Quelqu'un connaît-il un tel outil de ligne de commande?
Droggl
21
Une étape supplémentaire consiste à canaliser la sortie de cela dans une commande finale «sort -n». Cela triera les résultats selon lesquels les lignes apparaissent le plus souvent.
samoz
79
Si vous ne souhaitez imprimer que des lignes en double, utilisez 'uniq -d'
DmitrySandalov
6
Si vous voulez trier à nouveau le résultat, vous pouvez utiliser à sortnouveau comme:sort <file> | uniq -c | sort -n
Abhishek Kashyap
414

Cela imprimera uniquement les lignes en double , avec les nombres:

sort FILE | uniq -cd

ou, avec les options longues GNU (sous Linux):

sort FILE | uniq --count --repeated

sur BSD et OSX, vous devez utiliser grep pour filtrer les lignes uniques:

sort FILE | uniq -c | grep -v '^ *1 '

Pour l'exemple donné, le résultat serait:

  3 123
  2 234

Si vous souhaitez imprimer le nombre de toutes les lignes, y compris celles qui n'apparaissent qu'une seule fois:

sort FILE | uniq -c

ou, avec les options longues GNU (sous Linux):

sort FILE | uniq --count

Pour l'entrée donnée, la sortie est:

  3 123
  2 234
  1 345

Afin de trier la sortie avec les lignes les plus fréquentes en haut, vous pouvez faire ce qui suit (pour obtenir tous les résultats):

sort FILE | uniq -c | sort -nr

ou, pour obtenir uniquement des lignes en double, les plus fréquentes en premier:

sort FILE | uniq -cd | sort -nr

sur OSX et BSD, le dernier devient:

sort FILE | uniq -c | grep -v '^ *1 ' | sort -nr
Andrea
la source
1
Bon point avec l'option --repeated ou -d. Bien plus précis que d'utiliser "| grep 2" ou similaire!
Lauri
Comment puis-je modifier cette commande pour récupérer toutes les lignes dont le nombre de répétitions est supérieur à 100?
Black_Rider
@Black_Rider L'ajout de | sort -nou | sort -nrau tuyau triera la sortie par nombre de répétitions (croissant ou décroissant respectivement). Ce n'est pas ce que vous demandez, mais j'ai pensé que cela pourrait aider.
Andrea
1
@Black_Rider awk semble capable de faire toutes sortes de calculs: dans votre cas, vous pourriez le faire| awk '$1>100'
Andrea
4
@fionbio Il semble que vous ne puissiez pas utiliser -c et -d ensemble sur OSX uniq . Merci d'avoir souligné. Vous pouvez utiliser grep pour filtrer les lignes uniques :sort FILE | uniq -c | grep -v '^ *1 '
Andrea
72

Pour rechercher et compter les lignes en double dans plusieurs fichiers, vous pouvez essayer la commande suivante:

sort <files> | uniq -c | sort -nr

ou:

cat <files> | sort | uniq -c | sort -nr
kenorb
la source
30

Via :

awk '{dups[$1]++} END{for (num in dups) {print num,dups[num]}}' data

Dans la awk 'dups[$1]++'commande, la variable $1contient tout le contenu de la colonne1 et les crochets sont un accès au tableau. Ainsi, pour chaque 1ère colonne de ligne dans le datafichier, le nœud du tableau nommé dupsest incrémenté.

Et à la fin, nous bouclons sur le dupstableau avec numcomme variable et imprimons d'abord les nombres enregistrés puis leur nombre de valeurs dupliquées par dups[num].

Notez que votre fichier d'entrée a des espaces à la fin de certaines lignes, si vous les effacez, vous pouvez les utiliser $0à la place de la $1commande ci-dessus :)

αғsнιη
la source
1
N'est-ce pas un peu exagéré étant donné que nous en avons uniq?
Nathan Fellman
9
sort | uniqet la solution awk a des compromis de performances et de ressources assez différents: si les fichiers sont volumineux et que le nombre de lignes différentes est petit, la solution awk est beaucoup plus efficace. Il est linéaire dans le nombre de lignes et l'utilisation de l'espace est linéaire dans le nombre de lignes différentes. OTOH, la solution awk doit conserver toutes les différentes lignes en mémoire, tandis que le tri (GNU) peut recourir aux fichiers temporaires.
Lars Noschinski
14

Dans les fenêtres utilisant "Windows PowerShell", j'ai utilisé la commande mentionnée ci-dessous pour y parvenir

Get-Content .\file.txt | Group-Object | Select Name, Count

Nous pouvons également utiliser l'applet de commande where-object pour filtrer le résultat

Get-Content .\file.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select Name, Count
vigne
la source
pouvez-vous supprimer toutes les occurrences des doublons sauf la dernière ... sans changer l'ordre de tri du fichier?
jparram
6

En supposant que vous avez accès à un shell Unix standard et / ou à un environnement cygwin:

tr -s ' ' '\n' < yourfile | sort | uniq -d -c
       ^--space char

Fondamentalement: convertissez tous les caractères d'espace en sauts de ligne, puis triez la sortie traduite et alimentez-la en uniq et comptez les lignes en double.

Marc B
la source