hexdump 命令

一点感想:自从学习 Shell 脚本编程以来,有时候会觉得,使用图形化界面的工具实现一个稍微复杂的操作过于麻烦,并且如果你学习过 Vim 的基本操作和哲学思想后,就会了解命令行的组合可以比图形界面上有限的菜单,按钮能做更过的事情,即实现高度的定制化。

简单介绍

hexdump 工具可以将指定的文件或标准输入,以用户指定的格式进行展示,打印到控制台,提供了很多选项(options),如打印出对应字符的八进制,十六进制

基本选项

-b 八进制

1
-b One-byte octal display.  Display the input offset in hexadecimal, followed by sixteen space-separated, three column, zero-filled, bytes of input data, in octal, per line.

每行首先以十六进制展示输入偏移量,然后将输入的每个字节以八进制展示 (占 3 位,不足 3 位的用 0 填充),并以空格分隔

1
2
3
4
$ echo -n 'hello' | hexdump -b

0000000 150 145 154 154 157
0000005

-c 字符

1
-c      One-byte character display.  Display the input offset in hexadecimal, followed by sixteen space-separated, three column, space-filled, characters of input data per line.

每行首先以十六进制展示输入偏移量,然后展示输入的每个字符 (占 3 位,不足 3 位的用空格填充),并以空格分隔

1
2
3
$ echo -n 'hello' | hexdump -c
0000000 h e l l o
0000005

-C 十六进制+ASCII字符

1
-C Canonical hex+ASCII display.  Display the input offset in hexadecimal, followed by sixteen space-separated, two column, hexadecimal bytes, followed by the same sixteen bytes in %_p format enclosed in ``|'' characters.

每行首先以十六进制展示输入偏移量,然后展示每个字节的十六进制,随后是包含在两个 | 中的对应的字符,非打印字符以 . 展示

1
2
3
$ echo -n 'hello' | hexdump -C
00000000 68 65 6c 6c 6f |hello|
00000005

-C 选项应该是比较常用的,比较方便对比字符与对应的十六进制

-d 两个字节的十进制

1
-d      Two-byte decimal display.  Display the input offset in hexadecimal, followed by eight space-separated, five column, zero-filled, two-byte units of input data, in unsigned decimal, per line.

每行首先以十六进制展示输入偏移量,然后将输入数据中的每两个字节作为一个单元,并展示他们组合成的无符号十进制数

1
2
3
$ echo -n 'hello' | hexdump -d
0000000 25960 27756 00111
0000005

注意:两个字节组合的顺序与字符的顺序相反,例如 he, h 的十六进制是 0x68e 的十六进制是 0x65, 但是字节组合的顺序是 0x6568, 对应的十进制就是上面结果中的 2590

