web-dev-qa-db-fra.com

Le moyen le plus rapide de savoir si deux fichiers sont identiques sous Unix/Linux?

J'ai un script shell dans lequel je dois vérifier si deux fichiers sont identiques ou non. Je le fais pour beaucoup de fichiers, et dans mon script, la commande diff semble être le goulot d'étranglement des performances. 

Voici la ligne:

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

if ($status) then ...

Pourrait-il y avoir un moyen plus rapide de comparer les fichiers, peut-être un algorithme personnalisé à la place de la variable par défaut diff?

166
JDS

Je crois que cmp s'arrêtera à la différence du premier octet:

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

J'aime @Alex Howansky ont utilisé 'cmp --silent' pour cela. Mais j'ai besoin d'une réponse à la fois positive et négative pour utiliser:

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

Je peux ensuite l'exécuter dans le terminal ou avec un SSH pour vérifier les fichiers par rapport à un fichier constant.

39
pn1 dude

Pourquoi n'obtenez-vous pas le hachage du contenu des deux fichiers?

Essayez ce script, appelez-le par exemple script.sh et exécutez-le comme suit: script.sh fichier1.txt fichier2.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

Pour les fichiers qui ne sont pas différents, toute méthode nécessitera d'avoir lu les deux fichiers entièrement, même si la lecture avait eu lieu dans le passé.

Il n'y a pas d'alternative. Donc, créer des hachages ou des sommes de contrôle à un moment donné nécessite de lire le fichier en entier. Les gros fichiers prennent du temps.

La récupération des métadonnées de fichier est beaucoup plus rapide que la lecture d'un fichier volumineux.

Alors, y a-t-il des métadonnées de fichier que vous pouvez utiliser pour établir que les fichiers sont différents? Taille du fichier? ou même les résultats de la commande de fichier qui ne fait que lire une petite partie du fichier?

Exemple de taille de fichier fragment de code:

  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'  

Si les fichiers ont la même taille, vous êtes bloqué avec des lectures de fichiers complètes.

4
jim mcnamara

Essayez aussi d'utiliser la commande 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

La commande cksum affichera le nombre d'octets d'un fichier. Voir 'homme cksum'.

2
Nono Taps

Parce que je suis nul et que je n'ai pas assez de points de réputation, je ne peux pas ajouter cette friandise en commentaire. 

Toutefois, si vous souhaitez utiliser la commande cmp (et que vous n'avez pas besoin/ne voulez pas être commenté), vous pouvez simplement saisir le statut de sortie. Par la page de manuel cmp:

Si un fichier est "-" ou manquant, lisez l'entrée standard. Le statut de sortie est 0 si les entrées sont les mêmes, 1 si différent, 2 si problème.

Donc, vous pourriez faire quelque chose comme:

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

En faisant des tests avec un Raspberry Pi 3B + (j'utilise un système de fichiers en superposition et dois synchroniser régulièrement), j'ai effectué une comparaison de mon propre pour diff -q et cmp -s; notez qu'il s'agit d'un journal de/dev/shm, les vitesses d'accès au disque ne sont donc pas un problème:

[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

Je l'ai couru plusieurs fois. cmp -s a toujours eu des temps légèrement plus courts sur la boîte de test que j'utilisais. Donc si vous voulez utiliser cmp -s pour faire des choses entre deux fichiers ...

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