我能想到几个不同点;只是在这里思考,没有特定的顺序:
Python & Co. 旨在擅长编写脚本。 Bash & Co. 旨在仅擅长编写脚本,绝对不会妥协。 IOW:Python 被设计为擅长脚本和非脚本,Bash 只关心脚本。
-
Bash & Co. 是无类型的,Python & Co. 是强类型的,这意味着数字123、字符串123 和文件123 是完全不同的。但是,它们不是静态类型的,这意味着它们需要有不同的文字,以便将它们分开。
示例:
| Ruby | Bash
-----------------------------------------
number | 123 | 123
string | '123' | 123
regexp | /123/ | 123
file | File.open('123') | 123
file descriptor | IO.open('123') | 123
URI | URI.parse('123') | 123
command | `123` | 123
Python & Co. 旨在将向上扩展到 10000、100000 甚至 1000000 行程序,Bash & Co. 旨在将向下扩展到10 个字符程序。
在 Bash & Co. 中,文件、目录、文件描述符、进程都是一流的对象,在 Python 中,只有 Python 对象是一流的,如果你想操作文件、目录等,你必须先将它们包装在 Python 对象中。
Shell 编程基本上是数据流编程。没有人意识到这一点,即使是编写 shell 的人也没有意识到这一点,但事实证明,shell 非常擅长这一点,而通用语言则不然。在通用编程世界中,数据流似乎主要被视为一种并发模型,而不是一种编程范式。
我觉得试图通过将特性或 DSL 绑定到通用编程语言上来解决这些问题是行不通的。至少,我还没有看到令人信服的实现。有 RuSH(Ruby shell),它试图在 Ruby 中实现一个 shell,有 rush,这是 Ruby 中用于 shell 编程的内部 DSL,还有 Hotwire,这是一个Python shell,但 IMO 没有一个可以与 Bash、Zsh、fish 和朋友竞争。
实际上,恕我直言,目前最好的 shell 是 Microsoft PowerShell,考虑到现在的几个 十年,微软一直在拥有 最差的 shell evar。我的意思是,COMMAND.COM?真的吗? (不幸的是,他们仍然有一个蹩脚的终端。它仍然是从那以后一直存在的“命令提示符”,什么?Windows 3.0?)
PowerShell 基本上是通过忽略 Microsoft 所做的一切(COMMAND.COM、CMD.EXE、VBScript、JScript)而创建的,而是从 Unix shell 开始,然后删除所有向后兼容的垃圾(如用于命令替换的反引号)和稍微按摩一下,使其对 Windows 更友好(比如使用现在未使用的反引号作为转义字符,而不是作为 Windows 中路径组件分隔符的反斜杠)。在那之后,就是魔法发生的时候。
他们从上面解决了问题 1 和 3,与 Python 相比基本上做出了相反的选择。 Python首先关心大型程序,其次才是脚本。 Bash 只关心脚本。 PowerShell 首先关心脚本,其次才是大型程序。对我来说,一个决定性的时刻是观看 Jeffrey Snover(PowerShell 的首席设计师)的采访视频,当时面试官问他可以用 PowerShell 编写多大的程序,Snover 毫不犹豫地回答:“80 个字符。”在那一刻,我意识到这是终于微软的一个“获得”shell编程的人(可能与PowerShell不是由微软的编程语言组开发的事实有关(即 lambda-calculus 数学书呆子),也不是操作系统组(内核书呆子),而是服务器组(即实际使用 shell 的系统管理员),我可能应该认真看看 PowerShell。
数字 2 通过静态输入参数来解决。因此,您可以只写123,PowerShell 知道它是字符串、数字还是文件,因为 cmdlet(这是在 PowerShell 中调用的 shell 命令)向 shell 声明其参数的类型。这具有相当深刻的影响:与 Unix 不同,其中每个命令都负责解析自己的参数(shell 基本上将参数作为字符串数组传递),PowerShell 中的参数解析由 shell 完成。 cmdlet 将它们的所有选项、标志和参数,以及它们的类型和名称以及文档(!)指定给 shell,然后它可以在一个集中的位置执行参数解析、制表符补全、智能感知、内联文档弹出窗口等。 (这不是革命性的,PowerShell 设计者承认像 DIGITAL 命令语言 (DCL) 和 IBM OS/400 命令语言 (CL) 这样的 shell 是现有技术。对于曾经使用过 AS/400 的任何人来说,这听起来应该很熟悉. 在 OS/400 中,您可以编写一个 shell 命令,如果您不知道某些参数的语法,您可以简单地将它们省略并按 F4,这将带来一个菜单(类似于HTML 表单)带有标签字段、下拉列表、帮助文本等。这仅是因为操作系统知道所有可能的参数及其类型。)在 Unix shell 中,此信息通常重复三遍:在参数解析代码中在命令本身、用于制表符完成的 bash-completion 脚本和手册页中。
数字 4 解决了 PowerShell 对强类型对象的操作这一事实,其中包括文件、进程、文件夹等内容。
数字 5 特别有趣,因为 PowerShell 是我所知道的唯一 shell,编写它的人实际上 知道 shell 本质上是数据流这一事实引擎并特意将其实现为数据流引擎。
PowerShell 的另一个优点是命名约定:所有 cmdlet 都命名为 Action-Object,此外,特定操作和特定对象也有标准化名称。 (同样,这对 OS/400 用户来说应该很熟悉。)例如,与接收某些信息相关的所有内容都称为Get-Foo。对(子)对象进行的所有操作都称为Bar-ChildItem。因此,ls 等价于 Get-ChildItem(尽管 PowerShell 还提供内置别名 ls 和 dir - 事实上,只要有意义,它们就提供 Unix 和 CMD.EXE 别名以及缩写(@ 987654347@ 在这种情况下))。
但杀手级功能 IMO 是强类型对象管道。虽然 PowerShell 是从 Unix shell 派生的,但有一个非常重要的区别:在 Unix 中,所有通信(通过管道和重定向以及通过命令参数)都是使用非类型化、非结构化字符串完成的。在 PowerShell 中,它们都是强类型的结构化对象。这是如此令人难以置信的强大,以至于我真的想知道为什么没有人想到它。 (嗯,他们有,但他们从来没有流行过。)在我的 shell 脚本中,我估计多达三分之一的命令只是用作其他两个在通用文本格式上不一致的命令之间的适配器.许多这些适配器在 PowerShell 中消失了,因为 cmdlet 交换结构化对象而不是非结构化文本。如果您查看内部命令,那么它们几乎包含三个阶段:将文本输入解析为内部对象表示,操作对象,将它们转换回文本。同样,第一阶段和第三阶段基本上消失了,因为数据已经作为对象进来了。
然而,设计者非常注意通过他们所谓的自适应类型系统来保持 shell 脚本的动态性和灵活性。
无论如何,我不想把它变成 PowerShell 广告。 PowerShell 有很多不是那么棒的地方,尽管其中大部分都与 Windows 或特定实现有关,而与概念无关。 (例如,它是在 .NET 中实现的,这意味着如果 .NET 框架由于其他需要它的应用程序而尚未在文件系统缓存中,则第一次启动 shell 可能需要几秒钟。考虑到你经常使用 shell 不到一秒钟,这是完全不能接受的。)
我想说的最重要的一点是,如果你想看看现有的脚本语言和 shell 工作,你不应该停留在 Unix 和 Ruby/Python/Perl/PHP 家族 >。例如,Tcl 已经被提及。 Rexx 将是另一种脚本语言。 Emacs Lisp 将是另一个。在 shell 领域,有一些已经提到的大型机/中型 shell,例如 OS/400 命令行和 DCL。还有Plan9的rc。