你好!在去年花了一些时间研究 Git 手册页之后,我一直在思考一个问题:怎样才算一个好的手册页。

我花了很多时间为一些工具(如 tcpdump、git、dig 等)编写速查表,而这些工具的主要文档就是手册页。之所以这样做,是因为我经常发现手册页难以快速找到我想要的信息。

最近我一直在想——手册页本身能不能包含一个超棒的速查表?怎样才能让手册页更容易使用?我对这个问题的思考还处于非常初期的阶段,但我想先记下一些零散的想法。

我在 Mastodon 上问了一些人他们最喜欢的手册页,下面是一些在这些手册页中看到的很有意思的例子。

选项摘要

如果你读过很多手册页,你可能在 SYNOPSIS 部分见过类似这样的内容:一旦你几乎列出了整个字母表,就会变得很难看

ls [-@ABCFGHILOPRSTUWabcdefghiklmnopqrstuvwxy1%,]

grep [-abcdDEFGHhIiJLlMmnOopqRSsUVvwXxZz]

rsync 手册页有一个我以前从未见过的解决方案:它的 SYNOPSIS 非常简洁,像这样:

 本地:
     rsync [选项...] 源... [目标]

然后有一个“选项摘要”部分,每个选项都有一行摘要,像这样:

--verbose, -v            增加详细程度
--info=FLAGS             细粒度信息详细程度
--debug=FLAGS            细粒度调试详细程度
--stderr=e|a|c           更改 stderr 输出模式(默认:errors)
--quiet, -q              抑制非错误消息
--no-motd                抑制守护进程模式下的 MOTD

后面再是通常的 OPTIONS 部分,对每个选项进行完整描述。

按类别组织的选项部分

strace 手册页 按类别(如“通用”、“启动”、“跟踪”、“过滤”、“输出格式”)组织其选项,而不是按字母顺序。

作为实验,我尝试拿 grep 手册页,制作一个按类别分组的“选项摘要”部分,你可以在这里看到结果。我不确定我对结果怎么看,但这确实是个有趣的练习。在写的时候,我一直在想,我总记不住 grep-l 选项叫什么名字。每次在手册页里找到它,我都感觉花了很长时间,我试图思考什么样的结构能让我更容易找到它。也许分类是个办法?

速查表

有几个人向我推荐了 Perl 手册页系列(perlfuncperlre 等),我注意到的一个东西是 man perlcheat,它有这样的速查表部分:

 语法
 foreach (列表) { }     for (a;b;c) { }
 while   (e) { }        until (e)   { }
 if      (e) { } elsif (e) { } else { }
 unless  (e) { } elsif (e) { } else { }
 given   (e) { when (e) {} default {} }

我觉得这太酷了,这让我想知道是否还有其他方法可以在手册页中编写紧凑的、80 字符宽的 ASCII 速查表。

示例非常受欢迎

常见的评论大意是“我喜欢任何带示例的手册页”。有人提到了OpenBSD的手册页,而openbsd tail手册页末尾就提供了我常用的两种tail用法的示例。

我见过最多的情况是手册页的示例部分放在末尾,但有些手册页(比如之前的rsync手册页)会把示例放在开头。我在编写git-addgit rebase手册页时,就在开头放了一个简短示例。

目录与章节间的链接

这并非手册页本身的特性,但终端中查看手册页的一个问题是难以了解它包含哪些章节。

在编写Git手册页时,我和Marie做的一件事是给Git网站上HTML版本手册页的侧边栏添加目录

我还想在Git手册页的HTML版本中添加更多超链接,这样你可以点击“不兼容选项”直接跳转到对应章节。在Git项目中添加这类链接非常容易,因为Git的手册页是用AsciiDoc生成的。

我认为添加目录和内部超链接是一种不错的折中方案——既能改进手册页格式(至少是HTML版本),又无需维护完全不同的文档形式。不过要实现这一点,你需要搭建类似Git的AsciiDoc工具链。

