Linux злиття папок: rsync?


13

У мене є дві копії папки

src/
dest/

Я хочу об'єднати їх, зробивши наступне:

Якщо файл є лише в src, я хочу його переміститиdest

Якщо файл лише в dest, я хочу, щоб його ігнорували IE, залишали в спокої.

Якщо файл в обох і має однаковий вміст (IE однакового розміру та дати), видаліть зsrc

Якщо файл знаходиться в обох і не має однакового вмісту, залиште його, srcщоб я міг їх вручну об'єднати.

В цій останній категорії має бути лише дуже невелика кількість файлів (від 0% до 5% від загальної кількості файлів), але я не знаю, як відокремити один і той і інший від обох, але різних.

Я намагався розібратися, як це зробити, rsyncале поки безрезультатно.

Відповіді:


17

Я виконував лише обмежене тестування функціональності, тому будьте обережні з цією командою (--dry-run):

rsync -avPr --ignore-existing --remove-source-files src/ dest

Будь ласка, зверніть увагу на трейлінг /, оскільки це повториться в src замість копіювання самого src, це повинно підтримувати існуючі шляхи.

Використовуючи прапор --ignore-існуючий у поєднанні з прапором --remove-source-files, ви будете видаляти лише файли з src, які синхронізуються з src у dest, тобто файли, які раніше не існували лише у dest.

Для видалення не синхронізованих файлів, тобто тих, які вже існували у dest / як у src /, ви можете використовувати:

for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done

або

find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;

якщо назви файлів можуть містити пробіли / нові рядки /… Що стосується коментаря Гілла щодо спеціальних символів, це, безумовно, варто пам’ятати, і існує багато рішень, найпростішим було б передати -i до rm, що підкаже перед усім видаленням. Однак, якщо src / або його батьківський шлях передбачений для пошуку, проте, повністю кваліфікований шлях повинен призвести до того, що всі назви файлів будуть правильно оброблятися як командами diff, так і rm без цитування.


виправлення: ця команда не буде видаляти файли з src, якщо однакова копія вже існує у dest
Tok

Так :(. Це частина, яку мені важко розібратися.
Девід Онелл

2
Ну, хороша новина полягає в тому, що ви можете вирішити це самостійно без особливих клопотів: for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done(ви можете пропустити те, || echo $fileякщо вам подобається, воно включене для повноти)
Ток,

Nifty: це те, що мені було потрібно. Відредагуйте це у своїй відповіді, і я прийму її!
Девід Онелл

@Tok: Ваша команда подавить імена файлів, які містять спеціальні символи (пробіл \?*[, початковий -). Вам потрібно використовувати подвійні лапки навколо змінних підстановок , переходити --на утиліти перед іменами файлів, використовувати find … -exec …замість розбору результатів find. З rmкомандою в суміші це рецепт катастрофи.
Жил "ТАК - перестань бути злим"

6

унісон - це інструмент, який ви шукаєте. Спробуйте unison-gtk, якщо вам більше подобається gui. Але я не думаю, що це видалить подібні файли: унісон намагаються, щоб обидва каталоги були однаковими. Тим не менш, легко буде 1) визначити, які файли потрібно скопіювати; 2) які потребують ручного злиття.


Це не точно те, що вимагає ОП, але звучить так, ніби воно досягає кінцевої мети ОП. +1
Райан К. Томпсон

+1 На жаль, сервер, на якому я запускаю, не встановлює унісон, а також не маю дозволів його встановлювати. Але це може бути хорошою відповіддю для когось іншого.
Девід Онелл

1
Ви можете завантажити унісон виконуваний файл з seas.upenn.edu/~bcpierce/unison//download / ... . Встановіть його десь у вашому домашньому каталозі, це лише один файл.
JooMing

2

Наступний сценарій повинен робити справи розумно. Він переміщує файли з джерела до місця призначення, ніколи не перезаписуючи файл і не створюючи каталоги за необхідності. Вихідні файли, які мають відповідний інший файл у пункті призначення, залишаються в спокої, як і файли, які не є звичайними файлами чи каталогами (наприклад, символічні посилання). Файли, залишені у джерелі, - це файли, щодо яких виникає конфлікт. Остерігайся, я його взагалі не перевіряв.

cd src
find . -exec sh -c '
    set -- "/path/to/dest/$0"
    if [ -d "$0" ]; then #  the source is a directory 
      if ! [ -e "$1" ]; then
        mv -- "$0" "$1"  # move whole directory in one go
      fi
    elif ! [ -e "$0" ]; then  # the source doesn't exist after all
      :  # might happen if a whole directory was moved
    elif ! [ -e "$1" ]; then  # the destination doesn't exist
      mv -- "$0" "$1"
    elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then  # identical files
      rm -- "$0"
    fi
  ' {} \;

Іншим підходом було б зробити з'єднання, монтуючи один каталог над іншим, наприклад, з funionfs або unionfs-fuse .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.