Глава 5. Работа с файлами и каталогами
Работа с файлами и каталогами
Цель занятия — научиться копировать и перемещать файлы, редактировать текст, перенаправлять потоки и различать виды ссылок. Материал рассчитан на Ubuntu Server 26.04.1 LTS. Команды проверены на виртуальной машине 7 октября 2026 года. Работайте в VirtualBox под учётной записью student; имя машины соответствует её месту: 562-01–562-13.
1. Подготовка рабочего каталога
Все упражнения выполняются в домашнем каталоге. Сначала создайте данные, с которыми будете работать:
mkdir -p ~/chapter05/in ~/chapter05/out
cd ~/chapter05
printf 'Ubuntu Server\nРабота с файлами\n' > in/lesson.txt
ls -l in
Повторное выполнение printf с > заменит содержимое файла. Прежде чем повторять команды, проверьте, нет ли в нём сделанных вами изменений.
Запомнить: файл и каталог
Обычный файл содержит данные. Каталог связывает имена с объектами файловой системы. Полный путь начинается с
/, относительный отсчитывается от текущего каталога.
2. Копирование, перемещение и переименование
У cp сначала указывают источник, затем назначение:
cp in/lesson.txt out/lesson-copy.txt
cp in/lesson.txt out/
ls -l out
Первая команда задаёт новое имя копии. Вторая помещает файл в существующий каталог и сохраняет имя. Если файл назначения существует, обычный cp может заменить его. Для учебных работ удобно запрашивать подтверждение перезаписи:
cp -i in/lesson.txt out/lesson-copy.txt
cp -a in out/in-backup
При запросе cp -i ответ y разрешает перезапись, n сохраняет прежний файл назначения. В проверенной GNU cp 9.7 отказ от перезаписи возвращает код 1. Чтобы увидеть код, выполните сразу после команды printf 'Код завершения cp: %s\n' "$?", затем проверьте содержимое назначения. Такой результат нужно отличать от согласованной и выполненной перезаписи.
-a рекурсивно копирует каталог и пытается сохранить его атрибуты, включая временные метки, права и ссылки. Сохранение чужого владельца требует соответствующих полномочий. Простое копирование и полная резервная копия — разные операции.
Копирование каталогов и повторный запуск
cp -r включает рекурсивное копирование: вместе с каталогом обходятся его дочерние объекты. cp -a дополнительно сохраняет атрибуты и структуру ссылок. Для обычного каталога без одной из этих опций cp сообщит, что каталог пропущен.
Результат зависит от того, существует ли каталог назначения. Это можно увидеть в уже выполненной команде cp -a in out/in-backup:
| Состояние назначения перед запуском | Результат |
|---|---|
out/in-backup отсутствует |
Создаётся out/in-backup с содержимым in |
out/in-backup уже существует как каталог |
Источник помещается внутрь: появляется out/in-backup/in |
После первого выполнения повторите эту команду один раз и сравните дерево:
find out/in-backup -maxdepth 2 -type f -print
cp -a in out/in-backup
find out/in-backup -maxdepth 2 -type f -print
Для копирования содержимого в уже существующий каталог применяют другую запись:
mkdir -p out/content-copy
cp -a in/. out/content-copy/
find out/content-copy -maxdepth 2 -type f -print
Здесь in/. означает содержимое каталога, включая скрытые объекты; дополнительный уровень in не создаётся. Повторное выполнение может заменить совпадающие файлы, но не удаляет лишние файлы назначения. Такое копирование не является зеркалированием.
Запомнить: рекурсивная операция
Рекурсивная операция обрабатывает каталог и вложенные объекты. Наличие каталога назначения влияет на результат cp; перед повторением команды проверяйте существующую структуру.
mv перемещает объект, а внутри одного каталога служит для переименования:
mv out/lesson-copy.txt out/lecture.txt
mv -i out/lecture.txt in/
ls -l in out
Если назначение — существующий каталог, файл попадёт внутрь него. Если назначения нет, оно рассматривается как новое имя. При перемещении между файловыми системами данные приходится копировать; это не такое же быстрое изменение имени, как внутри одной файловой системы.
Несколько источников и имена с пробелами
Сначала создайте файлы и каталоги назначения:
printf 'Первый документ\n' > in/first.txt
printf 'Второй документ\n' > in/second.txt
printf 'Конспект с пробелом в имени\n' > 'in/lecture notes.txt'
mkdir -p out/batch out/moved
cp -iv in/first.txt in/second.txt 'in/lecture notes.txt' out/batch/
mv -iv out/batch/first.txt out/batch/second.txt out/moved/
ls -l out/batch out/moved
При нескольких источниках последний аргумент должен обозначать существующий каталог. -v показывает операции, -i запрашивает подтверждение замены существующего файла. Ожидаемый результат первого прохода: в out/moved находятся first.txt и second.txt, а в out/batch остаётся lecture notes.txt. Исходники в in сохранились, поскольку сначала выполнялось копирование.
Кавычки делают путь с пробелами одним аргументом. Для имени, начинающегося с дефиса, отделяют аргументы от опций через --, например cp -- ./-notes.txt out/; такой файл нужно сначала создать. Точка . обозначает текущий каталог, а не специальную опцию cp.
Удаляйте только подготовленные учебные файлы. rm -i файл запрашивает подтверждение; rmdir каталог удаляет пустой каталог. Удаление через rm обычно не отправляет файл в корзину.
Выучить: порядок аргументов
cp источник назначение— копирование;mv источник назначение— перемещение или переименование. Перед операцией проверьтеpwdи путь назначения.
3. Редактирование в Nano
Сначала проверьте наличие редакторов:
command -v nano
command -v vim
Если редактор не найден, выполните sudo apt update и установите нужный пакет: sudo apt install nano или sudo apt install vim. После успешной установки повторите проверку. На проверенном стенде уже установлены Nano 8.7.1 и Vim 9.1.
Теперь вернитесь в рабочий каталог и откройте подготовленный конспект:
cd ~/chapter05
nano in/lecture.txt
Введите заголовок «Конспект занятия», затем несколько строк текста. Сохраните файл сочетанием Ctrl+O, подтвердите имя клавишей Enter и выйдите через Ctrl+X. Если файл ещё не сохранён, редактор предложит сохранить изменения.
В подсказках Nano знак ^ означает Ctrl, а M- — Meta, обычно Alt. В Nano 8 и новее Ctrl+F начинает поиск вперёд, Ctrl+B — назад, Alt+F выбирает следующее совпадение вперёд. В старых инструкциях для поиска часто указан Ctrl+W. Ориентируйтесь на подсказки установленной версии и справку Ctrl+G, поскольку сочетания могут быть переназначены. Ctrl+K вырезает строку, Ctrl+U вставляет вырезанный текст. Это внутренний буфер редактора; он не обязан совпадать с буфером обмена Windows.
cat in/lecture.txt
Для конфигурационных файлов сначала изучают назначение файла и сохраняют копию, затем редактируют с нужными правами. Не добавляйте sudo к работе со своими конспектами: иначе можно получить файлы, принадлежащие root.
4. Основные режимы Vim
Откройте другой файл:
vim in/vim-notes.txt
При запуске Vim обычно находится в нормальном режиме. Нажмите i, чтобы вводить текст, напечатайте несколько строк и нажмите Esc, чтобы вернуться к командам.
| Команда | Действие |
|---|---|
i |
Перейти к вводу перед курсором |
a, A |
Ввод после курсора или в конце строки |
| Esc | Вернуться в нормальный режим |
:w и Enter |
Сохранить |
:q и Enter |
Выйти, если нет несохранённых изменений |
:wq и Enter |
Сохранить и выйти |
:q! и Enter |
Выйти, отбросив несохранённые изменения |
h, j, k, l |
Влево, вниз, вверх, вправо |
dd |
Удалить текущую строку |
x |
Удалить символ под курсором |
gg, G |
Перейти к первой или последней строке |
yy, затем p |
Скопировать строку и вставить после текущей |
u, Ctrl+R |
Отмена и повтор отменённого изменения |
/слово и Enter |
Поиск вперёд; n — следующее совпадение |
Для замены с подтверждением каждого совпадения используется :%s/старое/новое/gc. Двоеточие открывает командную строку Vim, % выбирает весь файл, s выполняет замену, / разделяет части, g обрабатывает все совпадения в каждой строке, c запрашивает подтверждение. Без g заменяется только первое совпадение в каждой обрабатываемой строке. Символы в шаблоне поиска могут иметь специальное значение. Не применяйте глобальные замены к системным файлам, не просмотрев совпадения.
В открытом in/vim-notes.txt введите две строки: Сервер Ubuntu. Ubuntu для занятий. и Ubuntu работает в VirtualBox. Вернитесь через Esc в нормальный режим и выполните :%s/Ubuntu/Ubuntu Server/gc. На каждом подтверждении нажмите y; n пропускает совпадение, Esc прекращает замену. Должны измениться три вхождения. Нажмите u, чтобы отменить замену, затем Ctrl+R, чтобы повторить её, и сохраните файл через :wq. Теперь файл существует для следующих упражнений.
После :wq редактор уже закрыт. Для проверки команд оболочки снова откройте сохранённый файл:
vim ~/chapter05/in/vim-notes.txt
Команда :!pwd запускает команду оболочки из Vim и показывает текущий каталог. :!ls -l ~/chapter05/in выводит список подготовленных файлов; после просмотра вернитесь в редактор по приглашению, обычно через Enter. Это запуск отдельной команды, а несохранённый текст буфера автоматически на диск не записывается.
Записать: режимы Vim
Нормальный режим предназначен для команд, режим вставки — для ввода текста, визуальный режим — для выделения. Нажатия клавиш имеют разный смысл в разных режимах; перед командой возвращайтесь через Esc в нормальный режим.
Выделение, окна и настройки Vim
Откройте уже сохранённый файл vim ~/chapter05/in/vim-notes.txt. В обычном режиме нажмите v, выделите текст движением курсора, затем y для копирования. Переместите курсор и нажмите p для вставки после него. V выделяет целые строки; Esc отменяет выделение. Команда d удаляет выделенное и сохраняет его в регистре, откуда его также можно вставить через p. Перед выходом решите, сохранять ли учебные изменения: :wq сохраняет, :q! отбрасывает несохранённые изменения.
Команды :split и :vsplit делят окно по горизонтали и вертикали. Ctrl+W, затем w переключает окна; :close закрывает текущее окно. Два окна могут показывать один буфер: изменение текста в одном видно в другом. Окно — область отображения, буфер — редактируемое содержимое файла.
:set number включает номера строк, :set nonumber отключает. Чтобы настройка сохранялась при последующих запусках, откройте nano ~/.vimrc и добавьте отдельную строку set number, сохранив существующие настройки. Стандартные настройки редактора не меняют сам текст документа.
5. Стандартные потоки
Программа обычно получает три стандартных файловых дескриптора: 0 — стандартный ввод, 1 — стандартный вывод, 2 — стандартный поток ошибок. При работе в терминале они обычно связаны с терминалом, но оболочка может изменить это соединение.
| Дескриптор | Название | Назначение | Пример перенаправления |
|---|---|---|---|
| 0 | stdin | Данные, которые программа читает | < in/lesson.txt |
| 1 | stdout | Основной вывод программы | > out/result.txt или 1> out/result.txt |
| 2 | stderr | Диагностические сообщения | 2> out/errors.txt |
Дескриптор — номер открытого канала ввода-вывода в процессе. Ввод может поступать из файла, терминала или другой программы; для программы важен канал, а не только клавиатура.
cat < in/lesson.txt
wc -l < in/lesson.txt
cat in/lesson.txt > out/result.txt
printf 'Дополнительная строка\n' >> out/result.txt
cat out/result.txt
< задаёт входной файл, > создаёт или обнуляет выходной, >> дописывает в конец. Обнуление происходит ещё до запуска программы. Поэтому команда вида cat файл > файл уничтожает исходное содержимое.
Разделите нормальный вывод и ошибки:
Пример предполагает, что missing-file в текущем каталоге отсутствует. Проверьте это через ls -ld missing-file: сообщение об отсутствии здесь ожидаемо. Если объект существует, выберите для всех команд этого примера другое отсутствующее имя.
ls in/lesson.txt missing-file > out/list.txt 2> out/errors.txt
cat out/list.txt
cat out/errors.txt
ls in/lesson.txt missing-file > out/combined.txt 2>&1
В последней строке сначала stdout направляется в файл, затем stderr связывается с текущим stdout. Порядок перенаправлений важен. Запись 2>&1 > файл имеет другой результат.
Два порядка перенаправлений
Сначала вернитесь в каталог упражнения. Выполняйте эти команды непосредственно в обычном интерактивном терминале, где stdout исходно выводится на экран:
cd ~/chapter05
ls in/lesson.txt missing-file > out/order-a.txt 2>&1
ls in/lesson.txt missing-file 2>&1 > out/order-b.txt
cat out/order-a.txt
cat out/order-b.txt
| Команда | Что увидите на экране при её запуске | Что окажется в файле |
|---|---|---|
> out/order-a.txt 2>&1 |
Вывод ls перенаправлен | Имя существующего файла и сообщение об отсутствующем |
2>&1 > out/order-b.txt |
Сообщение об отсутствующем файле | Только имя существующего файла |
Перенаправления выполняются слева направо. 2>&1 делает stderr копией текущего назначения stdout. При последующем перенаправлении stdout назначение stderr автоматически не меняется. Порядок строк в объединённом файле не гарантируется, а язык диагностического сообщения зависит от локали.
Конвейер | передаёт stdout одной команды на stdin следующей:
cat in/lesson.txt | wc -l
find in -type f -name '*.txt' | sort
Кавычки вокруг *.txt оставляют шаблон для find, а не для предварительного раскрытия оболочкой. Обычный конвейер не передаёт stderr. /dev/null позволяет отбросить поток, например команда > /dev/null, но не исправляет ошибки программы.
Вывод на экран и сохранение через tee
cat in/lesson.txt | tee out/tee-copy.txt | wc -l
cmp in/lesson.txt out/tee-copy.txt
tee записывает полученный stdin в файл и одновременно передаёт те же данные в stdout, откуда их читает wc. На экране будет количество строк исходного файла. При совпадении cmp ничего не печатает и завершается с кодом 0. Для одновременного показа самого текста и записи достаточно cat in/lesson.txt | tee out/tee-copy.txt; обычный tee заменяет файл, tee -a дописывает.
Записать: перенаправление и конвейер
Перенаправление меняет канал ввода или вывода команды. Конвейер соединяет stdout одной команды со stdin следующей.
teeпозволяет одновременно сохранить поток и передать его дальше.
Оболочка выполняет перенаправление своими правами. Поэтому sudo команда > защищённый-файл не даёт оболочке право записи. Когда запись с повышенными правами действительно нужна, применяют sudo tee, изучив сначала назначение файла.
Выучить: потоки и результат выполнения
stdout — основной вывод, stderr — диагностические сообщения. Наличие текста в stderr само по себе не определяет успех: результат программы выражает код завершения, доступный в Bash через
$?сразу после команды.
6. Жёсткие и символические ссылки
Создайте обе ссылки на подготовленный файл:
cd ~/chapter05
ln in/lesson.txt in/lesson-hard.txt
ln -s lesson.txt in/lesson-symbolic.txt
ls -li in/lesson*.txt
readlink in/lesson-symbolic.txt
У исходного имени и жёсткой ссылки одинаковый номер inode. Это два имени одного объекта; изменение содержимого через одно имя видно через другое. Жёсткие ссылки обычно нельзя создать между разными файловыми системами или на каталог.
Одинаковый номер inode сравнивают в пределах одной файловой системы. Inode хранит тип, права, владельцев, временные метки и другие сведения; имя файла хранится в записи каталога. Число жёстких ссылок видно в колонке после прав у ls -l. Для lesson.txt и lesson-hard.txt после создания ссылки ожидается число 2, если ранее не создавались другие жёсткие ссылки.
Символическая ссылка хранит путь. Здесь относительный путь lesson.txt отсчитывается от каталога in, где находится сама ссылка, а не от текущего рабочего каталога пользователя.
mv in/lesson.txt in/lesson-renamed.txt
cat in/lesson-hard.txt
cat in/lesson-symbolic.txt
Жёсткая ссылка продолжит открывать данные. Символическая станет «оборванной»: указанного пути больше нет. Верните имя и проверьте результат:
mv in/lesson-renamed.txt in/lesson.txt
cat in/lesson-symbolic.txt
Удаление имени жёсткой ссылки не удаляет другие имена. Данные освобождаются после исчезновения последней жёсткой ссылки и последнего открытого использования файла. Удаление самой символической ссылки через rm имя-ссылки не удаляет объект назначения. Не добавляйте завершающий / при удалении ссылки на каталог.
Копия и два вида ссылок
| Свойство | Обычная копия файла | Жёсткая ссылка | Символическая ссылка |
|---|---|---|---|
| Что создаётся | Отдельный объект с копией содержимого | Ещё одно имя того же объекта | Отдельный объект, содержащий путь |
| Inode | Другой | Тот же в той же файловой системе | Собственный, отличный от цели |
| Изменение текста через новое имя | Меняется только копия | Видно через все имена этого объекта | Меняет цель при переходе по ссылке |
| Переименование исходного имени | На копию не влияет | На оставшееся имя не влияет | Может нарушить путь к цели |
| Удаление исходного имени | Копия остаётся | Данные доступны через оставшееся имя | Ссылка остаётся, но цель по этому пути отсутствует |
| Переход между файловыми системами | Копирование возможно | Нельзя создать такую ссылку между ФС | Путь может указывать на другую ФС |
| Ссылка на каталог | Каталог можно отдельно скопировать рекурсивно | Обычно запрещена | Поддерживается |
При сохранении файла редактор иногда заменяет его новым объектом вместо записи в прежний. Поэтому поведение жёстких ссылок при таком сохранении нужно проверять отдельно; для наглядной проверки записи в существующий объект используют дописывание через оболочку. Даже CoW-копия с первоначально общими блоками остаётся отдельным объектом с независимым содержимым после изменений.
Символическая ссылка на каталог
cd ~/chapter05
ln -s in notes-dir
ls -ld notes-dir
readlink notes-dir
cat notes-dir/lesson.txt
rm -i -- notes-dir
ls -ld in
Пример предполагает, что имя notes-dir свободно. При ошибке «File exists» сначала выясните назначение существующего объекта, не заменяйте его принудительно. Ссылка notes-dir хранит относительный путь in, который отсчитывается от ~/chapter05. После подтверждения удаляется сама ссылка, а каталог in и его документы остаются. Если переместить относительную ссылку в другой каталог, смысл её пути может измениться даже без перемещения цели.
Запомнить: inode и ссылка
Inode содержит сведения об объекте файловой системы. Жёсткая ссылка связывает имя с inode. Символическая ссылка содержит путь к другому объекту.
7. Практическое задание
Этап 1. Подготовка и конспект
Создайте отдельный каталог ~/chapter05/practice и подкаталоги source, copies, moved. Если уже выполняли итоговую работу, выберите новый свободный каталог вместо перезаписи прежних результатов. В Nano создайте source/notes.txt с определениями stdin, stdout, stderr и рекурсивного копирования. Создайте также source/network.txt и source/storage.txt с одной строкой текста в каждом. Сохраните файлы и проверьте их через cat.
Ожидаемый результат: три исходных файла существуют до копирования; конспект читается и содержит четыре определения.
Этап 2. Копирование и перемещение
Одной командой скопируйте network.txt и storage.txt в copies. Переименуйте копию network.txt в network-copy.txt и переместите её в moved. Исходники не меняйте. Объясните, почему каталог назначения нескольких источников нужно создать заранее.
Ожидаемый результат: исходные три файла остаются в source; storage.txt находится также в copies, network-copy.txt — в moved.
Этап 3. Редактирование в Vim
Сделайте отдельную копию notes.txt для тренировки. Откройте её в Vim, добавьте строку через A, перейдите к началу и концу через gg и G, скопируйте строку и выполните замену выбранного слова с подтверждением. Отмените замену через u, повторите через Ctrl+R, сохраните результат. Не меняйте исходный конспект, используемый далее для проверки ссылок.
Ожидаемый результат: тренировочная копия сохранена; студент объясняет режимы редактора, замену и отмену.
Этап 4. Потоки
Из каталога practice запустите ls для source/notes.txt и заведомо отсутствующего файла. Сохраните stdout и stderr в отдельные файлы. Затем выполните два варианта объединения потоков из раздела 5, используя новые имена результатов в copies. Через tee сделайте копию конспекта и сравните её с исходным файлом командой cmp.
Ожидаемый результат: основной вывод и ошибка разделены; показана разница порядка перенаправлений; копия tee совпадает с исходником. Сообщение об отсутствующем файле в этом опыте ожидаемо.
Этап 5. Копия и ссылки
Для source/notes.txt создайте обычную копию, жёсткую и символическую ссылки с отдельными именами в каталоге practice. Учтите, что относительный путь в символической ссылке отсчитывается от её каталога. Покажите ls -li, затем допишите строку через жёсткую ссылку с >>.
Ожидаемый результат: исходник и жёсткая ссылка имеют одинаковый inode, обычная копия и символическая ссылка — собственные. Дописанная строка видна в исходнике и при чтении через обе ссылки, но не появилась в обычной копии.
Переименуйте исходный notes.txt в notes-renamed.txt. Проверьте чтение жёсткой и символической ссылок, затем верните исходное имя. Создайте символическую ссылку на каталог source и проверьте чтение файла через неё.
Ожидаемый результат: жёсткая ссылка работает после переименования, символическая на старый путь временно нарушается и снова работает после возврата имени. Ссылка на каталог позволяет обратиться к его файлам.
Что представить в отчёте
- Свой hostname, пользователя student и путь каталога работы.
- Дерево созданных файлов или вывод find, результат копирования и перемещения.
- Конспект определений и сохранённую тренировочную копию из Vim.
- Два файла раздельных потоков и объяснение порядка
2>&1. - Результат сравнения копии tee и вывод inode для копии и ссылок.
- Результаты чтения ссылок до переименования, после него и после восстановления имени.
- Краткие ответы: чем копия отличается от жёсткой ссылки; почему символическая ссылка может оборваться; почему нельзя читать файл и одновременно перенаправлять вывод в него через
>.
Критерий выполнения: результат подтверждён файлами и выводом команд, а студент объясняет поведение операций. Только скриншота ввода команды недостаточно. Учебные файлы сохраняйте до проверки преподавателем.
Документация для сверки: cp в Ubuntu 26.04, Bash: перенаправления и раскрытия, Nano в Ubuntu 26.04, учебник Vim. Для ссылок дополнительно прочитайте установленную справку man ln.