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

Fastest way to tell if two files are the same in Unix/Linux?

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

这条线是:

1
2
3
diff -q $dst $new > /dev/null

if ($status) then ...

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


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

1
cmp --silent $old $new || echo"files are different"


我喜欢@alex howansky为此使用了'cmp--silent'。但我需要积极和消极的回应,所以我使用:

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

然后,我可以在终端或使用ssh运行这个命令,根据一个常量文件检查文件。


为什么不把这两个文件的内容都列出来呢?

尝试这个脚本,调用它,例如script.sh,然后按如下方式运行:script.sh file1.txt file2.txt

1
2
3
4
5
6
7
8
9
10
11
#!/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


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

别无选择。因此,在某个时间点创建哈希或校验和需要读取整个文件。大文件需要时间。

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

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

文件大小示例代码片段:

1
2
3
4
5
  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'

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


还可以尝试使用cksum命令:

1
2
3
4
5
6
7
8
9
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命令将输出文件的字节计数。见"Man cksum"。


因为我太差劲了,没有足够的声望点,所以我不能把这些小道消息作为评论。

但是,如果您要使用cmp命令(不需要/不想详细说明),您可以直接获取退出状态。根据cmp手册:

If a FILE is '-' or missing, read standard input. Exit status is 0
if inputs are the same, 1 if different, 2 if trouble.

所以,你可以这样做:

1
2
3
4
5
6
7
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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[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 atest.copya? 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在两个文件之间执行操作…

1
2
3
4
5
6
7
8
9
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"