Bash Script: підраховуйте унікальні рядки у файлі


129

Ситуація:

У мене є великий файл (мільйони рядків), що містить IP-адреси та порти з кількох годинних мережевих захоплень, один ip / порт на рядок. Рядки такого формату:

ip.ad.dre.ss[:port]

Бажаний результат:

Існує запис для кожного пакету, який я отримав під час реєстрації, тому є багато дублюючих адрес. Я хотів би мати можливість запустити це через якийсь скрипт оболонки, який зможе зменшити його до рядків формату

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

де countкількість зустрічей цієї конкретної адреси (і порту). Ніякої особливої ​​роботи не потрібно проводити, розглядайте різні порти як різні адреси.

Поки я використовую цю команду, щоб скребти всі IP-адреси з файлу журналу:

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

З цього моменту я можу використовувати досить простий регулярний вираз, щоб викреслити всі IP-адреси, надіслані моєю адресою (що мене не хвилює)

Потім я можу використовувати наступні дані для вилучення унікальних записів:

sort -u ips.txt > intermediate.txt

Я не знаю, як я можу об'єднати відліки рядків якось із сортуванням.

Відповіді:


303

Ви можете скористатися uniqкомандою для отримання підрахунку відсортованих повторних рядків:

sort ips.txt | uniq -c

Щоб отримати найчастіші результати вгорі (завдяки Петру Яричу):

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

10
Мені подобається, як -bgrвипадково виглядає мнемонічне bigger, чого ми хочемо вгорі.
dwanderson

1
В якості невеликої функції для вашого .bashrcабо .bash_aliasesфайлу: function countuniquelines () { sort "$1" | uniq -c | sort -bgr; }. Телефонуйте countuniquelines myfile.txt.
Йоган

Не впевнений, чому ні sort -nr.
Накілон

5

Для підрахунку загальної кількості унікальних рядків (тобто не враховуючи повторюваних рядків) ми можемо використовувати uniqабо Awk за допомогою wc:

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

Масиви Awk асоціативні, тому вони можуть працювати трохи швидше, ніж сортування.

Створення текстового файлу:

$  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

Цікаво. Можливо, помітна різниця для величезних наборів даних
Вуг

1

Це найшвидший спосіб отримати підрахунок повторних рядків, щоб вони були добре роздруковані, розкреслені від найменших до найчастіших:

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

Якщо ви не дбаєте про продуктивність і хочете запам'ятати щось легше, просто запустіть:

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

PS:

сортувати -n проаналізувати поле як число, що є правильним, оскільки ми сортуємо за допомогою підрахунків.


!В {!seen[$0]++}надлишковий тут, як ми тільки робимо друк на END.
Амір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.