Bash Script: conta le righe univoche nel file


129

Situazione:

Ho un file di grandi dimensioni (milioni di linee) contenente indirizzi IP e porte da una cattura di rete di diverse ore, un ip / porta per linea. Le linee sono di questo formato:

ip.ad.dre.ss[:port]

Risultato desiderato:

C'è una voce per ogni pacchetto che ho ricevuto durante la registrazione, quindi ci sono molti indirizzi duplicati. Mi piacerebbe poterlo eseguire attraverso uno script di shell di qualche tipo che sarà in grado di ridurlo a righe del formato

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

dove countè il numero di occorrenze di quello specifico indirizzo (e porta). Non è necessario eseguire alcun lavoro speciale, trattare porte diverse come indirizzi diversi.

Finora, sto usando questo comando per eliminare tutti gli indirizzi IP dal file di registro:

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

Da ciò, posso usare un regex abbastanza semplice per estrarre tutti gli indirizzi IP che sono stati inviati dal mio indirizzo (di cui non mi interessa)

Posso quindi utilizzare quanto segue per estrarre le voci univoche:

sort -u ips.txt > intermediate.txt

Non so come posso aggregare i conteggi delle righe in qualche modo con l'ordinamento.

Risposte:


303

È possibile utilizzare il uniqcomando per ottenere conteggi di righe ripetute ordinate:

sort ips.txt | uniq -c

Per ottenere i risultati più frequenti in alto (grazie a Peter Jaric):

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

10
Mi piace come per -bgrcoincidenza assomigli a un mnemonico bigger, che è quello che vogliamo in cima.
dwanderson,

1
Come una piccola funzione per la vostra .bashrco il .bash_aliasesfile di: function countuniquelines () { sort "$1" | uniq -c | sort -bgr; }. Chiama da countuniquelines myfile.txt.
Johan,

Non so perché no sort -nr.
Nakilon,

5

Per contare il numero totale di linee uniche (ovvero non considerare linee duplicate) possiamo usare uniqo Awk con wc:

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

Gli array di Awk sono associativi, quindi potrebbe essere un po 'più veloce dell'ordinamento.

Generazione di file di testo:

$  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

Interessante. Potrebbe fare una differenza apprezzabile per enormi set di dati
Wug,

1

Questo è il modo più veloce per ottenere il conteggio delle righe ripetute e farle stampare piacevolmente dal meno frequente al più frequente:

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

Se non ti interessano le prestazioni e desideri qualcosa di più facile da ricordare, esegui semplicemente:

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

PS:

sort -n analizza il campo come un numero, che è corretto poiché stiamo ordinando usando i conteggi.


Qui !in {!seen[$0]++}è ridondante, poiché eseguiamo solo la stampa in END.
Amir,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.