如何使用Bash将一个目录合并到另一个目录?


77

我正在寻找将文件从一个目录合并到另一个目录的shell脚本。

样品:

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 2010年

Answers:


86

您可能只想要cp -R $1/* $2/-这是一个递归副本。

(如果可能存在隐藏文件(名称以点开头的文件),则应在该命令前添加前缀shopt -s dotglob;以确保它们匹配。)


93
cp -RT source/ destination/

中的所有文件和目录source将以结尾destination。例如,source/file1将复制到destination/file1

-T标志source/file1将从复制停止destination/source/file1。(不幸的是,cp在macOS上不支持该-T标志。)


效果很好,它可以将/ folder / data复制并合并到folder2 / data
nwgat 2015年

2
我认为这种解决方案是因为它与.dotfiles一样“按原样”工作。
fnkr

5
在Mac OS X / darwin上,您将要使用cp -r source/ destination-完全按照指示使用/是很棘手的。
罗恩·沃特伦

荣幸地成为赞成这个答案的人,因此使之等于现在接受的一分之一。
Hadrien TOMA

请注意,它将覆盖目的地中与源名称相同的所有文件
brianegge

17

看一下rsync

rsync --recursive html/ html_new/

Rsync设置了很多标志,请查看rsync联机帮助页以了解详细信息


6

只需使用rsync-它是用于远程复制之外的本地文件复制和合并的好工具。

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

请注意,仅将source_folder的内容复制到目标位置时,源文件夹上的斜杠是必需的。如果不选择它,它将复制source_folder及其内容,这可能不是您想要的,因为您要合并文件夹。


有一个小的错字,多余的连字符,所以应该是rsync -av /path/to/source_folder/ /path/to/destination_folder/
vim

4

即使这个问题及其公认的答案很古老,我还是添加我的答案,因为目前使用的问题cp要么无法处理某些极端情况,要么需要交互工作。通常边缘的情况下/脚本化/便携/多源并不重要,虽然,在这种情况下,简单的胜利,这是更好地使用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:从不跟随源中的符号链接
  • --preserve=all:保留指定的属性(默认值:mode,ownership,timestamps),如有可能,还保留其他属性:context,links,xattr,all
  • --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,在这种特定的递归模式下,cp仍然会在破坏每个文件之前询问,因此我们通过管道yes传输到它来实现非交互
  • [管道输出到/dev/null]:这是为了使混乱的问题字符串保持沉默cp: overwrite 'xx'?
  • [return-val&提前退出]:这可确保在副本失败后循环立即退出,并1在出现错误时返回

顺便说一句:

  • 我还在系统上与此一起使用的一个时髦的新标记--reflink=auto用于进行所谓的“轻量复制”(写时复制,具有与硬链接相同的速度优势,而相同的尺寸优势直到并成​​反比)到将来文件有多大的差异)。最近的GNU接受此标志cp,并且在最近的Linux内核上对兼容文件系统不做任何操作。YMWV-a-lot在其他系统上。


2

不行cp -r

cp -r html_new/* html

或(因为第一个版本不会复制“ .something”文件)

cd html_new; cp -r . ../html

请注意,如果复制的目录中的任何文件是管道,-r 则从管道读取。为避免这种情况,请-R改用。


当“合并”多个目录等时,还要考虑-n(不使用垃圾桶)或-f(强制)选项以保留现有文件或覆盖它们。
Tomasz Gandor 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.