Ich habe ein Shell-Skript, in dem ich überprüfen muss, ob zwei Dateien gleich sind oder nicht. Ich mache dies für eine Menge von Dateien, und in meinem Skript scheint der diff
-Befehl der Leistungsengpass zu sein.
Hier ist die Zeile:
diff -q $dst $new > /dev/null
if ($status) then ...
Könnte es einen schnelleren Weg zum Vergleich der Dateien geben, vielleicht einen benutzerdefinierten Algorithmus anstelle der Standardvariable diff
?
Ich glaube, dass cmp
beim ersten Byte-Unterschied aufhört:
cmp --silent $old $new || echo "files are different"
Ich mag, dass @Alex Howansky dafür 'cmp --silent' verwendet hat. Aber ich brauche sowohl positive als auch negative Antworten, also verwende ich:
cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'
Ich kann dies dann im Terminal oder mit einer SSH ausführen, um Dateien gegen eine konstante Datei zu prüfen.
Warum bekommen Sie nicht den Hash für beide Dateien?
Versuchen Sie es mit diesem Skript, nennen Sie es beispielsweise script.sh und führen Sie es dann wie folgt aus: 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
Für Dateien, die sich nicht unterscheiden, müssen bei jeder Methode beide Dateien vollständig gelesen werden, auch wenn der Lesevorgang in der Vergangenheit war.
Es gibt keine Alternative. Das Erstellen von Hashes oder Prüfsummen zu einem bestimmten Zeitpunkt erfordert das Lesen der gesamten Datei. Große Dateien brauchen Zeit.
Das Abrufen von Datei-Metadaten ist viel schneller als das Lesen einer großen Datei.
Gibt es also Dateimetadaten, mit denen Sie feststellen können, dass die Dateien unterschiedlich sind? Dateigröße? oder sogar Ergebnisse des Datei-Befehls, der nur einen kleinen Teil der Datei liest?
Beispiel für Codefragment der Dateigröße:
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'
Wenn die Dateien die gleiche Größe haben, bleiben Sie beim Lesen der Dateien hängen.
Versuchen Sie auch den Befehl cksum zu verwenden:
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
Der Befehl cksum gibt die Anzahl der Bytes einer Datei aus. Siehe 'Man Cksum'.
Da ich schlecht bin und nicht genügend Reputationspunkte habe, kann ich dieses Leckerbissen nicht als Kommentar hinzufügen.
Wenn Sie jedoch den Befehl cmp
verwenden (und nicht ausführlich sein müssen/wollen), können Sie einfach den Beendigungsstatus abrufen. In der cmp
-Manpage:
Wenn eine Datei '-' ist oder fehlt, lesen Sie die Standardeingabe. Ausgangsstatus ist 0 wenn die Eingänge gleich sind, 1 wenn verschieden, 2 wenn Probleme.
Du könntest also so etwas tun:
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
Beim Testen mit einem Raspberry Pi 3B + (ich verwende ein Overlay-Dateisystem und muss regelmäßig synchronisiert werden), führte ich einen Vergleich mit diff -q und cmp -s durch. Beachten Sie, dass dies ein Protokoll aus/dev/shm ist. Daher ist die Zugriffsgeschwindigkeit auf Festplatten kein Problem:
[[email protected] 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
[[email protected] shm]# pico /root/rwbscripts/utils/squish.sh
Ich habe es ein paar Mal laufen lassen. cmp -s hatte auf der von mir verwendeten Testbox immer etwas kürzere Zeiten. Wenn Sie also mit cmp -s zwischen zwei Dateien wechseln möchten ...
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"