sort и uniq
sort упорядочивает строки лексически или численно; -k выбирает ключ сортировки по полю, -n сортирует численно, -r разворачивает. uniq -c подсчитывает последовательные одинаковые строки. Идиома sort | uniq -c | sort -rn строит таблицу частот от большего к меньшему.
У тебя есть лог-файл с тысячами строк. Какой IP-адрес сделал больше всего запросов? Какой HTTP-код чаще всего встречается? Что входит в топ-10 эндпоинтов по числу обращений? Это вопросы частоты, и ответ — трёхэтапный конвейер: sort | uniq -c | sort -rn. Эта идиома работает с любым потоком текстовых строк — без базы данных, без скриптового языка, без предобработки. sort и uniq — одни из старейших утилит Unix, и вместе они — рабочая лошадка анализа логов на лету. Ключевое: uniq сворачивает только соседние одинаковые строки, поэтому перед подсчётом всегда нужно сортировать.
К концу урока ты сможешь сортировать любой текстовый поток по содержимому или по полю, подсчитывать частоты и строить ранжированную таблицу.
После этого урока ты сможешь использовать sort для упорядочивания строк лексически и численно, использовать -k для сортировки по конкретному полю, использовать -r для разворота, использовать uniq -c для подсчёта последовательных дубликатов и использовать конвейер sort | uniq -c | sort -rn для построения таблицы частот от большего к меньшему.
sort упорядочивает строки лексически по умолчанию. Лексический порядок сравнивает символ за символом по значениям ASCII/Unicode. Это означает, что 10 сортируется перед 9, потому что '1' < '9' как символы — классическая ловушка.
printf '10\n9\n100\n2\n' | sort
# 10
# 100
# 2
# 9Строки в ASCII-порядке (цифры сравниваются слева направо как символы). Для алфавитной сортировки строк это правильно, для числовых значений — нет.
-n переключает на численную сортировку. Числа разбираются как значения, а не последовательности символов.
printf '10\n9\n100\n2\n' | sort -n
# 2
# 9
# 10
# 100Всегда используй -n, когда данные — столбец чисел. Забыть -n — одна из самых распространённых ошибок в sort внутри шелл-скриптов.
-r разворачивает порядок сортировки. В сочетании с -n даёт порядок от большего к меньшему.
printf '10\n9\n100\n2\n' | sort -rn
# 100
# 10
# 9
# 2-u дедуплицирует: sort -u аналогично sort | uniq, но быстрее, потому что дедупликация происходит во время прохода сортировки.
printf 'b\na\nb\nc\na\n' | sort -u
# a
# b
# cИспользуй sort -u, когда нужны только уникальные значения; используй sort | uniq -c, когда нужны уникальные значения со счётчиками.
-k N сортирует по полю N. По умолчанию sort считает пробельные символы разделителями полей. -k2 сортирует по второму разделённому пробелами полю; -k2,2 сортирует только по полю 2 (без -k2,2 сортировка продолжается по последующим полям как по критериям разрыва связей).
cat sizes.txt
# 150M /var/log
# 2G /usr
# 800M /home
sort -k1 sizes.txt # лексически по размеру: 150M, 2G, 800M (неверный порядок)
sort -k2 sizes.txt # лексически по пути: /home, /usr, /var/logДля численной сортировки по полю объедини -k с -n:
# Сортировать лог доступа по размеру ответа (поле 10 в Combined Log Format)
sort -k10 -n access.log | tail -5Пять самых больших ответов в конце — в конце численно отсортированного списка. Добавь -r, чтобы поставить самый большой первым.
Для пользовательского разделителя добавь -t:
sort -t: -k3 -n /etc/passwdСортировать /etc/passwd по UID (поле 3), численно, с : как разделителем.
uniq -c подсчитывает последовательные одинаковые строки. Ему необходим отсортированный ввод — uniq сравнивает каждую строку только с непосредственно предыдущей. Если одинаковые строки не соседствуют, каждая группа получает свой счётчик.
printf 'error\nwarn\nerror\n' | uniq -c
# 1 error
# 1 warn
# 1 error ← подсчитана отдельно, так как не соседствуетПосле sort:
printf 'error\nwarn\nerror\n' | sort | uniq -c
# 2 error
# 1 warnТеперь обе строки error соседствуют, поэтому они свёртываются в один счётчик 2.
Идиома топ-N: sort | uniq -c | sort -rn. Три стадии работают вместе:
sort— сделать одинаковые строки соседними.uniq -c— подсчитать каждую группу, производя строки вида4 error.sort -rn— отсортировать численно в обратном порядке, чтобы элемент с наибольшим счётчиком был первым.
Добавь | head -10, чтобы получить топ 10.
# Топ-10 IP-адресов в лог доступа nginx (IP — поле 1)
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10# Топ HTTP-кодов состояния
awk '{print $9}' access.log | sort | uniq -c | sort -rnФормат вывода uniq -c: счётчик, затем пробел, затем значение. Второй sort -rn сортирует по счётчику, потому что он — первое поле. Эта идиома переносима в любую область: типы ошибок, user agent’ы, хэши SQL-запросов, названия событий.
Найти 5 наиболее частых уровней логирования в лог-файле приложения.
Предположим, каждая строка начинается с ключевого слова уровня: ERROR, WARN, INFO, DEBUG.
grep -oE '^(ERROR|WARN|INFO|DEBUG)' app.log \
| sort | uniq -c | sort -rn | head -5grep -oE '^(ERROR|WARN|INFO|DEBUG)' извлекает только ключевое слово уровня в начале каждой строки (по одному на строку). Конвейер затем подсчитывает и ранжирует их.
Для syslog-файла, где уровень не в начале:
awk '{print $5}' /var/log/syslog | sort | uniq -c | sort -rn | head -10Поле 5 в syslog — обычно имя процесса. Замени номер поля на тот, который содержит нужное измерение. Конвейер одинаков независимо от этого.
▸Почему это работает
На macOS (BSD sort) численная сортировка (-n) и разворот (-r) работают идентично. Основные отличия: BSD sort не поддерживает -V (версионная сортировка, например для сравнения v1.9 и v1.10), а нумерация полей -k одинакова. Идиома sort | uniq -c | sort -rn работает идентично на Linux и macOS. Флаг разделителя -t для sort также принимается BSD sort без проблем.
▸Частая ошибка
Самые распространённые ошибки sort: (1) забыть -n для числовых данных — sort по умолчанию выдаёт лексический порядок, и 10 сортируется перед 9; (2) запускать uniq -c без предварительной сортировки — несмежные одинаковые строки каждая получает свой счётчик 1, молча давая неверные частоты; (3) использовать -k N без -k N,N — sort -k2 сортирует по полю 2, но затем продолжает использовать последующие поля как критерии разрыва связей, что может давать неожиданный порядок при одинаковых значениях поля 2.
Ты запускаешь: printf 'b\na\nb\nc\n' | uniq -c без предварительной сортировки. Сколько строк в выводе?
sort упорядочивает строки лексически по умолчанию; -n переключает на численное сравнение; -r разворачивает; -k N,N сортирует по конкретному полю; -t РАЗД задаёт пользовательский разделитель полей. uniq -c подсчитывает последовательные одинаковые строки — входные данные должны быть отсортированы, иначе счётчики неверны. Идиома sort | uniq -c | sort -rn | head -N — универсальный конвейер таблицы частот: сделать одинаковые строки соседними, подсчитать их, ранжировать по убыванию счётчика, взять топ N. Этот шаблон работает без изменений на логах, потоках событий, CSV-колонках, выводе команд — на всём, что можно свести к одному значению на строку.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.