How do I compare binary files in Linux?
--
Track title: CC D Schuberts Piano Sonata D 850 in D
--
Chapters
00:00 Question
00:55 Accepted answer (Score 250)
01:51 Answer 2 (Score 255)
02:09 Answer 3 (Score 188)
03:31 Answer 4 (Score 75)
03:49 Thank you
--
Full question
https://superuser.com/questions/125376/h...
Question links:
[cmp -l]: https://man7.org/linux/man-pages/man1/cm...
Answer 2 links:
[image]: https://i.stack.imgur.com/v1fw3.png
Answer 3 links:
[DHEX]: http://www.dettus.net/dhex/
[VBinDiff]: http://www.cjmweb.net/vbindiff/
[jojodiff]: http://jojodiff.sourceforge.net/
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#linux #diff #binaryfiles
#avk47
ANSWER 1
Score 288
As ~quack pointed out:
% xxd b1 > b1.hex
% xxd b2 > b2.hex
And then
% diff b1.hex b2.hex
or
% vimdiff b1.hex b2.hex
ACCEPTED ANSWER
Score 269
This will print the offset and bytes in hex:
cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'
Or do $1-1 to have the first printed offset start at 0.
cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'
Unfortunately, strtonum() is specific to GAWK, so for other versions of awk—e.g., mawk—you will need to use an octal-to-decimal conversion function. For example,
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)}'
Broken out for readability:
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)
}'
ANSWER 3
Score 83
There's a tool called DHEX which may do the job, and there's another tool called VBinDiff.
For a strictly command-line approach, try jojodiff.
ANSWER 4
Score 52
diff + od method that works for byte addition / deletion
diff <(od -An -tx1 -w1 -v file1) \
<(od -An -tx1 -w1 -v file2)
which you may want to alias in Bash as:
bdiff() {
diff <(od -An -tx1 -w1 -v "$1") \
<(od -An -tx1 -w1 -v "$2")
}
Generate a test case with a single removal of 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
Output:
64d63
< 40
If you also want to see the ASCII version of the character:
bdiff() (
f() (
od -An -tx1c -w1 -v "$1" | paste -d '' - -
)
diff <(f "$1") <(f "$2")
)
bdiff file1 file2
Output:
64d63
< 40 @
Tested on Ubuntu 16.04.
I prefer od over xxd because:
- it is POSIX,
xxdis not (comes with Vim) - has the
-Anto remove the address column withoutawk.
Command explanation:
-Anremoves the address column. This is important otherwise all lines would differ after a byte addition / removal.-w1puts one byte per line, so that diff can consume it. It is crucial to have one byte per line, or else every line after a deletion would become out of phase and differ. Unfortunately, this is not POSIX, but present in GNU.-tx1is the representation you want, change to any possible value, as long as you keep 1 byte per line.-vprevents asterisk repetition abbreviation*which might interfere with the diffpaste -d '' - -joins every two lines. We need it because the hex and ASCII go into separate adjacent lines. Taken from: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next- we use parenthesis
()to definebdiffinstead of{}to limit the scope of the inner functionf, see also: https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash
See also: