命令行界面准则

2020-12-21 15:34:25

开源指南,可帮助您编写更好的命令行程序,采用传统的UNIX原理并在现代进行更新。

Mark Hurrell设计。感谢Andreas Jansson的早期贡献,以及Andrew Reitz,Ashley Williams,Brendan Falk,Chester Ramey,Dj Walker-Morgan,Jacob Maine,James Coglan,Michael Dwan和Steve Klabnik的初稿。

在1980年代,如果您想让个人计算机为您做一些事情,那么您需要知道在遇到C:\ gt;时要键入什么内容。或〜$。帮助以厚厚的螺旋装订手册的形式出现。错误消息不透明。没有堆栈溢出来保存您。但是,如果您有幸能够访问Internet,可以从Usenet获得帮助。早期的互联网社区中充斥着与您一样沮丧的其他人,他们可以帮助您解决问题,或者至少提供一些道义上的支持和友善。

四十年后,计算机变得所有人都可以使用,这常常以低级最终用户控制为代价。在许多设备上,根本没有命令行访问权限,部分原因是它违反了公司的企业利益围墙花园和应用商店。

如今,大多数人不知道命令行是什么,更不用说为什么要打扰命令行了。正如计算先驱艾伦·凯(Alan Kay)在2017年的一次采访中所说:“由于人们不了解计算的含义,他们认为在iPhone上安装它,这种错觉与“吉他英雄”与真正的吉他相同的错觉一样糟糕。”

凯(Kay)的“真正的吉他”不是CLI,也不完全是CLI。他在谈论编程计算机的方法,这些计算机可以提供CLI的功能,并且可以超越在文本文件中编写软件的能力。基于我们已经生活了数十年的基于文本的局部最大值。

想象一个未来,我们对计算机进行编程的方式会非常令人兴奋。即使在今天,电子表格也是迄今为止最受欢迎的编程语言,无代码运动正在迅速兴起,因为它试图取代对有才华的程序员的某些强烈需求。

然而,由于其艰苦的工作,数十年的局限性和无法解释的怪癖,命令行仍然是计算机上功能最丰富的角落,它使您可以拉开帷幕,查看实际情况,并在一定程度上与计算机进行创造性的交互GUI无法承受的复杂性和深度。几乎任何笔记本电脑都可以使用它,任何想学习它的人都可以使用。它可以交互使用,也可以自动化,而且其变化速度不如系统的其他部分。 。其稳定性具有创造价值。

因此,尽管我们仍然拥有它,但我们应该尝试使其实用性和可访问性最大化。

自从早期以来,我们对计算机编程的方式发生了很多变化。过去的命令行是机器优先的:仅是脚本平台之上的REPL,但是随着通用解释语言的蓬勃发展, shell脚本缩水了。今天的命令行是人为本的:一个基于文本的UI,可以访问各种工具,系统和平台。过去,编辑器位于终端内部,而如今,终端就像通常是编辑器的功能,并且出现了类似git的多工具命令,包括命令内的命令以及执行整个工作流程而不是原子功能的高级命令。

受传统UNIX哲学的启发,出于对鼓励使用更令人愉悦和可访问的CLI环境的兴趣,并以我们作为程序员的经验为指导,我们决定是时候重新考虑构建命令行程序的最佳实践和设计原则了。

本文档涵盖了高级设计理念和具体准则。由于我们的实践者哲学不要过多地哲学化,因此准则上的内容要重一些。我们相信通过示例进行学习,因此我们提供了很多示例。

本指南未涵盖emacs和vim等全屏终端程序。全屏程序是利基项目,我们中很少有人能够设计一个。

如果要创建CLI程序,并且正在为其UI设计寻找原理和具体的最佳实践,则本指南适合您。

如果您是专业的“ CLI UI设计师”,那就太好了–我们很乐意向您学习。

如果您想避免与40年来的CLI设计惯例相抵触的错误,本指南非常适合您。

如果您想通过程序的良好设计和有用的帮助使人们满意,那么本指南绝对适合您。

如果要创建GUI程序,则本指南不适合您-尽管您仍然决定阅读它,则可能会学到一些GUI反模式。

