it-swarm.com.de

Wie kann man am schnellsten feststellen, ob zwei Dateien unter Unix/Linux identisch sind?

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?

166
JDS

Ich glaube, dass cmp beim ersten Byte-Unterschied aufhört:

cmp --silent $old $new || echo "files are different"
302
Alex Howansky

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.

39
pn1 dude

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
16
jabaldonedo

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.

4
jim mcnamara

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'.

2
Nono Taps

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
0
Gregory Martin

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"
0
Jack Simth