Shell 就像编辑器一样:每个人都有自己喜欢的选择并极力为该选择辩护(还告诉您为什么应该使用该选择)。确实如此,shell 可提供不同的功能,但它们都实现了数十年前开发的核心理念。
我第一次使用现代 shell 是在二十世纪 80 年代,当时我正在 SunOS 上开发软件。当我了解了将一个程序的输出用作另一个程序的输入(甚至多次连环地使用)的能力后,我就有了一种简单且高效的方式来创建过滤器和转换。该核心理念提供了一种方式来构建一些简单工具,这些工具足够灵活,可与其他工具组合使用。通过这种方式,shell 不仅提供了一种与内核和设备交互的方式,还提供了现在作为软件开发中的常见设计模式的集成服务(比如管道和过滤器)。
让我们首先简单介绍一下现代 shell 的发展历史,然后探讨如今一些可用于 Linux 的外来的有用 shell。
shell 的发展历史
Shell(或命令行解释器)具有很长的历史了,但我们的讨论从第一个 UNIX® shell 开始。(贝尔实验室的)Ken Thompson 于 1971 年开发了第一个用于 UNIX 的 shell,名为 V6 shell。类似于它在 Multics 中的前身,这个 shell (/bin/sh) 是一个在内核外部执行的独立用户程序。globbing(参数扩展的模式匹配,比如 *.txt)等概念是在一个名为 glob的独立实用程序中实现的,就像用于评估条件表达式的 if 命令一样。这种独立性可保持 shell 很小,只需不到 900 行 C 源代码(请参见 参考资料 获取原始源代码的链接)。
该 shell 为重定向(< > 和 >>)和管道(| 或 ^)引入了一种紧凑的语法,这种语法已延续到现代 shell 中。您也可以找到对调用顺序命令(使用 ;)和异步命令(使用 &)的支持。
Thompson shell 缺少的是编写脚本的能力。它的唯一用途就是用作一个交互式 shell(命令解释器)来调用命令和查看结果。
1977 年以来的 UNIX shell
撇开 Thompson shell,我们开始将目光转移到 1977 年引入 Bourne shell 时的现代 shell。Bourne shell 由 Stephen Bourne 在 AT&T Bell Labs 为 V7 UNIX 创建,它在如今仍然是一个有用的 shell(在一些情况下还被用作默认的根 shell)。作者在研究 ALGOL68 编译器之后开发了 Bourne shell,所以您会发现它的语法比其他 shell 更加类似于 Algorithmic Language (ALGOL)。尽管使用 C 开发,源代码本身甚至使用了宏赋予它一种 ALGOL68 特色。
Bourne shell 有两个主要目标:用作一个命令解释器来交互式执行操作系统命令,以及用于编写脚本(编写可通过 shell 调用的可重用脚本)。 除了取代 Thompson shell,Bourne shell 还提供了相对于其前身的多项优势。Bourne 向脚本中引入了控制流、循环和变量,提供了一种更加强大的语言来与操作系统交互(包括交互式和非交互式)。该 shell 还允许您使用 shell 脚本作为过滤器,提供对处理信号的集成支持,但缺乏定义函数的能力。 最后,它整合了我们如今使用的许多功能,包括命令替换(使用反引号)和用于将保留的字符串文字嵌入到脚本中的 HERE 文档。
Bourne shell 不仅是向前发展的重要一步,也是众多衍生的 shell 的基础,其中许多 shell 如今应用在典型的 Linux 系统中。图 1 演示了重要 shell 的系列。Bourne shell 导致了 Korn shell (ksh)、Almquist shell (ash) 和流行的 Bourne Again Shell(或 Bash)的开发。在 Bourne shell 发布时,C shell (csh) 正在开发。图 1 显示了主要系列,但没有展示所有影响,也没有展示一些具有重要贡献的 shell。
图 1. 1977 年以来的 Linux shell
我们稍后将分析其中一些 shell,查看为它们的进步做出贡献的语言和功能示例。
基本 shell 架构
一种假想的 shell 的基本架构很简单(Bourne 的 shell 就是一个证据)。在图 2 中可以看到,基本架构看起来类似一个管道,其中会分析和解析输入,展开符号(使用各种方法,比如括号、波浪号、变量、参数扩展和替换,以及文件名生成),最终执行命令(使用 shell 内置的命令或外部命令)。
图 2. 假想 shell 的简单架构
在 参考资料 部分中,您可以找到一些链接来了解开源 Bash shell 的架构。
探索 Linux shell
现在让我们看看其中一些 shell,回顾它们所做的贡献并在每个 shell 中查看示例脚本。查看的内容包括 C shell、Korn shell 和 Bash。