如果您正在设计Minecraft的沉浸式全屏CLI端口,则本指南不适合您。(但我们迫不及待想看到它!)

传统上,UNIX命令是在假设它们将主要由其他程序使用的情况下编写的,它们在编程语言中的功能比图形应用程序具有更多的共同点。

如今,即使许多CLI程序主要由人使用(或什至仅由人使用),但它们的许多交互设计仍然保留了过去的包..现在是时候摆脱一些包:了:如果要主要使用命令对于人类,应该首先为人类设计。

最初的UNIX哲学的核心宗旨是,可以将具有简洁接口的小型简单程序组合起来以构建更大的系统,而不是在程序中添加越来越多的功能,而是要使程序模块化,以根据需要进行重新组合。

在过去,管道和shell脚本在组合程序的过程中起着至关重要的作用。它们的作用可能会随着通用解释语言的兴起而减弱,但它们并没有消失。大规模的自动化(以CI / CD,业务流程和配置管理的形式)蓬勃发展。使可组合程序变得与以往一样重要。

幸运的是,针对此特定目的而设计的UNIX环境的悠久惯例今天仍然对我们有所帮助。标准的in /​​ out / err,信号,退出代码和其他机制可确保不同的程序很好地单击在一起。文本很容易在命令之间传递。JSON是一种较新的发明,可以在需要时为我们提供更多结构,并使我们可以更轻松地将命令行工具与Web集成。

无论您要构建什么软件,您都可以绝对确定人们会以您意想不到的方式使用它。您的软件将成为更大系统中的一部分-您唯一的选择是是否将其做得很好。 。

最重要的是,针对可组合性的设计不必首先与针对人类的设计相冲突。本文档中的许多建议都涉及如何实现两者。

终端的约定已扎根在我们的手指上。我们必须通过了解命令行语法,标志,环境变量等来支付前期费用,但只要程序保持一致,它就可以长期有效。

CLI应该尽可能遵循现有的模式。这就是使CLI直观易懂的原因。这就是使用户高效的原因。

话虽如此,有时一致性会与易用性相冲突。例如,许多历史悠久的UNIX命令默认情况下不会输出太多信息,这可能会给不熟悉命令行的人造成混乱或担忧。

当遵循约定会损害程序的可用性时,可能是时候打破它了,但是这样的决定应该谨慎。

终端是一个纯信息的世界。您可以争辩说信息是界面,就像任何界面一样,信息太多或太少。

当挂起几分钟时,一条命令说的太少了,用户开始怀疑它是否坏了;当转储页面和调试输出的页面时,一条命令说了太多了,淹没了松散碎屑中真正重要的部分。最终结果是相同的:缺乏清晰度,使用户感到困惑和烦恼。

要实现这种平衡可能非常困难,但是对于软件来说,授权和服务于用户至关重要。

在使功能变得可发现时,GUI占了上风。您可以做的所有事情都摆在屏幕上的前面,因此您无需学习任何内容就可以找到所需的内容,甚至可以发现自己没有做过的事情。''不知道有可能。

假定命令行界面与此相反,您必须记住如何做。1987年出版的原始Macintosh Human Interface Guidelines建议“视点(而不是记住类型)”。 ),就像您只能选择其中一个。

这些事情不必相互排斥。使用命令行的效率来自于记住命令,但是没有理由命令不能帮助您学习和记住。

可发现的CLI包含全面的帮助文本,大量示例,建议下一步要执行的命令,建议发生错误时应采取的措施,可以从GUI窃取很多想法以使CLI更加易于学习和使用,甚至对于高级用户。

GUI设计(特别是在早期)大量使用了隐喻:台式机,文件,文件夹,回收站,这很有意义,因为计算机仍在努力使自己合法化。隐喻的易于实现是其中之一。图形用户界面(GUI)在CLI上具有巨大的优势。但具有讽刺意味的是,CLI始终体现了一个偶然的隐喻:这是一次对话。

除了最简单的命令外,运行一个程序通常还涉及多个调用,通常是因为很难在第一次就正确地执行它:用户键入命令,获取错误,更改命令,获取其他错误等等,直到它起作用为止。这种通过反复失败来学习的模式就像用户与程序进行的对话。

