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 видит и обрабатывает только те директории и файлы, которые уже существуют на целевой стороне.

Потенциальные улучшения и альтернативы

  1. Скрипты автоматизации: Вы можете расписать вышеописанные операции в виде скрипта для автоматизации процесса. Добавьте логику для создания файлов фильтров каждый раз, когда запускается синхронизация, что обеспечивает актуальность данных.

  2. Права доступа: Если операции выполняются в среде с ограничениями по правам доступа, устанавливайте временные ограничения на запись в новые каталоги, чтобы запустить rsync с ограничениями на создание директорий.

  3. Проверенные патчи и функции: Иногда community-решения и обновления rsync предлагают специфические патчи для подобного поведения. Если такие патчи уже существуют в последних версиях, рассмотрите возможность обновления своей версии rsync.

Процесс настройки rsync для работы без создания новых директорий может обойтись без сложных манипуляций, если использовать вышеописанные методы и инструменты фильтрации. Однако важно тщательно протестировать скрипты и настройки в контролируемой среде, чтобы избежать возможных потерь данных или некорректной синхронизации.

Оцените материал
Добавить комментарий

Капча загружается...