我有一个使用 Ubuntu 的家庭文件服务器。
最近,我的一个驱动器已满,所以我又买了一个并把它扔在那里。
我有一个非常大的文件夹,目录大小约为1.7T,包含相当数量的文件。
我用了GCP将文件从旧驱动器复制到新驱动器,似乎工作正常。
我现在想根据旧驱动器上的原始目录验证新驱动器上的新目录,然后再从旧驱动器中删除数据以释放空间。我知道我可以通过 CRC 检查来做到这一点。
具体来说,我可以如何做到这一点?
答案1
我只需使用diff
命令:
diff -rq --no-dereference /path/to/old/drive/ /path/to/new/drive/
这会读取并比较目录树中的每个文件并报告任何差异。该-r
标志以递归方式比较目录,而该-q
标志只是在文件不同时将消息打印到屏幕上,而不是打印实际差异(就像对文本文件那样)。--no-dereference
如果存在不同的符号链接,例如,在一个目录中存在符号链接,而在其对应的目录中存在链接到的文件的副本,则该标志可能很有用。
如果diff
命令打印无输出,这意味着目录树确实是相同的;可以运行echo $?
验证其退出状态为0
,说明两组文件是相同的。
我不认为计算 CRC 或校验和在这种情况下特别有用。如果两组文件位于不同的系统上,并且每个系统都可以计算自己的文件组的校验和,因此只需要通过网络发送校验和,则更有意义。计算校验和的另一个常见原因是保留校验和的副本以供将来使用。
答案2
同步通常用于复制文件而不是gcp
,但它也可用于验证副本,无论副本是如何制作的。简单地做
rsync -niaHc /origfolder/ /copyfolder
请小心以/
.选项有
-n
请勿复制(请勿更改)-i
逐项列出差异-a
保留(即比较,因为我们有-n
)权限、所有权、符号链接等并递归目录-H
保留硬链接-c
比较校验和
输出显示一个代码,详细说明每个不同文件或目录的差异。如果它们相同则没有输出。该代码具有一些列YXcstpoguax
,其中每个字符是一个点(.
如果比较的方面没问题),或者是一个字母:
Y is type of update:
< sent (not appropriate in this case)
> need to copy
c missing file or directory
h is hard link
. no update
* and rest of line is a message, eg *deleting
X file type: f file d dir L symlink D device S special file
c checksum differs. + new item " " same
s size differs
t timestamp differs
p permissions differ
o owner differ
g group differ
u (not used)
a acl differ
x extended attributes differ
例如,
.d..t...... a/b/ directory timestamp differs
cL+++++++++ a/b/d -> /nosuch2 symbolic link missing
cS+++++++++ a/b/f special file missing (a/b/f is a fifo)
>f..t...... a/b/ff file timestamp differs
hf a/b/xx1 => a/b/xx files should be a hard linked
cLc.t...... a/b/z -> /tmp/hi2 symbolic link to different name
cd+++++++++ a/c/ directory missing
>f+++++++++ a/c/i.10 missing file needs to be copied
请参阅man rsync
下文--itemize-changes
了解更多详细信息。如果第三列c
或第四列存在差异s
,则说明数据已严重损坏。其他标志(例如不同的权限、所有者或时间戳)对您来说可能不太重要。如果所有文件都被标记为“丢失”,那么您可能没有提供正确的目录进行比较。如果您确定,运行不带该-n
标志的 rsync 将“修复”差异。
答案3
我有同样的问题,我用过安东尼的回答,有一点扭曲。
如果出现某些硬件故障(例如输入/输出错误),导致 diff 退出,直接应用他的答案将会失败。
我整理了他的答案,以及这个答案,并将其全部放入:
find /path/to/original -type f -exec bash -c 'diff -rq --no-dereference "$@" "/path/to/destination/$(sed -r "s/^.*(<first-common-ancestor>.*)$/\1/g" <<<"$@")"' bash {} \;
- 替换
/path/to/original
为您复制的原始目录的路径。 - 替换
/path/to/destination
为您复制到的目标目录的路径。 - 替换
<first-common-ancestor>
为两者之间的共同祖先目录。示例:您正在从 复制/media/foo/bar
到/media/test/dst/
,因此dst
,在复制操作完成后, 具有目录bar
。第一个共同祖先就bar
在这里;因为下面的所有文件bar
都将具有相同的相对路径。
一些注意事项:
bash -c
和部分bash {}
用于对文件名进行安全替换;为了安全起见,不要受到可能的攻击(例如特权提升)的伤害。- 该
sed
部分是删除找到的文件的绝对路径并仅使用相对路径(这与 using 不同execdir
)。如果您不确定这有什么用,请尝试将其删除并检查错误消息:) - 将
<<<
变量作为字符串读取,而不是将其作为要读取的文件的路径读取。