运行一个命令来设置工具,然后学习运行哪些命令才能真正开始使用它。

运行多个命令以设置操作,然后运行最终命令以运行该操作(例如添加多个git,然后执行git commit)。

探索系统-例如,进行大量的cd和ls操作以了解目录结构,或者通过git log和git show探索文件的历史记录。

承认命令行交互的对话性质意味着您可以运用相关技术进行设计,可以在用户输入无效时建议可能的更正,可以在用户经过多步过程时使中间状态清晰可见,您可以为他们确认在一切令人恐惧之前,一切看起来都不错。

用户正在与您的软件进行交谈,无论您是否想要它。最糟糕的是,这是一次敌对的交谈,使他们感到愚蠢和愤慨;充其量,这是一次愉快的交流,可以使他们以新发现的知识和快速的感觉加速他们的发展之路。成就。

健壮性既是客观的又是主观的属性,软件当然​​应该健壮:应该对意外的输入进行适当的处​​理,在可能的情况下操作应该是幂等的,但是它也应该健壮。

您希望您的软件感觉不会崩溃,而是希望它感觉立竿见影,反应灵敏,就好像它是一台大型机械机器,而不是脆弱的塑料“软开关”一样。

主观的健壮性需要关注细节并认真思考可能出问题的地方。这有很多小事情:让用户了解正在发生的事情,解释常见错误的含义,而不是打印看上去令人恐惧的堆栈跟踪。

一般而言,鲁棒性也可以来自保持简单性的原因。很多特殊情况和复杂的代码会使程序变得脆弱。

命令行工具是程序员的创新工具包,因此应易于使用,但这并不意味着将其转变为视频游戏或使用大量表情符号(尽管表情符号inherent本质上没有错)。用户感觉自己站在他们一边,希望他们成功,您已经仔细考虑了他们的问题以及如何解决它们。

虽然我们希望遵循我们的建议会带给您一些帮助,但您没有可以采取的行动清单来确保他们有这种感觉。让用户高兴意味着每时每刻都超出他们的期望,这始于同情。

航站楼的世界一团糟,到处都是不一致的地方,这使我们放慢了脚步并让我们自己去猜测。

但是,不可否认的是,这种混乱一直是力量的源泉。与UNIX降级的计算机环境一样,该终端对您可以构建的内容几乎没有任何限制。在这个空间中,各种各样的发明蓬勃发展。

具有讽刺意味的是,本文档劝告您遵循现有模式,并提出与数十年来命令行传统相矛盾的建议。我们与任何人一样都违反规则。

也可能是您必须违反规则的时候了,这样做的目的是明确目的。

“在明显损害生产力或用户满意度的情况下,请放弃该标准。” —人道界面Jef Raskin

这是您可以做的一些特定的事情,可以使您的命令行程序更好。

第一部分包含您需要遵循的基本内容。弄错这些错误,您的程序将很难使用或成为不良的CLI公民。

其余的都很不错。如果您有时间和精力来添加这些东西,您的程序将比普通程序好很多。

这样的想法是,如果您不想对程序的设计考虑得太仔细,则不必:只需遵循以下规则,您的程序就可能会很好。考虑了一下,确定规则对您的程序是错误的,这很好。(没有中央机构会拒绝您的程序,因为他们不遵守任意规则。)

此外,这些规则并不是一成不变的。如果您出于充分的理由不同意一般规则,我们希望您可以提出更改。

您需要遵循一些基本规则。弄错这些规则,您的程序将很难使用,或者被彻底破坏。

尽可能使用命令行参数解析库。您的语言是内置的,还是优秀的第三方。它们通常会以合理的方式处理参数,标记解析,帮助文本甚至拼写建议。

成功返回零退出代码,失败返回非零退出代码是脚本确定程序成功或失败的方式,因此您应正确报告此错误将非零退出代码映射到最重要的失败模式。

将输出发送到stdout。命令的主要输出应该转到stdout。任何机器可读的内容也应该转到stdout,这是管道在默认情况下发送内容的位置。

