Подсчёт уникальных IP в access-логе, где IP — первое поле
У вас есть access.log в стиле nginx: один запрос на строку, поля разделены пробелами, IP клиента — в первом поле. Выведите число различных IP, встречающихся в файле.
Ограничения: только стандартные shell-инструменты (awk, sort, uniq, wc); не пишите программу на другом языке. Считайте, что файл не помещается удобно в редактор, но помещается на диск.
# access.log: "203.0.113.7 - - [10/Oct/2024:13:55:36 +0000] \"GET / HTTP/1.1\" 200"
# ваш конвейер здесь
Напишите однострочник.
Извлеките первое поле, схлопните до различных значений и сосчитайте: awk '{print $1}' access.log | sort -u | wc -l. sort -u убирает дубликаты за один проход, а wc -l считает оставшиеся строки; ... | sort | uniq | wc -l равнозначно. Для счётчиков по IP используйте sort | uniq -c | sort -rn. Стоимость определяется сортировкой за O(n log n).
- ✗Применять
uniqбез предшествующегоsort, из-за чего несоседние дубликаты выживают - ✗Считать сырые строки вместо различных значений первого поля
- ✗Извлекать не то поле — IP это
$1, а не$2
- →Как изменить конвейер, чтобы вывести 10 самых активных IP?
- →Почему
sort -uздесь равнозначенsort | uniqи когда они расходятся?
Решение
IP — это первое поле, разделённое пробелами. Извлеките его, сведите к множеству различных значений и сосчитайте оставшееся:
awk '{print $1}' access.log | sort -u | wc -l
то есть множество различных значений за один проход. (sort | uniq — то же самое; один uniq неверен, ведь убирает лишь соседние дубликаты.)
awk '{print $1}'— выдаёт только IP клиента из каждой строки.sort -u— сортирует и оставляет лишь первую строку из каждой группы одинаковых,wc -l— считает оставшиеся строки = число различных IP.
Чтобы отранжировать IP по числу запросов, а не просто сосчитать:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
uniq -c приписывает каждому IP его счётчик; sort -rn упорядочивает по нему по убыванию. Основная стоимость — это sort за O(n log n) по числу строк.