sort -u file.txt убирает повторяющиеся строки и сортирует остаток; awk '!seen[$0]++' file.txt убирает их и оставляет исходный порядок. Что нужно вам — зависит от того, несёт ли порядок смысл: в логе он несёт всегда. Один uniq не делает ни того, ни другого.
1. Почему uniq в одиночку не помогает
$ clai убери повторы из access.log→ uniq access.log10.0.0.710.0.0.310.0.0.710.0.0.910.0.0.310.0.0.710.0.0.1
Файл вернулся без изменений. uniq схлопывает только соседние одинаковые строки, а в живом файле повторы разбросаны. Отсюда и классическая связка sort | uniq.
2. Убрать повторы и отсортировать
$ clai убери повторы и отсортируй файл→ sort -u access.log10.0.0.110.0.0.310.0.0.710.0.0.9
sort -u делает обе работы за один проход — короче и быстрее, чем пайп в uniq.
3. Убрать повторы, сохранив порядок
$ clai убери повторы, но оставь исходный порядок строк→ awk '!seen[$0]++' access.log10.0.0.710.0.0.310.0.0.910.0.0.1
Вот настоящее отличие от sort -u: остаётся первое вхождение каждой строки, порядок не тронут. Это важно для логов и всего, что пишется по времени. Плата — память: awk держит все уникальные строки, и на файлах в десятки гигабайт это заметно.
4. Сколько раз встречается каждая строка
$ clai посчитай, сколько раз встречается каждая строка→ sort access.log | uniq -c | sort -rn 3 10.0.0.7 2 10.0.0.3 1 10.0.0.9 1 10.0.0.1
Тот самый рецепт «топ-N» для логов. uniq -c считает, второй sort -rn поднимает частые наверх.
5. Только те строки, что повторялись
$ clai покажи только строки, которые встречаются больше одного раза→ sort access.log | uniq -d10.0.0.310.0.0.7
-d оставляет только дубли, -u — наоборот, только одиночные строки: в этом файле 10.0.0.1 и 10.0.0.9. Удобно, когда сравниваешь два списка.
6. Дедупликация по одному полю
$ clai оставь по одной строке на каждый URL→ awk '!seen[$2]++' req.logGET /a 200GET /b 404
$2 — второе поле. Так схлопывают лог по URL, по IP или по идентификатору сессии, сохраняя целиком первую встреченную строку.
Gotchas
sort -u file > fileобнуляет файл. Проверено: шелл обрезает файл под запись раньше, чемsortуспевает его прочитать, и на выходе ноль строк. Правильно —sort -u file -o file: у sort есть штатный флаг записи в собственный вход, и он работает.uniqтребует отсортированного ввода. Безsortперед ним он молча вернёт почти тот же файл. Не ошибка, а тихо неверный ответ.- Порядок и сортировка — разные требования.
sort -uдаёт алфавитный порядок,awk '!seen[$0]++'— исходный. Для логов почти всегда нужен второй, а показывают обычно первый.
Related questions
Как найти строки, общие для двух файлов? comm -12 <(sort a.txt) <(sort b.txt). Оба входа должны быть отсортированы — для этого и нужна подстановка процессов.
Как не учитывать регистр? sort -uf сравнивает без учёта регистра; awk '!seen[tolower($0)]++' делает то же, сохраняя порядок.
А если файл не влезает в память? sort -u сбрасывает промежуточные данные во временные файлы и переваривает вход больше оперативной памяти; вариант с awk на том же файле может её исчерпать.
See also
- Достать колонки CSV через awk
- Найти и заменить во всех файлах
- Посчитать файлы в папке: рекурсивно и по типам
CliAI сам выбирает между вариантом с сортировкой и вариантом с сохранением порядка по вашей формулировке и сначала показывает команду. Поставить одной строкой.