Текст — главный формат данных в Linux
В 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 выводит для нескольких файлов.
