Skip to content

Latest commit

 

History

History
820 lines (611 loc) · 33 KB

File metadata and controls

820 lines (611 loc) · 33 KB

Этап 5. Coreutils и конвейеры: обработка текста

Зачем это нужно

В предыдущих главах мы работали с файлами поштучно: создавали, копировали, редактировали в 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)».

Конвейер (pipe)

Конвейер — это самый важный механизм в этой главе. Символ | (вертикальная черта, «пайп») соединяет stdout одной команды с stdin другой:

  ┌──────────┐  stdout    stdin  ┌──────────┐
  │ Команда 1│────────────|──────│ Команда 2│
  └──────────┘                   └──────────┘

Примеры:

# Посчитать количество файлов в каталоге
ls /etc | wc -l

# Показать первые 5 строк из отсортированного списка
ls /etc | sort | head -5

Конвейер можно наращивать — соединять три, четыре и более команд:

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

Данные «текут» слева направо: вывод каждой команды становится вводом следующей. Далее в этой главе мы будем активно использовать конвейеры.

Подготовка: пример лог-файла nginx

Чтобы практиковаться на реальных данных, создадим файл с примером логов веб-сервера 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 — подсчёт строк, слов и символов

Команда 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.log
15 /home/student/wordpress-project/logs/access.log

В нашем логе 15 записей — 15 запросов к серверу.

Другие полезные флаги:

Флаг Что считает
-l Строки
-w Слова
-c Байты
-m Символы (для UTF-8 может отличаться от байтов)

wc отлично работает в конвейере — подсчитывает строки, приходящие на stdin:

# Сколько файлов в /etc?
ls /etc | wc -l

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

Команда 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 их не заметит. Поэтому uniq почти всегда используется после sort.

# Извлечь IP-адреса, отсортировать и убрать дубликаты
cut -d ' ' -f 1 ~/wordpress-project/logs/access.log | sort | uniq
10.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 вырезает из каждой строки определённые поля (столбцы) или диапазоны символов.

По разделителю (самый частый вариант)

cut -d '<разделитель>' -f <номера_полей>
  • -d ' ' — разделитель — пробел;
  • -f 1 — взять первое поле;
  • -f 1,3 — первое и третье поле;
  • -f 1-3 — поля с первого по третье.

Примеры на нашем лог-файле:

# Извлечь только IP-адреса (первое поле, разделитель — пробел)
cut -d ' ' -f 1 ~/wordpress-project/logs/access.log
192.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.log
192.168.1.10
192.168.1.10
192.168.1.25
10.0.0.5 - -
...

grep — поиск строк по шаблону

grep — одна из самых важных и часто используемых команд в Linux. Она фильтрует строки, содержащие заданный шаблон (образец):

grep '<шаблон>' <файл>

Простой поиск

# Найти все строки с кодом 404
grep '404' ~/wordpress-project/logs/access.log
192.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.log
10.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.log
4
# Показать все строки, КРОМЕ успешных (не содержащих 200)
grep -v '200' ~/wordpress-project/logs/access.log
# Найти слово «server» во всех файлах конфигурации
grep -r 'server' ~/wordpress-project/config/

grep в конвейере

grep часто используется как фильтр в середине конвейера:

# Сколько раз IP 10.0.0.5 обращался к серверу?
grep '10.0.0.5' ~/wordpress-project/logs/access.log | wc -l
4
# Какие 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.

Что значит «экранировать»? Некоторые символы имеют специальное значение — точка означает «любой символ», * — «повторение» и т.д. Экранирование — это способ сказать: «воспринимай этот символ буквально, а не как спецсимвол». Для этого перед ним ставится обратная косая черта \. Запись \. означает «именно точка», а не «любой символ».

Примеры с grep

# Строки, начинающиеся с 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 — потоковая замена текста

