从开始接触比较Geek的领域之后,CLI和GUI的区别一直是热门话题。

现在几乎所有人都没办法离开GUI,对于程序员等专业用户来说不可能离开CLI。但是即使是技术工具,有时候CLI也用起来很不舒服。于是产生了一些想法,想看看这些工具优点缺点是什么呢。

说CLI用起来不舒服,至少对记忆力差又粗心大意的家伙是这样的。比如说我打算写这篇文章,于是在终端上敲自己写的脚本 ./blog.py 创建文章。然而我忘了该用什么参数创建文章了。敲了 ./blog.py -h 才知道我该用 ./blog.py new "post title"

看到有一个流行工具的开发者也说,每次用自己写的工具都要 -h 一下。

优缺点

在这之前我必须讲CLI无与伦比的优点。

首先是编程方便,很复杂的功能对GUI来说,在处理交互上可能要花费一个月时间,编写相同功能CLI的话可能只会用几天。

其次,也是最重要的是可组合:可以简单地将小程序组合起来实现各自所需要的复杂大功能。而且也方便GUI等程序在别处调用。

再次,就是跨平台。CLI不需要考虑太多平台相关的东西。而且还可以在它之上包装GUI。

还有一个就是,CLI方便远程执行,一行 ssh 命令就能做到。

而GUI的优点,易用性之类老生常谈就不说了。实际上我觉得傻瓜式根本不怎么重要。

一个优点是,GUI能呈现各种多媒体数据。而CLI基本只能呈现文本(当然也有办法显示图片啦但是很麻烦也不好用)。

比起这些,对我来说GUI更大的优点在于 ,它进行的操作是自解释的,我不需要在旁边去翻 --help 或者 man 都可以在操作的同时理解自己进行的操作的意义。很多时候我只需要一句话的小提示而已,并不需要去看 man

而且进行操作的时候,所有可以进行的操作都是被枚举出来呈现在界面上的。比如说某处可以输入A, B, C的时候,A, B, C不需要记在执行者的脑子里,或者用另外的手段去查找。而是直接在下拉框中,被列出来呈现给你。

CLI也需要达到类似的能力,所以才有了shell补全。就像很多人写代码的时候没办法离开代码补全一样,shell补全也显得很重要。

然而编程语言的代码是非常结构化的,语法什么的都是统一的,所以才能准确地补全。而命令行程序是几乎没有结构的,不管是参数还是输出,都没有一种数据交互的统一方式。

所以CLI的shell程序只能靠社区给这些程序编写补全。而一些小众的程序,就不可能获得这种能力。即使是流行程序的补全,也只是方便补全常用操作而已,难以列出所有合适的值。

GUI对你的操作的结构是有检查的。一个理想的GUI程序,你进行的所有操作都是合法的。不能按的按钮会变灰,不能用的值不会显示。不同的意图在GUI的结构上差别很大(想想 rm -rf /usr /... 吧,在GUI里会多一个列表项)。

现在我们甚至有explainshell这种专门的工具去解释一个命令的意图,这显然是一种缺点。

一种工具的原型

最深刻感到这些不便是因为学习ffmpeg的时候,浩瀚的参数让我心生恐惧。而且一些参数放置的位置都会影响功能(比如 -ss)。所以我构思了这样的工具,帮助执行CLI命令的时候能构造正确的命令,并且能提供自解释的文档:

aGDAm9y

其中命令行的参数是用可以拖拽的小块组成的。需要加某个参数就可以拖到下面去。还可以拖放交换顺序。鼠标移到小块上,会显示对这个参数用途的简要说明。

如果参数后面必须跟数字,就只能在滑块文本框输入数字;如果参数后面必须跟某些枚举值(比如说 off/on)那么就会显示成下拉框,诸如此类。这样就能方便构造出正确的命令了。

这设想有很多问题。比如说,这也要社区针对性写大量规则;再比如说滑块什么的过于繁琐。以及需求也不是很大。现在已经有explainshell了,再配合脑子记,没有太多用的必要。

但这种让我进一步去思考UI的可能性,能不能结合GUI和CLI部分优点(和继承部分缺点)产生一种介于两者之间的用户界面呢?

当然能。

中间带

我遇见过许多这些介于两者中间的东西,都是一些特殊领域的系统。

IM 中的 bot

telegram-bot

Telegram Bot 给我的感受很好,比如说截图里自动出现的操作,比 /help 方便多了。返回的结果也有格式,可以返回图片等结果。而且也有简单的widgets系统。虽然这类bot原理上来说也是文本命令,但是大家都用得很开心。

telegram-bot-inline-keyboard

这里的 inline keybord 就能解决枚举的问题。

TermKit

TermKit

