判断两个文件在Unix/Linux中是否相同的最快方法?

JDS*_*JDS 205 unix linux diff file

我有一个shell脚本,我需要检查两个文件是否相同.我这样做是为了很多文件,在我的脚本中,diff命令似乎是性能瓶颈.

这是行:

diff -q $dst $new > /dev/null

if ($status) then ...
Run Code Online (Sandbox Code Playgroud)

是否有更快的方法来比较文件,可能是自定义算法而不是默认算法diff

Ale*_*sky 357

我相信cmp会停在第一个字节差异:

cmp --silent $old $new || echo "files are different"
Run Code Online (Sandbox Code Playgroud)

  • `cmp -s $ old $ new`也有效.`-s`是`--silent`的缩写 (8认同)
  • 作为速度提升,您应该在比较内容之前检查文件大小是否相等.有谁知道cmp是否这样做? (7认同)
  • @ BeowulfNode42是的,`cmp`的任何体面实现都会先检查文件大小.这是GNU版本,如果你想看到它包含的其他优化:http://git.savannah.gnu.org/cgit/diffutils.git/tree/src/cmp.c (6认同)
  • 要运行多个命令,可以使用方括号:cmp -s old new || {不回声;回声 回声一样 } (3认同)
  • 如何添加多个命令而不是一个?我想复制一个文件并进行 roboot。 (2认同)
  • @Rohmer 提到的(`-s` 选项)也是可移植的,`--silent` 没有在 POSIX 标准中定义。 (2认同)

pn1*_*ude 47

我喜欢@Alex Howansky为此使用'cmp --silent'.但我需要积极和消极的回应,所以我使用:

cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'
Run Code Online (Sandbox Code Playgroud)

然后我可以在终端中运行它或使用ssh来检查文件与常量文件.

  • 如果你的`echo success`命令(或你放在其中的任何其他命令)失败,你的"否定响应"命令将会运行.你应该使用"if-then-else-fi"结构.例如,像[这个简单的例子](http://stackoverflow.com/a/16034851/5419599). (15认同)

jab*_*edo 17

为什么不获取两个文件内容的哈希值?

尝试使用此脚本,将其命名为script.sh,然后按如下方式运行:script.sh file1.txt file2.txt

#!/bin/bash

file1=`md5 $1`
file2=`md5 $2`

if [ "$file1" = "$file2" ]
then
    echo "Files have the same content"
else
    echo "Files have NOT the same content"
fi
Run Code Online (Sandbox Code Playgroud)

  • OP要求最快的方式...不会搜索第一个非匹配位(使用cmp)更快(如果它们不匹配)而不是散列整个文件,特别是如果文件很大? (10认同)
  • 仅供参考,这不能保证有效,所以应该有免责声明...... (6认同)
  • @will呃,它有效地保证有效.从数学上讲,它不起作用的几率大约是1 /(2 ^ 511)`.除非你担心有人[故意试图造成碰撞](http://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5- hash-value)这种方法产生误报的想法并不是一个严重的问题.`cmp`仍然更有效,因为在文件不匹配的情况下它不必读取整个文件. (5认同)
  • @THISUSERNEEDSHELP这是因为散列算法不是*一对一.它们的设计使得散列空间很大,不同的输入很有可能产生不同的散列.但实际情况是,散列空间是有限的,而散列的可能文件的范围不是 - 最终你会发生碰撞.在密码学中,它被称为[生日攻击](https://en.wikipedia.org/wiki/Birthday_attack). (2认同)
  • @ Ajedi32通常2 ^ 511似乎很大,就哈希算法而言,它很小。在一个1MiB文件中,有8388608个位,从而为总共1个可能的文件(大小正好为1MiB)提供了2 ^ 8388608位的总可能组合。这意味着2 ^ 511的哈希空间将在MINIMUM处有2 ^ 8388608/2 ^ 511 = 2 ^ 8388097冲突。文件大小的每个额外字节都会使它增加2 ^ 8。哈希冲突非常经常发生,脚本/程序需要能够处理它们。cmp不仅将在本地存储上更快,而且将更加准确。 (2认同)
  • 如果你进行一对多的比较,md5是最好的.您可以将md5哈希存储为属性,也可以将数据存储在数据库中.如果出现一个新文件,您必须检查文件系统中的任何位置是否存在相同的文件,那么您所做的就是计算新文件的哈希值并检查以前的所有文件.我确定Git在提交期间使用散列来检查文件更改,但是他们使用SHA1. (2认同)
  • @ BeowulfNode42这就是为什么我在评论开头加上“除非您担心有人故意创建碰撞” (2认同)

Vas*_*kov 16

快速安全地比较任意两个文件:

if cmp --silent -- "$FILE1" "$FILE2"; then
  echo "files contents are identical"
else
  echo "files differ"
fi
Run Code Online (Sandbox Code Playgroud)

它可读、高效,适用于任何文件名,包括 "` $()


Gre*_*tin 14

因为我很烂而且没有足够的声望点,所以我不能将这个花絮添加为评论。

但是,如果您要使用该cmp命令(并且不需要/不想变得冗长),您只需获取退出状态即可。根据cmp手册页:

如果 FILE 为“-”或缺失,则读取标准输入。输入相同时退出状态为 0,不同时为 1,故障时为 2。

因此,您可以执行以下操作:

STATUS="$(cmp --silent $FILE1 $FILE2; echo $?)"  # "$?" gives exit status for each comparison

if [[ $STATUS -ne 0 ]]; then  # if status isn't equal to 0, then execute code
    DO A COMMAND ON $FILE1
else
    DO SOMETHING ELSE
fi
Run Code Online (Sandbox Code Playgroud)

编辑:感谢大家的评论!我在这里更新了测试语法。但是,如果您正在寻找与此答案在可读性、样式和语法方面类似的内容,我建议您使用 Vasili 的答案。

  • 这可以简化为 `if cmp --silent -- "$FILE1" "$FILE2"; 然后...否则...fi` (2认同)

小智 8

您可以通过 sha256 等校验和算法进行比较

sha256sum oldFile > oldFile.sha256

echo "$(cat oldFile.sha256) newFile" | sha256sum --check

newFile: OK
Run Code Online (Sandbox Code Playgroud)

如果文件不同,结果将是

newFile: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
Run Code Online (Sandbox Code Playgroud)