如何在Bash中创建一个只包含十六进制字符且没有空格的文件十六进制转储?

233

如何在Linux使用Bash创建一个未修改二进制文件的十六进制转储?odhexdump命令都会在转储中插入空格,这并不理想。

是否有一种方法可以简单地写入一个长字符串,其中包含所有十六进制字符,但输出中没有空格或换行符?


9个回答

300
xxd -p file

或者如果你想在一行上显示所有内容:

xxd -p file | tr -d '\n'

19
逆转此过程:使用命令"xxd -r -ps hexascii.txt file" (无论是否包含换行符都可以)。 - Curtis Yallop

120

格式化字符串可以使得十六进制转储的行为完全符合你的需求(没有任何空格,每个字节单独显示):

hexdump -ve '1/1 "%.2x"'

1/1 的意思是“每种格式都应用一次,并占用一个字节”,"%.2x" 是实际的格式字符串,就像在 printf 中一样。在此情况下:2字符十六进制数,如果较短,则前导零。


9
你需要加上"-v"参数,否则它会删除重复的字节并用星号替换它们。 - Dennis Williamson
2
我想知道hexdump本身是否能够将换行符(仅)附加到输出的末尾..(显然的附加;echo使其无法用作bash别名) - mykhal
3
我的别名是:alias to_hex="hexdump -ve '1/1 \"%.2x\"' && echo"。该命令表示将别名to_hex绑定到一个操作中,该操作使用hexdump命令将输入的数据转换为十六进制格式,并使用echo命令将结果打印到屏幕上。 - devstuff
迭代计数和字节计数默认为1,因此可以省略1/1,只留下hexdump -ve '"%.2x"' - Alex Che
@mykhal,如果您知道输出中的字节数,那么这是可能的。比如说,如果您使用hexdump仅输出前13个字节:hexdump -n 13 -e '13/1 "%.2x" "\n"' - Alex Che
1
您可以使用 xdd -p -r < dump > file 将此输出反转回二进制。 - dagelf

29

似乎取决于 od 版本的细节。在OSX上,使用以下命令:

od -t x1 -An file |tr -d '\n '

(这将以十六进制字节形式打印,不包括地址。当然,之后会删除空格。)

3
在这种情况下,我还会补充 -v 参数,否则它将跳过带有 * 的重复项。 - Ciro Santilli OurBigBook.com

12

Perl一行命令:

perl -e 'local $/; print unpack "H*", <>' file

1
已验证。匹配 "xxd -p file | tr -d '\n'"。 - Curtis Yallop
1
提示:要执行反转操作,请使用以下 Perl 命令:perl -e 'local $/; print pack "H*", <>' <hexascii.txt >file - Curtis Yallop
“local $/” 是不必要的。 - Curtis Yallop
更新最后一条评论:对于“pack”,“local $ /”是不必要的。对于“unpack”,您需要它,但可以选择放置“undef $ /”。$ /是行分隔符(默认为NL)。未定义将其放入 slurp 模式。因此,在字符串上下文中引用<>会将整个二进制文件提取而不将其解析为行。 - Curtis Yallop
1
反转的另一种形式2(十六进制ASCII码转二进制),删除任何换行符(xxd -ps -r会添加它们):perl -pe 's/\n//g; $=pack "H*", $' <hexascii.txt >file - Curtis Yallop
显示剩余2条评论

4

你可以使用Python来实现这个目的:

python -c "print(open('file.bin','rb').read().hex())"

...其中file.bin是您的文件名。

说明:

  1. rb(读取二进制)模式打开file.bin
  2. 读取内容(返回bytes对象)。
  3. 使用bytes方法.hex(),它返回没有空格或换行符的十六进制转储。
  4. 打印输出。

3

其他答案更为优选,但对于纯Bash解决方案,我修改了这里的答案中的脚本,使其能够输出连续流的十六进制字符,代表文件的内容。(它的普通模式是模拟hexdump -C。)


2
简述;
$ od -t x1 -A n -v <empty.zip | tr -dc '[:xdigit:]' && echo 
504b0506000000000000000000000000000000000000
$

说明:

使用od工具打印单个十六进制字节(-t x1)---没有地址偏移量(-A n)和没有省略重复的“组”(-v) ---从已重定向到标准输入的empty.zip文件中。将其导入tr,删除(-d)十六进制字符集('[:xdigit:]')的补集(-c)。您可以选择像我在这里所做的那样打印一个尾随换行符(echo),以将输出与下一个shell提示分开。

参考资料:


1
这段代码生成了一个“纯”的十六进制转储字符串,并且比给出的所有其他示例都运行得更快。它已经在填充了二进制零和所有换行符的1GB文件上进行了测试。它不依赖于数据内容,而是读取1MB的记录,而不是按行读取。
perl -pe 'BEGIN{$/=\1e6} $_=unpack "H*"'

数十次定时测试表明,对于1GB的文件,以下这些方法速度较慢。所有测试都是将输出写入文件,然后通过校验和进行验证。测试了三个1GB的输入文件:所有字节、所有二进制零和所有LF。
hexdump -ve '1/1 "%.2x"'                    #  ~10x  slower
od -v -t x1 -An | tr -d "\n "               #  ~15x  slower
xxd -p | tr -d \\n                          #   ~3x  slower
perl -e 'local \$/; print unpack "H*", <>'  # ~1.5x  slower
- this also slurps the whole file into memory

要反转这个过程:

perl -pe 'BEGIN{$/=\1e6} $_=pack "H*",$_'

1

我认为这是最受支持的版本(只需要POSIX定义的trod行为):

cat "$file" | od -v -t x1 -A n | tr -d ' \n'

这段代码使用od将每个字节作为十六进制打印出来,不带地址,不跳过重复的字节,使用tr删除输出中所有空格和换行符。请注意,甚至连尾随的换行符都没有被输出。(意图使用cat是为了允许多核处理,其中cat可以等待文件系统,而od仍在处理之前读取的部分。单核用户可能需要将其替换为< "$file" od ...以减少启动一个额外进程的开销.)

不需要在这里使用“cat”,只需将文件名传递给“od”。 - Martin
我同意历史上连接标准输入被认为是更好的选择,对于单核心CPU来说仍然是正确的解决方案。然而,在现代系统中,单个插座CPU中有许多空闲核心,我认为允许cat并行读取管道缓冲区的输入比在任何时候都与od一起读取更好。这减少了od因读取文件而停顿的可能性。 - Mikko Rantalainen
我进行了一些微基准测试,似乎在开始使用cat确实允许并行使用多个CPU核心来执行任务,但实际上,核心之间的交互会导致额外的工作量,因此避免在管道开头使用cat仍然更快-至少对于本地可访问的文件而言。如果文件位于远程网络驱动器上且连接速度较慢,则在此处使用cat可以提高性能。话虽如此,od只能处理约4 MB / s,因此在大多数情况下它将成为瓶颈。 - Mikko Rantalainen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接