Часть 1. Шпаргалка: Переменные и Кавычки
1. Переменная БЕЗ кавычек ($VAR)
Правило: Bash подставляет текст и тут же делит его на отдельные аргументы по пробелам и переносам строк.
- Пример:
FILES="/logs/file1.log /logs/file2.log" - Команда:
rm $FILES - Что видит система: Вызов
rmс двумя аргументами. Это то, что нам нужно для удаления группы файлов. - Опасность: Если в имени одного файла есть пробел (например,
my file.txt), Bash разобьет его наmyиfile.txt, и удаление сломается.
2. Переменная В ДВОЙНЫХ кавычках ("$VAR")
Правило: Защищает пробелы внутри переменной. Весь текст внутри воспринимается как один неделимый аргумент. Переменные ($) внутри раскрываются.
- Пример:
FILE="my access log.log" - Команда:
rm "$FILE" - Что видит система: Удалить один файл с именем
my access log.log. - Что будет, если подставить список: Если внутри
$FILESлежит 5 файлов, кавычки склеят их в одну гигантскую нечитаемую строку, иrmвыдаст ошибку (как у вас в примере).
3. Подстановка команд ($(...))
Правило: Выполняет команду внутри скобок прямо сейчас и возвращает её текстовый вывод.
- Пример:
rm $(find / -name "*.log") - Как это работает:
findнаходит файлы \(\rightarrow \) превращает их в строку через пробел \(\rightarrow \) Bash подставляет их вrm. - Важно: Кавычки внутри скобок
$("...")защищают только то, что внутри скобок, помогая самой команде правильно отработать.
Часть 2. Создаем «Полигон» для тренировок
Запустите эту команду в вашем терминале. Она создаст тестовую структуру папок прямо в вашем домашнем каталоге в папке bash_lab:
bash
mkdir -p ~/bash_lab/logs/archive ~/bash_lab/project/data && \
touch ~/bash_lab/logs/access.log.{1..5} && \
touch ~/bash_lab/logs/archive/old_access.log.{1..3} && \
touch "~/bash_lab/project/data/bad name.log" && \
echo "Лабораторная среда успешно создана в папочке ~/bash_lab!"
Используйте код с осторожностью.
Структура, которую вы получили:
~/bash_lab/logs/— здесь лежат файлыaccess.log.1,access.log.2и т.д.~/bash_lab/logs/archive/— архивные логи.~/bash_lab/project/data/— здесь лежит коварный файлbad name.log(с пробелом в имени).
Часть 3. Задания для самопроверки (Потренируйтесь!)
Попробуйте выполнить эти задания на созданном полигоне. Переходите к ответам только после того, как попробуете сами!
- Задание 1: Сохраните путь
~/bash_lab/logsв переменнуюLOG_DIR. Используя эту переменную, найдите все файлыaccess.log.*черезfind. - Задание 2: Запишите результат поиска файлов из папки
archiveв переменнуюOLD_FILESс помощью$(...). Выведите результат на экран черезecho. - Задание 3: Попробуйте удалить файл
bad name.logс пробелом, используя переменную. Поймите, почемуrm $VARсломается, аrm "$VAR"сработает.
Нажмите, чтобы посмотреть правильные ответы-решения
Решение задания 1:
bash
LOG_DIR="~/bash_lab/logs"
find ~/bash_lab/logs -name "access.log.*" -type f
Используйте код с осторожностью.
(Обратите внимание: ~ внутри кавычек "~/..." может не раскрыться в некоторых версиях Bash, поэтому в переменных лучше указывать полный путь или писать LOG_DIR=$HOME/bash_lab/logs)
Решение задания 2:
bash
OLD_FILES=$(find ~/bash_lab/logs/archive -name "old_access.log.*" -type f)
echo "$OLD_FILES"
Используйте код с осторожностью.
(Обязательно оберните $OLD_FILES в кавычки в команде echo, чтобы сохранились переносы строк).
Решение задания 3:
bash
BAD_FILE="~/bash_lab/project/data/bad name.log"
# Ошибочный вариант (выдаст ошибку, что файлов bad и name.log не существует):
rm $BAD_FILE
# Правильный вариант (удалит файл успешно):
rm "$BAD_FILE"
Используйте код с осторожностью.
Вы можете очистить весь полигон одной командой rm -rf ~/bash_lab, когда закончите тренировки.
Какое из заданий вызвало у вас больше всего вопросов при проверке в терминале? Можем подробнее разобрать поведение Bash в этом конкретном случае!
В ответах искусственного интеллекта могут быть ошибки. Подробнее…
Вы сказали: «давай еще с вариациями grep и чтобы можно было почуствовать разницу кавычек скобок скобос с квачками и $ также нове пространство максимальная ваиативнсоть 30 задачек но нужны тоже примеры»
Отличный запрос! Использование grep в связке с find и переменными — это классика системного администрирования. Здесь кавычки и скобки играют еще более критическую роль, так как у grep есть свои регулярные выражения, которые Bash может случайно испортить, если их не экранировать.
Давайте расширим наш полигон, разберем ключевые правила для grep и перейдем к интерактивному набору из 30 задач.
Часть 1. Разница в кавычках и скобках при работе с grep
Когда мы подключаем grep, правила Bash начинают работать в полную силу:
1. Одинарные кавычки '...' (Абсолютная изоляция)
- Что делают: Запрещают Bash трогать вообще всё внутри. Символы
$,*,\становятся просто текстом. - Для чего нужны: Идеально для регулярных выражений
grep. - Пример:
grep 'errors.*404' file.log. Bash передаст в grep маскуerrors.*404без изменений. Если написать в двойных кавычках"errors.*404", Bash может попытаться найти переменную$404(и сотрет эту часть).
2. Двойные кавычки "..." (Частичная изоляция)
- Что делают: Склеивают пробелы, но разрешают раскрывать переменные
$VARи подстановку команд$(...). - Для чего нужны: Когда внутрь поиска
grepнужно передать переменную. - Пример:
SEARCH="ERROR";grep "$SEARCH" file.log— Bash сначала подставит слово ERROR, а потом запустит grep.
3. Подстановка команд со встроенными кавычками $("...")
- Что делают: Кавычки внутри скобок защищают аргументы внутренней команды, а не внешней.
- Пример:
grep "error" $(find /logs -name "*.log") - Как это работает: Сначала
findищет файлы, маска*.logзащищена кавычками от раскрытия в текущей папке. Затем список файлов подставляется вgrep.
Часть 2. Обновляем полигон (Максимальная вариативность)
Запустите этот скрипт в терминале. Он создаст новую структуру с логами, внутри которых записаны реальные строки (ошибки, IP-адреса, даты):
bash
mkdir -p ~/grep_lab/web ~/grep_lab/auth ~/grep_lab/backup && \
echo -e "192.168.1.10 - - [20/Jul/2026] \"GET /index.html\" 200\n192.168.1.15 - - [20/Jul/2026] \"POST /login\" 403\nCRITICAL: Database connection failed" > ~/grep_lab/web/access.log && \
echo -e "192.168.1.50 - - [20/Jul/2026] \"GET /api/v1\" 404\nWARNING: Low disk space" > ~/grep_lab/web/error.log && \
echo -e "Jul 20 12:00:01 sshd[1234]: Accepted password for root\nJul 20 12:05:10 sshd[1234]: Failed password for invalid user admin" > ~/grep_lab/auth/secure.log && \
echo -e "SUCCESS: Backup created\nERROR: Replication failed on 192.168.1.10" > ~/grep_lab/backup/report.txt && \
touch "~/grep_lab/web/spaced name.log" && \
echo "SUCCESS: This is a file with space" > "~/grep_lab/web/spaced name.log" && \
echo "Полигон ~/grep_lab создан! Внутри файлов есть реальный текст для grep."
Используйте код с осторожностью.
Часть 3. 30 практических задач для тренировки
Задания разбиты по блокам от простых к продвинутым. Пытайтесь сначала написать команду сами, а затем сверяйтесь с ответом.
Блок А: Базовый grep и кавычки (Задачи 1-10)
- Задача: Найдите слово «ERROR» в файле
~/grep_lab/backup/report.txt. - Задача: Найдите строку «Failed password» в файле
~/grep_lab/auth/secure.log(используйте одинарные кавычки). - Задача: Сохраните слово «CRITICAL» в переменную
QUERY. Используя двойные кавычки, найдите это слово в папке~/grep_lab/web/access.log. - Задача: Попробуйте найти то же самое, но используя одинарные кавычки:
grep '$QUERY' .... Посмотрите на результат. Почему он пустой? - Задача: Найдите все строки, содержащие цифру 403 или 404 в папке
~/grep_lab/web/с помощью расширенного grep (grep -E), используя маску ‘403|404’. - Задача: Найдите слово «SUCCESS» в файле с пробелом
spaced name.log. Поймите, почему кавычки для имени файла обязательны. - Задача: Запишите имя файла с пробелом в переменную
FILE. Выведите строку со словом «SUCCESS», правильно экранировав переменную. - Задача: Посчитайте количество строк (флаг
-c) со словомpasswordв файлеsecure.log. - Задача: Найдите IP-адрес
192.168.1.10в файлеreport.txt. Защитите точки в IP-адресе экранированием (\.), чтобы grep не воспринял их как «любой символ». - Задача: Найдите слово «Database» регистронезависимо (флаг
-i) в папке~/grep_lab/web/access.log.
Посмотреть решения задач 1-10
bash
# 1
grep "ERROR" ~/grep_lab/backup/report.txt
# 2
grep 'Failed password' ~/grep_lab/auth/secure.log
# 3
QUERY="CRITICAL"; grep "$QUERY" ~/grep_lab/web/access.log
# 4
grep '$QUERY' ~/grep_lab/web/access.log # Пусто, т.к. grep ищет буквально текст $QUERY, а не значение переменной
# 5
grep -E '403|404' ~/grep_lab/web/*
# 6
grep "SUCCESS" "~/grep_lab/web/spaced name.log"
# 7
FILE="~/grep_lab/web/spaced name.log"; eval grep "SUCCESS" "$FILE" # Или без eval, если путь абсолютный: grep "SUCCESS" "/home/user/grep_lab/web/spaced name.log"
# 8
grep -c 'password' ~/grep_lab/auth/secure.log
# 9
grep '192\.168\.1\.10' ~/grep_lab/backup/report.txt
# 10
grep -i 'database' ~/grep_lab/web/access.log
Используйте код с осторожностью.
Блок Б: Подстановка команд $() и связка find + grep (Задачи 11-20)
- Задача: С помощью
findнайдите все файлы*.logв~/grep_labи передайте их вgrepдля поиска слова «Accepted», используя синтаксисgrep ... $(find ...). - Задача: Используя подстановку
$(), найдите слово «failed» во всех файлах, найденныхfindв папке~/grep_lab/web. - Задача: Сохраните список файлов, возвращенных
find, в переменнуюLOG_FILES. Передайте эту переменную вgrepбез кавычек, чтобы найти слово «Replication». Почему тут кавычки НЕ нужны? - Задача: Попробуйте сделать то же самое, что в задаче 13, но оберните переменную в кавычки:
grep "Replication" "$LOG_FILES". Какую ошибку выдаст система? - Задача: Используя
$(find ...), найдите файлы проекта и выполните в них поиск строк, начинающихся со слова «Jul» (регулярное выражение'^Jul'). - Задача: Выведите только имена файлов (флаг
grep -l), в которых встречается IP-адрес192.168.1.15, используя подстановку$(find). - Задача: Сохраните команду поиска файлов в переменную
CMD="find ~/grep_lab -name '*.log'"и попытайтесь запустить её черезgrep "Accepted" $($CMD). - Задача: Найдите слово «failed» во всех файлах
*.txt, используя$()подстановку. - Задача: Напишите однострочник, который найдет файлы через
find, погрепает в них слово «WARNING», и запишет результат grep в новый файл~/grep_lab/alerts.txt. - Задача: Попробуйте использовать
grepвнутри$(). Запишите результат поиска слова «root» из логов в переменнуюROOT_LOGи выведите её черезecho.
Посмотреть решения задач 11-20
bash
# 11
grep "Accepted" $(find ~/grep_lab -name "*.log" -type f)
# 12
grep -i "failed" $(find ~/grep_lab/web -type f)
# 13
LOG_FILES=$(find ~/grep_lab -type f); grep "Replication" $LOG_FILES # Без кавычек, чтобы Bash разбил список файлов на отдельные аргументы для grep.
# 14
grep "Replication" "$LOG_FILES" # Ошибка "No such file or directory", т.к. grep воспримет весь список как имя одного файла с переносами строк.
# 15
grep '^Jul' $(find ~/grep_lab -type f)
# 16
grep -l '192\.168\.1\.15' $(find ~/grep_lab -type f)
# 17
CMD="find /home/student/grep_lab -name *.log -type f"; grep "Accepted" $(eval $CMD)
# 18
grep -i "failed" $(find ~/grep_lab -name "*.txt")
# 19
grep "WARNING" $(find ~/grep_lab -type f) > ~/grep_lab/alerts.txt
# 20
ROOT_LOG=$(grep "root" $(find ~/grep_lab -type f)); echo "$ROOT_LOG"
Используйте код с осторожностью.
Блок В: Продвинутые сценарии и ловушки синтаксиса (Задачи 21-30)
- Задача: Что произойдет, если запустить
grep "SUCCESS" $(find ~/grep_lab -type f)? (Подсказка: на полигоне есть файл с пробеломspaced name.log). Посмотрите на ошибку. - Задача: Как решить проблему из задачи 21? (Подсказка: вместо
$()использовать встроенный флагfind -exec grep ... {} +). - Задача: Создайте переменную
MASK="*.log". Используяfindи подстановку, найдите файлы по этой маске, правильно экранировав маску внутриfind. - Задача: Найдите во всех файлах строки, которые НЕ содержат слово «SUCCESS» (флаг
grep -v), используя подстановкуfind. - Задача: Сохраните регулярное выражение для поиска IP-адресов
'[0-9]\{3\}\.[0-9]\{3\}'в переменнуюIP_REGEX. Используя двойные кавычки для переменной, вызовитеgrep "$IP_REGEX"на файлах изfind. - Задача: Напишите команду, которая проверяет, есть ли слово «CRITICAL» в логах. Если есть — выводит «Авария!», если нет — «Всё ок». (Используйте
if grep ... $(find ...)). - Задача: Используя вложенные скобки
$($( ... )), найдите файлы черезfind, погрепайте в них имена файлов, содержащих «ERROR», и передайте это в следующую команду (для тренировки синтаксиса). - Задача: Положите в переменную
EXCLUDE="-v SUCCESS". Запуститеgrep $EXCLUDE(без кавычек) на файлеreport.txt. Объясните, почему без кавычек это работает как флаг, а с кавычками"$EXCLUDE"сломается. - Задача: Используя
find, найдите файлы из папкиauth, найдите в них слово «sshd», но выведите только второе поле (используя пайп| awk '{print $5}'внутри или снаружи). - Задача: Очистите весь полигон
~/grep_lab. Какую команду нужно выполнить, чтобы случайно не удалить другие важные папки в системе?
Посмотреть решения задач 21-30
bash
# 21
grep "SUCCESS" $(find ~/grep_lab -type f) # Выдаст ошибку: grep: .../spaced: No such file; grep: name.log: No such file. Способ $() сломался из-за пробела.
# 22
find ~/grep_lab -type f -exec grep "SUCCESS" {} + # Этот способ абсолютно устойчив к пробелам в именах файлов!
# 23
MASK="*.log"; find ~/grep_lab -name "$MASK"
# 24
grep -v "SUCCESS" $(find ~/grep_lab -name "*.txt" -o -name "*.log")
# 25
IP_REGEX='[0-9]\{3\}\.[0-9]\{3\}'; grep "$IP_REGEX" $(find ~/grep_lab -name "*.log")
# 26
if grep -q "CRITICAL" $(find ~/grep_lab -type f); then echo "Авария!"; else echo "Всё ок"; fi # Флаг -q скрывает вывод grep, оставляя только статус кода.
# 27
grep "ERROR" $(find ~/grep_lab -type f)
# 28
EXCLUDE="-v SUCCESS"; grep $EXCLUDE ~/grep_lab/backup/report.txt # Без кавычек Bash делит строку на флаг -v и аргумент SUCCESS. В кавычка "$EXCLUDE" grep воспримет "-v SUCCESS" как один странный поисковый паттерн.
# 29
grep "sshd" $(find ~/grep_lab/auth -type f) | awk '{print $5}'
# 30
rm -rf ~/grep_lab
Используйте код с осторожностью.
С чего начать?
Рекомендую скопировать скрипт создания полигона, запустить его и по очереди вводить команды из Блока А.