Как мне объединить один каталог в другой, используя Bash? - PullRequest
65 голосов
/ 31 декабря 2010

Я ищу сценарий оболочки, который объединяет файлы из одного каталога в другой.

Пример:

html/
  a/
    b.html
  index.html

html_new/
  a/
    b2.html
    b.html

Использование:

./mergedirs.sh html html_new

Результат:

html/
  a/
    b.html
    b2.html
  index.html

html/a/b.html был заменен на html_new/a/b.html
html/a/b2.html был скопирован с html_new/a/b2.html
html/index.html остался без изменений

Ответы [ 7 ]

75 голосов
/ 22 ноября 2013
cp -RT source/ destination/

Все файлы и каталоги в source окажутся в destination.Например, source/file1 будет скопировано в destination/file1.

. Флаг -T останавливает копирование source/file1 в destination/source/file1.

73 голосов
/ 31 декабря 2010

Вы, вероятно, просто хотите cp -R $1/* $2/ - это рекурсивная копия.

(Если могут быть скрытые файлы (те, чьи имена начинаются с точки), вы должны поставить перед этой командой префикс shopt -s dotglob;, чтобыуверен, что они совпадают.)

15 голосов
/ 01 января 2011

Взгляните на rsync

rsync --recursive html/ html_new/

Rsync получил множество флагов, чтобы установить, так что смотрите на rsync manpage для деталей

6 голосов
/ 23 декабря 2013

Просто используйте rsync - это отличный инструмент для локального копирования и объединения файлов в дополнение к удаленному копированию.

rsync -av /path/to/source_folder/ /path/to/destination_folder/

Обратите внимание, что косая черта в исходной папке необходима для копирования только содержимого source_folder в место назначения. Если вы отключите его, он скопирует исходные_файлы и их содержимое, что, вероятно, не то, что вы ищете, поскольку вы хотите объединить папки.

2 голосов
/ 27 мая 2016

Несмотря на то, что этот вопрос и его принятый ответ являются древними, я добавляю свой ответ, потому что существующие в настоящее время использующие cp либо не обрабатывают некоторые крайние случаи, либо требуют интерактивной работы.Часто крайние случаи / scriptable / portability / множественные источники не имеют значения, хотя, в этом случае простота выигрывает, и лучше использовать cp напрямую с меньшим количеством флагов (как в других ответах), чтобы уменьшить когнитивную нагрузку - но дляэти другие раза (или для многократно используемой функции) этот вызов / функция полезен и, кстати, не относится к bash (хотя я понимаю, что этот вопрос касался bash, так что в данном случае это всего лишь бонус).Некоторые флаги могут быть сокращены (например, с -a), но я включил все явно в длинную форму (за исключением -R, см. Ниже) для пояснения.Очевидно, просто удалите все флаги, если есть какая-то особенность, которую вы не хотите (или вы используете не-posix ОС, или ваша версия cp не обрабатывает этот флаг - я проверял этов GNU coreutils 8.25 cp):

mergedirs() {
    _retval=0
    _dest="$1"
    shift
    yes | \
        for _src do
            cp -R --no-dereference --preserve=all --force --one-file-system \
                  --no-target-directory "${_src}/" "$_dest" || { _retval=1; break; }
        done 2>/dev/null
    return $_retval
}

mergedirs destination source-1 [source-2 source-3 ...]

Объяснение:

  • -R: имеет слегка отличную семантику от -r / --recursive в некоторых системах(особенно в отношении специальных файлов в исходных каталогах), как объяснено в этот ответ
  • --no-dereference: никогда не переходите по символическим ссылкам в SOURCE
  • --preserve=all: сохраняйтеуказанные атрибуты (по умолчанию: режим, владелец, временные метки), если возможно, дополнительные атрибуты: контекст, ссылки, xattr, все
  • --force: если не удается открыть существующий файл назначения, удалите его и повторите попытку
  • --one-file-system: остаться в этой файловой системе
  • --no-target-directory: обрабатывать DEST как обычный файл (объясненный в этот ответ , а именно: If you do a recursive copy and the source is a directory, then cp -T copies the content of the source into the destination, rather than copying the source itself.)
  • [канальный ввод от yes]: даже с --force, в этом конкретном рекурсивном модеe cp все еще спрашивает перед тем, как загромождать каждый файл, поэтому мы достигаем неинтерактивности, передавая вывод из yes в него
  • [конвейерный вывод в /dev/null]: это заставляет замолчать грязную строку вопросовпо линиям cp: overwrite 'xx'?
  • [return-val & early exit]: это гарантирует, что цикл завершается сразу же после сбоя копии, и возвращает 1, если произошла ошибка

КСТАТИ:

  • Причудливый новый флаг, который я также использую с этим в моей системе, - --reflink=auto для выполнения так называемых «легких копий» (копирование при записи, ста же скорость дает преимущества, что и жесткие ссылки, и тот же размер выигрывает до и обратно пропорционально тому, насколько сильно файлы расходятся в будущем).Этот флаг принят в недавнем GNU cp и делает больше, чем просто запрет совместимых файловых систем в последних ядрах Linux.YMWV-много в других системах.
2 голосов
/ 31 декабря 2010
cd html
cp -r . /path/to/html_new
2 голосов
/ 31 декабря 2010

Не будет cp -r работать?

cp -r html_new/* html

или (поскольку первая версия не будет копировать файлы ".something")

cd html_new; cp -r . ../html

Обратите внимание, что -r читает из каналов , если какой-либо из файлов в скопированном каталоге является каналом.Чтобы избежать этого, используйте -R.

...