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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4572225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:01:20  来源:igfitidea点击:

How do I merge one directory into another using Bash?

bashshellscriptingcommand-linesh

提问by NVI

I'm looking for shell script that merge files from one directory into another.

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

Sample:

样本:

html/
  a/
    b.html
  index.html

html_new/
  a/
    b2.html
    b.html

Usage:

用法:

./mergedirs.sh html html_new

Result:

结果:

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

html/a/b.htmlwas replaced by html_new/a/b.html
html/a/b2.htmlwas copied from html_new/a/b2.html
html/index.htmlwas kept untouched

html/a/b.html被替换为html_new/a/b.html
html/a/b2.html被复制自html_new/a/b2.html
html/index.html保持不变

回答by Flimm

cp -RT source/ destination/

All files and directories in sourcewill end up in destination. For example, source/file1will be copied to destination/file1.

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

The -Tflag stops source/file1from being copied to destination/source/file1instead. (Unfortunately, cpon macOS does not support the -Tflag.)

-T标志不再source/file1被复制到destination/source/file1。(遗憾的是,cp在 macOS 上不支持该-T标志。)

回答by Luke Maurer

You probably just want cp -R $1/* $2/— that's a recursive copy.

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

(If there might be hidden files (those whose names begin with a dot), you should prefix that command with shopt -s dotglob;to be sure they get matched.)

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

回答by CarlG

Take a look att rsync

看看 rsync

rsync --recursive html/ html_new/

Rsync got alot of flags to set so look at rsync manpage for details

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

回答by Gavster

Just use rsync - it's a great tool for local file copy and merging in addition to remote copying.

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

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

Note that the trailing slash on the source folder is necessary to copy only the contents of source_folder to the destination. If you leave it off, it will copy the source_folder andit's contents, which is probably not what you are looking for since you want to merge folders.

请注意,源文件夹上的尾部斜杠是仅将 source_folder 的内容复制到目标所必需的。如果您不使用它,它将复制 source_folder及其内容,这可能不是您要查找的内容,因为您要合并文件夹。

回答by rowanthorpe

Even though this question and its accepted answer are ancient, I am adding my answer because the presently existing ones using cpeither don't handle some edge-cases or require working interactively. Often edge-cases/scriptability/portability/multiple-sources don't matter though, in which case simplicity wins, and it is better to use cpdirectly with less flags (as in other answers) to reduce cognitive load - but for those othertimes (or for a robustly reusable function) this invocation/function is useful, and incidentally isn't bash-specific (I realise this question was about bash though, so that's just a bonus in this case). Some flags can be abbreviated (e.g. with -a), but I have included all explicitly in long-form (except for -R, see below) for the sake of explanation. Obviously just remove any flags if there is some feature you specifically don'twant (or you are on a non-posix OS, or your version of cpdoesn't process that flag - I tested this on GNU coreutils 8.25's cp):

尽管这个问题及其公认的答案很古老,但我还是要添加我的答案,因为目前使用的答案cp要么不处理某些边缘情况,要么需要交互工作。通常边缘情况/脚本性/可移植性/多源并不重要,在这种情况下,简单性获胜,最好cp直接使用较少的标志(如在其他答案中)以减少认知负荷 - 但对于其他时间(或者对于一个健壮的可重用函数)这个调用/函数很有用,顺便说一句,它不是特定于 bash 的(我意识到这个问题是关于 bash 的,所以在这种情况下这只是一个奖励)。一些标志可以缩写(如用-a),但我已经包括了所有明确的长篇(除-R,见下文)以供解释。显然,如果有一些您特别想要的功能(或者您使用的是非 posix 操作系统,或者您的版本cp不处理该标志 - 我在 GNU coreutils 8.25 上对此进行了测试),显然只需删除任何标志cp

mergedirs() {
    _retval=0
    _dest=""
    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 ...]

Explanation:

解释:

  • -R: has subtly different semantics from -r/--recursiveon some systems (particularly with respect to special files in source dirs) as explained in this answer
  • --no-dereference: never follow symbolic links in SOURCE
  • --preserve=all: preserve the specified attributes (default: mode,ownership,timestamps), if possible additional attributes: context, links, xattr, all
  • --force: if an existing destination file cannot be opened, remove it and try again
  • --one-file-system: stay on this file system
  • --no-target-directory: treat DEST as a normal file (explained in in this answer, namely: 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.)
  • [piped input from yes]: even with --force, in this particular recursive mode cpstill asks before clobbering each file, so we achieve non-interactiveness by piping output from yesto it
  • [piped output to /dev/null]: this is to silence the messy string of questions along the lines of cp: overwrite 'xx'?
  • [return-val & early exit]: this ensures the loop exits as soon as there is a failed copy, and returns 1if there was an error
  • -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,在这种特定的递归模式下cp仍然会在破坏每个文件之前询问,因此我们通过管道输出yes到它来实现非交互性
  • [管道输出到/dev/null]:这是为了让一连串混乱的问题保持沉默cp: overwrite 'xx'?
  • [return-val & early exit]:这确保循环一旦有失败的副本就退出,1如果有错误则返回

BTW:

顺便提一句:

  • A funky new flag which I also use with this on my system is --reflink=autofor doing so-called "light copies" (copy-on-write, with the same speed benefits as hard-linking, and the same size benefits until and in inverse proportion to how much the files diverge in the future). This flag is accepted in recent GNU cp, and does more than a no-op with compatible filesystems on recent Linux kernels. YMWV-a-lot on other systems.
  • 我也在我的系统上使用了一个时髦的新标志,--reflink=auto用于进行所谓的“轻拷贝”(写时拷贝,具有与硬链接相同的速度优势,并且相同大小的优势直到和成反比到将来文件有多大差异)。这个标志在最近的 GNU 中被接受cp,并且在最近的 Linux 内核上对兼容的文件系统做了更多的无操作。YMWV-很多在其他系统上。

回答by DVK

Wouldn't cp -rwork?

会不会cp -r工作?

cp -r html_new/* html

or (since the first version won't copy ".something" files)

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

cd html_new; cp -r . ../html

Please note that -rreads from pipesif any of the files in the copied directory are pipes. To avoid that, use -Rinstead.

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

回答by Brian Clapper

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