在Unix/Linux中判断两个文件是否具有相同内容的最快方法是什么?

xt0899hw  于 2022-11-04  发布在  Unix
关注(0)|答案(9)|浏览(240)

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

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

if ($status) then ...

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

js81xvg6

js81xvg61#

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

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

ecfsfe2w2#

我喜欢@Alex Howansky用“cmp --silent”来表达这个意思。但是我需要正面和负面的回应,所以我用途:

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

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

kuuvgm7e

kuuvgm7e3#

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

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

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

gupuwyp2

gupuwyp24#

因为我吸,没有足够的声誉点,我不能把这个花絮作为一个评论。
但是,如果您要使用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的答案。

pu82cl6c

pu82cl6c5#

对于没有不同的文件,任何方法都需要完全读取这两个文件,即使读取是在过去。
没有其他选择。因此在某个时间点创建哈希或校验和需要阅读整个文件。大文件需要时间。
文件元数据检索比阅读大文件快得多。
那么,是否有任何文件元数据可以用来确定文件是不同的?文件大小?甚至是文件命令的结果,它只读取了文件的一小部分?
文件大小示例代码片段:

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'

如果文件大小相同,则您将无法读取全部文件。

2eafrhcq

2eafrhcq6#

另请尝试使用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命令将输出文件的字节计数。请参阅“man cksum”。

jm81lzqq

jm81lzqq7#

在用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"
zujrkrfu

zujrkrfu8#

如果你正在寻找更多的可定制的差异,那么git diff可以使用。

if (git diff --no-index --quiet -- old.txt new.txt) then
  echo "files contents are identical"
else
  echo "files differ"
fi

"安静"
禁用程序的所有输出。隐含--exit-code。

--退出代码

使程序退出时的代码类似于diff(1),即如果存在差异,则退出时的代码为1,0表示没有差异。
此外,还有各种算法和设置可供选择:[ref](英文)
--差分算法={耐心|极小的|直方图|迈尔斯}
选择diff算法。变量如下:

default,myers基本的贪婪diff算法。目前,这是默认值。
minimal花费额外的时间以确保产生尽可能小的差异。
patience生成补丁时使用“patience diff”算法。
直方图此算法将耐心算法扩展为“支持低出现次数的常见元素”。

相关问题