我有时需要将目录结构中的大量数据从一台计算机复制/同步到另一台计算机。我为此使用的典型程序是 rsync、syncthing 或 seafile。
为了不完全依赖复制/同步程序(或我选择的选项)的正确性,我通常会生成一个校验和文件(使用cfv
) 并将其与数据复制/同步,以便我稍后可以检查目标计算机上的一切是否正常。例如,cfv
可以很好地查看来自原点的所有文件是否已安全到达。
但是,我遗漏了一个选项,即查看副本中是否有原始文件中没有的文件。据我所知,cfv
没有选项可以查找此类“附加”文件。我采用的解决方案是为副本创建一个新的校验和文件并将其与原始文件进行比较,但这意味着必须对每个文件计算四次校验和(在两台计算机上生成和检查)。
有没有更好的解决办法?
答案1
如果您只想检测“其他”文件,那么计算校验和对我来说似乎有点小题大做。您不需要检查实际数据(文件内容);您需要检查元数据(现有路径)。
要获取所有相对路径/synced/dir
,请运行
(cd /synced/dir && find . | sort) > structure.txt
在两侧都执行此操作,然后diff
生成文件。请注意,情况是对称的,因此您将在任何一侧检测到“附加”和“丢失”的文件(此处的“附加”相当于那里的“丢失”,反之亦然)。
要忽略一侧(或另一侧)的“附加”文件,请分别diff
使用grep '^>'
(或grep '^<'
)过滤输出。
如果两个目录在单个系统中可用(已安装),则此 Bash 语法可能会有用:
diff <(cd /original/dir && find . | sort) <(cd /backup/dir && find . | sort) | grep '^>'
这并不完全可靠(例如文件名中的换行符可能会破坏逻辑),请将我的示例视为概念证明。重点是,您无需读取文件内容即可检测到其他文件。
笔记:
sort
find
是必要的,因为即使目录是精确的副本,两个-s 也可能返回不同顺序的条目;- sole
diff
可以比较目录,但是这种模式在这里没有用,因为它会尝试比较相应文件的内容,而这种行为是我们首先要避免的。
答案2
Kamil Maciorowski 的回答非常好,但我认为他的解决方案可以在问题概述的背景下简化,并遵循以下步骤:
1) 在源上创建校验和文件。以下是使用以下命令执行此操作的 bash 脚本cfv
:
#!/bin/bash
# create md5 checksum file for all files in the current directory tree
# filename for checksum file
FN="${PWD##*/}.md5"
# create checksum file
cfv -rr -C -L -t md5 -f $FN
它从当前目录开始,不遵循符号链接递归下降,并在当前目录中创建单个校验和文件。
2)从源同步/复制到目标。
3)检查目标上的校验和文件(使用cfv
),和find
使用、sort
和查找其他文件comm
:
#!/bin/bash
# test md5 checksum file w.r.t. all files in the current directory tree
# filename for checksum file
FN="${PWD##*/}.md5"
# test checksum file
cfv -T -f $FN
# check whether there are additional files
echo ----------- additional files -----------
CHECK=`tempfile`
sed 's .\{34\} ' $FN | sort > $CHECK
LOCAL=`tempfile`
find -P -type f -printf '%P\n' | sort > $LOCAL
comm -13 $CHECK $LOCAL
与 Kamil Maciorowski 的答案不同的是,我没有为源创建单独的文件列表,而是使用通过提取的校验和文件中的文件名sed
。这假定校验和文件采用标准md5sum
格式:32 个字符校验和、空格、'*' 或 ' ' 表示二进制/文本模式、文件名。