find и на перменные $ на «» на $(«») 30 задачек

Часть 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)

  1. Задача: Найдите слово «ERROR» в файле ~/grep_lab/backup/report.txt.
  2. Задача: Найдите строку «Failed password» в файле ~/grep_lab/auth/secure.log (используйте одинарные кавычки).
  3. Задача: Сохраните слово «CRITICAL» в переменную QUERY. Используя двойные кавычки, найдите это слово в папке ~/grep_lab/web/access.log.
  4. Задача: Попробуйте найти то же самое, но используя одинарные кавычки: grep '$QUERY' .... Посмотрите на результат. Почему он пустой?
  5. Задача: Найдите все строки, содержащие цифру 403 или 404 в папке ~/grep_lab/web/ с помощью расширенного grep (grep -E), используя маску ‘403|404’.
  6. Задача: Найдите слово «SUCCESS» в файле с пробелом spaced name.log. Поймите, почему кавычки для имени файла обязательны.
  7. Задача: Запишите имя файла с пробелом в переменную FILE. Выведите строку со словом «SUCCESS», правильно экранировав переменную.
  8. Задача: Посчитайте количество строк (флаг -c) со словом password в файле secure.log.
  9. Задача: Найдите IP-адрес 192.168.1.10 в файле report.txt. Защитите точки в IP-адресе экранированием (\.), чтобы grep не воспринял их как «любой символ».
  10. Задача: Найдите слово «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)

  1. Задача: С помощью find найдите все файлы *.log в ~/grep_lab и передайте их в grep для поиска слова «Accepted», используя синтаксис grep ... $(find ...).
  2. Задача: Используя подстановку $(), найдите слово «failed» во всех файлах, найденных find в папке ~/grep_lab/web.
  3. Задача: Сохраните список файлов, возвращенных find, в переменную LOG_FILES. Передайте эту переменную в grep без кавычек, чтобы найти слово «Replication». Почему тут кавычки НЕ нужны?
  4. Задача: Попробуйте сделать то же самое, что в задаче 13, но оберните переменную в кавычки: grep "Replication" "$LOG_FILES". Какую ошибку выдаст система?
  5. Задача: Используя $(find ...), найдите файлы проекта и выполните в них поиск строк, начинающихся со слова «Jul» (регулярное выражение '^Jul').
  6. Задача: Выведите только имена файлов (флаг grep -l), в которых встречается IP-адрес 192.168.1.15, используя подстановку $(find).
  7. Задача: Сохраните команду поиска файлов в переменную CMD="find ~/grep_lab -name '*.log'" и попытайтесь запустить её через grep "Accepted" $($CMD).
  8. Задача: Найдите слово «failed» во всех файлах *.txt, используя $() подстановку.
  9. Задача: Напишите однострочник, который найдет файлы через find, погрепает в них слово «WARNING», и запишет результат grep в новый файл ~/grep_lab/alerts.txt.
  10. Задача: Попробуйте использовать 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)

  1. Задача: Что произойдет, если запустить grep "SUCCESS" $(find ~/grep_lab -type f)? (Подсказка: на полигоне есть файл с пробелом spaced name.log). Посмотрите на ошибку.
  2. Задача: Как решить проблему из задачи 21? (Подсказка: вместо $() использовать встроенный флаг find -exec grep ... {} +).
  3. Задача: Создайте переменную MASK="*.log". Используя find и подстановку, найдите файлы по этой маске, правильно экранировав маску внутри find.
  4. Задача: Найдите во всех файлах строки, которые НЕ содержат слово «SUCCESS» (флаг grep -v), используя подстановку find.
  5. Задача: Сохраните регулярное выражение для поиска IP-адресов '[0-9]\{3\}\.[0-9]\{3\}' в переменную IP_REGEX. Используя двойные кавычки для переменной, вызовите grep "$IP_REGEX" на файлах из find.
  6. Задача: Напишите команду, которая проверяет, есть ли слово «CRITICAL» в логах. Если есть — выводит «Авария!», если нет — «Всё ок». (Используйте if grep ... $(find ...)).
  7. Задача: Используя вложенные скобки $($( ... )), найдите файлы через find, погрепайте в них имена файлов, содержащих «ERROR», и передайте это в следующую команду (для тренировки синтаксиса).
  8. Задача: Положите в переменную EXCLUDE="-v SUCCESS". Запустите grep $EXCLUDE (без кавычек) на файле report.txt. Объясните, почему без кавычек это работает как флаг, а с кавычками "$EXCLUDE" сломается.
  9. Задача: Используя find, найдите файлы из папки auth, найдите в них слово «sshd», но выведите только второе поле (используя пайп | awk '{print $5}' внутри или снаружи).
  10. Задача: Очистите весь полигон ~/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

Используйте код с осторожностью.


С чего начать?

Рекомендую скопировать скрипт создания полигона, запустить его и по очереди вводить команды из Блока А.

Оставьте комментарий