将消息发送到stderr.log消息,错误等都应发送到stderr,这意味着将命令通过管道传输时,这些消息将显示给用户,而不是馈入下一个命令。

默认情况下显示简洁的帮助文本。如果可以,则在运行myapp或myapp子命令时默认显示帮助。除非您的程序非常简单且默认情况下很明显(例如ls),或者您的程序以交互方式读取输入(例如cat )。

jq做得很好,当您输入jq时,它会显示介绍性描述和示例,然后提示您传递jq --help以获得标志的完整列表:

$ jqjq-命令行JSON处理器[1.6版]用法:jq [options]< jq filter> [file ...] jq [options] --args< jq filter> [strings ...] jq [options] --jsonargs< jq filter> [JSON_TEXTS ...] jq是用于处理JSON输入,将给定过滤器应用于其JSON文本输入并以标准输出上的JSON形式生成过滤器结果的工具。最简单的过滤器是。,它会复制jq输入到其输出的输入未修改(格式设置除外,但请注意,IEEE754用于内部数字表示,这意味着所有含义)有关更高级的过滤器,请参见jq(1)联机帮助页(" man jq")和/或https://stedolan.github.io/jq示例:$ echo' {" foo&#34 ;: 0}' | jq。 {" foo&#34 ;: 0}有关选项列表,请使用jq --help。

忽略传递的任何其他标志和参数,您应该可以在任何内容的末尾添加-h,并且应该显示帮助。请勿重载-h。

提供反馈和问题的支持路径。顶层帮助文本中的网站或GitHub链接很常见。

在帮助文本中,链接到文档的Web版本。如果您有子页面的特定页面或锚点,则直接链接到该文档。如果Web上有更详细的文档或可能引起进一步阅读的更多阅读资料,则特别有用。某物的行为。

以示例为先。用户倾向于在其他形式的文档上使用示例,因此请在帮助页面上首先显示它们,尤其是常见的复杂用法。如果它有助于解释其作用并且时间不长,也请显示实际输出。

您可以通过一系列示例来讲述一个故事,为复杂的使用打下基础。

如果您有大量的示例,请将它们放在备忘单命令或网页中的其他位置。拥有详尽的高级示例很有用,但您不想使帮助文本过长。

对于更复杂的用例,例如与其他工具集成时,可能需要编写完整的教程。

不要担心手册页。我们相信,如果您遵循这些指南来获取帮助和文档,则不需要手册页。没有足够的人使用手册页,并且它们无法在Windows上运行。框架和程序包管理器使输出手册页变得容易,但是,否则您最好花费时间来改进Web文档和内置帮助文本。

如果您的帮助文本很长,请通过寻呼机将其传递。这是男人为您做的一件有用的事情。请参见下面“输出”部分中的建议。

在帮助文本的开头显示最常见的标志和命令。有很多标志是可以的,但是如果您有一些真正的标志,请先显示它们。例如,Git命令显示了开始使用的命令首先是最常用的子命令:

$ gitusage:git [--version] [--help] [-C< path>] [-c< name> =< value>] [--exec-path [=< path>]] [ --html-path] [--man-path] [--info-path] [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] [--git-dir =< path>] [--work-tree =< path>] [--namespace =< ; name>]< command> [< args>]这些是在各种情况下使用的常见Git命令:启动工作区(另请参阅:git帮助教程)将存储库克隆到新目录init创建一个空的Git存储库或在当前目录上重新初始化一个现有的work更改(另请参见:每天都有git help)添加将文件内容添加到索引mv移动或重命名文件,目录或符号链接重置将当前HEAD重置为指定状态rm从工作树和索引中删除文件检查历史记录和状态(另请参见:git help修订版)bisect使用二进制搜索查找引入了错误grep的提交打印与模式日志匹配的行显示提交日志显示显示各种对象状态显示工作树状态…

在帮助文本中使用格式。加粗的标题使扫描更加容易。但是,请尝试以不依赖终端的方式进行操作,以免用户盯着转义字符。

$ heroku apps-帮助列出您的应用程序用法$ heroku apps OPTIONS -A,--all包括所有应用程序

......