13

У меня есть две копии папки

src/
dest/

Я хочу объединить их, делая следующее:

Если файл находится только в src , я хочу, чтобы он был перемещен в dest

Если файл находится только в dest , я хочу, чтобы он игнорировался в IE.

Если файл находится в обоих файлах и имеет одинаковое содержимое (IE одинакового размера и даты), удалите из src

Если файл находится в обоих файлах и не имеет идентичного содержимого, оставьте его в src чтобы я мог вручную объединить их.

Только очень небольшое количество файлов (от 0% до 5% от общего количества файлов) должно быть в этой последней категории, но я не знаю, как отделить в обоих и одинаковые от обоих, но разные.

Я пытался выяснить, как это сделать с помощью rsync но пока безрезультатно.

3 ответа3

17

Я провел только ограниченное тестирование функциональности, поэтому будьте осторожны с этой командой (--dry-run):

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

Пожалуйста, обратите внимание на конечный символ /, так как он будет возвращаться в src вместо того, чтобы копировать сам src, это должно поддерживать ваши существующие пути.

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

Для удаления несинхронизированных файлов, которые уже существуют в dest/ as в 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 без кавычек.

6

Унисон - это инструмент, который вы ищете. Попробуйте unison-gtk, если вы предпочитаете графический интерфейс. Но я не думаю, что он удалит похожие файлы: в унисон постарайтесь, чтобы оба каталога были одинаковыми. Тем не менее, это легко: 1) определить, какие файлы нужно скопировать; 2) какие из них требуют ручного слияния.

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.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .