执行 echo -n 'abcdefghij' | hexdump
期望排列如下:
61 62 63 64 65 66 67 68 69 6a
然而实际结果非常奇怪:
$ echo -n 'abcdefghij' | hexdump 0000000 6261 6463 6665 6867 6a69 000000a
原因是 hexdump 默认是按字(一个字两个字节)展示,并且每个字按小端法排序,如下图:

不得不说这个默认的规则非常抽象,如何让 hexdump 按照我们期望的,一个字节一个字节按输入顺序展示呢?
查看 man 手册,发现 hexdump 提供了一个选项:-C(大写),表示按标准的十六进制外加 ASCII 小窗展示输入的内容:
$ echo -n 'abcdefghij' | hexdump -C 00000000 61 62 63 64 65 66 67 68 69 6a |abcdefghij| 0000000a
这便是我们期望的结果了。
可能因为默认的规则太过抽象,hexdump 还提供了一个缩写:hd,hd 等价于 hexdump -C,测试如下:
$ echo -n 'abcdefghij' | hd 00000000 61 62 63 64 65 66 67 68 69 6a |abcdefghij| 0000000a
可以看到结果是一样的。

哎,弄一个彩蛋给你!☝️🤓
前面提到 hexdump 还提供了一个缩写 hd,等价于 hexdump -C。
$ type hd hd is /usr/bin/hd $ file /usr/bin/hd /usr/bin/hd: symbolic link to hexdump $ ls -l /usr/bin/hd lrwxrwxrwx 1 root root 7 7月18日 12:41 /usr/bin/hd -> hexdump
查看了 hd 的文件类型,竟然是一个指向 hexdump 的符号链接,那这个符号链接又是怎么把 -C 参数带过去的呢?
点击查看答案
打开 util-linux 的源码,发现 hexdump.c 文件中 main 函数调用了 parse_args 函数,parse_args 函数部分源码如下:
int parse_args(int argc, char **argv, struct hexdump *hex) { // 其他无关代码 ... if (list_empty(&hex->fshead)) { if (!strcmp(program_invocation_short_name, "hd")) { /* Canonical format */ add_fmt("\"%08.8_Ax\n\"", hex); add_fmt("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ", hex); add_fmt("\" |\" 16/1 \"%_p\" \"|\\n\"", hex); } else { add_fmt(hex_offt, hex); add_fmt("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"", hex); } } colors_init (colormode, "hexdump"); return optind; }
原来 hexdump 判断了 program_invocation_short_name 这个变量名,当它的值为 hd 时做了特殊处理,果然高端的效果只需要朴素的 if。
program_invocation_short_name 的值是怎么来的?
program_invocation_short_name 是一个在 glibc 中定义的全局变量,用于获取当前运行程序的简短名称。这个变量包含了调用程序的基本名称,即路径中最后一个斜杠之后的部分。与之相对的是 program_invocation_name,它包含了完整的程序调用名称,包括路径信息。这两个变量在 errno.h
头文件中声明,并且可以通过定义宏 _GNU_SOURCE
来启用它们的使用,即
#define _GNU_SOURCE #include <errno.h> #include <stdio.h> int main(int argc, char *argv[]) { printf("program_invocation_name: %s\n", program_invocation_name); printf("program_invocation_short_name: %s\n", program_invocation_short_name); }
验证:自己随便在其他什么地方建个名字叫 hd 的符号链接指向 /usr/bin/hexdump 应该是一样的效果。
$ ln -s /usr/bin/hexdump ~/hd $ echo 'abcdefghijk' | /home/cui/hd 00000000 61 62 63 64 65 66 67 68 69 6a 6b 0a |abcdefghijk.| 0000000c
发表回复