2010-12-31 2 views
52

Я ищу сценарий оболочки, который объединяет файлы из одного каталога в другой.Как слить один каталог в другой с помощью Bash?

Пример:

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 хранились нетронутым

+1

Пробовал 'cp -r html_new/* html'? После этого вы можете удалить каталог 'html_new'. – ismail

ответ

61

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

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

2

Не будет ли cp -r работы?

cp -r html_new/* html 

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

cd html_new; cp -r . ../html 

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

+0

Когда «слияние» нескольких каталогов и т. Д. Рассматривают также параметр «-n» (без clobber) или '-f' (force), чтобы либо сохранить существующие файлы, либо перезаписать их. –

13

гляньте ATT Rsync

rsync --recursive html/ html_new/ 

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

56
cp -RT source/ destination/ 

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

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

+0

работает красиво, копирует и слияния/папки/данные в папку2/data – wiak

+1

Я собираю это решение, потому что оно работает «как есть» с .dotfiles. – fnkr

5

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

Rsync --av/путь/к/source_folder// путь/к/destination_folder/

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

+0

есть маленькая опечатка, добавочный дефис, поэтому это должно быть 'rsync -av/path/to/source_folder// path/to/destination_folder /' – vim

1

Несмотря на то, что этот вопрос и его принятый ответ являются древними, я добавляю свой ответ, потому что существующие в настоящее время, используя cp, либо не обрабатывают некоторые крайние регистры, либо требуют интерактивной работы. Часто кросс-кейсы/возможность сценарирования/переносимость/множественные источники не имеют значения, но в этом случае простота выигрывает, и лучше использовать cp непосредственно с меньшим количеством флагов (как и в других ответах), чтобы уменьшить когнитивную нагрузку, но для них другой раз (или для надежной функции повторного использования) эта функция вызова полезна и, кстати, не является специфичной для bash (я понимаю, что этот вопрос касался bash, так что это просто бонус в этом случае). Некоторые флаги могут быть сокращены (например, с -a), но я включил все явно в длинную форму (за исключением -R, см. Ниже) для объяснения. Очевидно, просто удалите любые флаги, если есть какая-то особенность, которую вы конкретно указали не хотите (или вы находитесь в ОС, не относящейся к вам, или ваша версия cp не обрабатывает этот флаг - я тестировал это на GNU coreutils 8.25's 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 на некоторых системах (в частности, в отношении специальных файлов в исходных директорий), как описано в this answer
  • --no-dereference: никогда не следует символическим ссылкам в ИСТОЧНИКЕ
  • --preserve=all: сохранить заданные атрибуты (по умолчанию: режим, право собственности, временные метки), если это возможно дополнительные атрибуты: контекст, ссылки, некоторый атрибут, все
  • --force: если существующему файл назначения не может быть открыт, удалите его и попробуйте еще раз
  • --one-file-system: остаться на этой файловой системе
  • --no-target-directory: лечить DEST как обычный файл (объяснено в this answer, а именно: 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, в данном рекурсивном режиме cp все еще спрашивает, прежде чем затирания каждый файл, поэтому мы достигаем не-интерактивность, перенаправив вывод из yes к нему
  • [водопроводный выхода на /dev/null]: это чтобы заглушить беспорядочную строку вопросов вдоль линий cp: overwrite 'xx'?
  • [возвратного-валина & раннего выхода]: это гарантирует, что цикл выходит, как только есть неудачная копия, и возвращает 1 если произошла ошибка

BTW:

  • фанки новый флаг, который я использую с этим на моей системе --reflink=auto для выполнения так называемых «легких копий» (копирование при записи, с теми же преимуществами скорости, как жесткий сшиванию, и то же самое до и обратно пропорционально размеру файлов в будущем). Этот флаг принят в недавнем GNU cp и делает больше, чем нет-op с совместимыми файловыми системами на последних ядрах Linux. YMWV-a-lot в других системах.