404 votes

Comment comparer des fichiers binaires sous Linux?

J'ai besoin de comparer deux fichiers binaires et obtenir la sortie sous la forme :

pour chaque octet différent. Donc si file1.bin est

  00 90 00 11

sous forme binaire et file2.bin est

  00 91 00 10

Je veux obtenir quelque chose comme

  00000001 90 91
  00000003 11 10

Y a-t-il un moyen de le faire dans Linux ? Je connais cmp -l mais il utilise un système décimal pour les décalages et octal pour les octets ce que je voudrais éviter.

0 votes

Xdelta.org fonctionne assez bien. Il serait peut-être utile d'y jeter un œil.

0 votes

Parce que vous ne pouvez pas répondre à cette question (car vous n'êtes pas un utilisateur), je vote pour la fermeture. Une différence binaire explicitement demandée ici n'est pas du tout utile, et je suis enclin à penser que vous voulez quelque chose d'utile, si vous insérez un octet au début du fichier, tous les octets doivent-ils être marqués comme étant différents? Sans savoir cela, cela est simplement trop vague.

0 votes

Ne pas mentionner que cela va explicitement à l'encontre des règles sur plusieurs domaines, il s'agit de "programmation et développement de logiciels" et vous demandez un produit ou une recommandation plutôt que comment utiliser un produit spécifique.

232voto

Damian Powell Points 315

Cela affichera le décalage et les octets en hexadécimal :

cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'

Ou effectuez $1-1 pour que le premier décalage imprimé commence à 0.

cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'

Malheureusement, strtonum() est spécifique à GAWK, donc pour d'autres versions de awk, par exemple mawk, vous devrez utiliser une fonction de conversion octale en décimale. Par exemple,

cmp -l file1.bin file2.bin | mawk 'function oct2dec(oct,     dec) {for (i = 1; i <= length(oct); i++) {dec *= 8; dec += substr(oct, i, 1)}; return dec} {printf "%08X %02X %02X\n", $1, oct2dec($2), oct2dec($3)}'

Organisé pour la lisibilité :

cmp -l file1.bin file2.bin |
    mawk 'function oct2dec(oct,    dec) {
              for (i = 1; i <= length(oct); i++) {
                  dec *= 8;
                  dec += substr(oct, i, 1)
              };
              return dec
          }
          {
              printf "%08X %02X %02X\n", $1, oct2dec($2), oct2dec($3)
          }'

3 votes

@gertvdijk: strtonum est spécifique à GAWK. Je crois qu'Ubuntu utilisait précédemment GAWK par défaut, mais a changé à un moment donné à mawk. En tout cas, GAWK peut être installé et défini comme étant le choix par défaut (voir aussi man update-alternatives). Consultez ma réponse mise à jour pour une solution qui ne nécessite pas strtonum.

0 votes

Pourquoi ne pas simplement comparer le sha256sum des deux fichiers?

2 votes

@Rodrigo : Cela, ainsi que divers autres méthodes, montrera simplement si les fichiers diffèrent. Ma réponse répond à l'exigence de l'OP de montrer réellement quelles sont les différences.

230voto

akira Points 58339

Comme ~quack l'a souligné :

 % xxd b1 > b1.hex
 % xxd b2 > b2.hex

Et ensuite

 % diff b1.hex b2.hex

ou

 % vimdiff b1.hex b2.hex

97 votes

En Bash : diff <(xxd b1) <(xxd b2) mais le format de sortie de ceci (ou du vôtre) est loin de ce que l'OP a demandé.

12 votes

Avec vimdiff, cela colorera les octets dans les lignes où les deux 'fichiers' diffèrent.

0 votes

Aww, pourquoi n'y ai-je pas pensé ? Et je suis sûr d'avoir déjà utilisé cette technique par le passé aussi.

163voto

kenorb Points 22006

diff + xxd

Essayez diff dans la combinaison suivante de substitution de processus zsh/bash :

diff -y <(xxd foo1.bin) <(xxd foo2.bin)

Où :

  • -y vous montre les différences côte à côte (facultatif).
  • xxd est un outil en ligne de commande pour créer une sortie hexadécimale du fichier binaire.
  • Ajoutez -W200 à diff pour une sortie plus large (de 200 caractères par ligne).
  • Pour les couleurs, utilisez colordiff comme indiqué ci-dessous.

colordiff + xxd

Si vous avez colordiff, cela peut colorer la sortie de diff, par exemple :

