mv 具有 rsync 功能

mv 具有 rsync 功能

我正在尝试合并两个目录树,它们具有许多公共元素,但每个目录树都具有仅存在于两棵树之一中的元素。我遇到的主要问题是,当mv遇到具有相同相对路径的两个子目录时,它要么保留源(带有-f),要么保留目的地(带有-n),但我无法使其采用两个子目录的并集。我当然可以使用rsyncwith --remove-source-files,但这实际上会复制数据,然后删除旧文件,而不是真正的移动。这两个目录树包含数百 GB 的数据,并且都位于同一分区,因此,如果可能的话,为了节省时间,我希望进行真正的移动。

现在我已经有了,find * -type file -exec mv -n {} /destination/{}但这只会在目标目录已经存在时将文件从源移动到目标。我可以用类似的内容作为该命令的前缀mv -n * /destination/,但这只会带来顶级目录。有什么方法可以在一行中完成此操作吗?我总是可以编写一个脚本来在复制文件之前检查目录是否存在,但这似乎是一项基本任务,似乎应该有一种更简单的方法。

答案1

警告:此答案不适用于不支持硬链接(例如FAT)的文件系统。

另一种选择(可能更便携)是

光盘源目录
寻找 。 -type f -print0 | cpio --pass-through --null --link --make-directories目标目录

cpio(copy in&out) 是一种早于 的恐龙tar。与 一样tar,它可以创建档案或从档案中提取。与(如果我错了请纠正我)不同tar,它可以使用单个命令复制目录树。 (我猜你可以用 来做到这一点。)这就是意思。  表示“期望文件名由空值分隔”;即,读取输出。  意思是“如果可能的话,将文件从源目录链接到目标目录”。  不需要解释。tar -cf - source option(s) and arguments(s) | tar -xf - destination option(s) and arguments(s)--pass-through--nullfind … -print0--link--make-directories

这个可以缩写。如果需要的话可以添加或。cpio –p0ld dest_dir--verbose-v

那么,在这一切结束之后,

  • 检查是否有碰撞并进行适当处理。
  • 验证您的目标目录是否已填充硬链接。
  • 删除源目录。

答案2

你可以用来prename得到你想要的东西。在某些发行版(例如 Debian/Ubuntu)上,应将其默认安装并别名为rename.其他发行版可能使用不同的rename.您可以更改到源目录上方的目录并执行以下操作:

find source -exec prename 's:^source:/path/to/dest:' {} +

这将拒绝移动目标树中已存在的文件,并在目录名称重叠的情况下留下空目录,因此您可以在之后删除它们。您可以添加-f选项以prename使其覆盖现有文件。

例子:

$ mkdir -p dir1/{common,sub1} dir2/{common,sub2}

$ touch dir1/sub1/file dir2/sub2/file dir1/common/common dir2/common/common dir1/common/diff1 dir2/common/diff2

$ tree dir*
dir1
├── common
│   ├── common
│   └── diff1
└── sub1
    └── file
dir2
├── common
│   ├── common
│   └── diff2
└── sub2
    └── file

4 directories, 6 files

$ find dir2 -depth -exec rename 's/^dir2/dir1/' {} +
Can't rename dir2/sub2/file dir1/sub2/file: No such file or directory
dir2/common/common not renamed: dir1/common/common already exists
dir2/common not renamed: dir1/common already exists
dir2 not renamed: dir1 already exists

$ tree dir*
dir1
├── common
│   ├── common
│   ├── diff1
│   └── diff2
├── sub1
│   └── file
└── sub2
    └── file
dir2
└── common
    └── common

4 directories, 6 files

更新:

为了给出 的来源,它通常与(因此是“p”)prename捆绑在一起。perl在 Debian/Ubuntu 上,它是软件包的一部分perl。如果你想单独得到它,这个问题的回答者之一 -获取 Perl 重命名实用程序而不是内置重命名为它创建了一个单独的存储库 -https://github.com/subogero/rename

答案3

您实际上可以用来rsync移动文件而不是复制它们:

rsync -av --link-dest "$PWD"/src/ --remove-source-files src/ dst

按照正常的方式,rsync -av --remove-source-files src/ dst会将文件从 复制src/dst,然后删除源。通过添加该--link-dest选项并将其指向src/目录,目标文件将被链接而不是复制。

我能看到的唯一警告是:

  • --link-dest是相对于目标目录的,因此我们需要指定完整路径src/
  • rsync如果文件已链接,则不会报告文件已被复制,因此输出rsync -av --progress将报告未复制文件

注意。使用消耗了 90% 可用磁盘空间的文件进行测试。复制会失败(90% + 90% » 100%),但链接/移动工作正常。

相关内容