Пара 3: Shell, структура каталогов и текстовые утилиты

90 минут · 3 курс, ML.

Содержание и результат

Безопасно создавать, читать, копировать и искать файлы; понимать кавычки.

План занятия

0–10: контекст и исходная задача. 10–40: устройство и механизмы. 40–55: демонстрация команд. 55–80: лабораторная работа. 80–90: разбор результата и фиксация исправлений.

Практика выполняется в своей учебной папке и на localhost. Подготовка окружения описана в lab/README.md.

Команда — имя и аргументы

Shell разделяет слова до запуска программы.

Пробел обычно разделяет аргументы. Путь с пробелом нужно заключить в кавычки. Двойные кавычки сохраняют подстановку переменных, одинарные передают текст буквально. Звёздочку shell может раскрыть в список имён до запуска программы. Это объясняет, почему rm *.txt получает уже список файлов. -- во многих GNU-утилитах завершает параметры: имя, начинающееся с дефиса, после этого рассматривается как операнд. Не все программы имеют одинаковые флаги; проверяйте man или --help.

Аналогия: упаковка заказа в отдельные коробки; кавычки удерживают слова вместе.

Сначала осмотр, затем изменение

pwd и ls снижают риск работы не в той папке.

Терминал не всегда спрашивает подтверждение. cp копирует, mv перемещает или переименовывает, rm удаляет имя. Удаление в shell обычно не отправляет в корзину Windows. На курсе работаем в ~/devops-course/sandbox и используем rm -i для небольших опытов. Не учите привычку sudo перед любой ошибкой: отказ может говорить о неверном пути. Перед изменением прочитайте команду вслух: что является источником, что целью, есть ли перезапись? История команд полезна, но может содержать введённые секреты, поэтому пароли в аргументах не вводим.

Аналогия: прежде чем переносить коробки, проверьте номер склада.

Поиск и чтение

Ищем имя отдельно от текста внутри файла.

find ищет файловые объекты по условиям: имя, тип, размер. grep ищет совпадения в тексте. head и tail показывают начало и конец, less позволяет читать большой файл без загрузки всего текста на экран. wc -l считает строки. grep по умолчанию использует регулярные выражения; grep -F ищет буквальный текст. Выбор простого инструмента — инженерное решение: не нужен Python-скрипт ради одного поиска. Учебный файл мал, но команды пригодятся для логов и результатов экспериментов. Объясните, что grep не понимает смысл модели и не проверяет JSON как структурированный документ.

Имена и содержимое — разные пространства поиска.

Подробный разбор: Shell, имена файлов и текстовые утилиты

Terminal, shell и утилиты — три разных слоя

Shell превращает командную строку в запуск с аргументами и окружением.

Terminal, shell и утилиты — три разных слоя

Terminal или terminal emulator обеспечивает взаимодействие через псевдотерминал. Bash, zsh, dash, fish — программы, интерпретирующие команды. POSIX sh задаёт переносимый интерфейс, но /bin/sh не обязан быть Bash: в Ubuntu часто используется dash. Bash добавляет собственные конструкции; zsh тоже имеет особенности, fish не стремится быть POSIX shell. Shebang #!/usr/bin/env bash выбирает interpreter для исполняемого скрипта, а запуск bash script.sh выбирает его явно. Команда cd обычно builtin: дочерний процесс не мог бы изменить текущий каталог родителя. Export меняет окружение будущих детей; обычное присваивание shell-переменной не всегда экспортируется. Alias — удобство интерактивного shell, а не надёжная dependency скрипта. PATH содержит каталоги для поиска внешних программ; command -v помогает увидеть реальное разрешение имени.

Практическое следствие: Кавычки, expansion и разбиение argv происходят до исполнения утилиты. На Mac интерактивный zsh и системный старый Bash — разные среды.

Файл .env скрыт только от обычного списка

В Linux точка — соглашение об имени, а не особый секретный тип файла.

Файл .env скрыт только от обычного списка

У имени .env нет автоматического запрета чтения: ls без -a обычно не показывает имена, начинающиеся с точки, но cat .env читает их при разрешённом доступе. . — текущий каталог, .. — родительский; это специальные записи, а не обычные пользовательские файлы. .config хранит пользовательские настройки по распространённому соглашению XDG; .bashrc и .zshrc относятся к соответствующим shell. Windows имеет отдельный атрибут hidden, поэтому похожее отображение достигается другим механизмом. Gitignore тоже не защищает секрет: он влияет на выбор неотслеживаемых файлов, но уже закоммиченный .env остаётся в истории. На практике применяют доступ по правам, разделение конфигурации и секретов, исключение из репозитория и ротацию случайно раскрытого секрета. Не ставьте chmod 777 ради чтения конфигурации.

Практическое следствие: ls -a показывает скрытые имена; ls -A опускает специальные записи . и .. Hidden не означает encrypted или unreadable.

/etc, /var, /usr, /tmp: роли каталогов

По роли данных можно выбрать место хранения и область диагностики.

