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

时间:2010-12-31 20:42:57

标签: bash shell scripting command-line sh

我正在寻找将一个目录中的文件合并到另一个目录的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}}保持不变

8 个答案:

答案 0 :(得分:73)

cp -RT source/ destination/

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

-T标记阻止source/file1被复制到destination/source/file1

答案 1 :(得分:71)

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

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

答案 2 :(得分:15)

看看att rsync

rsync --recursive html/ html_new/

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

答案 3 :(得分:6)

只需使用rsync - 除了远程复制之外,它还是本地文件复制和合并的绝佳工具。

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

请注意,源文件夹上的尾部斜杠只需将source_folder的内容复制到目标。如果你把它关掉,它会复制source_folder 它的内容,这可能不是你想要的,因为你想要合并文件夹。

答案 4 :(得分:2)

cp -r不会有效吗?

cp -r html_new/* html

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

cd html_new; cp -r . ../html

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

答案 5 :(得分:2)

cd html
cp -r . /path/to/html_new

答案 6 :(得分:2)

尽管这个问题及其接受的答案很古老,但我正在添加我的答案,因为使用cp的现有答案要么不处理某些边缘情况,要么需要交互式工作。边缘情况/脚本性/可移植性/多源通常不重要,在这种情况下简单性获胜,并且最好直接使用cp使用较少的标记(如在其他答案中)以减少认知加载 - 但是对于那些其他次(或者对于强大的可重用函数),这个调用/函数很有用,并且顺便说一下,它不是特定于bash的(我知道这个问题是关于bash的,所以在这种情况下,这只是一个奖励)。有些标志可以缩写(例如使用-a),但为了便于说明,我已将所有标记明确地包含在长格式中(-R除外,见下文)。显然只要删除任何标记,如果您有一些特别不想想要的功能(或者您使用的是非posix操作系统,或者您的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:在this answer -r / --recursive的语义略有不同(特别是源dirs中的特殊文件) >
  • --no-dereference:永远不要关注SOURCE中的符号链接
  • --preserve=all:保留指定的属性(默认:模式,所有权,时间戳),如果可能的话还有其他属性:context,links,xattr,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仍然要求破坏每个文件之前,因此我们通过管道输出来实现非交互性{ {1}}到它
  • [输出到yes]:这是为了使/dev/null
  • 中的一堆杂乱的问题无声无息
  • [return-val&提前退出]:这确保一旦出现失败的副本就退出循环,并在出现错误时返回cp: overwrite 'xx'?

顺便说一句:

  • 一个时髦的新旗帜,我也在我的系统上使用它1来做所谓的"轻复制" (写时复制,具有与硬链接相同的速度优势,并且相同大小的好处直到与文件在未来分歧的数量成反比)。这个标志在最近的GNU --reflink=auto中被接受,并且在最近的Linux内核上不仅仅是兼容文件系统的无操作。 YMWV-a-lot在其他系统上。

答案 7 :(得分:0)

<块引用>

cp --recursive --no-target-directory [--no-clobber] "[IN]" "[OUT]"

  • --no-target-directory:将 OUT 视为普通文件,因此包含以 dot 开头的文件(隐藏文件)。

  • --no-clobber:如果您不想覆盖现有文件。无论如何,内部目录永远不会被覆盖。