288

我有一个 shell 脚本,我需要在其中检查两个文件是否包含相同的数据。我对很多文件执行此操作,并且在我的脚本中,该diff命令似乎是性能瓶颈。

这是行:

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

if ($status) then ...

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

4

8 回答 8

475

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

cmp --silent $old $new || echo "files are different"
于 2012-10-15T17:15:56.240 回答
69

我喜欢@Alex Howansky 为此使用了'cmp --silent'。但我需要正面和负面的回应,所以我使用:

cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'

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

于 2015-10-01T01:01:55.730 回答
27

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

if cmp --silent -- "$FILE1" "$FILE2"; then
  echo "files contents are identical"
else
  echo "files differ"
fi

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

于 2020-09-20T06:45:11.837 回答
15

因为我很烂并且没有足够的声望点,所以我无法将此花絮添加为评论。

但是,如果您要使用该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

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

于 2018-11-28T23:27:21.577 回答
3

对于没有不同的文件,任何方法都需要完全读取这两个文件,即使读取是过去的。

没有替代。因此,在某个时间点创建哈希或校验和需要读取整个文件。大文件需要时间。

文件元数据检索比读取大文件快得多。

那么,是否有任何文件元数据可用于确定文件不同?文件大小 ?甚至只是读取文件一小部分的文件命令的结果?

文件大小示例代码片段:

  ls -l $1 $2 | 
  awk 'NR==1{a=$5} NR==2{b=$5} 
       END{val=(a==b)?0 :1; exit( val) }'

[ $? -eq 0 ] && echo 'same' || echo 'different'  

如果文件大小相同,那么您将无法读取完整的文件。

于 2012-10-15T18:38:15.063 回答
2

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

sha256sum oldFile > oldFile.sha256

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

newFile: OK

如果文件不同,结果将是

newFile: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
于 2020-08-29T11:02:48.227 回答
1

使用 Raspberry Pi 3B+ 进行一些测试(我使用的是覆盖文件系统,并且需要定期同步),我对 diff -q 和 cmp -s 进行了自己的比较;请注意,这是来自 /dev/shm 内部的日志,因此磁盘访问速度不是问题:

[root@mypi shm]# dd if=/dev/urandom of=test.file bs=1M count=100 ; time diff -q test.file test.copy && echo diff true || echo diff false ; time cmp -s test.file test.copy && echo cmp true || echo cmp false ; cp -a test.file test.copy ; time diff -q test.file test.copy && echo diff true || echo diff false; time cmp -s test.file test.copy && echo cmp true || echo cmp false
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 6.2564 s, 16.8 MB/s
Files test.file and test.copy differ

real    0m0.008s
user    0m0.008s
sys     0m0.000s
diff false

real    0m0.009s
user    0m0.007s
sys     0m0.001s
cmp false
cp: overwrite âtest.copyâ? y

real    0m0.966s
user    0m0.447s
sys     0m0.518s
diff true

real    0m0.785s
user    0m0.211s
sys     0m0.573s
cmp true
[root@mypi shm]# pico /root/rwbscripts/utils/squish.sh

我跑了几次。cmp -s 在我使用的测试盒上的时间始终稍短。所以如果你想使用 cmp -s 在两个文件之间做一些事情......

identical (){
  echo "$1" and "$2" are the same.
  echo This is a function, you can put whatever you want in here.
}
different () {
  echo "$1" and "$2" are different.
  echo This is a function, you can put whatever you want in here, too.
}
cmp -s "$FILEA" "$FILEB" && identical "$FILEA" "$FILEB" || different "$FILEA" "$FILEB"
于 2018-11-09T17:53:09.537 回答
0

也尝试使用 cksum 命令:

chk1=`cksum <file1> | awk -F" " '{print $1}'`
chk2=`cksum <file2> | awk -F" " '{print $1}'`

if [ $chk1 -eq $chk2 ]
then
  echo "File is identical"
else
  echo "File is not identical"
fi

cksum 命令将输出文件的字节数。请参阅“人 cksum”。

于 2016-09-23T00:59:59.433 回答