Материал открыт для чтения

Войдите, чтобы сохранять прогресс и результаты.

Войти
Экспресс-погружение в DevOps

Работа с текстом и поиск

чтение ~18 минУрок 12 из 19

Текст — главный формат данных в Linux

crs express devops Image08

В Linux практически всё хранится в текстовых файлах: конфиги сервисов, логи приложений, скрипты автоматизации, пользовательские данные. Это не случайность — текстовый формат читается любым редактором, легко передаётся по сети, хорошо обрабатывается программами.

Представь реальную рабочую ситуацию: твой сервис упал в 3 часа ночи, мониторинг разбудил тебя. Лог-файл — 500 тысяч строк. Что произошло? Открывать в текстовом редакторе и листать — это пытка. В терминале — одна команда за несколько секунд находит всё, что нужно.

Именно поэтому работа с текстом — один из ключевых навыков DevOps-инженера. Эта статья расскажет о главных инструментах: как просматривать файлы, как искать в них нужное, как комбинировать команды в цепочки.


Просмотр файлов

Прежде чем искать по файлу, нужно уметь его просто прочитать. В Linux для этого есть несколько команд — каждая со своим характером.

cat — вывести файл целиком

cat (сокращение от concatenate) выводит содержимое файла прямо в терминал.

cat /etc/hostname
cat /etc/hosts
cat /etc/passwd

Это работает отлично для маленьких файлов. Если файл большой — тысячи строк — cat выведет всё разом и экран «улетит» вверх. В таких случаях лучше использовать less.

cat умеет выводить несколько файлов подряд (отсюда и название — «concatenate»):

cat file1.txt file2.txt file3.txt

Полезный флаг -n добавляет номера строк — удобно при изучении конфигов:

cat -n /etc/nginx/nginx.conf

head — первые строки файла

head выводит начало файла. По умолчанию — первые 10 строк.

head /var/log/syslog
head -n 20 /var/log/syslog
head -n 3 /etc/passwd

Флаг -n задаёт количество строк. head -n 20 выведет первые 20 строк.

Когда это нужно? Многие форматы файлов начинаются с заголовка — версии, схемы, описания. head позволяет быстро понять, что за файл перед тобой, не загружая его весь.

tail — последние строки файла

tail выводит конец файла. По умолчанию — последние 10 строк.

tail /var/log/syslog
tail -n 50 /var/log/nginx/error.log
tail -n 100 /var/log/auth.log

Логи растут снизу — новые записи добавляются в конец файла. Именно поэтому tail — это первая команда, которую запускают при разборе инцидента. Последние 50 строк лога почти всегда содержат то, что нужно.

tail -f — следить за файлом в реальном времени

Флаг -f (follow) — особенно полезный режим: tail не завершается, а продолжает следить за файлом и выводит новые строки по мере их появления.

tail -f /var/log/nginx/access.log
tail -f /var/log/syslog

Ты запускаешь команду, и терминал «живёт» — каждый новый запрос к серверу, каждое новое системное сообщение появляется у тебя на экране мгновенно. Чтобы остановить — нажми Ctrl+C.

Это очень удобно при отладке: открой tail -f в одном терминале, а во втором выполняй действия и смотри, что пишется в лог.

less — постраничный просмотр

less — интерактивный просмотрщик. Он открывает файл и позволяет им управлять: листать вверх и вниз, искать по содержимому — не загружая весь файл в память сразу.

less /var/log/syslog
less /etc/nginx/nginx.conf

Основные клавиши внутри less:

Клавиша Действие
стрелки / j / k Движение по строкам
пробел / PgDn Следующая страница
b / PgUp Предыдущая страница
G Перейти в конец файла
g Перейти в начало файла
/слово Поиск вперёд
?слово Поиск назад
n Следующее совпадение
q Выйти

Когда использовать less? Когда файл больше экрана. Конфиги, логи, любой файл длиннее пары десятков строк удобнее читать в less, а не через cat.


grep — поиск по содержимому

