现代化命令行工具相比于传统命令行工具,其汲取了现代 web 的优秀的 UI 和交互设计,所以对用户更加友好, 同时也保留了命令行操作的高效性,能让用户体会到hack
的乐趣。本片博文,将给大家讨论如何构建现代化命令行工具。 首先我会结合自身的经历,来谈谈为什么命令行是高效的,然后对比两组常用且核心功能相同的命令行工具, 让大家知道现代命令行工具一般具备哪些特征,最后依据这些特征,给大家总结使用 go 语言构建现代命令行的过程, 以及常用的库。
为什么偏爱命令行
作为一位 Hacker,我十分推崇键盘操作模式和以终端为中心的工作模式这两种理念哲学。很大程度上,这两种理念哲学是 Hacker 文化的重要部分。
键盘操作,与之相对应的是鼠标(触屏等)操作,这两种模式是目前的主流人机交互方式。对于使用过VIM
和Word
两种工具的用户, 会很容易理解,两种模式的区别。word
如今使用更加广泛,并且鼠标操作模式也一直是主流,而VIM
的使用人群则相对固定(开发者), 对于一个深度使用VIM
的人是很难抛弃它,VIM 吸引用户的魔力正是键盘操作模式,而 VIM 正是以键盘为中心操作模式的代表, 这种设计哲学几乎在很多专业软件都有体现,比如Jetbrains
这家公司的产品,主要提供流行语言的 IDE 产品, 其核心特色就是通过快捷键能够实现几乎所有功能(Jetbrains 定义为Action
),并且这些快捷键很容易定制,同时有Find Action
统一的入口。 这也是 Jetbrains 产品的优势所在,再比如VSCode
编辑器,能够从众多编辑器脱颖而出也正是因为其设计广泛采用了这种模式。
这两种模式在不同场景各有优势,鼠标能够让用户更容易上手,降低用户学习成本。 而对于开发者,键盘操作模式能显著提升生产力,还有在一些专业工具中, 大量使用快捷键代替繁琐的鼠标操作,能够使开发人员更加专注于工作,提高效率,因为键盘操作模式更容易产生肌肉记忆。
终端(终端模拟器)作为计算机发展的早期人与计算机进行的通信的工具,即使到现在,仍然无法被取代,并且相对于各种形形色色的程序,其仍然是最特殊和最具个性的一个。 终端的使用主要是通过命令行工具完成具体的工作,由于早期没有鼠标,终端的工作模式以键盘为主,这里提一下, 现代的终端程序也提供了对键盘的支持。微软个人PC
早期是十分不看重终端程序的,但是现在却也大力发展终端(这里微软终端开源仓库), 其主要原因是不想白白失去开发者这一膨大的用户群体,从中也可以看出,终端的重要地位。
上图是微软大力研发的命令行工具,对比传统的CMD
程序,我们能够从中发现现代命令行工具的影子。
如何设计现代的命令行工具。
良好的终端的体验通常包含以下四种工具的选择:
- 终端模拟器的选择,优秀终端模拟器一般提供良好的 UI 设计,分屏,Session 管理等;比如 Mac 用户通常会使用 Iterm2 而不是自带终端程序, 正是 Iterm2 的用户体验更加出色,功能更加齐全;
- Shell 的选择,Shell 发展至今,也有很多选择,优秀的 Shell 提供自动提示,插件集成,良好的 UI 等,注意并不是每个系统都对所有类型 Shell 提供支持的, 所以选择通用 Shell 会降低后续迁移的风险,Oh-My-Zsh 是现代 Shell 中的佼佼者;
- 包管理方式,当命令行工具变得越来越多,所带来的管理代价也越来越大,包管理工具能够帮助管理安装,卸载,升级等, 包管理工具也是命令行工具;
- 命令行工具的选择,如何在众多质量层次不齐的工具中选择,这很大程度影响了用户体验,这是本文后续重点的讨论的内容;
命令行工具通常实现一组相关的功能,功能是吸引用户使用的最重要的点,不过这里我们无法讨论功能的好坏, 但是如果有一组实现相同功能的命令行工具给你选择,你该如何选择呢?毫无疑问,你会使用更简洁,方便的那一个, 这就是命令行工具的用户体验的重要性,让你的用户留下来。
RTFM(阅读该死的手册Read The Fucking Manual)
文化在命令行工具的用户群体的流行,也是对许多命令行工具的吐槽, 甚至,正是因为命令行工具的不易使用,才会让很多人觉得命令行很高大上。出现这一现象的原因,一是命令行工具大都是开源工具, 开发质量无法得到保证,并且无法跟上现代用户的使用需求。二是大多数公司更重视应用 APP 和浏览器的设计和用户体验的优化, 忽视命令行工具的优化。例如 Github 这样的企业到今年才有了官方的命令行工具cli
。三是用户群体的忍耐性高,命令行工具的用户群体, 似乎是习惯了其糟糕的体验。
说到这里,什么样的命令行工具可以称得上现代的?用户体验优秀的命令行工具和普通命令行工具有什么区别呢? 事实上,也确实没有相关衡量标准的建立,不过,下面通过对比两组工具(没有使用过的读者可以试着使用),相信大家心中会有答案。
mysql VS mycli
以上两款工具都是mysql
的客户端,但是大多数用户在使用 mycli 后会选择它,因其提供使用者良好的补全,同时界面的 UI 也更加现代。
python VS ipython
以上是两种 python 交互 Shell,ipython 提供的提示更加方便,同时也能方便查阅读文档,方便导出代码段,查询操作历史等功能, 这些功能相当实用。
大家可以对比使用以上两组工具,更能够明白一个良好的用户体验为什么能让用户留下来。虽然目前没有事实的标准, 但是现代的命令行工具一般具有以下特点:
- 良好的提示和补全,特别提一点动态信息的补全,如 mycli 能够补全字段,表和数据库这些信息;
- 现代 UI 设计,如对于重点数据使用颜色标注,长时间的操作提供状态条,输出的内容排版等;
- 遵循标准统一规范(Unix/Posix,BSD,GNU风格的参数),不滥用
Flag,Args,Subcommand
这些元素。比如开关这种动作应该使用子命令而不是通过 flag 控制。 统一规范有利于用户快速上手; - 详细有序的输出信息,如在打印一组规则的输出时,表格会更加合理;
- 便携的输入,在一些情况使用交互式输入,会对用户更优化,对于需要输入如 yaml 等格式的文件,使用默认编辑器会更合理。
go构建现代命令行工具及相关库整理
目前,我们已经可以通过很多工具构建命令行工具,最简单原始的方式就是通过 Shell 脚本,各个语言也都有命令行开发库和工具, 在所有语言中最常见也是最适合开发的语言是C
,node
和python
。为什么这三种语言比较合适,这里就不再赘述了。
随着Golang
这几年的发展,相关库生态的丰富,加上Golang
语言本身很适合构建命令行工具(最终构建物就是可执行文件), 所以也出现大量通过 Go 开发的命令行工具,如kubectl,hugo,cli等
。下面结合自己的使用经历和经验, 给大家整理了go 如何选择合适工具来开发现代命令行工具。
对于下面的工具和库,这里只做简单的介绍,详细用法参考使用文档。
根据上述我们总结的优秀命令行工具的特点,我们来选择适合的库。首先选择框架,目前使用比较多的有cobra
和cli
, 由于已有许多成熟的项目使用了cobra
,所以建议使用这个库,可以参考其他的项目中优秀的设计模式,上手很简单, 下面是一个简单的示例程序:
1 | var rootCmd = &cobra.Command{ |
这个库能够方便实现子命令(嵌套命令),同时能够自动生成帮助信息(help)和手册(man page),也能够生成补全信息, 命令行参数也符合 Posix 的标准,其为我们做了很多工作,所以我们已经成功一大半了。底层搭好了,剩下的就是美化的工作。
格式化输出
首先是输出的格式化,用户通过命令行获取信息,能够让用户快速定位到关键信息很重要,研究表明, F型,分层蛋糕型和斑点型
的输出是最友好的三种输出模型。不要让输出过分紧凑,适当的保留空白区域,有利于降低用户的阅读难度。
列表输出是最常见的一种形式,go 中通过库 Tablewriter 能够很好的处理表格的格式化。
1 | data := [][]string{ |
1 | +------+-----------------------+--------+ |
对于其他固定类型的可视化,可以使用termui
,这个工具提供了很多小组件,如饼图,柱状图等格式化数据,有需要的小伙伴, 可以自行了解学习。
色彩
添加各种色彩有很多好处,一方面可以提醒用户重要的信息,另一方面一些颜色本身也具备传递信息的功能。如红色通常代表错误和危险操作, 绿色通常代表成功,黄色提醒需要注意,蓝色代表着状态良好。配合终端模拟器,合理使用色彩,会让你的命令行工具更加出彩。
go 中通过 Color 能够打印带有色彩的文本信息,对于 Log 的打印,logrus 库也提供了彩色支持。
图片 Logo
在输出中添加图片和 logo 能够拉近与用户的距离,同时图片相比文字能够传递更多的信息,更容易被用户接受, 有的终端模拟器可能不支持图片,所以在使用中需要考虑所面向的用户,及其使用环境。
状态条
一些耗时操作,如上传下载文件,如果没有任何输出,这可能会导致用户强行关闭程序,通过一个实时状态条, 就能轻松过解决。Go 中有很多这样的库如 progressbar, cheggaaa/pb 等。下面是简单的 cheggaaa/pb 的 Demo:
1 | count := 100000 |
构建一个用户体验优秀的命令行工具,以上几个方面是非常值得考虑的。当然除了以上几点, 你还需要考虑如何发布你的工具,版本升级,文档维护等问题。
除了借鉴开源的命令行工具,大家也可以参考项目 hack, 这是我开源的一个命令行工具,主要功能是简化Mac工作流,同时在实现功能的同时也在尝试构建现代化命令行工具, 目前已经有以上相关优化的实践样例。
总结
这篇博文,对于哪些深度使用命令行工具的读者,可能会更容易体会其价值。一个排斥命令行工具的人,可能不容器理解, 当然,这也很正常,现在想起刚接触命令行工具的自己,同样也是排斥的。我想告诉这些读者,如果你是一位开发者, 那么请先尝试拥抱命令行工具,再回头来阅读,你应该会有所收获。
如果想要快速构建命令行工具,尝试通过创建一个符合自己用户习惯的命令行工具(如将多个命令行工具的功能聚合成一个的形式),用来简化日常工作流。就像hack
项目一样, 相信你会很快上手。