我有一个Shell脚本,在其中需要检查两个文件是否包含相同的数据。我对大量文件执行此操作,并且在我的脚本中,该diff
命令似乎是性能瓶颈。
这是一行:
diff -q $dst $new > /dev/null
if ($status) then ...
有没有一种比较快速的方法来比较文件,也许是自定义算法而不是默认算法diff
?
我有一个Shell脚本,在其中需要检查两个文件是否包含相同的数据。我对大量文件执行此操作,并且在我的脚本中,该diff
命令似乎是性能瓶颈。
这是一行:
diff -q $dst $new > /dev/null
if ($status) then ...
有没有一种比较快速的方法来比较文件,也许是自定义算法而不是默认算法diff
?
Answers:
我相信cmp
会在第一个字节的差异处停止:
cmp --silent $old $new || echo "files are different"
cmp -s $old $new
也可以。-s
的缩写--silent
cmp
将首先检查文件大小。这是GNU版本,如果您想查看它包括的其他优化:git.savannah.gnu.org/cgit/diffutils.git/tree/src/cmp.c
我喜欢@Alex Howansky为此使用了'cmp --silent'。但是我需要正面和负面的回应,所以我使用:
cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'
然后,我可以在终端中或使用ssh来运行此程序,以对照常量文件检查文件。
为什么不同时获取两个文件内容的哈希值?
尝试此脚本,将其称为例如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
因为我很烂并且没有足够的声誉点,所以我无法在评论中添加此花絮。
但是,如果您要使用该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
cmp --silent $FILE1 $FILE2 ; if [ "$?" == "1" ]; then echo "files differ"; fi
而反过来又是更复杂的方法,cmp --silent $FILE1 $FILE2 || echo "files differ"
因为您可以直接在表达式中使用命令。它代替$?
。结果,将比较命令的存在状态。这就是其他答案。顺便说一句 如果有人在苦苦挣扎--silent
,则并非到处都支持它(busybox)。使用-s
对于没有不同的文件,任何方法都将需要完全读取两个文件,即使读取是过去的。
没有替代。因此,在某个时间点创建哈希或校验和需要读取整个文件。大文件需要时间。
文件元数据检索比读取大文件要快得多。
那么,是否可以使用任何文件元数据来确定文件是否不同?文件大小 ?甚至什至只读取文件一小部分的file命令的结果?
文件大小示例代码片段:
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'
如果文件大小相同,则您将无法读取完整文件。
ls -n
到,如果用户或组名避免出现问题有空格。
也尝试使用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”。
md5
无论如何都会读取整个文件,因此cmp
,在第一个差异处停止会更快。
用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"