Команда 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 в конвейере

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 — это мини-язык программирования для обработки текстовых данных. Звучит сложно, но базовое использование простое. awk автоматически разбивает каждую строку на поля (столбцы) по пробелам и позволяет обращаться к ним по номерам:

  • $1 — первое поле;
  • $2 — второе поле;
  • $NF — последнее поле;
  • $0 — вся строка целиком.

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

awk '{print $N}' файл

Примеры

# Извлечь IP-адрес (1-е поле) и код ответа (9-е поле)
awk '{print $1, $9}' ~/wordpress-project/logs/access.log
192.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.log
192.168.1.10 3421
192.168.1.10 1532
192.168.1.25 2100
10.0.0.5 150
...

Фильтрация в awk

awk может фильтровать строки по условию — аналогично grep, но с доступом к отдельным полям:

# Показать строки, где код ответа (поле 9) равен 404
awk '$9 == 404' ~/wordpress-project/logs/access.log
# Показать IP-адреса запросов с кодом ответа 403
awk '$9 == 403 {print $1}' ~/wordpress-project/logs/access.log
10.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

Комбинирование: решаем реальные задачи

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

Задача 1: найти 3 самых активных IP-адреса

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

Задача 2: подсчитать количество запросов с ошибками

awk '$9 >= 400' ~/wordpress-project/logs/access.log | wc -l
5

Пять запросов с кодом ответа 400 и выше (ошибки клиента и сервера).

Задача 3: список уникальных URL, которые запрашивали

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.

Задача 4: сохранить только ошибки в отдельный файл

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.log

Задача 5: общий объём переданных данных

awk '{sum += $NF} END {print sum, "байт"}' ~/wordpress-project/logs/access.log

Здесь awk суммирует значения последнего поля (размер ответа) по всем строкам. Блок END выполняется после обработки всех строк и выводит итог.

Практическое задание

Все задания выполняются на файле ~/wordpress-project/logs/access.log.

  1. Подсчитайте общее количество строк в лог-файле с помощью wc.

  2. С помощью grep найдите все строки, содержащие GET. Сколько их? (Подсказка: grep -c.)

  3. Извлеките из лога только IP-адреса (первое поле) с помощью cut или awk. Выведите список уникальных IP-адресов.

  4. Найдите все запросы, которые вернули код 200. Подсчитайте их количество.

  5. С помощью grep и регулярного выражения найдите все строки, где URL заканчивается на .php.

  6. Определите, какой IP-адрес сделал больше всего запросов. Используйте цепочку: awk | sort | uniq -c | sort -rn | head -1.

  7. Используя sed, выведите содержимое лог-файла, заменив все вхождения HTTP/1.1 на HTTP/2. (Не изменяйте файл — просто выведите на экран.)

  8. С помощью awk выведите только те строки, где размер ответа (последнее поле) больше 3000 байт.

  9. Перенаправьте все строки с кодом 403 в файл ~/wordpress-project/logs/blocked.log. Проверьте результат командой cat.

  10. (*) Определите самую часто запрашиваемую страницу (URL). Подсказка: извлеките URL (7-е поле), отсортируйте, подсчитайте и покажите первую строку.

Итоги

В этой главе вы:

  • разобрались с тремя стандартными потоками: stdin, stdout, stderr;
  • научились перенаправлять вывод в файл (>, >>) и ошибки (2>);
  • освоили конвейер | — главный инструмент комбинирования команд;
  • познакомились с утилитами обработки текста:
    • wc — подсчёт строк, слов, байт;
    • sort — сортировка;
    • uniq — удаление дубликатов и подсчёт повторений;
    • cut — извлечение столбцов;
    • grep — фильтрация строк по шаблону;
    • sed — потоковая замена текста;
    • awk — обработка текста по столбцам;
  • узнали основы регулярных выражений: ., *, ^, $, [], \;
  • научились решать реальные задачи цепочками команд на примере логов nginx.

В следующей главе мы перейдём к основам bash-скриптов — научимся объединять команды в файлы-программы, которые можно запускать повторно, и познакомимся с переменными окружения и PATH.