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 的方方面面都臭骂了一通), 现在我至少部分上与他们共情。