Сравните две папки и скопируйте / свяжите уникальные записи в новую папку

Как я могу скопировать все уникальные файлы из двух исходных папок в новую папку назначения?

Как заданная операция: Как я могу вычислить разницу между двумя папками?

4 ответа

Решение

Чтобы скопировать все файлы из foo/ а также bar/ в baz/, самый простой способ - просто скопировать оба и позволить одному перезаписать другой:

cp --recursive foo/ baz/
cp --recursive bar/ baz/

Если вы хотите быть немного чище, а не копировать с bar/ все, что существует в foo/Вы могли бы написать:

cp --recursive foo/ baz/
( cd bar/
  find -exec bash -c ' if ! [[ -e ../foo/"{}" ]] ; then
                         cp "{}" ../baz/"{}"
                       fi
                     ' \;
)

Вы можете использовать тот же подход, чтобы создать список файлов в bar/ которые не существуют в foo/:

( cd bar/
  find -exec bash -c ' if ! [[ -e ../foo/"{}" ]] ; then
                         echo bar/"{}"
                       fi
                     ' \;
)

(или вы могли бы изменить echo bar/"{}" в printf %s\0 bar/"{}" использовать нулевой байт, а не символ новой строки, в качестве разделителя).

В качестве альтернативы вы можете написать:

diff --old-line-format=%L --new-line-format= --unchanged-line-format= \
     <( cd foo/ ; find | sort ) <( cd bar/ ; find | sort )

который проходит выходы cd foo/ ; find | sort а также cd bar/ ; find | sort в diff как входные файлы, и говорит diff распечатать строки, найденные только в первом входном файле, и отбросить все остальное. (Примечание: это сломается, если какие-либо имена файлов содержат символы новой строки.)

Ничто из вышеперечисленного не сравнивает содержимое разных файлов просто потому, что я не уверен, что делать, если они разные. Изучение содержимого файла может использовать diff -r -q foo/ bar/ в качестве отправной точки, но что нам с этим делать?

Вы можете попробовать это:

cd <First Dir>
find . > /tmp/first.dat
cd <Second Dir>
find . > /tmp/second.dat
comm -23 /tmp/first.dat /tmp/second.dat | while read line; do cp <First Dir>/$line <New Dir> ; done
comm -13 /tmp/first.dat /tmp/second.dat | while read line; do cp <SecondDir>/$line <New Dir> ; done

Я уверен, что есть и другие способы (без дополнительных файловых операций, предложенных здесь), но здесь есть относительно простой способ сделать это.

Предположения:
А1) интересует только прямое содержимое папки.
A2) Предполагается, что файлы с одинаковым именем имеют идентичное содержимое.

1) создать / использовать пустой временный каталог (tmp)
2) скопировать содержимое sourceDir1 в tmp
3) удалить содержимое sourceDir2 из tmp
- Теперь у вас есть уникальные файлы sourceDir1 в tmp
4) переместить содержимое tmp в нужное место
5) повторите шаги 2)-4) с заменой ролей sourceDir1 и sourceDir2

Заметки:
N1) Вы можете использовать ls перечислить файлы (или каталоги) и перенаправить их в файл (скажем, s1.tmp). Затем вы можете сравнить список файлов (каталогов) другой папки, используя grep чтобы увидеть, указан ли текущий файл (каталог) в s1.tmp. Вы можете использовать эту технику, чтобы вычислить, какие каталоги вводить для рекурсивной обработки (таким образом ослабляя A1)).
N2) Если речь идет о текстовых файлах, вы можете использовать diff, чтобы увидеть, идентичны ли они. Если да, действуйте, как и раньше, в противном случае обработайте регистр с одинаковым именем файла, соответствующим содержимым (например, скопируйте оба файла в каталог назначения, используя уникальные расширения, чтобы указать их источник - логика здесь зависит от вашей цели).
N3) Вы также можете сравнить двоичные файлы, см. Stackru#4013223 и superuser#135911

Сначала я думал, что смогу решить эту проблему с умным использованием rsync но на самом деле ничего не получалось.

Таким образом, моим окончательным решением был небольшой скрипт на Python (gist).

Другие вопросы по тегам