我需要比较两个二进制文件并以以下形式获取输出
<文件偏移量十六进制> <文件 1 字节十六进制> <文件 2 字节十六进制>
对于每个不同的字节。因此file1.bin
如果
00 90 00 11
二进制file2.bin
形式
00 91 00 10
我想要得到类似的东西
00000001 90 91
00000003 11 10
在 Linux 中有没有办法做到这一点?我知道cmp -l
但是它使用十进制系统表示偏移量,使用八进制系统表示字节,这是我想避免的。
答案1
这将以十六进制打印偏移量和字节:
cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'
或者让$1-1
第一个打印偏移量从 0 开始。
cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'
不幸的是,strtonum()
这是 GAWK 独有的,因此对于其他版本的 awk(例如 mawk),您将需要使用八进制到十进制的转换函数。例如,
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)}'
为了便于阅读,分解如下:
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)
}'
答案2
作为~嘎嘎指出:
% xxd b1 > b1.hex
% xxd b2 > b2.hex
进而
% diff b1.hex b2.hex
或者
% vimdiff b1.hex b2.hex
答案3
diff
+xxd
尝试diff
在以下 zsh/bash 组合中进行进程替换:
diff -y <(xxd foo1.bin) <(xxd foo2.bin)
在哪里:
-y
并排显示差异(可选)。xxd
是用于创建二进制文件的十六进制转储输出的 CLI 工具。- 添加
-W200
以diff
获得更宽的输出(每行 200 个字符)。 - 对于颜色,请
colordiff
按如下所示使用。
colordiff
+xxd
如果你有colordiff
,它可以为输出着色diff
,例如:
colordiff -y <(xxd foo1.bin) <(xxd foo2.bin)
否则通过以下方式安装:sudo apt-get install colordiff
。
示例输出:
vimdiff
+xxd
您还可以使用vimdiff
,例如
vimdiff <(xxd foo1.bin) <(xxd foo2.bin)
提示:
- 如果文件太大,
-l1000
则为每个文件添加限制(例如)xxd
答案4
diff
+od
适用于字节添加/删除的方法
diff <(od -An -tx1 -w1 -v file1) \
<(od -An -tx1 -w1 -v file2)
你可能想在 Bash 中将其别名为:
bdiff() {
diff <(od -An -tx1 -w1 -v "$1") \
<(od -An -tx1 -w1 -v "$2")
}
生成一个删除第 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
输出:
64d63
< 40
如果您还想查看该字符的 ASCII 版本:
bdiff() (
f() (
od -An -tx1c -w1 -v "$1" | paste -d '' - -
)
diff <(f "$1") <(f "$2")
)
bdiff file1 file2
输出:
64d63
< 40 @
在 Ubuntu 16.04 上测试。
我od
更喜欢xxd
,因为:
- 它是 POSIX,
xxd
不是(Vim 自带) - 有
-An
删除地址栏的权限,无需awk
。
命令解释:
-An
删除地址列。这很重要,否则在添加/删除一个字节后,所有行都会有所不同。-w1
每行放一个字节,这样 diff 就可以使用它。每行一个字节至关重要,否则删除后的每一行都会变得不同步并且不同。不幸的是,这不是 POSIX,但在 GNU 中存在。-tx1
是您想要的表示形式,更改为任何可能的值,只要每行保留 1 个字节即可。-v
防止星号重复缩写*
,这可能会干扰差异paste -d '' - -
每两行连接一次。我们需要它,因为十六进制和 ASCII 位于不同的相邻行中。摘自:https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next- 我们使用括号
()
来定义bdiff
而不是{}
限制内部函数的范围f
,另请参阅:https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash
也可以看看: