我有嵌套的文件夹,里面有一堆相互硬链接的文件。我想断开硬链接(将它们转换为单独的文件),然后立即将每一对转换为 reflink(因此它们具有不同的 inode 但使用磁盘的同一部分)。
find -type f -links +1
会找到所有的硬链接,而像这样的命令
cp --reflink=always my_file.bin my_file_copy.bin
将在不使用更多磁盘空间的情况下复制文件,将其创建为 reflink。
如何将这些组合起来通过一整套嵌套文件夹并将每个硬链接转换为引用链接,用相同的文件名替换它们?
您已标记
ubuntu
,我了解您不仅限于严格的 POSIX 工具及其 POSIX 选项。笔记:
my_file.bin
硬链接变为my_file.bin
引用链接。不会有my_file_copy.bin
。(这个注释是为了防止你想在保持硬链接完好无损的情况下创建my_file_copy.bin
reflinkmy_file.bin
。这个问题在这件事上并不是很清楚,它my_file_copy.bin
出于某种原因引入了。)mktemp
或cp
失败则mv
不会执行。在任何情况下,您都不应该丢失原始内容,除非其他一些进程修改了临时文件。find
一个一个地测试文件,它永远不会覆盖(转换)所有到任何 inode 的硬链接。如果所有硬链接都被处理,find
那么-links +1
最后一个硬链接将失败。原来的 inode 会继续存在。这意味着如果原始文件已打开并且将被修改(不更改 inode 编号),那么修改将在某处保留(但很难提前判断哪个硬链接将最后处理并保留其 inode 编号)。不应发生打开的文件完全取消链接、修改并在文件系统关闭后立即从文件系统中删除的情况。cp
或mv
失败,则临时文件将继续存在。您可能希望将 stderr 捕获到文件 (2>some_file
) 并稍后进行调查。-print
如果 shell 代码成功,将采取行动。它只是在那里,所以你可以看到发生了什么。find-sh
在这里解释:什么是第二个 shsh -c 'some shell code' sh
?编辑:正如卡米尔所指出的,不要做
for x in $(find ...)
. 使用find -execdir sh -c
格式是使用查找输出的正确方法。不过,我会在这里留下我的答案。您可以编写一个小型 Bash 脚本或直接在 bash shell 中编写一个 for 循环:
$ for filename in $(find -type f -links +1); do echo "I found this file: ${filename}"; done
此示例将从
find
命令中获取每一行并将其放入${filename}
您可以使用的变量中。在这里,我们只是I found this file: $filename
为每个打印一个,但你可以用你的复制命令替换它,它可能看起来像这样:$ for filename in $(find -type f -links +1); do echo "Copying ${filename} to ${filename}_copy.bin"; cp --reflink=always ${filename} ${filename}_copy.bin; done
或者,如果您想将其放在 Bash 脚本中,以便更容易阅读和使用。创建一个
copy_script.sh
包含以下内容的文件:然后保存并运行
$ bash ./copy_script.sh