Из простых утилит — ответ на вопрос за одну строку
grep и файлы в дереве каталогов findsort, uniq, wc, cuttar и распаковывать ихУ каждого процесса есть три стандартных потока. По умолчанию все они подключены к терминалу, но их можно перенаправить.
| Поток | Номер | Куда по умолчанию | Что в нём |
|---|---|---|---|
| stdin — стандартный ввод | 0 | Клавиатура | Данные для программы |
| stdout — стандартный вывод | 1 | Экран | Результат работы |
| stderr — вывод ошибок | 2 | Экран | Сообщения об ошибках и диагностика |
Результат и ошибки идут разными потоками, хотя на экране смешиваются. Это видно, если вывести результат в файл:
$ ls /etc/hostname /nonexistent > out.txt
ls: невозможно получить доступ к '/nonexistent': Нет такого файла или каталога
$ cat out.txt
/etc/hostname
Ошибка осталась на экране, а в файл попал только результат. Так задумано: можно сохранить данные и при этом увидеть, что пошло не так.
| Запись | Что делает |
|---|---|
команда > файл | stdout в файл; файл перезаписывается |
команда >> файл | stdout в конец файла |
команда 2> файл | stderr в файл |
команда > файл 2>&1 | Оба потока в один файл (порядок важен: сначала stdout, потом «2 туда же, куда 1») |
команда 2> /dev/null | Выбросить ошибки: /dev/null поглощает всё |
команда < файл | stdin из файла |
$ echo one > f; echo two >> f; cat f
one
two
$ ls /etc/hostname /nonexistent > out.txt 2> err.txt
$ cat err.txt
ls: невозможно получить доступ к '/nonexistent': Нет такого файла или каталога
$ find /etc -name "*.conf" 2> /dev/null | wc -l # без «Отказано в доступе» на экране
118
> стирает файл до запуска команды. sort data.txt > data.txt оставит пустой файл: оболочка очистила его раньше, чем sort начал читать. Пишите в новый файл и затем переименовывайте.Перенаправление выполняет ваша оболочка, а не sudo. Поэтому sudo echo текст > /etc/файл не сработает: в файл пишет оболочка без прав root. Правильно — через tee, который сам открывает файл: echo текст | sudo tee /etc/файл (раздел 06).
Знак | соединяет stdout одной команды со stdin следующей. Каждая утилита делает одну вещь, а конвейер складывает из них решение. Возьмём журнал веб-сервера, где каждая строка — один запрос:
$ head -3 access.log
192.168.1.10 - - [14/Oct/2026:10:01:12 +0300] "GET / HTTP/1.1" 200 5120
192.168.1.15 - - [14/Oct/2026:10:01:40 +0300] "GET /about.html HTTP/1.1" 200 2048
10.0.0.7 - - [14/Oct/2026:10:02:03 +0300] "GET /admin HTTP/1.1" 404 162
Вопрос: с каких адресов было больше всего запросов?
$ cut -d" " -f1 access.log | sort | uniq -c | sort -rn
4 10.0.0.7
3 192.168.1.10
2 192.168.1.15
1 192.168.1.22
| Шаг | Что делает |
|---|---|
cut -d" " -f1 | Из каждой строки — первое поле при разделителе «пробел»: IP-адрес |
sort | Сортирует, чтобы одинаковые адреса оказались рядом |
uniq -c | Схлопывает соседние повторы и пишет их число. Без предварительного sort не работает |
sort -rn | По числу (-n), по убыванию (-r) |
Конвейер собирают постепенно: добавили команду, посмотрели промежуточный результат, добавили следующую. Если данных много, на каждом шаге ставьте в конец | head.
$ grep " 404 " access.log | cut -d" " -f7 # что искали несуществующего
/admin
/wp-login.php
/.env
/phpmyadmin/
Адрес 10.0.0.7 перебирает типовые пути админок и файлов с паролями — это автоматический сканер. Такие записи на любом открытом сервере появляются в первые часы работы; что с ними делать — в курсе «Основы кибербезопасности».
grep шаблон файлы выводит строки, в которых есть шаблон. Если файлы не указаны — ищет в stdin, поэтому его ставят в конвейер.
| Опция | Что делает | Пример |
|---|---|---|
-i | Без учёта регистра | grep -i error |
-v | Строки без шаблона | grep -v '^#' — без комментариев |
-c | Только число строк | grep -c 404 access.log → 4 |
-n | С номерами строк | 4:192.168.1.10 … "POST /login …" |
-r | Рекурсивно по каталогу | grep -r PermitRootLogin /etc/ssh/ |
-l | Только имена файлов с совпадением | grep -rl listen /etc/nginx/ |
-E | Расширенные регулярные выражения | grep -E ' (404|500) ' |
-A 3, -B 3 | Плюс 3 строки после / до совпадения | Контекст ошибки в журнале |
$ grep -r PermitRootLogin /etc/ssh/
/etc/ssh/sshd_config:#PermitRootLogin prohibit-password
/etc/ssh/sshd_config:# the setting of "PermitRootLogin prohibit-password".
$ grep -v '^#' /etc/fstab | grep . # без комментариев и пустых строк
Шаблон grep — регулярное выражение. Основные символы: ^ — начало строки, $ — конец, . — любой символ, * — повтор предыдущего 0 и более раз, [0-9] — символ из диапазона. Шаблон берите в одинарные кавычки, чтобы оболочка не раскрыла * и $ раньше grep.
find обходит дерево каталогов и выбирает файлы по условиям: имени, типу, размеру, времени изменения, владельцу.
$ find /etc -name "*.conf" 2>/dev/null | head -3
/etc/udev/udev.conf
/etc/udev/iocost.conf
/etc/selinux/semanage.conf
$ find /var/log -type f -size +1M # файлы больше 1 МБ
$ find ~ -type f -mtime -1 # изменённые за последние сутки
$ find /srv -user anna -type d # каталоги пользователя anna
$ find /tmp -name "*.tmp" -mtime +7 -delete # удалить .tmp старше 7 дней
| Условие | Значение |
|---|---|
-name "*.log" | Имя по шаблону; кавычки обязательны, иначе шаблон раскроет оболочка. -iname — без учёта регистра |
-type f / -type d | Файл / каталог |
-size +100M | Больше 100 МБ (- — меньше) |
-mtime -1 / +7 | Изменён менее суток назад / более 7 суток назад |
-maxdepth 1 | Не спускаться глубже указанного уровня |
-exec команда {} \; | Выполнить команду для каждого найденного, {} — имя файла |
$ find . -name "*.log" -exec wc -l {} \;
10 ./access.log
-delete или -exec rm запустите тот же find без них и посмотрите список. И ставьте -delete последним: условия, записанные после него, уже не ограничат удаление.| Команда | Что делает |
|---|---|
sort | Сортирует строки. -n — как числа, -r — обратно, -h — размеры 1K/2M, -t: -k3 — по третьему полю с разделителем : |
uniq | Убирает соседние повторы; -c — считает их, -d — только повторяющиеся |
wc | Считает строки -l, слова -w, байты -c |
cut | Вырезает поля: -d — разделитель, -f1,3 — поля |
tee файл | Пишет поток и в файл, и дальше по конвейеру |
$ sort -t: -k3 -n /etc/passwd | tail -3 | cut -d: -f1,3 # пользователи с наибольшим UID
systemd-network:998
student:1000
nobody:65534
$ grep " 404 " access.log | tee 404.txt | wc -l # сохранить и посчитать
4
Для разбора полей, разделённых несколькими пробелами, cut неудобен — там используют awk '{print $9}'. Подробно awk и sed разбираются в курсе «Bash-скрипты и автоматизация».
tar собирает каталог в один файл с сохранением прав и дат, а с опцией z ещё и сжимает его (gzip). Так переносят сайты, делают резервные копии и скачивают исходники.
$ tar -czf site.tar.gz site # c — создать, z — сжать, f — имя архива
$ tar -tzf site.tar.gz # t — показать содержимое
site/
site/index.html
site/css/
site/css/s.css
$ tar -xzf site.tar.gz -C restore # x — распаковать в каталог restore
$ tar -czf backup-$(date +%F).tar.gz site # имя с датой: backup-2026-10-14.tar.gz
Буквы запоминаются как действия: create, extract, list; z — gzip, v — показывать имена файлов, f — имя архива, оно всегда идёт сразу после опций. $(date +%F) подставляет в команду текущую дату — так архивы не затирают друг друга.
-C) и сначала смотрите содержимое через -t. Архив может содержать сотни файлов без общего каталога и рассыпать их по текущему.> перезаписывает, >> дописывает, 2>/dev/null глушит ошибки| передаёт вывод следующей команде; конвейер строят по шагу, проверяя промежуточный результатsort | uniq -c | sort -rn — частотный анализ чего угодноgrep ищет строки (-r, -i, -v, -c), find — файлы по имени, размеру, времениsudo — | sudo tee файлtar -czf — упаковать, -tzf — посмотреть, -xzf … -C — распаковать