Один символ, два разных результата
Типичная история: человек хочет обновить копию папки с документами, запускает rsync, а на выходе получает вложенную папку внутри папки, и все файлы лежат на уровень глубже, чем нужно. Частая причина одна: отсутствие косой черты в конце пути источника. rsync трактует её буквально и документирует это поведение в справке.
Если источник записан со слешем, например rsync -a docs/ backup/, то в backup попадает содержимое docs: файлы и подпапки встают прямо в backup. Если слеша нет, как в rsync -a docs backup/, то rsync переносит сам каталог docs целиком, и в итоге получается backup/docs/ с теми же файлами внутри.
Для пути назначения слеш в конце при уже существующем каталоге на результат не влияет: содержимое попадёт в него. Но принято ставить слеш и там, чтобы подчеркнуть, что это папка.
Это правило сформулировано для rsync. Команда cp -r с косой чертой ведёт себя иначе, причём версии cp для macOS и для Linux тоже отличаются, так что переносить привычку по аналогии не стоит. Чтобы увидеть разницу своими глазами, достаточно двух пробных запусков с ключом -n, которые разобраны в следующем разделе.
Проверка на тестовых папках
Создайте песочницу, в которой ничего не жалко. Все пути ниже находятся в одной папке, и вы сможете удалить её целиком командой rm -r ~/rsync-slash по окончании.
- mkdir -p ~/rsync-slash/docs ~/rsync-slash/backup1 ~/rsync-slash/backup2
- touch ~/rsync-slash/docs/one.txt ~/rsync-slash/docs/two.txt
- rsync -avn ~/rsync-slash/docs/ ~/rsync-slash/backup1/
- rsync -avn ~/rsync-slash/docs ~/rsync-slash/backup2/
Сравните вывод третьей и четвёртой команд. В первом случае имена файлов идут без префикса: one.txt, two.txt. Во втором перед ними стоит docs/: docs/one.txt, docs/two.txt, и появляется строка с самим каталогом docs/. Это и есть разница между «содержимое» и «папка целиком».
Ключ -n здесь защищает от случайных записей, а -v печатает список. Когда результат совпадёт с замыслом, повторите нужную команду без -n.
Если вы набираете пути вручную, обратите внимание на автодополнение по клавише Tab: оболочка при дополнении имени каталога обычно сама добавляет слеш в конце, а значит, поведение rsync меняется незаметно. Перед запуском перечитайте строку целиком, особенно если вы копировали её из чужой инструкции.
Что делает --delete
По умолчанию rsync только добавляет и обновляет файлы в приёмнике. Всё, что уже лежит в целевой папке и отсутствует в источнике, остаётся нетронутым. Это безопасно, но копия со временем накапливает лишнее: файлы, удалённые в оригинале, остаются в резервной копии.
Ключ --delete меняет договорённость: приёмник приводится к виду источника, и всё лишнее удаляется. Для зеркала это нужное поведение, для случайно перепутанных папок — риск. Если перепутать местами источник и приёмник, удалятся файлы, которые считались основными.
| Команда | Что произойдёт с файлом, которого нет в источнике |
|---|---|
| rsync -a src/ dst/ | останется в dst |
| rsync -a --delete src/ dst/ | будет удалён из dst |
| rsync -avn --delete src/ dst/ | в списке появится строка deleting, файл цел |
Внимание на слеш: при --delete путь с косой чертой и без неё сравнивает разные уровни. Для src/ приёмник целиком приводится к содержимому src, и любой посторонний файл в нём считается лишним. Для src без слеша сравнивается только вложенная папка dst/src. Поэтому связку «слеш плюс --delete» нужно перечитывать особенно внимательно. Отдельная ловушка: если источник оказался пустым (например, не подключён диск или опечатка в пути), --delete способен убрать из приёмника всё содержимое.
Подробный разбор того, как читать строки репетиции, есть в соседней статье про пробный запуск.
Безопасная схема работы с зеркалом
Зеркалирование удобно, когда оформлено как привычка из нескольких шагов, а не как разовая команда по памяти. Ниже один из возможных порядков, адаптируйте его под свои задачи.
- Назначьте имена. Удобно хранить пути в переменных оболочки: SRC и DST, и печатать их перед запуском через echo, чтобы убедиться, что источник и приёмник стоят на своих местах.
- Репетиция. Запустите rsync -ain --delete "$SRC/" "$DST/" и прочитайте все строки deleting.
- Остановка при сомнении. Если в списке удаляемого есть то, чего вы не ожидали, остановитесь и разберитесь с путями.
- Боевой запуск. Повторите команду без -n.
- Контроль. Запустите ещё один пробный проход: пустой план говорит о том, что деревья совпали.
Кавычки вокруг переменных важны: пути с пробелами без них распадутся на несколько аргументов, и rsync получит лишние источники. Этот риск не связан с rsync и касается любой команды оболочки.
Если вам нужно не удалять сразу, а сохранять замещаемое, в справке rsync описаны ключи --backup и --backup-dir для хранения заменяемых и удалённых файлов в отдельной папке. Подробности смотрите в man rsync для установленной версии, потому что набор опций у разных сборок отличается. Любые команды с --delete сначала отрабатывайте только на тестовых папках.
Типичные ошибки и их признаки
Ошибки с rsync обычно видны сразу, если вы читаете вывод пробного запуска. Вот соответствие между признаком и вероятной причиной.
| Что вы видите | Вероятная причина | Что сделать |
|---|---|---|
| Внутри приёмника лишняя вложенная папка | источник без слеша | добавить слеш в конце пути источника |
| Файлы внезапно пропали из приёмника | использован --delete при неверных путях | восстановить из резервной копии и перепроверить пути |
| Список к передаче огромен при каждом запуске | отличаются времена изменения | сверить файловые системы, при необходимости изучить ключ -c |
| Ошибка про отсутствие каталога | путь назначения введён с опечаткой | создать каталог или поправить путь |
Отдельный случай — файловые системы с ограничениями: на некоторых носителях нельзя сохранить права и владельцев, и ключ -a будет выдавать сообщения об ошибках установки атрибутов. Решение зависит от носителя, и универсального ключа тут нет, нужно смотреть справку.
Если вы копируете по сети, те же правила действуют для путей на удалённой стороне. Для разовой передачи одного файла проще воспользоваться scp, о нём есть отдельная страница. А для Windows логика зеркала с удалением реализована в robocopy, и там тоже существует режим пробного запуска.