od—最奇特的文本实用程序

作者:Randy Zack

假设您正在为 Linux 编写下一个伟大的电子表格程序,并且进展顺利。您有一个程序可以编辑单元格、格式化屏幕,并完成所有真正好的电子表格功能。您甚至可以将工作表保存在用户指定的文件中。但是,当您更改文件格式后,您意识到需要逐字节检查文件,以确定上次更改出了什么问题。您知道 Emacs 可以显示该文件,但您不记得确切如何进入十六进制模式,或者进入后该怎么做。

或者假设您正在为自己喜欢的文字处理器编写查看器程序,该程序仅在您第二喜欢的操作系统(WINE 和 DOSEMU 除外)下运行。因此,您需要弄清楚 .wpd 文件中每个二进制代码到底是什么,这样您就可以通过试错法确定每个二进制代码的作用。(试错过程将会是多么漫长。)

或者,也许您对当 curses 程序定位光标时发送到终端的确切转义序列感到好奇。(也许这个例子有点牵强,但仍然很有趣。)

如果以上任何一种情况描述了您当前的困境,那么 od 正是适合您的实用程序。od 代表八进制转储(Octal Dump),因为它在计算机用户开始使用十六进制表示一切之前就已命名,并且因为它可以将文件(二进制或非二进制)转储为您能想到的几乎任何形式。

那么,让我们看看 od 可以做什么。最容易尝试的事情是获取 od 自身的八进制转储。列表 1 显示了命令 od `which od` 输出的前 6 行。关于此示例,有几点需要注意。(注意:我使用的是较旧的 a.out 版本的 od,因此这可能与您在系统上看到的完全不同。)为了解释,第一列是文件中的“偏移量”,其余列是文件中的实际数据。

关于此列表,有三点需要注意。首先,所有数字都是八进制或以 8 为基数的。据我所知,现在没有人再使用八进制记数法了。当然,对于 GNU 版本的 od,有一些选项可以更改所有内容的显示方式——稍后会详细介绍。

其次,所有数字都是 16 位宽。由于 Linux 是一个 32 位操作系统,这可能不是您想要的。同样,有一些方法可以修改此行为。

第三,输出的第三行包含一个单独的 *。这是 od 表示有很多行与前一行完全相同,但已从输出中删除的方式。然后,它在偏移量(八进制)2000 处继续输出,这是与前一行不同的第一行。(您能猜到这种行为也可以修改吗?它可以。)

如前所述,od 有许多选项用于格式化输出。首先要提到的是 -t xS-t xL,这将使输出以十六进制(以 16 为基数)显示。SL 修饰符告诉 od 一次读取 16 位 (S) 或 32 位 (L)。对于所有 C 程序员来说,是的,这些修饰符代表“short”(短整型)和“long”(长整型)。还有其他修饰符,并且可以在 od 的手册页中找到对它们的良好描述。列表 2 显示了命令输出的前六行

od -t xS `which od`

od 也可以输出文件的字符。如果您想进行一些比较,可以将十六进制输出与字符输出穿插显示。只需在命令行中同时给出这两种类型即可(参见列表 3),如下所示:

od -t xS -t c `which od`

关于此示例,有几点需要注意。字符类型参数不接受大小修饰符——它们一次只读取一个字符。这就是为什么我们使用 -t c 而不是 -t cS

此外,字符数据的排序看起来很奇怪。十六进制转储中的前 4 个字节是 010b 0064,而字符转储中的前 4 个字节是 \v 001 d \0。这是因为我的 Linux 机器运行在基于 Intel 的芯片组上,它是一个小端架构。其他架构的打印方式会有所不同。事实上,这是我所知道的确定您运行的机器是大端还是小端的最简单方法。确定此情况的实际命令类似于

echo abcd | od -t xS

小端机器将输出

0000000 6261 6463 000a
而大端机器将输出
0000000 6162 6364 0a00
我还没有真正见过 Linux 在 SPARC 或 DEC Alpha 芯片上运行;我猜这些 Linux 系统将是大端的。

让我们回到最后一个例子。请注意,最后一个例子的字符输出中有很多反斜杠。这是 od 用来表示它尝试打印的字符实际上不是可打印字符的一种方法。另一种方法是以八进制显示字符。第一种方法的示例是 \v\0 以及(在偏移量 2024 处)。第二种方法的示例是 001315(分别在偏移量 0001 和 2017 处)。(偏移量仍然是十六进制——我们正在解决这个问题。)

如果您真的讨厌八进制,并且想以不同的基数查看偏移量,od 允许这样做。选项是 -A x 以十六进制查看偏移量,或 -A d 以十进制显示偏移量。(不要再展示这些命令的列表了——直接做吧。)

您可能已经注意到 od 始终每行显示 16 个字节。当然,您也可以使用 -w 选项更改此设置。-w 标志后面的参数是读取的字节数,然后输出一行文本。在没有 -w 标志的情况下,默认值为 16(您可以从所有示例中看到)。带 -w 标志的默认值(即 -w 本身)为 32。不幸的是,我无法在我的机器上使此选项正常工作。我给出的每个数字(-w20、-w18、-w16)都导致 od 报告“无效的宽度规范”。(我使用的是 GNU textutils 版本 1.9,仅供参考。)

有时您想查看整个文件,而不是抑制任何输出。-v 选项告诉 od 不要跳过任何行,并输出所有内容。如果您需要比较两个不同的二进制文件,并且您想比较文件中的实际字节,而不跳过任何输出,这将非常有用。

最后,所有这些选项都有长格式,这与 GNU 实用程序标准相同。例如,-v 开关可以扩展为 --output-duplicates。我倾向于在脚本中使用长格式,以便其他人清楚地了解我发送给程序的选项,而在我只是工作时使用短格式。

那么,您究竟如何查看当 curses 程序定位光标时发送到终端的转义序列呢?尝试命令

tput cup 10 10 | od -t c

Randy Zack 的电子邮箱是 randy@acucobol.com。

加载 Disqus 评论