这和我理想中的模样很相近了,以full feature的terminal (shell) 为目标的半GUI平台。但是这个项目停止了。我找到一些类似的项目也都停止了。

Excel

是的 就是Excel。虽然Excel和传统CLI没什么关系,但是也能达到可编程可组合的目的。有结构化的富媒体,并且编程起来还蛮方便,不需要考虑很多复杂的GUI交互。

excel

Jupyter

jupyter

Jupyter本身和Python密切,所以继承了Python的优秀的素质。再加上有类型的block,可以让人往里面塞各种东西。能塞文章,还能塞widgets进去。从截图就能看出这是一种优秀的介于CLI和GUI之间的东东。截图来自官网的例子。

还有不少

在很多领域特定的地方都出现了类似这样的功能强大、编程简单、表现力丰富而且可组合的工具。

但是…

但这些东西都有各自的问题。

  • Telegram只是一个聊天软件。Bot虽然设计得富有启发,但和运行通用的程序无关。
  • Excel也是差不多的原因。而且还有M$的原因、这个软件本身的制约,还有编程语言的问题…
  • TermKit想要兼容原本的shell命令,只是手工给某些操作做了格式化,这根本不彻底,就算这个项目没有死,最后的结果也不会和我们现在手里用的终端有什么巨大差别。
  • Jupyter可以胜任很多任务。Python语法在调用功能的时候还是不怎么方便(比如说用Python函数操作文件和shell指令的区别)。基于文件的结构和我们一般在Terminal上的Ad-Hoc操作也不太一样(或许是好事?),在自解释方面能仰仗Python的一些机制(比如说文档字符串)。Jupyter不是为了这个目的设计的,如果拿来通用操作会很难受,但目前来从系统上来说是最接近我期望的。

理想中是什么样

理想中是这样的UI系统:

  • 可组合、可编程(管道等)
  • 可以无GUI运行(比如说脚本中)
  • 跨平台
  • 编程简单,不需要考虑太多交互
  • 有结构化、类型化的输入
  • 构造命令通过GUI有可靠的补全(想想IDE的补全和Telegram的Inline Keyboard)
  • 构造命令的时候可以有简单的说明,以及快速跳转到对应文档的能力
  • 有结构化的输出,并且支持输出表格等格式、多媒体和简单小控件
  • 可以降级到使用普通CLI程序,普通CLI程序也可以渐近式支持

为此需要付出这些代价:

  • 比纯CLI要麻烦一点的编程(但不会像GUI那样麻烦)
  • 比GUI高许多的使用门槛
  • 现在的命令行用着感觉好好的人不会喜欢的
  • 比GUI更多的限制,只能用指定的格式,而不能在GUI一样随心所欲地去布局。(参见Telegram Bot的总总限制,当然没那么严重,而且也会加入扩展能力吧)
  • 现有CLI程序不会立刻得到增强。必须有一种抽象层格式化输入输出。否则用现有的CLI程序和普通的shell里用没多少区别。(不会像TermKit那样特殊对待)

这样的UI系统会是什么样子呢。

从实现上来说。用某种通用的协议,以有类型的方式输入输出(比如说JSON或者XML,我更希望是LISP)。特殊格式的数据能被界面解释成图形化的东西或者文本,也能在命令之间相互处理。除了一次运行的命令以外,还有demon程序,它是启动为服务器和界面交互的。这样也能跨过互联网远程操作服务器上的程序。

这协议因为是统一的格式,所以可以做到自动退回成纯文本。这样能方便调用传统的shell程序进行处理。或许很多能在传统shell中调用。

也需要一种脚本语言来代替shell语言。(我更希望是LISP,不过括号太多了)

从组合性来说,不适合设计成每个程序一个窗口的感觉了。

也许可以从图形编程语言那里找灵感。Excel的表格(网格)式说不定也是合适的选择。

最简单的选择是Jupyter那种流式的,也和传统的shell相似。

还有一种可行的选择就是Workflowy/OrgMode多层级列表,如前前篇文章说的,我正在做这样的笔记本。感觉用这种结构来表示各种命令的调用和返回,也挺合适的。

list-limui-demo

脑洞这种新型的UI系统让我觉得很有意思。

从想法上,它应该是对GUI的再限制,以及对CLI有克制的增强。它的目的是成为一种无处不在的通用UI系统。只是能在保持CLI优点的同时尽可能获得GUI的优点。从限制中得到某些统一的方式来满足专业用户的编程简单、可组合等要求,同时不失方便实用简洁。

因此我当初构思的时候起了个名字叫LimUI,意思就是「限制」。不过这个坑实在太大了,根本想不到要开挖…

于是我写一篇文章说说思路,说不定有什么类似工作被我忽略了,或者我的想法有很大问题。