如何复制合并两个目录?


111

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

/images/ad  
/images/fe  
/images/foo  

...和其他4000个文件夹

另一个像:

/images2/ad  
/images2/fe  
/images2/foo

...和其他4000个文件夹

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


1
两个目录中的最终文件名称是否相同?
Simply_Me 2014年

不,例如在图像/广告中为1.jpg,2.jpg和3.jpg。但是在images2 / ad中是4.jpg和5.jpg
ssierral 2014年

4
@AmirAliAkbari,我不认为它是重复的-另一个问题基本上是“ MV是否合并?” (答案:否)。这个问题是关于如何合并两个目录层次结构的。
maxschlepzig 2016年

Answers:


172

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

rsync -a /path/to/source/ /path/to/destination

在您的情况下:

rsync -a /images2/ /images/

(请注意在末尾加上斜杠images2,否则它将复制到/images/images2。)

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

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


14
..add -P(如果您想查看进度
。– Meetai.com 2015年

1
我要补充一点,即使您确实想移动它们而不是复制它们,在这里使用棘手的shell循环也没有好处-在这种情况下,只需使用rsync,然后rm -r /images
通配符

1
我还要指出,在每个目录中都包含斜杠非常重要。例如,如果您仅运行rsync -a images images2,它将仅将images2复制到图像中,而不是合并它们。
凯尔·查利斯

1
@ s3cur3哦。从2到(隐式)1.这很不直观。谢谢,我确定了答案。
吉尔斯

1
@MaxCoplan不。Rsync不是交互式工具。
吉尔斯

43

正如已经发布的,最好的选择当然是rsync。但是,统一也将是完成此工作的出色软件。两者都可以在多个操作系统中使用。

同步

rsync从源到目标在一个方向上同步。因此,以下陈述

rsync -avh --progress Source Destination

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

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

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

-h便于阅读。

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

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

rsync -avhu --progress source destination

统一

统一在两个方向上同步。因此以下声明

unison Source Destination

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

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

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

2
我要提到的是,正确的文件夹路径应在末尾加斜杠rsync -avh --progress source/ destination/,否则源文件夹将在目标文件夹中创建,至少在我这样的情况下。
电极

这对我来说非常有用(文件夹中有斜杠)。谢谢!
Leopoldo Sanczyk '16

5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

images2使用扩展的glob(以避免解析问题ls)遍历所有内容,然后mv将这些项目的内容放入中的匹配条目images。用于从球形路径中basename剥离引导线images2


请添加有关命令功能的更多详细信息,以便它也对以后的读者有用:)
Ramesh 2014年

1

@ inulinux12,您可以从命令行使用以下一行for循环:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

这会将所有文件从images2移到images其各自目录中。注意:这假定没有文件具有相同的名称。

例如:

执行前:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

执行后:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5

3
不要解析的输出lsmywiki.wooledge.org/ParsingLs
Etan Reisner

@EtanReisner谢谢你的建议;尽管考虑到问题中给出的信息,但情况似乎非常狭窄。
Simply_Me 2014年

2
@Simply_Me虽然通常会很好,但您确实不希望在遇到您不指望的案件时将其炸毁。这可能会导致真正糟糕的问题。更不用说它(通常是这种情况)几乎可以用一个简单的glob替换掉。请参阅我的答案作为示例。
Etan Reisner 2014年

@Simply_Me方案包括带空格的文件名,这在图像中很常见。
Gilles 2014年

@Gilles和@Etan Reisner,谢谢您的投入,我非常感谢!更新并测试了我使用字符串替换的答案,并且比basename在这种特定情况下使用它更快(无需为此basename而做)。再次感谢您的建设性评论。
Simply_Me 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.