Как скопировать-объединить две директории?

112

У меня есть две директории images и images2 с этой структурой в Linux:

/images/ad  
/images/fe  
/images/foo  

... и другие 4000 папок

а другой как:

/images2/ad  
/images2/fe  
/images2/foo

... и другие 4000 папок

Каждая из этих папок содержит изображения, а имена каталогов под изображениями и изображениями2 одинаковы, однако их содержимое различно. Затем я хочу узнать, как я могу скопировать и объединить изображения / images2 / ad в images / ad, изображения / images2 / foo в images / foo и т. Д. Со всеми 4000 папками ..

ssierral
источник
1
конечные файлы имеют одинаковые имена в обоих каталогах?
Simply_Me
Нет ... например, в изображениях / объявлениях 1.jpg, 2.jpg и 3.jpg. Но в images2 / ad есть 4.jpg и 5.jpg
ssierral
4
@AmirAliAkbari, я не думаю, что это дубликат - другой вопрос, в основном, это: «Объединяет ли mv?» (ответ: нет). Этот вопрос о том, как объединить 2 иерархии каталогов.
maxschlepzig

Ответы:

173

Это работа для rsync . Нет смысла делать это вручную с помощью цикла оболочки, если вы не хотите перемещать файл, а не копировать его.

rsync -a /path/to/source/ /path/to/destination

В твоем случае:

rsync -a /images2/ /images/

(Обратите внимание на косую черту images2, в противном случае она будет скопирована в /images/images2.)

Если изображения с тем же именем существует в обоих каталогах, вышеприведенная команда будет перезаписывать /images/SOMEPATH/SOMEFILEс /images2/SOMEPATH/SOMEFILE. Если вы хотите заменить только старые файлы, добавьте эту опцию -u. Если вы хотите всегда сохранять версию /images, добавьте эту опцию --ignore-existing.

Если вы хотите переместить файлы из /images2rsync, вы можете передать эту опцию --remove-source-files. Затем rsync копирует все файлы по очереди и удаляет каждый файл, когда это будет сделано. Это намного медленнее, чем перемещение, если каталоги источника и назначения находятся в одной файловой системе.

жилль
источник
14
..добавить -P, если вы хотите увидеть прогресс ..
Meetai.com
1
Я хотел бы добавить , что нет никакой пользы , используя хитрую петлю оболочки здесь , даже если вы действительно хотите , чтобы переместить их вместо того , чтобы копировать их-в этом случае просто использовать rsync, а затем rm -r /images.
Уайлдкарт
1
Я также хотел бы отметить, что важно включать конечные слеши для каждого каталога . Например, если вы просто запустили rsync -a images images2, он просто скопирует images2 в изображения, а не объединит их.
Кайл Чаллис
1
@ s3cur3 Ох. От 2 до (неявно) 1. Это не интуитивно понятно. Спасибо, я исправил свой ответ.
Жиль
1
@MaxCoplan Нет. Rsync не является интерактивным инструментом.
Жиль
43

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

Rsync

rsync синхронизируется в одном направлении от источника к месту назначения. Поэтому следующее утверждение

rsync -avh --progress Source Destination

синхронизирует все от источника до места назначения . Объединенная папка находится в пункте назначения .

-a означает «архив» и рекурсивно копирует все из источника в место назначения, сохраняя почти все.

-v дает больше выходных данных ("подробный").

для человека читабельно.

- прогресс, чтобы показать, сколько работы сделано.

Если вы хотите только обновить в целевую папку с новыми файлами из исходной папки:

rsync -avhu --progress source destination

унисон

унисон синхронизируется в обоих направлениях. Поэтому следующее утверждение

unison Source Destination

синхронизирует обе директории в обоих направлениях и, наконец, источник равен месту назначения. Это все равно что дважды выполнять rsync от источника к месту назначения и наоборот.

Для более продвинутого использования посмотрите справочные страницы или следующие веб-сайты:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/
debiarch
источник
2
Я хочу упомянуть, что правильный путь к папке должен быть с косой чертой в конце rsync -avh --progress source/ destination/, иначе исходная папка будет создана в папке назначения, по крайней мере, в моем случае, как это было.
Electroid
Это прекрасно работает для меня (с косой чертой в папках). Спасибо!
Леопольдо Санчик
5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

Выполните цикл по всему содержимому, images2используя расширенный глобус (чтобы избежать проблем с синтаксическим анализом ls), затем mvсодержимое этих элементов до соответствующей записи в images. Использует, basenameчтобы лишить ведущий images2от сгущенного пути.

Этан Рейснер
источник
пожалуйста, добавьте больше подробностей о том, что делает ваша команда, чтобы она была полезна и для будущих читателей :)
Рамеш,
1

@ inulinux12, вы можете использовать следующий однострочный forцикл из командной строки:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

Это переместит все файлы из images2к imagesв соответствующих каталогах. Примечание: предполагается, что ни один файл не имеет одинакового имени.

Например:

До исполнения:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

После исполнения:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5
Просто я
источник
3
Не анализируйте вывод ls. mywiki.wooledge.org/ParsingLs
Этан Рейснер
@EtanReisner Спасибо за предложение; кажется довольно узким сценарием, хотя, учитывая информацию, приведенную в вопросе.
Simply_Me
2
@Simply_Me Хотя это правда, что обычно все будет в порядке, вы действительно не хотите, чтобы он взорвался, когда попадете в дело, на которое вы не рассчитывали. Это может вызвать действительно плохие проблемы. Не говоря уже о том, что он довольно часто (как в этом случае) почти тривиально заменяется простым шаром. Посмотрите мой ответ как пример этого.
Этан Рейснер
@Simply_Me Сценарии включают имена файлов с пробелами, что довольно часто встречается в изображениях.
Жиль
@Gilles и @Etan Reisner, спасибо за вклад, я ценю это! Обновил и проверил мой ответ на использование подстановки строк, и это оказалось быстрее, чем использование basenameв этой конкретной ситуации (не нужно вызывать basenameэто). Еще раз спасибо за конструктивные комментарии.
Simply_Me