/etc, /var, /usr, /tmp: роли каталогов

/etc содержит конфигурацию конкретного хоста; современный смысл важнее спорной расшифровки имени. /usr содержит установленный userland: программы, библиотеки и общие данные. /var предназначен для изменяемых данных — журналов, очередей и состояния приложений. /home содержит домашние каталоги; /root — домашний каталог root, а не синоним /. /run хранит состояние текущей загрузки; /tmp — временные файлы. /proc и /sys — интерфейсы виртуальных файловых систем со сведениями ядра, /dev — специальные объекты устройств. На merged-/usr системах /bin и /sbin могут быть ссылками внутрь /usr, поэтому старый рисунок «каждый каталог отдельный диск» неверен. FHS описывает соглашения, но конкретное приложение или контейнер может выбирать другое размещение. Всегда проверяем эффективный config и mounts.

Практическое следствие: Настройки, код, runtime state и пользовательские данные имеют разные сроки жизни и требования к резервному копированию.

grep, sed и awk решают разные задачи

Текстовый поток можно отобрать, преобразовать и разобрать без изменения оригинала.

grep, sed и awk решают разные задачи

Grep выбирает строки по совпадению. -F ищет буквальный текст, -E использует расширенное регулярное выражение, -n добавляет номер строки. Sed применяет команды к потоку: s/old/new/ меняет первое совпадение в строке, флаг g — все подходящие совпадения. Без -i результат идёт в stdout, исходный файл сохраняется. Awk работает с записями и полями, умеет фильтрацию и вычисления; его стандартное разделение по whitespace не является полноценным CSV-парсером с кавычками. Sort упорядочивает строки, uniq объединяет соседние одинаковые, поэтому для полного подсчёта обычно нужны sort | uniq -c. Locale влияет на порядок и классы символов; LC_ALL=C полезен, когда нужен определённый байтовый порядок. GNU/BSD варианты флагов различаются. Для JSON выбираем JSON-парсер, а не пытаемся извлечь вложенную структуру регулярным выражением.

Практическое следствие: Фильтрацию и преобразование сначала выводим в новый файл; sed -i используется после проверки и с учётом различий GNU/BSD.

Опыт: связать рисунок с наблюдением

mkdir -p ~/devops-course/text-demo
cd ~/devops-course/text-demo
printf "INFO status=ok\nERROR status=failed\n" > events.log
printf "local-setting\n" > .settings
ls
ls -a
grep -n -F ERROR events.log
sed 's/failed/retry/' events.log
awk '{print $1}' events.log
command -v sh bash grep sed

Сохраните отфильтрованные ERROR в отдельный файл, сравните оригинал и результат. Работающие команды не требуют sudo. Прочитайте man grep / man sed своей ОС перед использованием расширенных флагов.

Источники подробного разбора

Команды и наблюдения

Окружение: Ubuntu / Bash.

mkdir -p ~/devops-course/sandbox
cd ~/devops-course/sandbox
printf "OK run=1
ERROR run=2
OK run=3
" > "run log.txt"
cp -- "run log.txt" backup.txt
grep -n -F ERROR "run log.txt"
find . -type f -name "*.txt"
wc -l "run log.txt"
cmp "run log.txt" backup.txt

Кавычки делают run log.txt одним аргументом; шаблон find заключён в кавычки, чтобы его обработал find, а не shell.

Ожидаемый результат: grep находит строку 2; wc показывает 3; cmp молчит и возвращает 0.

Вариант для macOS

mkdir, cp, grep, find, head, tail, less, wc и cmp доступны. Linux find -maxdepth не считайте переносимым; для поиска по всему учебному дереву достаточно команды выше. BSD и GNU-флаги могут различаться. Проверяйте man на своей системе.

mkdir -p ~/devops-course/sandbox
cp -- "run log.txt" backup.txt
grep -n -F ERROR "run log.txt"
find . -type f -name "*.txt"
wc -l "run log.txt"

Практика: Архив экспериментальных запусков

  1. Создайте три файла, один с пробелом в имени.
  2. Скопируйте их в отдельную папку backup без изменения оригиналов.
  3. Найдите строки ERROR и посчитайте файлы через find.
  4. Переименуйте один файл и удалите только специально созданную копию с rm -i.

Результат: history-команды без секретов и найденные строки с номерами.

Проверка: Оригиналы сохранены; все пути с пробелами обработаны корректно.

Неисправность для разбора: Неэкранированный пробел разбил имя на два аргумента.

Решение и диагностика

Используйте mkdir -p backup; cp -- ./.txt backup/ до появления новых текстовых файлов в текущей папке. grep -n -F ERROR "run log.txt". Для подсчёта этих учебных имён find . -maxdepth 1 -type f -name ".txt" | wc -l. Поясните ограничение подсчёта по строкам для необычных имён с переводом строки; в этом упражнении такие имена не создаём.

Основные выводы

Самостоятельная работа

Создать шпаргалку из восьми команд: цель, пример, риск неправильного применения.

Источники