grep (Global Regular Expression Print) — вероятно, самая используемая команда в арсенале DevOps. Она читает файл строка за строкой и выводит только те строки, которые содержат заданный паттерн.

Базовый синтаксис:

grep "что_ищем" имя_файла

Как это работает: grep проходит по каждой строке файла и проверяет, содержит ли она заданный текст. Если да — выводит строку целиком. Если нет — пропускает. Это как фильтр: из тысяч строк остаются только нужные.

Самые полезные флаги:

grep "ERROR" /var/log/app.log
grep -i "error" /var/log/app.log
grep -n "ERROR" /var/log/app.log
grep -c "ERROR" /var/log/app.log
grep -v "INFO" /var/log/app.log
grep -r "TODO" ./src/
grep -l "ERROR" /var/log/*.log

Что делает каждый флаг:

  • без флагов — выводит все строки, содержащие ERROR
  • -i — поиск без учёта регистра (найдёт Error, ERROR, error)
  • -n — добавляет номер строки перед каждым совпадением, удобно когда нужно потом открыть файл в редакторе
  • -c — выводит только число совпадений, не сами строки
  • -v — инверсия: выводит строки, которые не содержат паттерн
  • -r — рекурсивный поиск: заходит во все поддиректории
  • -l — выводит только имена файлов, где найдено совпадение (без содержимого)

Совет для новичков: начни с простого. Просто напиши grep "слово" файл и посмотри, что выводится. Флаги добавляй по мере необходимости. -i и -n — самые частые.

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

grep поддерживает регулярные выражения — специальный язык для описания паттернов. Звучит страшно, но базовые вещи очень просты:

grep "^ERROR" app.log
grep "\.py$" filelist.txt
grep "ERROR\|WARN" app.log
grep -E "ERROR|WARN|CRIT" app.log

Символы ^ и $ — это так называемые якоря:

  • ^ERROR — строка начинается с ERROR (без ^ нашло бы и some ERROR here)
  • \.py$ — строка заканчивается на .py (точка экранируется \., иначе она означает «любой символ»)
  • ERROR\|WARN — OR в базовых регулярных выражениях; с флагом -E можно писать просто ERROR|WARN

На практике регулярки помогают делать точечный поиск. Например, grep "^2024-01-15" найдёт только строки, начинающиеся с конкретной даты — а не строки, где эта дата встречается где-то в середине.

Реальные сценарии: grep на практике

Сценарий 1: найти все неудачные попытки входа по SSH.

На серверах постоянно идут атаки перебором паролей. Чтобы увидеть атаки:

grep "Failed password" /var/log/auth.log

Сценарий 2: найти, с каких IP идут атаки.

grep "Failed password" /var/log/auth.log | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"

Флаг -o выводит только совпадающую часть строки, -E включает расширенные регулярные выражения. Результат — чистый список IP-адресов.

Сценарий 3: найти ошибки только за последний час.

Если логи содержат временные метки вида 2024-01-15 14:, можно искать по паттерну времени:

grep "2024-01-15 14:" /var/log/app.log | grep "ERROR"

Сценарий 4: найти конфиги, где упоминается старый адрес сервера.

Когда мигрируешь инфраструктуру и нужно обновить все ссылки на старый адрес:

grep -r "old-server.company.com" /etc/

Сценарий 5: исключить шумные строки из лога.

Приложение пишет сотни DEBUG строк, которые мешают видеть реальные проблемы:

grep -v "DEBUG" /var/log/app.log | grep -v "TRACE"

Сценарий 6: проверить, слушает ли порт нужный процесс.

ss -tlnp | grep ":80"

Pipe | — конвейер команд

Pipe (знак |) — одна из самых мощных концепций Unix/Linux. Идея проста: вывод одной команды становится входом следующей. Команды соединяются в цепочку, как станции на сборочном конвейере.

команда1 | команда2 | команда3 | ...

Почему это мощно? Каждая утилита Linux делает одну вещь, но хорошо. Pipe позволяет комбинировать простые инструменты в сложные решения — без написания кода, прямо в терминале.

Аналогия: представь завод. Первый рабочий вырезает детали, передаёт второму — тот шлифует, передаёт третьему — тот красит. Никто не ждёт, пока предыдущий закончит всю партию — работа течёт непрерывно. Так же работает pipe: данные проходят через команды поэтапно.

Как это работает шаг за шагом

Рассмотрим пример: нужно найти 5 самых частых ошибок в логе.

Шаг 1: получить все строки с ошибками.

grep "ERROR" /var/log/app.log

Результат: тысячи строк с ERROR.

Шаг 2: отсортировать их, чтобы одинаковые строки оказались рядом.

grep "ERROR" /var/log/app.log | sort

Шаг 3: подсчитать количество повторений каждой уникальной строки.

grep "ERROR" /var/log/app.log | sort | uniq -c

Шаг 4: отсортировать по убыванию числа повторений.

grep "ERROR" /var/log/app.log | sort | uniq -c | sort -rn

Шаг 5: оставить только первые 5 строк.

grep "ERROR" /var/log/app.log | sort | uniq -c | sort -rn | head -n 5

Вот так, добавляя команды через |, мы постепенно получаем именно то, что нужно. Каждый шаг легко понять и проверить по отдельности — просто убери | и всё что после него.

Ещё практические примеры pipe

Найти процесс по имени:

ps aux | grep nginx

ps aux выводит все процессы. grep nginx оставляет только строки, содержащие nginx.

Топ-10 самых тяжёлых директорий:

du -sh /var/* | sort -rh | head -n 10

du -sh /var/* — размер каждой поддиректории. sort -rh — сортировка по размеру в обратном порядке (флаг -h понимает K, M, G). head -n 10 — первые 10.

Список уникальных пользователей, которые заходили по SSH:

grep "Accepted" /var/log/auth.log | awk '{print $9}' | sort -u

Количество активных соединений по каждому порту:

ss -tn | awk 'NR>1 {print $4}' | cut -d: -f2 | sort | uniq -c | sort -rn

wc — подсчёт строк, слов и байт

wc (word count) — простая но незаменимая утилита. В DevOps почти всегда используется с pipe, чтобы получить число строк.

wc -l file.txt
wc -w file.txt
wc -c file.txt
  • -l — количество строк (line count)
  • -w — количество слов
  • -c — количество байт (размер файла)

Запомни одну вещь: wc -l в конце pipeline — это «сколько?». Вместо того чтобы видеть все строки, ты получаешь одно число.

Практически всегда wc применяется в конце pipeline:

grep "ERROR" app.log | wc -l

Это отвечает на вопрос: «сколько строк с ошибками в логе?». Не выводит сами строки — только число.

ls /etc | wc -l

Сколько файлов и директорий в /etc?

grep "Failed password" /var/log/auth.log | wc -l

Сколько неудачных попыток входа за всё время?

find /var/log -name "*.log" | wc -l

Сколько log-файлов на сервере?


sort и uniq — сортировка и дедупликация

sort — отсортировать строки

sort читает строки и выводит их в отсортированном порядке. Это кажется тривиальным, но без сортировки невозможно использовать uniq — а значит, невозможен весь паттерн частотного анализа.

sort file.txt
sort -n numbers.txt
sort -r file.txt
sort -rn numbers.txt
sort -u file.txt
sort -k2 table.txt
  • без флагов — алфавитная сортировка
  • -n — числовая сортировка. Без неё 10 окажется между 1 и 2 (так работает алфавит)
  • -r — обратный порядок (reverse)
  • -rn — числовая сортировка от большего к меньшему
  • -u — sort + убрать дубликаты за один проход
  • -k2 — сортировать по второму полю (столбцу)

Почему нужна числовая сортировка? Потому что при алфавитной сортировке числа сравниваются как строки, символ за символом: 1, 10, 100, 2, 20, 3. При числовой (-n): 1, 2, 3, 10, 20, 100. Когда uniq -c добавляет счётчики вида 120 ERROR и 9 WARNING, алфавитная сортировка поставит 9 после 120 — что неверно. Используй -n.

uniq — убрать дублирующиеся строки

uniq убирает соседние одинаковые строки. Именно поэтому перед ним почти всегда стоит sort — чтобы одинаковые строки оказались рядом.

sort names.txt | uniq
sort names.txt | uniq -c
sort names.txt | uniq -d
sort names.txt | uniq -u
  • без флагов — убрать дубликаты, оставить по одной копии
  • -c — добавить счётчик: сколько раз встречалась каждая строка
  • -d — показать только строки, которые дублировались (только дубликаты)
  • -u — показать только уникальные строки (которые встречаются ровно один раз)

Комбинация sort | uniq -c | sort -rn — классический паттерн для анализа частотности. Он появляется снова и снова в работе с логами, конфигами, данными. Вот примеры:

Какие URL запрашиваются чаще всего:

awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Какие IP-адреса чаще всего стучатся в SSH:

grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -10

find — поиск файлов

find — мощный инструмент для поиска файлов по самым разным критериям: имя, тип, размер, время изменения, права доступа.

Ключевое отличие от grep: grep ищет текст внутри файлов. find ищет сами файлы в файловой системе. Это разные задачи с разными инструментами.

Поиск по имени

find /etc -name "*.conf"
find /var/log -name "*.log"
find . -name "config.yaml"
find /home -name ".bashrc"

Паттерн в кавычках — это glob (не регулярное выражение): * означает «любое количество любых символов». Точка в начале имени файла (.bashrc) — скрытый файл, find их тоже находит.

Несколько важных деталей:

  • find /etc — ищет в директории /etc и всех её поддиректориях рекурсивно
  • . — означает текущую директорию
  • -name чувствителен к регистру; используй -iname для поиска без учёта регистра

Поиск по типу

find . -type f
find . -type d
find . -type l
  • -type f — только файлы (file)
  • -type d — только директории (directory)
  • -type l — только символические ссылки (link)

Это важно: если искать *.conf без -type f, можно случайно получить директории с именем something.conf. Указывай тип явно, когда уверен, что ищешь именно файлы.

Поиск по времени и размеру

find /var/log -name "*.log" -mtime -1
find /var/log -name "*.log" -mtime +30
find /tmp -size +100M
find /home -size +1G
  • -mtime -1 — изменены за последние 24 часа (меньше 1 дня назад)
  • -mtime +30 — изменены более 30 дней назад
  • -size +100M — размер больше 100 МБ

Можно комбинировать условия. Найти старые логи, которые занимают место:

find /var/log -name "*.log" -mtime +30 -size +10M

Все указанные условия объединяются по AND: файл должен соответствовать всем условиям одновременно.

Действия с найденными файлами

find может не просто находить файлы, но и сразу что-то с ними делать:

find /tmp -name "*.tmp" -delete
find . -name "*.log" -exec wc -l {} \;
find . -name "*.py" -exec grep -l "import os" {} \;
  • -delete — удалить найденные файлы
  • -exec команда {} \; — выполнить команду для каждого найденного файла. {} — место, куда подставляется имя файла

Будь осторожен с -delete. Сначала запусти find без -delete, убедись, что находит нужные файлы, и только потом добавляй -delete.


Перенаправление ввода-вывода

В Linux у каждой команды есть три стандартных потока данных:

Поток Номер Название По умолчанию
stdin 0 Стандартный ввод Клавиатура
stdout 1 Стандартный вывод Экран
stderr 2 Стандартный вывод ошибок Экран

По умолчанию вывод идёт на экран. Перенаправление меняет это поведение — ты говоришь системе: «не выводи на экран, а запиши вот сюда».

Перенаправление stdout в файл

ls -la /etc > etc_files.txt
ls -la /var >> all_files.txt
  • > — записать вывод в файл. Если файл существует — он будет перезаписан с нуля. Будь аккуратен: старое содержимое удаляется без предупреждения.
  • >> — добавить вывод в конец файла. Если файла нет — создать. Существующий файл не трогается.

Пример: сохранить список установленных пакетов перед обновлением системы:

dpkg -l > packages_before.txt

Теперь, если что-то пойдёт не так, можно сравнить состояние до и после.

Перенаправление stderr

Ошибки и обычный вывод идут в разные потоки. Это позволяет их разделять:

./deploy.sh 2> deploy_errors.log
./deploy.sh > deploy_output.log 2> deploy_errors.log
./deploy.sh > deploy_all.log 2>&1
find /etc -name "*.conf" 2>/dev/null
  • 2> — перенаправить только ошибки (поток 2) в файл
  • 2>&1 — перенаправить поток ошибок (2) туда же, куда идёт stdout (1). Это значит: «ошибки и обычный вывод — в одно место»
  • 2>/dev/null — выбросить ошибки. /dev/null — специальный файл-«чёрная дыра», всё записанное в него исчезает

Зачем 2>/dev/null? Когда ищешь что-то в /etc, find будет ругаться на директории, к которым нет доступа: Permission denied. Это засоряет вывод. 2>/dev/null убирает эти ошибки, оставляя только результаты поиска:

find /etc -name "*.conf" 2>/dev/null

tee — и на экран, и в файл

Иногда нужно видеть вывод на экране и одновременно сохранять его в файл. Для этого существует tee:

./deploy.sh | tee deploy.log
./deploy.sh | tee -a deploy.log
  • без -a — перезаписывает файл
  • -a — добавляет в конец файла (как >>)

Вывод при этом отображается на экране как обычно, и одновременно пишется в файл. Удобно для долгих операций — видишь прогресс и сохраняешь лог.


Практические примеры

Топ-10 IP-адресов в Nginx-логе

Nginx пишет IP клиента первым полем в access.log. Чтобы узнать, кто делает больше всего запросов:

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

awk '{print $1}' берёт первое поле каждой строки (IP-адрес). Дальше классический pipeline: сортировка, подсчёт, сортировка по числу, первые 10.

Подсчитать 500-е ошибки за сегодня

grep " 500 " /var/log/nginx/access.log | grep "$(date +%d/%b/%Y)" | wc -l

$(date +%d/%b/%Y) подставляет сегодняшнюю дату в формат Nginx-лога, например 15/Jan/2024. Двойная фильтрация: сначала по коду 500, потом по сегодняшней дате.

Найти конфиги с упоминанием паролей

Когда нужно найти, где в конфигах хранятся секреты в открытом виде:

grep -r "password" /etc/ 2>/dev/null

2>/dev/null убирает ошибки «нет доступа», чтобы не мешали.

Мониторинг ошибок в реальном времени

tail -f /var/log/nginx/error.log | grep --line-buffered "error"

tail -f следит за файлом в реальном времени. --line-buffered в grep нужен, чтобы строки появлялись сразу, не накапливаясь в буфере. Открой в одном терминале, а в другом делай запросы — видишь ошибки мгновенно.

Найти и удалить временные файлы старше 7 дней

Очистка /tmp от старых файлов — типичная задача обслуживания:

find /tmp -type f -mtime +7 -delete

Сохранить статус сервисов в файл

Перед масштабными изменениями на сервере полезно зафиксировать текущее состояние:

systemctl list-units --state=running > running_services.txt

Найти самые большие файлы в домашней директории

find /home -type f -size +50M | xargs du -sh | sort -rh | head -10

xargs передаёт найденные файлы команде du -sh — та показывает читаемый размер каждого.

Посчитать строки во всех Python-файлах проекта

find . -name "*.py" -type f | xargs wc -l | tail -1

tail -1 оставляет только итоговую строку, которую wc выводит для нескольких файлов.

Материал изучен?

Войдите, чтобы сохранить прогресс и перейти к практической лаборатории.

Войти и продолжить