我发现 xxd 对于在终端中简单操作二进制数据来说非常好且方便。然而它有一个限制,即程序输出的所有地址都限制为 32 位。例如
root:/# xxd -s 0x5baae0000 /dev/sda
baae0000: 2d7c 6176 6976 6172 7c61 7469 7a61 720a -|avivar|atizar.
请注意,开头的 5 不见了。这意味着直接使用它xxd -r
最终会比我想要的早超过 100 亿字节的区域。换句话说,我想这样做,
root:/# echo HELLO | xxd -o 0x5baae0000 | xxd -r - /dev/sdb
但我最终不得不通过做这样的事情来解决这个问题,
root:/# echo HELLO | xxd -o 0x5baae0000 | xxd -r -seek 0x500000000 - /dev/sdb
它在解析补丁时将丢失的 0x5000000 字节偏移量添加回目标文件中。
无论如何,我想知道是否有一种未知/聪明的方法让 xxd 使用 64 位地址,或者有一个像 xxd 一样运行但没有这些限制的替代程序?
答案1
xxd
使用long
s 作为地址,但显式将其截断为 32 位似乎没有任何办法可以解决这个问题。那是vim 问题 #3791(感谢您的报告),现在已在补丁 8.1.0854 中修复。
然而,它似乎对输入没有限制(使用-r
),因此您可以使用标准od
来打印十六进制转储:
od -j 0x5baae0000 -Ax -vtx1 -N16 /dev/sda
这将输出类似的内容:
5baae0000 2d 7c 61 76 69 76 61 72 7c 61 74 69 7a 61 72 0a
5baae0010
但请注意,od
包括 GNU 在内的多种实现od
并没有寻找达到指定的偏移量,-j
但读取并跳过所有数据,这对于像您的情况这样的大型块设备来说是不切实际的。
或者,如果您关心 ASCII 方面,请使用 BSDhexdump
的
$ hexdump -ve '"%_ax:" 16/1 " %02x"' -e '" " 16 "%_p" "\n"' -s 0x5baae0000 -n 16 /dev/sda
5baae0000: 2d 7c 61 76 69 76 61 72 7c 61 74 69 7a 61 72 0a -|avivar|atizar
两者都可以喂食xxd -r
您实际上可以使用以下命令重现xxd
的输出格式(没有 32 位地址限制)hexdump
:
hexdump -ve '"%08_ax: " 2/1 "%02x"" " 2/1 "%02x"" " 2/1 "%02x"" " 2/1 "%02x"" "
2/1 "%02x"" " 2/1 "%02x"" " 2/1 "%02x"" " 2/1 "%02x"
' -e '" " 16/1 "%_p" "\n"'
也不od
支持hexdump
等效的xxd
's-o
来偏移地址,但您始终可以对其输出进行后处理,以将偏移量添加到地址字段,例如:
perl -pe 's/^\w+/sprintf "%08x", 0xabcdef + hex$&/e'
无论如何,要将特定偏移处的数据写入文件,您不需要xxd
,您可以使用dd
:
echo HELLO | dd bs=1 seek="$((0x5baae0000))" of=/dev/sda
或ksh93
>#((...))
寻求运营商:
echo HELLO 1<> /dev/sda >#((0x5baae0000))
orzsh
的sysseek
内置:
zmodload zsh/system
{
sysseek -u 1 $((0x5baae0000)) &&
echo HELLO
} 1<> /dev/sda
您还可以使用xxd
0 偏移量并使用 dd/ksh93/zsh 来执行寻求:
echo HELLO | xxd | { sysseek -u 1 $((0x5baae0000)) && xxd -r; } 1<> /dev/sda
或者:
echo HELLO | xxd | { dd bs=1 seek="$((0x5baae0000))" count=0 && xxd -r; } 1<> /dev/sda
¹ 看着来源,GNUod
使用fstat()
来获取输入的大小(而不是lseek(SEEK_END)
),以免搜索到文件末尾,这在像 Linux 这样st_size
不反映块设备大小的系统上不适用于块设备