177 votes

Bash script : compter les lignes uniques dans un fichier

Situation :

J'ai un gros fichier (des millions de lignes) contenant des adresses IP et des ports provenant d'une capture réseau de plusieurs heures, une ip/un port par ligne. Les lignes sont de ce format :

ip.ad.dre.ss[:port]

Résultat souhaité :

Il y a une entrée pour chaque paquet que j'ai reçu pendant la journalisation, donc il y a beaucoup d'adresses en double. J'aimerais pouvoir faire passer ceci par un shell script de quelque sorte qui sera capable de le réduire à des lignes du format

ip.ad.dre.ss[:port] count

donde count est le nombre d'occurrences de cette adresse (et de ce port) spécifique. Il n'y a pas de travail particulier à faire, traitez les différents ports comme des adresses différentes.

Pour l'instant, j'utilise cette commande pour extraire toutes les adresses IP du fichier journal :

grep -o -E [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)? ip_traffic-1.log > ips.txt

À partir de là, je peux utiliser une expression rationnelle assez simple pour extraire toutes les adresses IP qui ont été envoyées par mon adresse (dont je ne me soucie pas).

Je peux alors utiliser la méthode suivante pour extraire les entrées uniques :

sort -u ips.txt > intermediate.txt

Je ne sais pas comment je peux agréger le nombre de lignes avec le tri.

381voto

Michael Hoffman Points 8557

Vous pouvez utiliser le uniq pour obtenir le nombre de lignes répétées triées :

sort ips.txt | uniq -c

Pour obtenir les résultats les plus fréquents en haut (merci à Peter Jaric) :

sort ips.txt | uniq -c | sort -bgr

21voto

qwr Points 840

A compter le nombre total de lignes uniques (c'est-à-dire sans tenir compte des lignes dupliquées) nous pouvons utiliser uniq ou Awk avec wc :

sort ips.txt | uniq | wc -l
awk '!seen[$0]++' ips.txt | wc -l

Les tableaux d'Awk sont associatifs, donc cela peut être un peu plus rapide que le tri.

Génération du fichier texte :

$  for i in {1..100000}; do echo $RANDOM; done > random.txt
$ time sort random.txt | uniq | wc -l
31175

real    0m1.193s
user    0m0.701s
sys     0m0.388s

$ time awk '!seen[$0]++' random.txt | wc -l
31175

real    0m0.675s
user    0m0.108s
sys     0m0.171s

8voto

C'est le moyen le plus rapide d'obtenir le nombre de lignes répétées et de les imprimer joliment, classées de la moins fréquente à la plus fréquente :

awk '{!seen[$0]++}END{for (i in seen) print seen[i], i}' ips.txt | sort -n

Si vous ne vous souciez pas des performances et que vous voulez quelque chose de plus facile à mémoriser, il suffit de courir :

sort ips.txt | uniq -c | sort -n

PS :

trier -n analyse le champ comme un nombre, ce qui est correct puisque nous trions en utilisant les comptes.

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