Урок по треку Linux 8 мин

grep, sed, awk, find, xargs за 8 минут

Поиск и обработка текста и файлов: регулярки, замены, подсчёты по колонкам, безопасный xargs.

На собесе по Linux почти всегда дают лог и просят «посчитать, найти, вытащить». Пять утилит закрывают 90% таких задач. Главная идея: каждая делает одно дело, а пайп склеивает их в конвейер.

grep: найти строки

grep ERROR app.log              # строки с ERROR
grep -i error app.log           # без учёта регистра
grep -v DEBUG app.log           # всё, кроме DEBUG
grep -c ERROR app.log           # число строк с совпадением
grep -n timeout app.log         # с номерами строк
grep -r "TODO" src/             # рекурсивно по каталогу
grep -E '5[0-9]{2} ' access.log # расширенные регулярки
grep -o 'user=[a-z]*' app.log   # только совпавшая часть
grep -w 'id' file               # целое слово, не «idle»
grep -A2 -B1 Exception app.log  # контекст: 2 строки после, 1 до
grep -F 'a.b[1]' file           # фиксированная строка без регулярок

-c считает строки, а не вхождения. Чтобы посчитать все вхождения: grep -o pattern | wc -l.

sed: потоковая правка

sed 's/foo/bar/' f        # первая замена в каждой строке
sed 's/foo/bar/g' f       # все замены
sed -n '10,20p' f         # напечатать строки 10-20
sed '/^#/d' f             # удалить комментарии
sed -i.bak 's/8080/9090/' app.conf   # правка файла с бэкапом
sed -E 's/([0-9]+)ms/\1 ms/' f       # группы и обратные ссылки

Разделитель в s может быть любым: sed 's#/var/log#/data/log#g' удобнее для путей. -i без суффикса на macOS (BSD sed) требует пустой аргумент -i '', в GNU sed нет. Это частая причина «скрипт работал у меня на маке».

awk: колонки и подсчёты

awk читает строки, делит их на поля $1, $2, ... (по пробелам или по -F), $0 вся строка, NF число полей, NR номер строки.

awk '{print $1}' access.log                  # первая колонка
awk -F: '{print $1, $7}' /etc/passwd         # логин и shell
awk '$9 >= 500' access.log                   # фильтр по колонке
awk '{s += $10} END {print s}' access.log    # сумма
awk '{c[$1]++} END {for (ip in c) print c[ip], ip}' access.log   # группировка
awk 'NR > 1' data.csv                        # пропустить заголовок
awk -v lim=100 '$2 > lim' f                  # переменная снаружи

Ассоциативные массивы делают из awk маленький GROUP BY. Порядок обхода for (k in arr) не определён, поэтому результат сортируют отдельно.

sort, uniq, cut, wc, tr, head, tail

sort -n            # числовая сортировка (иначе 10 < 9)
sort -k2,2nr       # по второму полю, числом, по убыванию
sort -t, -k3,3     # разделитель запятая
uniq -c            # схлопнуть ПОДРЯД идущие повторы со счётчиком
cut -d, -f2        # второе поле CSV
tr 'a-z' 'A-Z'     # заменить символы
tail -f app.log    # следить за ростом файла

uniq работает только с соседними строками, поэтому перед ним почти всегда sort. Классика: топ-10 IP по запросам:

awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

find: искать файлы

find /var/log -name '*.log' -mtime +7      # старше 7 суток
find . -type f -size +100M                 # больше 100 МиБ
find . -type d -empty                      # пустые каталоги
find /srv -user deploy -perm -o+w          # владелец и права
find . -name '*.tmp' -delete               # удалить найденное
find . -name '*.py' -exec grep -l TODO {} + # выполнить команду пачкой

Маску в кавычках: без них shell сам раскроет *.log в текущем каталоге. -exec ... {} \; запускает команду на каждый файл, {} + пачками, это гораздо быстрее.

xargs: из строк в аргументы

find . -name '*.log' -print0 | xargs -0 gzip
cat urls.txt | xargs -n1 -P4 curl -sO     # по одному, 4 параллельно
grep -l old *.conf | xargs sed -i 's/old/new/'

xargs по умолчанию режет ввод по пробелам и переводам строк, поэтому имя my file.log превратится в два аргумента. Безопасная пара: find -print0 | xargs -0. Флаг -r (GNU) не запускает команду на пустом вводе.

Регулярные выражения

Базовые (grep, sed по умолчанию) и расширенные (grep -E, sed -E, awk). В базовых +, ?, |, () и {} надо экранировать (\+, \{3\}), в расширенных нет. ^ начало строки, $ конец, . любой символ, [0-9] класс, \b или -w граница слова.

Частые ошибки

  • uniq -c без sort: одинаковые строки, идущие не подряд, посчитаются отдельно.
  • sort для чисел без -n.
  • grep -c вместо подсчёта всех вхождений.
  • xargs без -0 на именах с пробелами.
  • find -name *.log без кавычек.
  • sed -i в скрипте, который запускают и на Linux, и на macOS.

Что спросят на собесе

  • Найти топ IP или URL в access-логе одной строкой.
  • Чем -exec {} \; отличается от -exec {} + и от xargs.
  • Почему перед uniq нужен sort.
  • Как заменить строку во всех конфигах каталога.
  • Удалить файлы старше N дней и почему find | xargs rm опасен без -print0.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.