shell 语言(如bash、zsh、fish )与上面的脚本语言有什么区别,使它们更适合 shell?
使用命令行时,shell 语言似乎要容易得多。尽管有相反的报道,但我感觉使用 bash 比在 ipython 中使用 shell 配置文件要顺畅得多。我想大多数人都会同意我的观点,即大部分中型到大型编程在 Python 中比在 bash 中更容易。我使用 Python 作为我最熟悉的语言,Perl 和 Ruby 也是如此。
我试图阐明原因,但除了假设两者对字符串的不同处理与此有关外,我无法阐明原因。
这个问题的原因是我希望开发一种可以在两者中使用的语言。如果您知道这种语言,请也将其发布。
正如 S.Lott 解释的那样,这个问题需要澄清一下。我在询问 shell 语言 与脚本语言的特性。所以比较不是关于各种交互(REPL)环境的特性,比如历史和命令行替换。该问题的另一种表达方式是:
一种适用于复杂系统设计的编程语言能否同时表达有用的单行代码,可以访问文件系统或控制作业?编程语言可以有效地放大和缩小吗?
我能想到几个不同点;只是在这里思考,没有特别的顺序:
Python & Co. 旨在擅长编写脚本。Bash & Co. 被设计为 只 擅长编写脚本,绝不妥协。IOW:Python 被设计为擅长脚本和非脚本,Bash 只关心脚本。
Bash & Co. 是无类型的,Python & Co. 是强类型的,这意味着数字123、字符串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 绑定到通用编程语言上来解决这些问题是行不通的。至少,我还没有看到令人信服的实现。有尝试在 Ruby 中实现 shell 的 RuSH (Ruby shell),有 rush ,它是 Ruby 中用于 shell 编程的内部 DSL,还有 Hotwire ,它是 Python shell,但 IMO 没有一个比这更接近与 Bash、Zsh、fish 和朋友竞争。
实际上,恕我直言,目前最好的外壳是 Microsoft PowerShell ,考虑到几十年来 ,微软一直在使用 最差 的外壳 evar ,这非常令人惊讶。我的意思是,COMMAND.COM?真的吗?(不幸的是,他们仍然有一个蹩脚的终端。它仍然是从那以后一直存在的“命令提示符”,什么?Windows 3.0?)
COMMAND.COM
PowerShell 基本上是通过忽略 Microsoft 所做的一切(COMMAND.COM、、CMD.EXEVBScript、JScript)而创建的,而是从 Unix shell 开始,然后删除所有向后兼容的垃圾(如用于命令替换的反引号)并稍微按摩它以使其更像 Windows - 友好(例如使用现在未使用的反引号作为转义字符而不是反斜杠,后者是 Windows 中的路径组件分隔符)。在那之后,就是魔法发生的时候。
CMD.EXE
他们从上面解决了 问题 1 和 3 ,与 Python 相比基本上做出了相反的选择。Python首先关心大型程序,其次才是脚本。Bash 只关心脚本。PowerShell 首先关心脚本,其次才是大型程序。对我来说,一个决定性的时刻是观看 Jeffrey Snover(PowerShell 的首席设计师)的采访视频,当时面试官问他可以用 PowerShell 编写多大的程序,Snover 毫不犹豫地回答:“80 个字符。” 在那一刻,我意识到这 终于 是微软的一个“获得”shell编程的人(可能与PowerShell 既不是 由微软的编程语言组(即 lambda-calculus math nerds)或操作系统组(kernel nerds)而是由服务器组(即实际 使用 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 中,这些信息通常是重复了 3 次:在命令本身的参数解析代码中、在bash-completion制表符完成的脚本中以及在手册页中。
F4
bash-completion
第 4 点通过 PowerShell 对强类型对象(包括文件、进程、文件夹等)进行操作这一事实得到解决。
5 号 特别有趣,因为 PowerShell 是我所知道的唯一 shell,编写它的人实际上 意识到 shell 本质上是数据流引擎,并故意将其实现为数据流引擎。
PowerShell 的另一个好处是命名约定:所有 cmdlet 都被命名Action- Object,此外,特定操作和特定对象也有标准化名称。(同样,这对 OS/400 用户来说应该很熟悉。)例如,与接收某些信息相关的所有内容都称为Get- Foo. 并且在(子)对象上操作的所有内容都称为Bar-ChildItem. 因此,等效于lsis Get-ChildItem(尽管 PowerShell 还提供内置别名ls和dir……事实上,只要有意义,它们就提供 Unix 和CMD.EXE别名以及缩写(gci在这种情况下))。
Action- Object
Get- Foo
Bar-ChildItem
ls
Get-ChildItem
dir
gci
但 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。