colordiff -y <(xxd foo1.bin) <(xxd foo2.bin)

Sinon, installez via : sudo apt-get install colordiff.

Exemple de sortie :

sortie de fichier binaire dans le terminal - diff -y <(xxd foo1.bin) <(xxd foo2.bin) | colordiff

vimdiff + xxd

Vous pouvez également utiliser vimdiff, par exemple

vimdiff <(xxd foo1.bin) <(xxd foo2.bin)

Astuces :

  • si les fichiers sont trop volumineux, ajoutez une limite (par ex. -l1000) pour chaque xxd

12 votes

La commande peut être simplifiée comme colordiff -y <(xxd foo1.bin) <(xxd foo2.bin).

3 votes

Si vous n'avez pas colordiff, cela fera la même chose sans couleurs : diff -y <(xxd foo1.bin) <(xxd foo2.bin)

7 votes

Si vous voulez juste savoir si les deux fichiers sont en fait les mêmes, vous pouvez utiliser l'interrupteur -q ou --brief, qui ne montrera de sortie que lorsque les fichiers diffèrent.

68voto

njd Points 10568

Il existe un outil appelé DHEX qui pourrait faire l'affaire, et il y a un autre outil appelé VBinDiff.

Pour une approche strictement en ligne de commande, essayez jojodiff.

12 votes

DHEX est génial pour comparer des binaires si c'est ce que vous voulez faire. Alimentez-le avec deux fichiers et il vous emmène directement à une vue comparative, en mettant en évidence les différences, avec une facilité de déplacement vers la prochaine différence. De plus, il est capable de fonctionner avec de grands terminaux, ce qui est très utile sur les moniteurs grand format.

7 votes

Je préfère VBinDiff. DHEX utilise le processeur même en étant inactif, je pense qu'il redessine tout le temps ou quelque chose comme ça. VBinDiff ne fonctionne pas avec les terminaux larges cependant. Mais les adresses deviennent étranges avec les terminaux larges de toute façon, puisque vous avez plus de 16 octets par ligne.

2 votes

Vbindiff nous permet en fait de modifier le fichier, merci!

36voto

Méthode qui fonctionne pour l'ajout / la suppression de bytes

diff <(od -An -tx1 -w1 -v file1) \
     <(od -An -tx1 -w1 -v file2)

Générer un cas de test avec une suppression unique du byte 64 :

for i in `seq 128`; do printf "%02x" "$i"; done | xxd -r -p > file1
for i in `seq 128`; do if [ "$i" -ne 64 ]; then printf "%02x" $i; fi; done | xxd -r -p > file2

Sortie :

64d63
<  40

Si vous souhaitez également voir la version ASCII du caractère :

bdiff() (
  f() (
    od -An -tx1c -w1 -v "$1" | paste -d '' - -
  )
  diff <(f "$1") <(f "$2")
)

bdiff file1 file2

Sortie :

64d63
<   40   @

Testé sur Ubuntu 16.04.

Je préfère od à xxd car :

  • il est POSIX, xxd ne l'est pas (livré avec Vim)
  • possède l'option -An pour supprimer la colonne d'adresse sans utiliser awk.

Explication des commandes :

  • -An supprime la colonne d'adresse. Ceci est important sinon toutes les lignes différeraient après un ajout / retrait de byte.
  • -w1 met un byte par ligne, afin que diff puisse le traiter. Il est crucial d'avoir un byte par ligne, sinon chaque ligne après une suppression serait décalée et différente. Malheureusement, ce n'est pas POSIX, mais présent dans GNU.
  • -tx1 est la représentation que vous souhaitez, changez-la à n'importe quelle valeur possible, tant que vous gardez 1 byte par ligne.
  • -v empêche l'abréviation de répétition d'astérisque * qui pourrait interférer avec le diff
  • paste -d '' - - joint chaque deux lignes. Nous en avons besoin car les hexadécimaux et l'ASCII vont dans des lignes adjacentes séparées. Tiré de : https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
  • nous utilisons des parenthèses () pour définir bdiff au lieu de {} pour limiter la portée de la fonction interne f, voir aussi : https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash

Voir aussi :

1 votes

Le bon côté de cette méthode est que od est extrêmement puissant. En particulier, cela permet de comparer des objets plus longs qu'un octet, par exemple, des nombres flottants sur 32 bits. Exemple : diff -u <(od -tf4 -w1 fileA.bin) <(od -tf4 -w1 fileB.bin).

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X