我能想到几个区别;只是随便列举一下,没有特定顺序:
Python & Co. are designed to be good at scripting. Bash & Co. are designed to be only good at scripting, with absolutely no compromise. IOW: Python is designed to be good both at scripting and non-scripting, Bash cares only about scripting.
Bash & Co. are untyped, Python & Co. are strongly typed, which means that the number 123
, the string 123
and the file 123
are quite different. They are, however, not statically typed, which means they need to have different literals for those, in order to keep them apart.
Example:
| 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. are designed to scale up to 10000, 100000, maybe even 1000000 line programs, Bash & Co. are designed to scale down to 10 character programs.
In Bash & Co., files, directories, file descriptors, processes are all first-class objects, in Python, only Python objects are first-class, if you want to manipulate files, directories etc., you have to wrap them in a Python object first.
Shell programming is basically dataflow programming. Nobody realizes that, not even the people who write shells, but it turns out that shells are quite good at that, and general-purpose languages not so much. In the general-purpose programming world, dataflow seems to be mostly viewed as a concurrency model, not so much as a programming paradigm.
我有一种感觉,试图通过在通用编程语言上添加功能或DSL来解决这些问题是行不通的。至少,在我看来,我还没有看到一个令人信服的实现。有RuSH(Ruby shell),它试图在Ruby中实现一个shell,有
rush,它是Ruby中的一个内部DSL,用于shell编程,有
Hotwire,它是一个Python shell,但在我看来,这些都无法与Bash、Zsh、fish和其他工具相提并论。
实际上,我认为当前最好的shell是
Microsoft PowerShell,这非常令人惊讶,考虑到微软多年来一直拥有最差的shell。我的意思是,COMMAND.COM?真的吗?(不幸的是,它们仍然有一个糟糕的终端。它仍然是自Windows 3.0以来一直存在的“命令提示符”)
PowerShell基本上是通过忽略微软曾经做过的一切(如COMMAND.COM、CMD.EXE、VBScript和JScript等),从Unix shell开始创建,然后删除所有向后兼容的垃圾(例如用于命令替换的反引号),并进行了一些调整,以使其更加Windows友好(例如使用现在未使用的反引号作为转义字符,而不是在Windows中作为路径组件分隔符的反斜杠)。之后,魔法就发生了。
他们通过与Python相比基本上做出相反的选择来解决以上的问题1和3。Python首先关注大型程序,其次是脚本。Bash只关心脚本。PowerShell首先关注脚本,其次是大型程序。对我来说,一个定义性时刻是观看Jeffrey Snover(PowerShell的首席设计师)的访谈视频时,面试官询问他可以用PowerShell编写多大的程序,Snover毫不犹豫地回答:“80个字符。”在那一刻,我意识到这终于是一个“懂得”shell编程的微软员工(可能与PowerShell既不是由微软的编程语言组(即λ演算数学迷)开发,也不是由操作系统组(内核迷)开发,而是由服务器组(即实际使用shell的系统管理员)开发有关),我应该认真看看PowerShell。
第二点通过静态类型的参数解决。因此,您只需编写123
,PowerShell就知道它是字符串、数字还是文件,因为cmdlet(在PowerShell中称为shell命令)将其参数的类型声明给了shell。这具有相当深远的影响:与Unix不同,在Unix中,每个命令都负责解析自己的参数(shell基本上将参数作为字符串数组传递),而在PowerShell中,参数解析由 shell 完成。 cmdlets指定了它们所有选项、标志和参数,以及它们的类型、名称和文档(!),然后可以在一个集中的地方执行参数解析、制表符完成、IntelliSense、内联文档弹出窗口等。(这并非是革命性的,PowerShell的设计者承认像DIGITAL Command Language(DCL)和IBM OS/400 Command Language(CL)这样的shell是先前的艺术品。对于任何曾经使用过AS/400的人来说,这应该听起来很熟悉。在OS/400中,您可以编写一个shell命令,如果您不知道某些参数的语法,您可以简单地将它们留空并按下F4,这将带来一个菜单(类似于HTML表单),其中包含带标签的字段、下拉菜单、帮助文本等。这仅仅是因为操作系统知道所有可能的参数及其类型才有可能实现。)在Unix shell中,这些信息经常重复三次:在命令本身的参数解析代码中,在用于制表符完成的bash-completion
脚本中以及在man页面中。
第四点通过PowerShell基于强类型对象操作来解决,其中包括文件、进程、文件夹等。
第五点特别有趣,因为PowerShell是我所知道的唯一一个shell,编写它的人实际上意识到shell本质上是数据流引擎,并故意将其实现为数据流引擎。
PowerShell的另一个好处是命名约定:所有cmdlet都命名为Action-Object
,而且还有针对特定操作和特定对象的标准化名称。 (这应该听起来很熟悉,对于OS/400用户而言)。例如,与接收某些信息相关的所有内容都称为Get-Foo
。而所有在(子)对象上操作的内容都称为Bar-ChildItem
。因此,与ls
相当的是Get-ChildItem
(尽管PowerShell还提供了内置别名ls
和dir
- 实际上,每当有意义时,它们都提供Unix和CMD.EXE
别名以及缩写(在这种情况下为gci
))。
但我认为最强大的功能是强类型对象管道。虽然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。
123
不能定义两种不同的类型。另外,你有没有一个解释PowerShell自适应类型系统的链接?谷歌似乎没有给我任何我能理解的东西。 - Muhammad Alkarourix.ToString()
中,取决于x
的类型,执行哪个ToString()
)。而在PowerShell中,则正好相反:语言根据过程决定将参数解释为什么类型。另外一种解释是,语法根据参数类型动态构建,并且只有一种解析令牌的方法。 - Jörg W Mittag