- Вопрос или проблема
- Новые возможности!
- Хотя оригинальный ответ все еще имеет значение как прототип для чего-то другого…
- Ответ или решение
- Теория
- Пример
- Применение
- Шаг 1: Создание списка уже существующих директорий
- Шаг 2: Создание списков включения и исключения
- Шаг 3: Запуск rsync с фильтром
- Потенциальные улучшения и альтернативы
Вопрос или проблема
Возможно ли с помощью rsync не создавать директории на приемной стороне?
Представьте, что у меня есть такой источник:
a/
a/x.txt
b/
b/y.txt
И у меня есть такая приемная сторона:
a/
a/z.txt
Желаемый результат от rsync source destination
:
a/
a/x.txt
a/z.txt
Конечно, в моей реальной ситуации задействованы тысячи файлов/папок, и я не хочу использовать решения, связанные с явным списком синхронизированных папок, которые я могу сделать. Я ищу чистый способ, который просто предотвратит создание любых папок на приемной стороне. С помощью исключения или фильтрации… Это даже может быть что-то вне rsync, например, хак с разрешениями, если rsync не может это сделать…
Для информации это действительно просто получить такие ситуации, в моем случае у меня есть:
- Сервер с 2 дисками, скажем
A
иB
. И локальный дискC
. - Я обычно использую
rsync
, чтобы синхронизировать (и объединять) удаленныеA
иB
в локальныйC
. - Затем иногда я просто хочу синхронизировать некоторые файлы из
C
обратно вA
иB
. (Только новые файлы… несуществующие папки на приемной стороне не нужны)
Попробуйте следующее:
rsync -av src:/dir/to/files/* /dest/dir
Если у вас есть несколько вложенных подкаталогов, сначала нужно сделать что-то вроде этого:
find /dir/to/files -type d -print
Пропустить этот список каталогов через цикл и вызывать rsync каждый раз. Конечно, если вы делаете это на удаленной машине, вам нужно выполнить find через ssh, сохранить результаты в массив, а затем выполнить цикл rsync.
Я реализовал это для rsync сейчас и отправил патч в основную репозиторию:
https://lists.samba.org/archive/rsync/2015-November/030455.html
может, сделать обычный rsync, а потом на втором этапе удалить все вновь созданные папки … звучит опасно.
Чтобы повысить безопасность этой операции, вы можете использовать другого пользователя, чем тот, который находится на системе назначения:
rsync $src $specialuser@server:$destination
Удаление удаленно созданных папок этим пользователем:
ssh $normalUser@destination "find $destination -type d -user $specialuser -exec rm -r {} \;"
И затем восстановите разрешения:
ssh $normalUser@destination "chown -R $defaultUser:$defaultGroup $destination"
черт, это выглядит грязно … это требует серьезных улучшений 😀
Вы можете сгенерировать набор правил фильтрации на целевой машине следующим образом:
find /destdir/ -type d -printf 'show /%P/\nshow /%P/*\n'; echo 'hide *'
Вы можете превратить это в аргументы командной строки или записать результат в файл и включить его, используя правило фильтра merge
. Вы, возможно, даже сможете сделать что-то вроде этого:
rsync srcdir/ target:/destdir/ --filter="merge "<(ssh target \
find /destdir/ -type d -printf 'show /%P/\nshow /%P/*\n'; echo 'hide *')
Идея состоит в том, чтобы предоставить список вещей, которые вы хотите синхронизировать (т.е. показать rsync). Этот список включает существующие директории и файлы непосредственно в них. Все, что находится вне этих директорий, будет скрыто от передачи, т.е. не будет создано на целевой стороне.
Любой каталог или файл, который существует на целевой стороне, но не существует на исходной, может быть удален, если вы также укажете --delete
. Если это не то, что вы хотите, возможно, вам лучше использовать include
и exclude
вместо show
и hide
.
Все это не тестировалось, поэтому я не несу ответственность за любые потери данных, которые это вам может причинить.
Новые возможности!
Я использую rsync версии 2.6.9 на MacOS и нашел эти переключатели, которые, кажется, предлагают именно то, что вам нужно.
--existing пропуск создания новых файлов на приемнике
--ignore-existing пропуск обновления файлов, которые существуют на приемнике
Хотя оригинальный ответ все еще имеет значение как прототип для чего-то другого…
Я бы рекомендовал создать файл include_file на вашей приемной стороне, используя скрипт для добавления /*
к каждой строке результата:
find [target_dir] -type d >[target_dir]/include.file
Затем вы можете использовать --include_file=[target_dir]/include.file
, чтобы указать включение только тех файлов, которые соответствуют шаблону в этом файле — который должен быть полным списком папок на целевой стороне под указанной точкой.
Если вы создадите скрипт для выполнения этого каждый раз, ваш список в include.file всегда будет актуальным. В противном случае вы можете решить просто обновлять их (по одному на каждом сервере, на который хотите синхронизировать) время от времени.
Если у меня будет время позже, я размещу здесь пригодный для использования скрипт на Python, но это должно дать вам хороший путь вперед.
.
Ответ или решение
Использование rsync
для синхронизации файлов без создания каталогов на принимающей стороне обладает определёнными нюансами. Зачастую rsync
используется для точного дублирования структуры директории между источником и назначением, включая как файлы, так и папки. Однако, когда требуется синхронизировать только файлы без создания новых каталогов, это может потребовать некоторых нестандартных решений.
Теория
По умолчанию rsync
создаёт все недостающие директории в целевом расположении, чтобы обеспечить копирование полных путей от источника. Этот механизм полезен для поддержания полной структурной идентичности между источником и назначением. Тем не менее, есть ситуации, когда создание новых директорий не является целесообразным или желательно избежать этого, как в вашем случае, когда вы хотите синхронизировать только файлы без создания новых каталогов. Один из способов избежать создания директорий – это тщательно управлять путями и использовать фильтры.
Пример
Рассмотрим структуру файлов, предложенную в вашем вопросе:
-
Источник:
a/ a/x.txt b/ b/y.txt
-
Назначение:
a/ a/z.txt
Желаемый результат:
a/
a/x.txt
a/z.txt
Применение
Для достижения желаемого результата, прежде всего, мы можем использовать опцию --existing
, которая не позволяет создавать новые файлы и каталоги в месте назначения, если их нет. Это обеспечивает синхронизацию только тех файлов, которые находятся в уже существующих каталогах на стороне назначения.
rsync -av --existing src/ dest/
Однако для вашей специфической ситуации, где пути и структура более сложные, можно использовать комбинацию фильтров и команды find
для генерации допустимых путей. Вот шаги для этого:
Шаг 1: Создание списка уже существующих директорий
Вы можете использовать команду find
для перечисления всех каталогов на стороне назначения:
find /dest/ -type d -print
Шаг 2: Создание списков включения и исключения
Создайте файл правил фильтрации, который будет включать только разрешенные пути:
find /dest/ -type d -printf 'show /%P/\nshow /%P/*\n' > /tmp/filter.txt
echo 'hide *' >> /tmp/filter.txt
Шаг 3: Запуск rsync с фильтром
Теперь можно запустить rsync
, используя файл фильтра:
rsync -av --filter='merge /tmp/filter.txt' src/ dest/
Этот подход гарантирует, что rsync
видит и обрабатывает только те директории и файлы, которые уже существуют на целевой стороне.
Потенциальные улучшения и альтернативы
-
Скрипты автоматизации: Вы можете расписать вышеописанные операции в виде скрипта для автоматизации процесса. Добавьте логику для создания файлов фильтров каждый раз, когда запускается синхронизация, что обеспечивает актуальность данных.
-
Права доступа: Если операции выполняются в среде с ограничениями по правам доступа, устанавливайте временные ограничения на запись в новые каталоги, чтобы запустить
rsync
с ограничениями на создание директорий. -
Проверенные патчи и функции: Иногда community-решения и обновления
rsync
предлагают специфические патчи для подобного поведения. Если такие патчи уже существуют в последних версиях, рассмотрите возможность обновления своей версииrsync
.
Процесс настройки rsync
для работы без создания новых директорий может обойтись без сложных манипуляций, если использовать вышеописанные методы и инструменты фильтрации. Однако важно тщательно протестировать скрипты и настройки в контролируемой среде, чтобы избежать возможных потерь данных или некорректной синхронизации.