1
2
$ echo $((16#6568))
25960

-x 两个字节的十六进制

1
-x      Two-byte hexadecimal display.  Display the input offset in hexadecimal, followed by eight, space separated, four column, zero-filled, two-byte quantities of input data, in hexadecimal, per line.

-d 类似

1
2
3
$ echo -n 'hello' | hexdump -x
0000000 6568 6c6c 006f
0000005

-n 只处理 n 个字节

1
-n length Interpret only length bytes of input.

-v 展示所有的字符

1
2
-v      Cause hexdump to display all input data.  Without the -v option, any number of groups of output lines, which would be identical to the immediately preceding group of output lines (except for the input offsets), are
replaced with a line comprised of a single asterisk.

格式化

-e 格式化字符串

1
2
-e format_string
Specify a format string to be used for displaying data.

指定格式化字符串

-f 包含格式化字符串的文件

1
2
-f format_file
Specify a file that contains one or more newline separated format strings. Empty lines and lines whose first non-blank character is a hash mark (#) are ignored.

一个格式化字符串由任意多个格式化单元(format unit)组成,每个格式化单元以空格分隔。一个格式化单元最多由三个部分组成:迭代次数(iteration count),字节个数 (byte count),以及格式字符串 (format)

迭代次数:可选的正整数,默认为1, 表示格式字符串要被应用多少次

字节个数: 可选的正整数. 如果指定了,它定义了每次应用格式字符串时,需要使用多少个字节

​ 如果指定了迭代次数和(或)字节个数,需要使用 / 来加以区分,如 1/4/4

格式字符串:必须指定,并且要包含在双引号中 "", 类似于 fprintf 中的格式字符串, 支持单个字符的转义序列:

1
2
3
4
5
6
7
8
NUL                  \0
<alert character> \a
<backspace> \b
<form-feed> \f
<newline> \n
<carriage return> \r
<tab> \t
<vertical tab> \v

如包含一个格式化单元的格式化字符串:'4/1 "%_p"' , 4 表示迭代次数,1表示每次使用一个字节,%_p 为格式字符串

也支持额外的转换字符串:

  • _a[dox] 展示输入偏移量 d,o,x 分表表示十进制,八进制和十六进制

  • _A[dox]_a[dox] 行为一致,但是只执行一次,当所有的输入数据都被处理了

  • _c 以默认的字符集打印出输入字符,非打印字符以八进制展示(占 3 位,不足三位用 0 填充),如果该字符支持转义序列,则会以转义序列的形式展示,如 \n

  • _p 以默认的字符集打印出输入字符. 非打印字符会被展示成 .

  • _u 打印出 ASCII 字符,控制字符会被展示成如下的名称(小写):

1
2
3
4
5
6
000 NUL  001 SOH  002 STX  003 ETX  004 EOT  005 ENQ
006 ACK 007 BEL 008 BS 009 HT 00A LF 00B VT
00C FF 00D CR 00E SO 00F SI 010 DLE 011 DC1
012 DC2 013 DC3 014 DC4 015 NAK 016 SYN 017 ETB
018 CAN 019 EM 01A SUB 01B ESC 01C FS 01D GS
01E RS 01F US 07F DEL

每个格式字符串需要使用字节个数等于所有格式化单元使用的字节个数加起来,每个格式化单元使用的字节个数 = 迭代次数 * 字节个数 (或者没有指定字节个数,格式单元需要的字节个数)

1
echo "ABCDEFGH" | hexdump -e '4/1 "%_p"'

上述中的格式化字符串需要使用的字节个数 = 4 * 1

输入数据,是以 “数据块”(blocks) 的形式处理的,一个数据块定义为所有格式化字符使用的最大字节数

指定格式化字符串的列子

打印输入数据的十六进制

1
2
3
$ echo hello | hexdump -v -e '/1 "%02X "' ; echo

68 65 6C 6C 6F 0A

打印输入数据的十六进制及字符

1
2
3
% echo hello | hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"'

68 65 6C 6C 6F 0A hello

打印十六进制,并加上前缀 x

1
2
3
# hex with preceding 'x'
$ echo hello | hexdump -v -e '"x" 1/1 "%02X" " "' ; echo
x68 x65 x6C x6C x6F x0A

打印十六进制,每行一个字节

1
2
3
4
5
6
7
8
# one hex byte per line
$ echo hello | hexdump -v -e '/1 "%02X\n"'
68
65
6C
6C
6F
0A

带偏移量

1
2
3
4
5
6
7
8
# byte# & ASCII with control chars
$ echo hello | hexdump -v -e '/1 "%_ad# "' -e '/1 " _%_u\_\n"'
0# _h_
1# _e_
2# _l_
3# _l_
4# _o_
5# _lf_

每行只打印一个字节对应的十六进制,以及对应的 ASCII 字符,行首打印偏移量,即序号

1
2
3
4
5
6
7
8
9
10
11
12
$ echo "ABCDEFG" | hexdump -e '/1 "%02_ad#  "' -e '/1 "%02X "' -e '/1 " %_u\n"'
00# 41 A
01# 42 B
02# 43 C
03# 44 D
04# 45 E
05# 46 F
06# 47 G
07# 0A lf


# lf 表示 LF 换行符

7C1C分隔符示例

1
2
3
4
5
6
7
8
9
10
11
12
# char.dat
echo -e "A\u007c\u001cB\u007c\u001cC" > char.dat

cat char.dat | hexdump -v -e '"%02_ad#\t"' -e '/1 "0x%02X\t"' -e '/1 "%_p\n"'
00# 0x41 A
01# 0x7C |
02# 0x1C .
03# 0x42 B
04# 0x7C |
05# 0x1C .
06# 0x43 C
07# 0x0A .
1
2
3
4
5
6
7
8
# a table of byte#, hex, decimal, octal, ASCII
% echo hello | hexdump -v -e '/1 "%_ad# "' -e '/1 "%02X hex"' -e '/1 " = %03i dec"' -e '/1 " = %03o oct"' -e '/1 " = _%c\_\n"'
0# 68 hex = 104 dec = 150 oct = _h_
1# 65 hex = 101 dec = 145 oct = _e_
2# 6C hex = 108 dec = 154 oct = _l_
3# 6C hex = 108 dec = 154 oct = _l_
4# 6F hex = 111 dec = 157 oct = _o_
5# 0A hex = 010 dec = 012 oct = _