我能想到一些不同之处;这里只是思想流,没有特别的顺序:
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中shell编程的内部DSL,有Hotwire,这是一个Python shell,但在我看来,这些都无法与Bash、Zsh、fish和朋友们竞争。
实际上,恕我直言,目前最好的外壳是微软的PowerShell,这是非常令人惊讶的,因为几十年来,微软一直有最糟糕的外壳。我是说,COMMAND.COM?真的吗?(不幸的是,他们的终端仍然很糟糕。它仍然是“命令提示符”,从那时起,什么?Windows 3.0 ?)
PowerShell基本上是通过忽略微软曾经做过的所有事情(COMMAND.COM, CMD.EXE, VBScript, JScript)来创建的,而是从Unix shell开始,然后删除所有向后兼容的问题(比如命令替换的反勾号),并对它进行了一些调整,使其更适合Windows(比如使用现在不使用的反勾号作为转义字符,而不是Windows中的路径组件分隔符反斜杠字符)。之后,就是奇迹发生的时候了。
They address problem 1 and 3 from above, by basically making the opposite choice compared to Python. Python cares about large programs first, scripting second. Bash cares only about scripting. PowerShell cares about scripting first, large programs second. A defining moment for me was watching a video of an interview with Jeffrey Snover (PowerShell's lead designer), when the interviewer asked him how big of a program one could write with PowerShell and Snover answered without missing a beat: "80 characters." At that moment I realized that this is finally a guy at Microsoft who "gets" shell programming (probably related to the fact that PowerShell was neither developed by Microsoft's programming language group (i.e. lambda-calculus math nerds) nor the OS group (kernel nerds) but rather the server group (i.e. sysadmins who actually use shells)), and that I should probably take a serious look at PowerShell.
Number 2 is solved by having arguments be statically typed. So, you can write just 123 and PowerShell knows whether it is a string or a number or a file, because the cmdlet (which is what shell commands are called in PowerShell) declares the types of its arguments to the shell. This has pretty deep ramifications: unlike Unix, where each command is responsible for parsing its own arguments (the shell basically passes the arguments as an array of strings), argument parsing in PowerShell is done by the shell. The cmdlets specify all their options and flags and arguments, as well as their types and names and documentation(!) to the shell, which then can perform argument parsing, tab completion, IntelliSense, inline documentation popups etc. in one centralized place. (This is not revolutionary, and the PowerShell designers acknowledge shells like the DIGITAL Command Language (DCL) and the IBM OS/400 Command Language (CL) as prior art. For anyone who has ever used an AS/400, this should sound familiar. In OS/400, you can write a shell command and if you don't know the syntax of certain arguments, you can simply leave them out and hit F4, which will bring a menu (similar to an HTML form) with labelled fields, dropdown, help texts etc. This is only possible because the OS knows about all the possible arguments and their types.) In the Unix shell, this information is often duplicated three times: in the argument parsing code in the command itself, in the bash-completion script for tab-completion and in the manpage.
第4个问题可以通过PowerShell对强类型对象(包括文件、进程、文件夹等)进行操作来解决。
第5点特别有趣,因为PowerShell是我所知道的唯一一个shell,编写它的人实际上意识到shell本质上是数据流引擎,并故意将其实现为数据流引擎。
Another nice thing about PowerShell are the naming conventions: all cmdlets are named Action-Object and moreover, there are also standardized names for specific actions and specific objects. (Again, this should sound familar to OS/400 users.) For example, everything which is related to receiving some information is called Get-Foo. And everything operating on (sub-)objects is called Bar-ChildItem. So, the equivalent to ls is Get-ChildItem (although PowerShell also provides builtin aliases ls and dir – in fact, whenever it makes sense, they provide both Unix and CMD.EXE aliases as well as abbreviations (gci in this case)).
But the killer feature IMO is the strongly typed object pipelines. While PowerShell is derived from the Unix shell, there is one very important distinction: in Unix, all communication (both via pipes and redirections as well as via command arguments) is done with untyped, unstructured strings. In PowerShell, it's all strongly typed, structured objects. This is so incredibly powerful that I seriously wonder why noone else has thought of it. (Well, they have, but they never became popular.) In my shell scripts, I estimate that up to one third of the commands is only there to act as an adapter between two other commands that don't agree on a common textual format. Many of those adapters go away in PowerShell, because the cmdlets exchange structured objects instead of unstructured text. And if you look inside the commands, then they pretty much consist of three stages: parse the textual input into an internal object representation, manipulate the objects, convert them back into text. Again, the first and third stage basically go away, because the data already comes in as objects.
然而,设计人员通过所谓的自适应类型系统(Adaptive Type System)非常小心地保持了shell脚本的动态性和灵活性。
Anyway, I don't want to turn this into a PowerShell commercial. There are plenty of things that are not so great about PowerShell, although most of those have to do either with Windows or with the specific implementation, and not so much with the concepts. (E.g. the fact that it is implemented in .NET means that the very first time you start up the shell can take up to several seconds if the .NET framework is not already in the filesystem cache due to some other application that needs it. Considering that you often use the shell for well under a second, that is completely unacceptable.)
我想说的最重要的一点是,如果你想看看现有的脚本语言和shell,你不应该止步于Unix和Ruby/Python/Perl/PHP家族。例如,前面已经提到了Tcl。Rexx将是另一种脚本语言。Emacs Lisp是另一个。在shell领域,有一些已经提到的大型机/中端shell,如OS/400命令行和DCL。还有,Plan9的rc。