避免有些人来喷我没用过 powershell,我还是声明一下,用,并且给 powershell 写过插件,先前把 bash/zsh 下的自动跳转 z.sh 移植到了 powershell 下面,主要是因为我在 PowerShell Gallery 网站中看了3-4个已有的 z.sh 移植,返现写的都特么的三脚猫,没有一个看得上眼的。所以对于 powershell 应该不算小白,评论他两句,应该也是可以的。
这里只谈 powershell 在管道里传递对象的事情,众所周知 ipython shell / powershell 之类的 shell 能在管道里传对象,看起来比以前传文本高级是吧?看起来很科学很现代是吧?然而兴一利必生一弊,对于这个特性不用太过迷信,有没有人想过这科学的另外一面是什么东西呢?
先来看看这个答案:为啥 Erlang 没有像 Go、Scala 语言那样崛起?-- 布丁的答案
以及它引述的文章:Rise of Worse Is Better
文中提到的,“Worse is Better”观点,从工程角度解释了,看起来更正确/一致以及更优雅的 erlang 却被不那么追求正确性,一致性和完整性的却一味追求简单性的对手所击败。
历史总是惊人的相似,XML 殷鉴不远,早十五年前,结构化的 XML 如日中天的时候,微软和其他厂商也曾经积极的推广过类似 SOAP 的各种基于 XML 的框架。在不同网络服务器之间使用 XML 看起来更科学,传输更标准化了,能描述的对象更多更强大了。
然而为啥 XML 十多年过去了还是那个鬼样子?并没有如当初推动者们所想象那样变为一统天下的描述性语言,大量网络服务之间的接口还在基于各种简单文本或者二进制协议?
首先是引入 XML 解析不论客户端或者服务端都需要引入一个很大的依赖包,来解析或者生成 XML,其次,各种 xml tag 占用额外的空间太多,传输更费带宽外,解析速度更慢更费内存;它不利于机器编解码,也同样不利于人手工修改编辑。
简而言之,远不如传统简单文本或者二进制协议那样不需要庞大的第三方库,仅仅百行 C 代码就可以完成解析和编码,速度快又没有额外信息,而且便于人类读写。
各种简单文本/二进制协议中,反而 JSON / MsgPack 逐渐取代了原有XML的位置,一个利于人读写,一个利于机器读写传输。他们都没有 XML 抽象能力高,描述力强,没有XML 那么完整一致和科学,然而 Worse is Better,违背了 KISS 原则的 XML,当他热火朝天的时候,四处受到各大厂商的追捧;而当它挂掉的时候,也是四处遭到嫌弃。
再来说一个成功的案例,Apache + CGI,早年 php 还没有流行的时候,动态页面(非静态html),都是提交给 cgi / fastcgi 这类程序来处理的,Apache 等网页服务器接受了页面请求后,如果发现请求页面位于 /cgi-bin/ 下面,则会执行对应目录下的 cgi 可执行程序,用管道+文本请求头发送给程序,然后 CGI 程序使用 printf 从标准输出将返回的页面或者内容传递给 Apache ,Apache 又用 HTTP 协议通过网络发送给请求者。
其实当时还有其他的设计方法,比如 Apache 加载动态页面的模块,程序由特定的 API 和 Apache 通信,这样的话调用起来更加强答,和 Apache 结合也更紧密,通过API进行沟通似乎能做的事情更多而已,然而 api 用起来一时爽,但更高的耦合度带来的是更多的约束,基于 API 的 CGI程序(或者说模块)和网页服务器之间必须使用相同的库进行沟通,那么网页服务器升级或者内部实现调整给 CGI 程序带来的影响是致命的,同时网页服务器限制了 CGI 程序的开发方式。
幸好历史没有选择这种基于 API 的高耦合方式,而是选择了基于简单文本的 CGI/fastcgi,这种基于简单文本的 CGI/fastcgi 接口,不论网页服务器怎么实现怎么升级,它都没有任何影响,cgi 程序,并且不限制你的开发方式,你除了可以用 C/C++ 写以外,你还可以用 perl 来写,用 python 来写,甚至用 shell 脚本来写,这就是简单性和可拆分行的力量。
说完三段历史,回过头来看 PowerShell / ipython shell 这个管道里传对象的逻辑,你会发现,它和历史上这些看起来很科学但实际上最终被代替的技术是多么的相似,管道里传对象这件事情同时违背了 KISS 原则和高内聚低耦合原则,让不同的命令从内部数据结构上都全部耦合到了一起,比起简单的文本协议,一个命令的内部数据结构升级引起的问题更可能是灾难性的;它要求在所有工具链都按照它的规矩来,丝毫不关注历史的连贯性和兼容性,却要求所有工具配合它重头设计一次;它更限制了工具程序的开发方式,必须要用 .Net ,不能像传统 shell那样,各种语言/脚本混合搭配,Unix/Linux 界几十年下来,各种工具的开发语言都没有能够做到统一,有shell脚本写的,有perl写的,有 C 语言写的,更有 python/ruby 写的。我不知道 PowerShell 需要用多少年来让所有工具都如他所愿的传递 .Net 对象?
其实现有管道系统你也可以传二进制啊,当你需要复杂对象的时候,用管道传递 msgpack 编码的对象即可,这样的实现有好多,比如 neovim 就是用 msgpack 通过管道和外层的 GUI 实现进行沟通的,rust 写的编辑器内核 xi-editor 也是通过管道+json和前端GUI实现进行交互的,它和 neovim 一样只做好编辑器内核,将 GUI 外壳扔给 Qt 或者 Electron 等实现。
所以传统管道虽然大部分时候用的文本,但它从不限制你使用二进制的 msgpack 或者 json 来传递复杂对象,这个思路是对的,就像 rustc 一样,默认错误输出给人看的,但是加一个参数就可以输出格式改成 json,方便其他程序解析成对象,这就是正确的打开方式,永远不要小看传统技术的可塑性和自我进化能力。
有时候真的是看似 Worse 的东西,其实是更好的选择,看似 Better 的东西,未必真如大家所想,PowerShell 这个管道里传对象的设计,几乎把我们上面说到三段历史中所有的错误都犯了一遍。
最后再扯一句闲话,感觉 PowerShell 一直都再拿 Bash 比来比去,然而从用户交互层面上,PowerShell 对标就对错了,现在大家用的更多的是 zsh / fish,bash 这些是再外部非开发环境下使用一下,或者编写高兼容性脚本时使用。
所以,承认 PowerShell 比起 cmd 来是有进步的,但要问它的一些设计思路是否会流行,是否会代替现有 shell,我这里撂句话:难上加难。
--
PS1:sh/bash 脚本的确比较晦涩,因为偏向 “外部命令整合的方便性”,必然会损害“内部结构的优雅性”,大部分指令都是直接面向外部命令的,要做一些语言内在的逻辑,都要绕着圈写,csh/tcsh 曾经就觉得 Bourne shell 的各种语法很反人类,所以设计到了模仿 C 语言语法的 if / for / while / case 还有各种数组等,但是对环境变量的操作没有 bourne shell 那么直白强大,更没法像后者一样对外部命令可以各种花式调用,所以最终 csh/tcsh 与 posix shell 失之交臂,死到了历史的阴沟里了。
PS2:所以 Python 虽然内在比较优雅,描述里更强,但是再编写系统管理脚本,对外部工具链整合这个场景下,效率远远没有 sh / bash 那么高。ps1脚本内部结构是优雅,但是同时也犯了和 csh/tcsh/python shell 一样的毛病,对传统系统管理类脚本的编写上显得啰嗦冗长和不够直接。
PS3:其实现在在 zsh 下写脚本,易读性已经好了不少了,描述能力也强了不少。
--
最后,真的不要成天眼睛盯着 bash 这种淘汰的东西说自己先进了,易用性和颜值上要多向 zsh / fish 看齐:
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有