![如何合并两个文件夹以便从一个文件夹中删除相同的文件,同时保留校验和差异?](https://linux22.com/image/186314/%E5%A6%82%E4%BD%95%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%96%87%E4%BB%B6%E5%A4%B9%E4%BB%A5%E4%BE%BF%E4%BB%8E%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%E5%88%A0%E9%99%A4%E7%9B%B8%E5%90%8C%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%8C%E5%90%8C%E6%97%B6%E4%BF%9D%E7%95%99%E6%A0%A1%E9%AA%8C%E5%92%8C%E5%B7%AE%E5%BC%82%EF%BC%9F.png)
我遇到这样一种情况,我需要从可能来自不同时间点的驱动器进行恢复,该时间点不仅在文件存在方面可能有所不同,而且存在一些损坏,其中许多文件明显已损坏。
我们将左侧文件夹命名为“A”,右侧文件夹命名为“B”。
我有责任合并这两个图像,这样:
- B 中存在但 A 中不存在的任何文件都应移动到 A,并且
- 两个位置中都存在且相同的任何文件都应从 B 中删除,最后
- 任何校验和不同的文件都应保留在 B 中,以便可以在 A 和 B 之间手动比较这些不同的文件,但除了这些具有不同校验和(即实际内容)的文件外,B 中不应保留任何其他内容。
笔记:在这一点上,日期几乎不重要,尽管它会好的在元数据中保留较旧的日期。
这怎么能干干净净地完成呢?不幸的是,我必须对数十 TB 的数据执行此操作,因此如果我不知道如何自动化此操作,这将是一个非常漫长的过程。看来 90-95% 的内容是相同的,因此应该制定一种“设置后就忘记它”的方法,为进行手动比较做好准备。
答案1
第 2 步和第 3 步似乎是最困难的,所以让我们从这些开始。
有一个名为的工具rdfind
可以查找重复文件。您可以决定在检测到重复项时该怎么做:在您的情况下,您希望将其从 B: 中删除rdfind -deleteduplicates true A B
。如果 A 和 B 中存在相同的文件,则保留 A 中的文件。其他选项是用硬链接或软链接替换副本,或者只是报告结果。
然后,保留在 B 中的文件要么是 B 所独有的,要么 B 中的文件与 A 中的不同。 将唯一的文件从 B 移动到 A:mv -i B/* A/
并no
在每次询问是否要覆盖时回答。您可以使用 自动化此操作yes no | mv -i B/* A/
。如果您使用 GNU mv,则可以使用mv --no-clobber B/* A/
.
当然,在对真实数据进行操作之前,您需要先进行练习。您可以轻松地在 A 和 B: 中创建指向文件的硬链接树mkdir training; cp -lr A training; cp -lr B training
,并在那里进行练习。
答案2
这里有一个方法,虽然简单,但是如果A中缺少很多文件,效率就很低。只需依次执行每个步骤即可。我假设只有目录和常规文件(比较特殊文件的元数据可以通过更多的工作来完成)。警告:未经测试的代码。
首先,将 B 中存在但 A 中不存在的文件复制到 A。尽可能保留元数据(时间戳、权限)。
rsync -a --ignore-existing B A
其次,从 B 中删除重复项。请注意,此时,最初 A 中不存在的文件现在是相同的。
cd B
find . -type f -exec sh '
for x; do
if cmp -s "$x" "$0/$x"; then rm "$x"; fi
done
' /path/to/A {} +
(可选)从 B 中删除空目录。
find B -depth -type d -exec rmdir {} + 2>/dev/null
这是低效的,因为在步骤 2 中,A 中已经缺失的每个文件现在都会被复制并进行比较,然后从 B 中删除。如果 A 中缺失很多文件,则对 B 进行一次传递会更有效将文件移动到 A 并删除重复项。如果 A 和 B 位于同一文件系统上,则尤其如此,这样可以便宜地移动文件,而不是通过复制然后删除源。
答案3
我首先会挑战您的要求。你正试图一步完成所有事情。在开始恢复文件之前,您最好知道恢复后的系统是什么样子。
实际上,首先获得差异比您想象的要容易。
步骤1
获取磁盘上每个文件的哈希值。无论如何你都必须这样做。所以不妨把它结束并完成。 如果没有太多硬链接,下面的命令效果很好。假设目录名为/media/A
和/media/B
。
cd /media/A
find . -type f -exec sha256sum {} + > ~/hashes.txt
这将为磁盘上的每个常规文件创建一个哈希值。如果文件是硬链接的,它将出现在每个名称下(并且已为每个名称扫描一次)。
第2步
识别变化
cd /media/B
sha256sum -c ~/hashes.txt > ~/check.txt
check.txt 现在将包含三种类型的行:
good/file: OK
missing/file: FAILED open or read
changed/file: FAILED
步骤3
作为快捷方式,您可以使用以下命令复制所有丢失的文件:
rsync -a --ignore-existing /media/A/ /media/B/
步骤4
那么你只需要担心改变的文件:
grep 'FAILED$' ~/check.txt | while read file ; do
echo "${file%: FAILED}"
done > ~/changed.txt
这将为您提供changed.txt,其中每一行都有一个文件名。每一个都是两个系统上已更改的文件。
现在由您来排序changed.txt
并确定要保留哪些文件以及将哪些文件从 B 覆盖到 A。
答案4
假设文件名中没有任何“换行符”,这应该可以工作:
cd B
find . -type f -print | while read f
do
[[ -f "A/$f" ]] || { echo mv "$f" "A/$f" ; continue; }
cmp "$f" "A/$f" && echo rm "$f"
done
运行它,如果看起来不错,请删除“echo”字样以运行实际的命令。