В предыдущих главах мы работали с файлами поштучно: создавали, копировали, редактировали в nano. Но в реальной работе системного администратора часто возникают задачи другого масштаба:
- в лог-файле nginx тысячи строк — как найти среди них ошибки?
- нужно быстро посчитать, сколько раз определённый IP-адрес обращался к серверу;
- требуется извлечь из конфигурационного файла только определённые параметры.
Для всего этого в Linux существует набор небольших утилит, каждая из которых делает одну простую вещь: подсчитать строки, отсортировать, отфильтровать, вырезать столбец. По отдельности они не впечатляют, но их сила — в возможности соединять друг с другом. Этот принцип называется философией Unix: каждая программа делает одно дело хорошо, а для сложных задач программы объединяются в цепочку.
Прежде чем перейти к самим утилитам, нам нужно разобраться, как работает этот механизм соединения — перенаправление ввода-вывода и конвейеры.
Каждая программа в Linux при запуске получает три потока данных:
┌─────────────┐
stdin (0) ──────▶│ │──────▶ stdout (1)
(ввод) │ Программа │
│ │──────▶ stderr (2)
└─────────────┘ (ошибки)
| Поток | Номер | Описание | По умолчанию |
|---|---|---|---|
| stdin | 0 | Стандартный ввод — откуда программа читает данные | Клавиатура |
| stdout | 1 | Стандартный вывод — куда программа пишет результат | Экран (терминал) |
| stderr | 2 | Стандартный вывод ошибок — куда программа пишет ошибки | Экран (терминал) |
Когда вы вводите ls -l, программа ls читает содержимое каталога и выводит
результат в stdout — вы видите его на экране. Если вы укажете несуществующий
каталог (ls /нет-такого), сообщение об ошибке пойдёт в stderr — и тоже
появится на экране, но через другой поток.
Символы > и >> позволяют направить вывод программы в файл вместо экрана.
# Записать список файлов в файл (создать или перезаписать)
ls -l > filelist.txt
# Добавить в конец файла (не затирая содержимое)
echo "новая строка" >> filelist.txtРазница между > и >>:
| Оператор | Действие |
|---|---|
> |
Создать файл или перезаписать его содержимое |
>> |
Добавить в конец файла |
Осторожно! Оператор
>без предупреждения перезаписывает файл. Если вы случайно выполнитеecho "тест" > important.conf, всё содержимое файла будет заменено словом «тест». Будьте внимательны с>и>>.
Чтобы перенаправить stderr (поток ошибок), используется 2>:
# Ошибки — в файл, результат — на экран
ls /etc /нет-такого 2> errors.txt
# Ошибки — в никуда (подавить сообщения об ошибках)
ls /нет-такого 2> /dev/nullФайл /dev/null — это «чёрная дыра» в Linux. Всё, что в него записано,
исчезает. Его используют, когда нужно подавить вывод ошибок.
Чтобы направить и stdout, и stderr в один файл:
command > output.txt 2>&1Запись 2>&1 означает «перенаправить поток 2 (stderr) туда же, куда идёт
поток 1 (stdout)».
Конвейер — это самый важный механизм в этой главе. Символ | (вертикальная
черта, «пайп») соединяет stdout одной команды с stdin другой:
┌──────────┐ stdout stdin ┌──────────┐
│ Команда 1│────────────|──────│ Команда 2│
└──────────┘ └──────────┘
Примеры:
# Посчитать количество файлов в каталоге
ls /etc | wc -l
# Показать первые 5 строк из отсортированного списка
ls /etc | sort | head -5Конвейер можно наращивать — соединять три, четыре и более команд:
команда1 | команда2 | команда3 | команда4Данные «текут» слева направо: вывод каждой команды становится вводом следующей. Далее в этой главе мы будем активно использовать конвейеры.
Чтобы практиковаться на реальных данных, создадим файл с примером логов веб-сервера nginx. Это записи о запросах к нашему будущему сайту WordPress.
Создайте файл:
nano ~/wordpress-project/logs/access.logВведите следующие строки (или скопируйте через терминал):
192.168.1.10 - - [15/Mar/2026:10:12:01 +0300] "GET / HTTP/1.1" 200 3421
192.168.1.10 - - [15/Mar/2026:10:12:02 +0300] "GET /style.css HTTP/1.1" 200 1532
192.168.1.25 - - [15/Mar/2026:10:13:15 +0300] "GET /about HTTP/1.1" 200 2100
10.0.0.5 - - [15/Mar/2026:10:14:03 +0300] "POST /wp-login.php HTTP/1.1" 403 150
192.168.1.10 - - [15/Mar/2026:10:15:22 +0300] "GET /wp-admin/ HTTP/1.1" 302 0
192.168.1.25 - - [15/Mar/2026:10:15:30 +0300] "GET /contact HTTP/1.1" 404 274
10.0.0.5 - - [15/Mar/2026:10:16:45 +0300] "POST /wp-login.php HTTP/1.1" 403 150
10.0.0.5 - - [15/Mar/2026:10:17:01 +0300] "POST /wp-login.php HTTP/1.1" 403 150
192.168.1.30 - - [15/Mar/2026:10:18:10 +0300] "GET / HTTP/1.1" 200 3421
192.168.1.30 - - [15/Mar/2026:10:18:11 +0300] "GET /style.css HTTP/1.1" 200 1532
192.168.1.25 - - [15/Mar/2026:10:19:05 +0300] "GET /blog HTTP/1.1" 200 4512
10.0.0.5 - - [15/Mar/2026:10:20:30 +0300] "POST /wp-login.php HTTP/1.1" 403 150
192.168.1.10 - - [15/Mar/2026:10:21:00 +0300] "GET /blog/first-post HTTP/1.1" 200 3800
192.168.1.30 - - [15/Mar/2026:10:22:15 +0300] "GET /about HTTP/1.1" 200 2100
192.168.1.25 - - [15/Mar/2026:10:23:40 +0300] "GET /wp-content/uploads/photo.jpg HTTP/1.1" 200 85432
Сохраните файл (Ctrl+X, Y, Enter).
Каждая строка — это один HTTP-запрос к серверу. Разберём формат на примере первой строки:
192.168.1.10 - - [15/Mar/2026:10:12:01 +0300] "GET / HTTP/1.1" 200 3421
Где:
| Элемент | Что означает |
|---|---|
192.168.1.10 |
IP-адрес клиента |
- (первый) |
Имя удалённого пользователя (часто пусто) |
- (второй) |
Идентификатор пользователя (часто пусто) |
[15/Mar/... +0300] |
Дата и время запроса |
"GET / HTTP/1.1" |
Сам запрос (метод, URL, протокол) |
200 |
Код ответа HTTP |
3421 |
Размер ответа сервера (в байтах) |
Код ответа HTTP говорит о результате запроса:
- 200 — OK, страница найдена;
- 302 — перенаправление на другой адрес;
- 403 — доступ запрещён;
- 404 — страница не найдена.
Теперь у нас есть данные для работы. Приступим к утилитам.
Команда wc (word count) подсчитывает количество строк, слов и байт в файле:
wc ~/wordpress-project/logs/access.log 15 210 1350 /home/student/wordpress-project/logs/access.log
Три числа: 15 строк, 210 слов, 1350 байт.
Чаще всего нужно только количество строк — для этого есть флаг -l:
wc -l ~/wordpress-project/logs/access.log15 /home/student/wordpress-project/logs/access.log
В нашем логе 15 записей — 15 запросов к серверу.
Другие полезные флаги:
| Флаг | Что считает |
|---|---|
-l |
Строки |
-w |
Слова |
-c |
Байты |
-m |
Символы (для UTF-8 может отличаться от байтов) |
wc отлично работает в конвейере — подсчитывает строки, приходящие на stdin:
# Сколько файлов в /etc?
ls /etc | wc -lКоманда sort сортирует строки в алфавитном порядке:
sort ~/wordpress-project/logs/access.logНа экране появятся все строки файла, отсортированные по первому символу
(по IP-адресу, потому что он стоит в начале каждой строки). Строки с 10.0.0.5
окажутся вверху, строки с 192.168.1.* — ниже. Сам файл при этом не изменится —
sort, как и большинство утилит в этой главе, выводит результат на экран (в stdout),
не трогая исходные данные.
Полезные флаги:
| Флаг | Действие |
|---|---|
-r |
Обратный порядок (от Я к А, от большего к меньшему) |
-n |
Числовая сортировка (иначе 9 будет после 10) |
-k N |
Сортировать по N-му полю (столбцу) |
-t 'X' |
Использовать символ X как разделитель полей |
-u |
Убрать дублирующиеся строки (как `sort |
Пример — отсортировать лог по коду ответа HTTP. Код ответа — это 9-е поле (поля разделены пробелами):
sort -k 9 -n ~/wordpress-project/logs/access.logСтроки с кодом 200 окажутся в начале, с 403 и 404 — в конце.
Команда uniq удаляет подряд идущие одинаковые строки. Это важный нюанс:
если одинаковые строки разделены другими строками, uniq их не заметит.
Поэтому uniq почти всегда используется после sort.
# Извлечь IP-адреса, отсортировать и убрать дубликаты
cut -d ' ' -f 1 ~/wordpress-project/logs/access.log | sort | uniq10.0.0.5
192.168.1.10
192.168.1.25
192.168.1.30
(Команду cut мы разберём чуть ниже — здесь она извлекает первое поле,
т.е. IP-адрес.)
Самый полезный флаг uniq — это -c (count). Он показывает количество
повторений каждой строки:
cut -d ' ' -f 1 ~/wordpress-project/logs/access.log | sort | uniq -c 4 10.0.0.5
4 192.168.1.10
4 192.168.1.25
3 192.168.1.30
Теперь видно, что IP-адрес 10.0.0.5 обращался к серверу 4 раза — и мы знаем
из лога, что все 4 раза это были попытки входа в wp-login.php с ответом 403.
Подозрительно!
Другие флаги:
| Флаг | Действие |
|---|---|
-c |
Показать количество повторений |
-d |
Показать только повторяющиеся строки |
-u |
Показать только уникальные (неповторяющиеся) строки |
Команда cut вырезает из каждой строки определённые поля (столбцы) или
диапазоны символов.
cut -d '<разделитель>' -f <номера_полей>-d ' '— разделитель — пробел;-f 1— взять первое поле;-f 1,3— первое и третье поле;-f 1-3— поля с первого по третье.
Примеры на нашем лог-файле:
# Извлечь только IP-адреса (первое поле, разделитель — пробел)
cut -d ' ' -f 1 ~/wordpress-project/logs/access.log192.168.1.10
192.168.1.10
192.168.1.25
10.0.0.5
...
# Извлечь URL запроса (7-е поле)
cut -d ' ' -f 7 ~/wordpress-project/logs/access.log/
/style.css
/about
/wp-login.php
...
# Извлечь первые 12 символов из каждой строки
cut -c 1-12 ~/wordpress-project/logs/access.log192.168.1.10
192.168.1.10
192.168.1.25
10.0.0.5 - -
...
grep — одна из самых важных и часто используемых команд в Linux.
Она фильтрует строки, содержащие заданный шаблон (образец):
grep '<шаблон>' <файл># Найти все строки с кодом 404
grep '404' ~/wordpress-project/logs/access.log192.168.1.25 - - [15/Mar/2026:10:15:30 +0300] "GET /contact HTTP/1.1" 404 274
Одна строка — значит, только одна страница не была найдена.
# Найти все обращения к wp-login.php
grep 'wp-login' ~/wordpress-project/logs/access.log10.0.0.5 - - [15/Mar/2026:10:14:03 +0300] "POST /wp-login.php HTTP/1.1" 403 150
10.0.0.5 - - [15/Mar/2026:10:16:45 +0300] "POST /wp-login.php HTTP/1.1" 403 150
10.0.0.5 - - [15/Mar/2026:10:17:01 +0300] "POST /wp-login.php HTTP/1.1" 403 150
10.0.0.5 - - [15/Mar/2026:10:20:30 +0300] "POST /wp-login.php HTTP/1.1" 403 150
Четыре неудачных попытки входа с одного IP-адреса. В реальной жизни это мог бы быть сигнал о попытке подбора пароля.
| Флаг | Действие |
|---|---|
-i |
Игнорировать регистр (grep -i 'get' найдёт и GET, и get) |
-c |
Показать только количество совпадений (не сами строки) |
-n |
Показать номера строк |
-v |
Инвертировать — показать строки, не содержащие шаблон |
-r |
Рекурсивный поиск по всем файлам в каталоге |
-l |
Показать только имена файлов с совпадениями |
Примеры:
# Сколько запросов вернули ошибку 403?
grep -c '403' ~/wordpress-project/logs/access.log4
# Показать все строки, КРОМЕ успешных (не содержащих 200)
grep -v '200' ~/wordpress-project/logs/access.log# Найти слово «server» во всех файлах конфигурации
grep -r 'server' ~/wordpress-project/config/grep часто используется как фильтр в середине конвейера:
# Сколько раз IP 10.0.0.5 обращался к серверу?
grep '10.0.0.5' ~/wordpress-project/logs/access.log | wc -l4
# Какие URL запрашивал IP 192.168.1.25?
grep '192.168.1.25' ~/wordpress-project/logs/access.log | cut -d ' ' -f 7/about
/contact
/blog
/wp-content/uploads/photo.jpg
До сих пор мы искали в grep точные слова: 404, wp-login. Но иногда нужен
более гибкий поиск — например, «все строки, начинающиеся с 192.168» или
«все файлы с расширением .php или .html». Для таких задач существуют
регулярные выражения (regular expressions, regex).
Регулярное выражение — это шаблон, описывающий множество строк. Вместо того чтобы искать конкретное слово, вы описываете паттерн — правило, которому строка должна соответствовать.
| Символ | Значение | Пример | Совпадёт с |
|---|---|---|---|
. |
Любой один символ | a.c |
abc, a1c, a-c |
* |
Предыдущий символ 0 или более раз | ab*c |
ac, abc, abbc |
^ |
Начало строки | ^192 |
Строки, начинающиеся с 192 |
$ |
Конец строки | php$ |
Строки, заканчивающиеся на php |
[] |
Любой символ из набора | [0-9] |
Любая цифра |
[^] |
Любой символ, кроме указанных | [^0-9] |
Любой символ, кроме цифры |
\ |
Экранирование спецсимвола | \.php |
Точка и php (буквально) |
Важно: точка
.в регулярных выражениях — это спецсимвол, означающий «любой символ». Если вам нужна именно точка (например, в имени файла.php), её нужно экранировать обратной косой чертой:\.php.Что значит «экранировать»? Некоторые символы имеют специальное значение — точка означает «любой символ»,
*— «повторение» и т.д. Экранирование — это способ сказать: «воспринимай этот символ буквально, а не как спецсимвол». Для этого перед ним ставится обратная косая черта\. Запись\.означает «именно точка», а не «любой символ».
# Строки, начинающиеся с 192
grep '^192' ~/wordpress-project/logs/access.log# Строки, содержащие .php (точка экранирована)
grep '\.php' ~/wordpress-project/logs/access.log# Строки с кодом ответа, начинающимся на 4 (400, 403, 404...)
grep '" 4[0-9][0-9] ' ~/wordpress-project/logs/access.logФлаг -E (или команда egrep) включает расширенный синтаксис с дополнительными
возможностями:
| Символ | Значение | Пример | Совпадёт с |
|---|---|---|---|
+ |
Предыдущий символ 1 или более раз | ab+c |
abc, abbc (но не ac) |
? |
Предыдущий символ 0 или 1 раз | colou?r |
color, colour |
| |
Или (альтернатива) | cat|dog |
cat или dog |
() |
Группировка | (ab)+ |
ab, abab, ababab |
# Найти строки с кодом 403 ИЛИ 404
grep -E '(403|404)' ~/wordpress-project/logs/access.logРегулярные выражения — обширная тема. Здесь мы разобрали только основы, достаточные для повседневной работы с grep. Со временем вы будете осваивать более сложные шаблоны по мере необходимости.
Команда sed (stream editor) обрабатывает текст «на лету» — строку за строкой.
Самая частая операция — замена (substitution):
sed 's/старое/новое/' файлБуква s означает substitute (заменить). sed заменит первое вхождение
шаблона в каждой строке. Чтобы заменить все вхождения в строке, добавьте
флаг g (global):
sed 's/старое/новое/g' файл# Заменить HTTP/1.1 на HTTP/2 в выводе (файл не изменяется)
sed 's/HTTP\/1.1/HTTP\/2/' ~/wordpress-project/logs/access.logВажно: по умолчанию sed выводит результат на экран, не изменяя исходный файл. Чтобы изменить сам файл, используйте флаг
-i:sed -i 's/старое/новое/g' файлБудьте осторожны с
-i— отменить изменения будет невозможно.
# Удалить все строки, содержащие 403 (d — delete)
sed '/403/d' ~/wordpress-project/logs/access.log# Показать только строки с 5-й по 10-ю (аналог head/tail, но гибче)
sed -n '5,10p' ~/wordpress-project/logs/access.logФлаг -n подавляет обычный вывод, а команда p (print) выводит только
указанные строки.
sed часто используется для преобразования данных между другими командами:
# Извлечь URL и убрать кавычки
cut -d '"' -f 2 ~/wordpress-project/logs/access.log | sed 's/ HTTP\/1.1//'GET /
GET /style.css
GET /about
POST /wp-login.php
...
awk — это мини-язык программирования для обработки текстовых данных.
Звучит сложно, но базовое использование простое. awk автоматически разбивает
каждую строку на поля (столбцы) по пробелам и позволяет обращаться к ним
по номерам:
$1— первое поле;$2— второе поле;$NF— последнее поле;$0— вся строка целиком.
awk '{print $N}' файл# Извлечь IP-адрес (1-е поле) и код ответа (9-е поле)
awk '{print $1, $9}' ~/wordpress-project/logs/access.log192.168.1.10 200
192.168.1.10 200
192.168.1.25 200
10.0.0.5 403
192.168.1.10 302
192.168.1.25 404
...
Преимущество awk перед cut — awk автоматически разбивает строку по пробелам (и любому количеству пробелов), а cut требует указания разделителя и считает каждый пробел отдельно.
# Извлечь IP-адрес и размер ответа (последнее поле)
awk '{print $1, $NF}' ~/wordpress-project/logs/access.log192.168.1.10 3421
192.168.1.10 1532
192.168.1.25 2100
10.0.0.5 150
...
awk может фильтровать строки по условию — аналогично grep, но с доступом к отдельным полям:
# Показать строки, где код ответа (поле 9) равен 404
awk '$9 == 404' ~/wordpress-project/logs/access.log# Показать IP-адреса запросов с кодом ответа 403
awk '$9 == 403 {print $1}' ~/wordpress-project/logs/access.log10.0.0.5
10.0.0.5
10.0.0.5
10.0.0.5
Если поля разделены не пробелами, а другим символом (например, двоеточием
в файле /etc/passwd), используйте флаг -F:
# Показать имена пользователей из /etc/passwd (разделитель — двоеточие)
awk -F: '{print $1}' /etc/passwdСила утилит — в комбинировании через конвейеры. Вот несколько типичных задач системного администратора, решённых цепочками команд.
awk '{print $1}' ~/wordpress-project/logs/access.log | sort | uniq -c | sort -rn | head -3Разберём по шагам:
| Шаг | Команда | Что делает |
|---|---|---|
| 1 | awk '{print $1}' |
Извлекает IP-адреса |
| 2 | sort |
Сортирует, чтобы одинаковые IP оказались рядом |
| 3 | uniq -c |
Считает повторения |
| 4 | sort -rn |
Сортирует по числу повторений (от большего к меньшему) |
| 5 | head -3 |
Берёт первые 3 строки |
Результат:
4 10.0.0.5
4 192.168.1.10
4 192.168.1.25
awk '$9 >= 400' ~/wordpress-project/logs/access.log | wc -l5
Пять запросов с кодом ответа 400 и выше (ошибки клиента и сервера).
awk '{print $7}' ~/wordpress-project/logs/access.log | sort -u/
/about
/blog
/blog/first-post
/contact
/style.css
/wp-admin/
/wp-content/uploads/photo.jpg
/wp-login.php
Флаг sort -u (unique) — сокращение для sort | uniq.
grep -E '" (4[0-9]{2}|5[0-9]{2}) ' ~/wordpress-project/logs/access.log > ~/wordpress-project/logs/errors.logЗдесь используется регулярное выражение для поиска кодов 4xx и 5xx, а результат перенаправляется в новый файл.
Проверим:
cat ~/wordpress-project/logs/errors.logawk '{sum += $NF} END {print sum, "байт"}' ~/wordpress-project/logs/access.logЗдесь awk суммирует значения последнего поля (размер ответа) по всем строкам.
Блок END выполняется после обработки всех строк и выводит итог.
Все задания выполняются на файле ~/wordpress-project/logs/access.log.
-
Подсчитайте общее количество строк в лог-файле с помощью
wc. -
С помощью
grepнайдите все строки, содержащиеGET. Сколько их? (Подсказка:grep -c.) -
Извлеките из лога только IP-адреса (первое поле) с помощью
cutилиawk. Выведите список уникальных IP-адресов. -
Найдите все запросы, которые вернули код
200. Подсчитайте их количество. -
С помощью
grepи регулярного выражения найдите все строки, где URL заканчивается на.php. -
Определите, какой IP-адрес сделал больше всего запросов. Используйте цепочку:
awk | sort | uniq -c | sort -rn | head -1. -
Используя
sed, выведите содержимое лог-файла, заменив все вхожденияHTTP/1.1наHTTP/2. (Не изменяйте файл — просто выведите на экран.) -
С помощью
awkвыведите только те строки, где размер ответа (последнее поле) больше 3000 байт. -
Перенаправьте все строки с кодом 403 в файл
~/wordpress-project/logs/blocked.log. Проверьте результат командойcat. -
(*) Определите самую часто запрашиваемую страницу (URL). Подсказка: извлеките URL (7-е поле), отсортируйте, подсчитайте и покажите первую строку.
В этой главе вы:
- разобрались с тремя стандартными потоками: stdin, stdout, stderr;
- научились перенаправлять вывод в файл (
>,>>) и ошибки (2>); - освоили конвейер
|— главный инструмент комбинирования команд; - познакомились с утилитами обработки текста:
wc— подсчёт строк, слов, байт;sort— сортировка;uniq— удаление дубликатов и подсчёт повторений;cut— извлечение столбцов;grep— фильтрация строк по шаблону;sed— потоковая замена текста;awk— обработка текста по столбцам;
- узнали основы регулярных выражений:
.,*,^,$,[],\; - научились решать реальные задачи цепочками команд на примере логов nginx.
В следующей главе мы перейдём к основам bash-скриптов — научимся объединять команды в файлы-программы, которые можно запускать повторно, и познакомимся с переменными окружения и PATH.