Script Bash: compter les lignes uniques dans le fichier

129

Situation:

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

ip.ad.dre.ss[:port]

Résultat désiré:

Il y a une entrée pour chaque paquet que j'ai reçu lors de la journalisation, donc il y a beaucoup d'adresses en double. J'aimerais pouvoir l'exécuter via un script shell quelconque qui pourra le réduire en lignes du format

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

countest le nombre d'occurrences de cette adresse (et port) spécifique. Aucun travail particulier ne doit être effectué, traitez les différents ports comme des adresses différentes.

Jusqu'à présent, 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 régulière assez simple pour extraire toutes les adresses IP qui ont été envoyées par mon adresse (dont je ne me soucie pas)

Je peux ensuite utiliser ce qui suit pour extraire les entrées uniques:

sort -u ips.txt > intermediate.txt

Je ne sais pas comment je peux agréger les nombres de lignes avec tri.

Wug
la source

Réponses:

303

Vous pouvez utiliser la uniqcommande 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
Michael Hoffman
la source
10
J'aime à quel point -bgrressemble par hasard à un mnémonique pour bigger, c'est ce que nous voulons au sommet.
dwanderson
1
En tant que petite fonction pour votre .bashrcou .bash_aliasesfichier: function countuniquelines () { sort "$1" | uniq -c | sort -bgr; }. Appelez countuniquelines myfile.txt.
Johan
Je ne sais pas pourquoi sort -nr.
Nakilon le
5

Pour compter le nombre total de lignes uniques (c'est-à-dire sans considérer les lignes en double), nous pouvons utiliser uniqou Awk avec wc:

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

Les tableaux d'Awk sont associatifs et peuvent donc s'exécuter un peu plus vite que le tri.

Générer un 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
qwr
la source
Intéressant.
Cela
1

C'est le moyen le plus rapide d'obtenir le décompte des lignes répétées et de les faire imprimer joliment, du moins fréquent au plus fréquent:

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 à retenir, exécutez simplement:

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

PS:

sort -n analyse le champ comme un nombre, c'est correct puisque nous trions en utilisant les nombres.

Luca Mastrostefano
la source
Le !in {!seen[$0]++}est redondant ici, car nous ne faisons que l'impression au niveau du END.
Amir