如何复制合并两个目录?

ssi*_*ral 177 ubuntu directory file-copy

我在Linux中有两个具有这种结构的目录images和images2:

/images/ad  
/images/fe  
/images/foo  
Run Code Online (Sandbox Code Playgroud)

...和其他 4000 个文件夹

另一个是这样的:

/images2/ad  
/images2/fe  
/images2/foo
Run Code Online (Sandbox Code Playgroud)

...和其他 4000 个文件夹

这些文件夹中的每一个都包含图像,图像和图像2下的目录名称完全相同,但它们的内容不同。然后我想知道如何将/images2/ad 的图像复制合并到images/ad 中,将/images2/foo 的图像复制合并到images/foo 中,等等所有4000 个文件夹。

Gil*_*il' 271

这是rsync的工作。除非您想移动文件而不是复制文件,否则使用 shell 循环手动执行此操作没有任何好处。

rsync -a /path/to/source/ /path/to/destination
Run Code Online (Sandbox Code Playgroud)

在你的情况下:

rsync -a /images2/ /images/
Run Code Online (Sandbox Code Playgroud)

(注意尾随斜杠images2,否则它会复制到/images/images2。)

如果在两个目录中存在具有相同名称的图片,上面的命令将覆盖/images/SOMEPATH/SOMEFILE/images2/SOMEPATH/SOMEFILE。如果您只想替换旧文件,请添加选项-u. 如果要始终保留版本/images,请添加选项--ignore-existing

如果要/images2使用 rsync从 移动文件,则可以传递选项--remove-source-files。然后 rsync 依次复制所有文件,并在完成后删除每个文件。如果源目录和目标目录在同一个文件系统上,这比移动要慢得多。

  • ..add -P 如果你想看到进展.. (30认同)
  • 我还想指出**为每个目录包含尾部斜杠很重要**。例如,如果你简单地运行`rsync -a images images2`,它只会将images2复制到images而不是合并它们。 (7认同)
  • @Wildcard,好吧,这与搬家不太一样。正如吉尔斯指出的那样,如果他们在同一个 fs 上,这比移动要慢得多;而且它需要更多的临时空间。 (4认同)
  • 有没有办法让 rsync 询问你是否要覆盖? (2认同)
  • @MaxCoplan 不。Rsync 不是交互式工具。 (2认同)

小智 64

正如已经发布的那样,最好的选择当然是rsync。尽管如此,这也是unison一个很好的软件来完成这项工作,尽管通常需要安装软件包。两者都可以在多个操作系统中使用。

同步

rsync 在从源到目标的一个方向上同步。所以下面的说法

rsync -avh --progress Source Destination
Run Code Online (Sandbox Code Playgroud)

同步从SourceDestination 的所有内容。合并后的文件夹位于Destination 中

-a 的意思是“存档”,并从源到目的地递归复制所有内容,几乎保留所有内容。

-v提供更多输出(“详细”)。

-h用于人类可读。

--progress显示完成了多少工作。

如果你只想要更新目标文件夹与新的从源文件夹中的文件:

rsync -avhu --progress source destination
Run Code Online (Sandbox Code Playgroud)

齐声

统一在两个方向同步。所以下面的说法

unison Source Destination
Run Code Online (Sandbox Code Playgroud)

在两个方向同步两个目录,最后源等于目标。这就像从源到目标执行两次 rsync,反之亦然。

有关更高级的用法,请查看手册页或以下网站:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/

  • 我想提一下,文件夹的正确路径应该在末尾带有斜杠`rsync -avh --progress source/destination/`,否则将在目标文件夹中创建源文件夹,至少在我的情况下是这样像这样。 (3认同)

Ian*_*len 10

有更快、更节省空间的方法来合并两个目录,使用选项--linkif cpthe paths are on the same file system,在相关文章的多个不同答案中进行了描述:(文章的标题并不完全是匹配用户的问题,并且答案解决标题主题、合并,而不是解决用户的实际问题。)

用 mv 合并文件夹?

选项--link表示cp不复制文件数据。一个例子是,其中的所有内容都/images2替换了其中的任何旧项目/images

cp --force --archive --update --link /images2/. /images

合并到后/images,你可以rm -rf /images2

如果文件树中的任何位置合并尝试将目录合并到具有相同名称的现有文件或符号链接,即它不会将指定的目录合并/images2/x到具有相同名称的现有文件或符号链接/images/x,并且如果您遇到这样的错误,您可以手动删除文件或符号链接,然后重新运行命令。

好处--link是没有数据被移动来合并目录。


asi*_*iby 8

这个问题的答案非常简单。我已经用过很多次了。

您需要做的就是...

cp -rf source_folder parent_of_dest_folder
Run Code Online (Sandbox Code Playgroud)

使用原始问题中的特定文件结构,命令将是......

cp -rf /images/* /images2/
Run Code Online (Sandbox Code Playgroud)

结果将是源和目标的合并版本。这也将递归地处理子目录。

正如@ingyhere 所指出的,上述命令将覆盖目标目录中的现有文件。如果您希望保留现有文件,则必须将-n参数添加到命令中cpcp在手册页中了解更多相关信息:https://man7.org/linux/man-pages/man1/cp.1.html# :~:text=links%20in%20SOURCE-,%2Dn%2C%20% 2D%2Dno%2Dclobber,-do%20not%20覆盖

cp -rfn /images/* /images2/
Run Code Online (Sandbox Code Playgroud)


Eta*_*ner 7

for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done
Run Code Online (Sandbox Code Playgroud)

循环images2使用扩展的 glob 的所有内容(以避免解析问题ls),然后mv将这些项目的内容循环到 中的匹配条目images。用于从全局路径中去除basename前导images2


ing*_*ere 6

这可以使用以下命令有效地合并cp而不覆盖:

cp -prnv /images/* /images2/
Run Code Online (Sandbox Code Playgroud)

选项:

-p -- preserve ownership, perms and detailed attributes
-r -- recursive
-n -- no overwrite
-v -- verbose (display operation detail for each file)
Run Code Online (Sandbox Code Playgroud)

要查看实际复制的内容,请按以下方式运行:

cp -prnv /images/* /images2/ | grep '\->'  # shows copies
Run Code Online (Sandbox Code Playgroud)

要查看未复制内容的反面,请使用grep -v '\->'.

如果您想做一些更复杂的事情,例如替换具有差异的文件,请使用或通过测试两侧然后根据退出代码进行复制来使用rsync自己的文件(不建议用于大文件或大目录 - 使用)。md5sumdiffrsync