time(1) 奇案, 或者我的 man page 在抽什么疯

今天算是体会到了 Unix hater handbook 里说的 man page 的糟糕之处了. 我稍微摆弄了一下 shell 里的 time(1). (btw, 这里用的是 zsh(1))

% where time
time: shell reserved word

time 并不是 PATH 中的可执行文件, 而是 shell 自带的. 这听上去还挺正常. 接下来就是事情变得糟糕的地方了.

% whereis time
time: /usr/share/man/man3p/time.3p.gz /usr/share/man/man1/time.1.gz /usr/share/man/mann/time.n.gz /usr/share/man/man3/time.3am.gz /usr/share/man/man7/time.7.gz /usr/share/man/man2/time.2.gz /usr/share/man/man1p/time.1p.gz

好多东西. 注意到 time(1) 了没有? 这其实有点奇怪. 因为 time 并不在 PATH 里. echo(1)printf(1) 有 GNU coreutils 的实现. cd 就只有 cd(1p). 而 man 1 time 里宣称:

Note: some shells (e.g., bash(1)) have a built-in time command that provides similar information on the usage of time and possibly other resources. To access the real command, you may need to specify its pathname (something like /usr/bin/time).

说得很好听, 但是我的电脑里没有 /usr/bin/time. 那这个 time(1) 的 man page 为什么会出现. 我姑且蒙在鼓里.

我们还能看到 time(1p). 所以看上去 time 是 POSIX standard shell 的一部分? 试试吧:

% dash -c time
dash: 1: time: not found

嗯哼? 不得不说 time 居然不是 POSIX standard shell 的一部分这件事确实让我很是震惊, 但更震惊的是: 既然 POSIX shell 没有这个函数, 干嘛要给我这个 man page 呀?

P.S. 事后我发现 time(1) 要额外安装, 在 community 仓库(yes, I use Arch btw), 当然是 GNU 的实现. 虽然说装上之后万事大吉, 但那鬼魅的 time(1) man page 还是像个幽灵般萦绕在我的心头. 更别提那个该死的 time(1p) 了.

让我们继续. 即使 dash 里没有 time, zsh 里总归是有的. time(1p) 提到了 time 适用参数有:

The following option shall be supported:

-p Write the timing output to standard error in the format shown in the STDERR section.

很不幸, zsh 中的 time 不接受这个参数:

% time -p nvim -es +"wq" 2>&1
zsh: command not found: -p
-p nvim -es +"wq" 2>&1  0.00s user 0.00s system 77% cpu 0.002 total

所以 zshtime 这方面并不是 POSIX 兼容的(???). Whatever, 我现在只想知道 zshtime 是怎么工作的. 直到这一步我才意识到 zsh 的 man pages 是多么的糟糕. 首先 man 1 zsh 并不能给你什么信息. 它只会告诉你再去找 zshbuiltins(1) 这个 man page 查找内置函数的相关信息. 这里我们在吐槽一下. zsh 的文档非常非常多而 且长. 如果你不太懂 shell, 那你甚至不知道要从哪找起 (man page 一些糟糕的功能缺失也导致最终用户查起命令来十分头大, 但那是另一个故事了). 事实上, zshbuiltins(1) 里并没有 time 的函数说明. 为什么呢?

% where cd
cd: shell built-in command

See? time 是和 if, for 一样的 shell 保留字而非内置函数. 所以当然查不到. 你需要去 zshmisc(1) 里找 time 的相关信息. 顺带一提, zshmisc(1) 的描述是:

% apropos zshmisc
zshmisc (1)          - everything and then some

太棒了. 我相信读文档的人一定能马上意识到这是关于 zsh 简单函数, 保留字, 管道的说明. 真是太浅显易懂了. 另外, zsh 还贴心地给出了 zshall(1) man page, i.e., 所有 zsh man page 的简单集合. 这样你就可以在一个几万行的 man page 里查找关键字, 而不是先猜这个关键字应该在哪个 zsh* 文档里. 谢谢你啊 zsh.

Anyway, 我找到了 time 的说明. 真好不是吗? 这还没完. 文档 (关于 time 的不超过 5 行) 告诉我, zshtime 格式遵从一个环境变量 TIMEFMT, 然后就没了. Wow. 于是我们又得在 zshparam(1) 里查找 TIMEFMT

我不得不指出 dashbash 的 man page 远远比 zsh 要整洁干净的多得多. 当然 这种比较不大公平: dash 功能简单而有限. bash 有自己的 texinfo 文档. 但这也不 是 zsh 把文档写得像迷宫一样的借口.

我怎么也没能想到仅仅是使用 time 会导向一个下午的研究, 查找, 与折磨. 这件事让我想起来 UNIX hater handbook 中对 UNIX man page 的种种挖苦 (那本书基本上把 UNIX 的方方面面都臭骂了一通), 现在我至少部分上与他们共情.