如果能有一种通用系统,让人轻松查找手册页中的特定选项(比如“-a是做什么的?”),那就太棒了。我知道最好的技巧是用手册页阅读器搜索类似^ *-a的内容,但我总记不住这么做,最后只能遍历手册页中所有-a实例,直到找到目标内容。

每个选项的示例

curl手册页为每个选项都提供了示例,HTML版本还带有目录,方便你快速跳转到感兴趣的选项。

例如,--cert的示例能让你直观看到可能还需要传递--key选项,就像这样:

  curl --cert certfile --key keyfile https://example.com

他们的实现方式是:每个选项对应[一个文件](https://github.com/curl/curl/blob/dc08922a61efe546b318daf964514ffbf41583 25/docs/cmdline-opts/append.md),文件中包含“示例”字段。

表格化数据格式

不少人说man ascii是他们最喜欢的手册页,它看起来是这样的:

 Oct   Dec   Hex   Char
 ───────────────────────────────────────────
 000   0     00    NUL '\0' (空字符)
 001   1     01    SOH (标题开始)
 002   2     02    STX (正文开始)
 003   3     03    ETX (正文结束)
 004   4     04    EOT (传输结束)
 005   5     05    ENQ (询问)
 006   6     06    ACK (确认)
 007   7     07    BEL '\a' (响铃)
 010   8     08    BS  '\b' (退格)
 011   9     09    HT  '\t' (水平制表符)
 012   10    0A    LF  '\n' (换行)

显然 man ascii 是一份不寻常的手册页,但我认为这份手册页的酷炫之处(除了它作为 ASCII 参考始终有用之外)在于,由于表格格式,你很容易快速扫描找到所需信息。这让我思考,是否还有更多机会在手册页中以“表格”形式展示信息,以便于快速浏览。

GNU 的做法

当我谈论手册页时,经常有人提到 GNU coreutils 的手册页(例如 man tail)没有示例,而 OpenBSD 的手册页则包含示例

我不打算深入探讨这个问题,因为这似乎是一个颇具争议的话题,我肯定无法在此充分讨论,但我认为以下几点是事实:

  • GNU 项目更倾向于在“info”手册中维护文档,而不是手册页。这个页面指出“手册页已不再维护”。
  • 阅读“info”手册有三种方式:HTML 版本、在 Emacs 中阅读,或使用独立的 info 工具。我听说一些 Emacs 用户喜欢 Emacs 的 info 浏览器。但我从未遇到过使用独立 info 工具的人。
  • tail 的 info 手册条目链接在手册页底部,并且其中包含示例。
  • FSF 曾经出售 GNU 软件手册的印刷版书籍(也许他们偶尔还会这样做?)。

当复杂度达到一定程度后,手册页会变得难以导航:虽然我从未使用过 coreutils 的 info 手册,将来可能也不会,但我几乎肯定会更倾向于通过 HTML 文档来查阅 GNU Bash 参考手册GNU C 库参考手册,而不是通过手册页。

其他几个与手册页相关的内容

以下是一些我觉得有趣的工具:

  • fish shell 附带一个 Python 脚本,用于从手册页自动生成 Tab 补全。
  • tldr.sh 是一个由社区维护的示例数据库,例如你可以运行 tldr grep。很多人告诉我他们觉得它很有用。
  • Dash Mac 文档浏览器内置了不错的手册页查看器。我仍然使用终端手册页查看器,但我喜欢它包含目录,看起来像这样:

思考受限格式是件有趣的事

man pages 的格式限制非常严格,思考在如此有限的排版选项中能做什么,其实挺有意思的。

尽管我非常喜欢写作,但一直有个坏习惯——从不读文档,所以对我来说,要判断自己到底觉得 man pages 里什么内容有用,其实有点难。我不太确定这篇文章里提到的大部分改进,是否真的能提升我的使用体验。(不过示例除外,我超爱示例!)

所以我很想听听,你觉得还有哪些 man pages 设计得很好,以及你喜欢它们的哪些地方。评论区在这里