Перекладывать, копировать и удалять файлы администратор делает каждый день, но именно тут люди теряют данные одной неосторожной командой. В этом уроке разберём связку cp/mv/rm/mkdir/rmdir/touch с теми ключами, что реально нужны, мощный поиск find, упаковку в архивы (tar, cpio, dd) и сжатие (gzip, bzip2, xz, zip). И отдельно - globbing, потому что половина ошибок начинается с того, что шаблон раскрылся не так, как вы думали.

Как это работает
Globbing - это раскрытие шаблонов имён самим шеллом, ДО запуска команды. Когда вы пишете rm *.log, программа rm никаких звёздочек не видит: bash сначала подставляет список совпавших файлов, и только потом передаёт их rm. Если совпадений нет, по умолчанию шаблон уходит в команду буквально (символом звёздочки), что приводит к сюрпризам. Базовые метасимволы: звёздочка - любая строка, знак вопроса - один символ, квадратные скобки - один символ из набора или диапазона. Это НЕ регулярные выражения, путать нельзя.
cp и mv по своей природе разные. cp читает данные и пишет новую копию (новый inode), mv в пределах одной файловой системы лишь переименовывает запись в каталоге - данные не двигаются, поэтому это мгновенно. Если же mv тащит файл на другой раздел, он вынужден копировать и потом удалять, и тут уже теряется атомарность. rm удаляет ссылку на inode; пока на inode есть хоть одна жёсткая ссылка или открытый дескриптор, данные живы.
find обходит дерево каталогов и применяет к каждому объекту цепочку условий. Важно понимать, что условия соединяются логическим И по умолчанию, а действие (-print, -delete, -exec) - это тоже часть выражения. Поэтому порядок условий влияет на скорость и иногда на смысл.
Архивирование и сжатие - разные операции. tar и cpio собирают много файлов и метаданных в один поток (архив), но сами не жмут. gzip/bzip2/xz сжимают один поток. zip делает и то и другое сразу. dd работает на уровне блоков и копирует байты как есть, не зная про файлы вовсе.
Команды и примеры
Копирование и перемещение с самыми нужными ключами:
Код: Выделить всё
cp -a /etc/skel /backup/skel # архивный режим: рекурсия + сохранить владельца, права, время, ссылки
cp -i file.txt /tmp/ # спросить перед перезаписью
cp -u src/* dst/ # копировать только если источник новее (update)
cp --reflink=auto big.img clone.img # CoW-копия на Btrfs/XFS: мгновенно, без дублирования блоков
mv -v old new # подробный вывод
mv -n a.txt /dst/ # не перезаписывать существующее (no-clobber)
Код: Выделить всё
mkdir -p proj/src/main/java # создать всю цепочку каталогов
rmdir -p proj/src/main/java # удалить пустые каталоги по цепочке
rm -rf build/ # рекурсивно и без вопросов - оружие массового поражения
rm -I *.tmp # спросить ОДИН раз, если файлов больше трёх (мягче чем -i)
touch -t 202606131200 report.txt # выставить mtime/atime вручную (формат YYYYMMDDhhmm)
touch -r ref.txt new.txt # скопировать временные метки с другого файла
Код: Выделить всё
find /var/log -type f -name "*.log" -size +50M # обычные файлы больше 50 МБ
find /home -type d -empty # пустые каталоги
find . -mtime -2 # изменены за последние 2 суток
find /etc -newermt "2026-06-01" ! -newermt "2026-06-10" # окно по дате
find / -perm -4000 -type f 2>/dev/null # все SUID-бинарники
find /tmp -type f -mtime +30 -delete # удалить старьё (встроенное действие)
find . -name "*.bak" -exec rm -v {} + # один rm на пачку файлов, не по одному
Архивы. tar в Debian/Ubuntu и RHEL/Fedora одинаков (GNU tar), различий по дистрибутивам тут нет:
Код: Выделить всё
tar -czvf logs.tar.gz /var/log # создать (c), gzip (z), подробно (v), в файл (f)
tar -tzvf logs.tar.gz # посмотреть содержимое, ничего не распаковывая
tar -xzvf logs.tar.gz -C /restore # распаковать в указанный каталог
tar -cJf data.tar.xz data/ # сжатие xz (заглавная J)
tar --zstd -cf data.tar.zst data/ # zstd - быстрый современный кодек, GNU tar 1.31+
Код: Выделить всё
find . -depth -print0 | cpio --null -ov --format=newc > arch.cpio # создать
cpio -idmv < arch.cpio # распаковать с сохранением путей
Код: Выделить всё
dd if=/dev/sda1 of=/backup/sda1.img bs=4M status=progress conv=fsync
Код: Выделить всё
gzip -9 dump.sql # быстро, средняя степень сжатия
bzip2 dump.sql # плотнее gzip, но медленнее
xz -9 dump.sql # лучшая степень, но память и время растут
gunzip dump.sql.gz # = gzip -d
xz -d dump.sql.xz # распаковать
zip -r site.zip site/ # архив И сжатие сразу; unzip site.zip для обратного
Частые грабли
- rm -rf с переменной: rm -rf "$DIR/" при пустой DIR превращается в rm -rf / - всегда проверяйте, что переменная задана.
- Шаблон без совпадений в bash по умолчанию передаётся буквально, и команда получает строку со звёздочкой. Лечится опцией shopt -s nullglob или failglob.
- Скрытые файлы (с точкой в начале) звёздочка НЕ захватывает - .bashrc при rm * уцелеет, а вот при cp -a каталога он скопируется.
- mv между разделами не атомарен: при сбое останется и оригинал, и недокопированный хвост.
- tar с абсолютными путями: GNU tar по умолчанию срезает ведущий слэш, но привычку класть относительные пути стоит закрепить, иначе распаковка может попасть не туда.
- find -delete без предварительного -print - запускайте сначала с печатью и убедитесь в списке, удаление необратимо.
- cp без -a теряет владельца, точные времена и символические ссылки (копирует цель ссылки, а не саму ссылку).
- Степень сжатия не бесплатна: xz -9 на большой базе может съесть гигабайты ОЗУ - на слабой машине упадёте по памяти.
- Создайте дерево: mkdir -p ~/lab/{a,b,c} и набейте файлами через touch ~/lab/a/file{1..5}.txt.
- Скопируйте каталог a в архивном режиме: cp -a ~/lab/a ~/lab/a_copy и сравните вывод ls -l - права и время совпали?
- Найдите все файлы больше 0 байт и старше "сейчас минус 1 минута" командой find, сначала с -print, затем с -delete.
- Запакуйте ~/lab в три формата: tar.gz, tar.xz, tar.zst и сравните размеры через ls -lh.
- Распакуйте tar.xz в новый каталог через -C и убедитесь, что структура цела.
- Сделайте образ небольшого файла через dd (if=, of=, bs=1M) и проверьте идентичность через cmp.
- Поэкспериментируйте с globbing: ls ~/lab/a/file[1-3].txt и ls ~/lab/a/file?.txt - объясните разницу в выводе.
- Чем отличается поведение mv при переносе файла в пределах одной ФС и между разными разделами?
- Что выведет bash при rm *.zzz, если ни один файл не совпал с шаблоном, и как изменить это поведение?
- В чём практическая разница между -exec команда {} \; и -exec команда {} + в find?
- Какой ключ tar отвечает за xz-сжатие и какой за просмотр содержимого без распаковки?
- Почему cp -a предпочтительнее обычного cp -r при бэкапе системных каталогов?
- Чем архивирование (tar) принципиально отличается от сжатия (gzip), и какая утилита делает оба действия сразу?