Rsync: рекурсивно синхронизировать все файлы, игнорируя структуру каталогов

Я пытаюсь создать bash script для синхронизации музыки с моего рабочего стола с мобильным устройством. Рабочий стол - это источник.

Есть ли способ сделать rsync рекурсивно синхронизировать файлы, но игнорировать структуру каталогов? Если файл был удален с рабочего стола, я хочу, чтобы его также удаляли на устройстве.

Структура каталогов на моем рабочем столе примерно такая.

    Artist1/
        Artist1/art1_track1.mp3
        Artist1/art1_track2.mp3
        Artist1/art1_track3.mp3
    Artist2/
        Artist2/art2_track1.mp3
        Artist2/art2_track2.mp3
        Artist2/art2_track3.mp3
    ...

Структура каталога, которую я хочу на устройстве:

    Music/
        art1_track1.mp3
        art1_track2.mp3
        art1_track3.mp3
        art2_track1.mp3
        art2_track2.mp3
        art2_track3.mp3
    ...

Ответ 1

Просто:

rsync -a --delete --include=*.mp3 --exclude=* \
    pathToSongs/Theme*/Artist*/. [email protected]:Music/.

выполнит задание, если у вас иерархия путей имеет фиксированное количество уровней.

ПРЕДУПРЕЖДЕНИЕ: если два файла песни имеют точно такое же имя, в то же время в одном каталоге назначения ваша резервная копия пропустит один из них!

Если else и для строгого ответа на ваш запрос, игнорируя структуру каталогов, вы можете использовать shopt -s globstar:

shopt -s globstar
rsync -a --delete --include=*.mp3 --exclude=* \
    pathToSongsRoot/**/. [email protected]:Music/.

В любом случае нет необходимости форкировать команду find.

Рекурсивно синхронизировать все файлы при игнорировании структуры каталогов

Для строгого ответа на вопрос не следует ограничиваться расширением:

shopt -s globstar
rsync -d --delete sourceRoot/**/. [email protected]:destRoot/.

При этом будут скопированы каталоги, но без содержимого. Все каталоги и будут храниться на одном уровне с destRoot/.

ПРЕДУПРЕЖДЕНИЕ. Если в каталогах дефферентов существуют несколько разных файлов с одинаковым именем, они просто будут перезаписаны по назначению, durring rsync, для окончательного хранения случайным образом только одного.

Ответ 2

Возможно, это недавний вариант, но я вижу вариант --no-relative, упомянутый в документации для --files-from, и он отлично работал.

find SourceDir -name \*.mp3 | rsync -av --files-from - --no-relative . DestinationDir/

Ответ 3

Ответ на ваш вопрос: Нет, rsync не может сделать это в одиночку. Но с помощью других инструментов мы можем добраться туда... После нескольких попыток я придумал следующее:

rsync -d --delete $(find . -type d|while read d ; do echo $d/ ; done) /targetDirectory && rmdir /targetDirectory/* 2>&-

Трудность заключается в следующем: чтобы включить удаление файлов в целевой позиции, вам необходимо:

  • укажите каталоги в качестве источников для rsync (он не удаляет, если источником является список файлов).
  • предоставить ему полный список источников сразу (rsync в цикле даст вам содержимое последнего каталога только в целевом объекте).
  • завершите имена каталогов косой чертой (в противном случае они создадут каталоги в целевом каталоге)

Таким образом, подстановка команд (материал, заключенный в $( )), делает следующее: он находит все каталоги и добавляет косую черту (/) в конце имен каталогов. Теперь rsync видит список исходных каталогов, все заканчиваются косой чертой и, таким образом, копируют их содержимое в целевой каталог. Опция -d сообщает об этом, а не копирует рекурсивно.

Второй трюк - это rmdir /targetDirectory/*, который удаляет пустые каталоги, созданные rsync (хотя мы этого не просили).

Я протестировал это, и удаление файлов, удаленных в исходном дереве, работало нормально.

Ответ 4

Если вы можете составить список файлов, вы уже решили проблему. Попробуйте:

find /path/to/src/ -name \*.mp3 > list.txt
rsync -avi --no-relative --progress --files-from=list.txt / [email protected]:/path/to/dest

Если вы снова запустите script для новых файлов, он будет копировать только отсутствующие файлы.

Если вам не нравится этот список, попробуйте выполнить одно предложение (но это другая логика)

find /path/to/src/ -name \*.mp3 -type f \
  -exec rsync -avi --progress {} [email protected]:/path/to/dest/  \;

В этом случае вы будете запрашивать каждый файл каждый раз, поскольку по типу предложения вы не можете предварительно создать список файлов.