捐赠?

Harley Hahn
个人主页

给 Harley
发送留言


来自 Harley Hahn 的
个人寄语

Unix 之书
主页

搜索

章节列表

目录

插图列表

各章...
   1   2   3
   4   5   6
   7   8   9
  10  11  12
  13  14  15
  16  17  18
  19  20  21
  22  23  24
  25  26

术语表

各附录...
  A  B  C
  D  E  F
  G  H

命令
摘要...

• 按字母顺序
• 按类别

Unix-Linux
年表

互联网
资源

错误与
勘误

推荐语


教师
与学生
资料...

主页
与概述

练习
与答案

Unix 模范
课程与
课程大纲

教师用
PowerPoint 文件

第 11 章...

Shell(The Shell)

如你所知,Shell 是读取并解释你命令 的程序。从最初开始,Shell 就被设计成 一个普通的程序,完成它的工作不需要 任何特殊权限。从这个意义上说,它和 Unix 系统上运行的其他任何程序都一样。

正因为这一基本设计,任何具备相应 编程能力的人都可以设计出他自己的 Shell,然后与其他 Unix 用户共享。 多年来发生的事情恰恰就是这样,因此 如今有大量不同的 Shell 在使用。你的 Unix 系统上至少会有几个,你想用哪 一个都可以。你甚至可以在不同的 Shell 之间来回切换。如果你想试试系统上 没有安装的 Shell,互联网上有各种各样 的 Shell 供你免费下载。

在本章中,我要回答几个问题:什么是 Shell?它为什么重要?最受欢迎的 Shell 有哪些?你应该使用哪一个?在接下来的 几章里,我会教你如何使用最重要的几个 Shell:Bash、Korn Shell、C-Shell 和 Tcsh。

跳至页首

什么是 Shell?(What is a Shell?)

一旦你开始使用 Unix,就会听到许多 关于 Shell 的说法。这个所谓的 "shell" 到底是个什么东西?答案有好几个。

简短的技术性回答是:SHELL(外壳) 是一个充当用户界面和脚本解释器的 程序,它允许你输入命令,并间接地访问 内核的服务。

说得再不那么技术化一点,让我给你 一个更详尽的、由两部分组成的 Shell 描述。首先,Shell 是一个命令处理器 (COMMAND PROCESSOR):一个读取并解释 你所输入命令的程序。每次你键入一条 Unix 命令,都是 Shell 在读它,并琢磨 该怎么做。大多数 Shell 还提供一些 功能,让你分分秒秒的日常工作更加 方便。例如,你可以调出、编辑并重新 输入之前的命令。

除了作为命令解释器,Shell 还支持某种 编程语言。使用这种语言,你可以编写 供 Shell 解释的程序,这些程序称为 SHELL 脚本(SHELL SCRIPTS)。这些脚本 既可以包含普通的 Unix 命令,也可以 包含特殊的 Shell 编程命令。每一类 Shell 都有自己的编程语言和规则。不过 通常来说,同一个"家族"中的 Shell 使用 相似的编程语言。(本章稍后会讲到 Shell 的两大主要家族。)

私下里说,这些解释都没有真正抓住那种 笼罩在 Shell 这个概念上的 je ne sais quoi — 那种说不清道不明的东西。 你看,Shell 是你进入 Unix 的主要界面。 由于 Shell 有很多种 — 你可以自行 选择使用哪个界面 — 而这个选择会 影响你使用 Unix 时的感受。

你可以想象,在行家里头,关于哪些 Shell 最好、哪些坚决不该碰,存在着 各种各样的争论。不过,在你成为有 经验的 Unix 用户之前,你用哪个 Shell 其实并不重要。这些差异虽然重要, 对初学者来说却无关紧要:你不妨就用 系统默认的那个 Shell。等你经验更丰富 之后,再挑选你最喜欢的 Shell,然后用它 为自己打造一个高度定制的工作环境。

到了那个时候 — 一旦你懂得如何 有意地去经营自己的工作环境 — 你就会开始理解人们对 Shell 那种神秘的 感情。你看不见它,也摸不着它,但它 永远都在那里,随时准备以最契合你 个人思考方式的方式,满足你的每一种需要。 (如果你是泛神论者,这一点你会觉得 再明白不过。)

— 提示 —

熟练掌握你当前正在使用的 Shell,远比 花大量时间去挑选"正确的" Shell,或者去说服一位忙碌的系统管理员 在你的系统上安装新 Shell 重要得多。

"如果你用不上你钟爱的 Shell,那就 爱上你正在使用的 Shell。" — Harley Hahn

名称的由来

Shell


关于 "shell" 这个名字, 有三种思考方式。第一,Unix Shell 提供了一个定义清晰的界面,用来保护 操作系统的内部机制。从这个意义上说, Shell 就像牡蛎的壳,把它脆弱的部分 与外界严酷的现实隔绝开来。

或者,你也可以想象一枚海螺壳, 一圈又一圈地盘旋而上。使用 Unix Shell 时,你可以随时把手头的事情 放下来,再去启动另一个 Shell 或另一个 程序。这样,你可以把任意多个程序挂起, 每一个都在前一个的"里面", 就像真正贝壳的一层层结构。

不过我的建议是:别去问 "shell" 这个名字是什么 意思。请把 shell 这个词当作一个全新的 技术术语(就像 RTFM 或 foo 一样), 让它的含义完全来自你多年使用 Unix 的 体验。

跳至页首

Bourne Shell 家族:
sh, ksh, bash
(The Bourne Shell Family: sh, ksh, bash)

Shell 是一个程序,和所有程序一样, 它以你键入的运行命令来命名。最早的 第一个 Shell 写于 1971 年,作者是 Unix 的最初创造者之一 Ken Thompson, 那时 Unix 诞生才两年(Unix 的历史见第 2 章)。按照给程序起 短名字的传统,Thompson 把 Shell 命名为 sh

让我们假设你是 20 世纪 70 年代初 的一位早期用户。下面是你使用 sh 程序的方式。首先,你键入 用户标识和密码登录系统(见第 4 章)。 一旦你的密码通过验证,各种启动过程 也执行完毕,Unix 就会替你运行 sh 程序,你的工作会话由此 开始。

sh 程序显示一个 Shell 提示符 (见第 4 章)并等待输入。你每输入 一条命令,sh 就做处理它所需的 一切事情;命令执行完毕,sh 显示一个新的 Shell 提示符,等待下一条 命令。最后,你按下 ^D 发出 eof [文件结束]信号,告诉 sh 再也没有输入数据了(见第 7 章)。 sh 捕获到这个信号之后(同样 见第 7 章)就终止运行,你也随之注销, 工作会话到此结束。

如今,使用 Shell 的体验与 1971 年 基本相同。诚然,现代的 Shell 比最初的 sh 程序强大得多,但它们仍然 是通过一条接一条地读取命令来充当你的 界面,并在没有更多数据时终止。(这就是 为什么 Shell 被称为 CLI,即命令行界面。)

最早的第一个 Shell(我们不妨称之为 Thompson Shell)从 1971 年用到 1975 年, 随 Unix 第一版(Version 1)直到 Unix 第六版(Version 6)一起分发。1975 年, 由 John Mashey 带领的一组贝尔实验室 程序员编写了一个新的 Shell。这个新 Shell 于 1976 年作为一个特殊版本 Unix 的一部分发布,该版本称为 Programmer's Workbench,也就是 PWB。因为 Mashey Shell(也叫 PWB Shell)的设计目的就是 取代原来的 Shell,所以它也被命名为 sh

为新 Shell 沿用同一个名字的好处在于, 作为用户,新 Shell 出现时你不必做任何 特别的事情。有一天你运行 sh 程序,得到的是旧 Shell;第二天你再运行 sh 程序,得到的就是新 Shell。 只要新 Shell 与旧 Shell 兼容,一切都 没问题。你在旧 Shell 里能做的一切照样 能做,而且如果你愿意,还可以 利用新 Shell 那些增强功能。

当一个新程序与旧程序之间存在这样的 关系时,我们就说新程序与旧程序向后 兼容(BACKWARDS COMPATIBLE)。例如, Mashey Shell 就与最初的 Thompson Shell 向后兼容。

因为 Shell 被设计成一个普通程序, 任何具备足够专长的人都可以把现有的 Shell 改成自己喜欢的样子,甚至可以 自己写一个 Shell(*)。1976 年,贝尔 实验室的另一位程序员 Steve Bourne 开始着手一个全新的 Shell。因为它的 设计目的是取代较旧的 Thompson Shell, 所以 BOURNE SHELL 也被命名为 sh

* 脚注

John Mashey 曾向我描述当年贝尔实验室 的情形。"有一段时间,我们那个 30 人的 部门里大概有 10 种不同口味的 Shell。 毕竟我们都是程序员,源代码就摆在那里, 而它又是一个普通的用户程序,所以任何 有兴致的人都会去'修一修'其中的东西。 这很快就乱套了,后来我们才把它 控制住……"

Mashey 和 Bourne 的 Shell 都带来了 重要的改进,尤其是在编程方面,很快 两者都在贝尔实验室内部赢得了大批 支持者。然而,虽然它们都与现有的 sh 程序向后兼容,彼此之间却 不兼容。这就引发了一场内部争论: 哪个 Shell 应该成为标准的 Unix Shell。 这场争论的结果意义深远,因为它在此后 多年改变了 Unix 的走向。

在连续三次 Unix 用户大会上,Mashey 和 Bourne 各自介绍自己的 Shell。 在两次会议之间,两人都努力增加新功能, 以完善自己的 Shell。为了彻底解决这个 问题,一个委员会成立并研究了此事; 他们选择了 Bourne Shell。

于是,随着 Unix 第七版(Version 7)的 发布,Bourne Shell 成为所有 Unix 用户 的默认 Shell。事实上,Bourne Shell 如此稳定、设计如此出色,以至于在很多年 里它都是标准的 Unix Shell。此后不时有 新版本的 Shell 发布,而每一次它都保持 向后兼容,并沿用 sh 这个名字。 Bourne Shell 用得如此广泛,以致今天 所有与之兼容的 Shell — 无论新旧 — 都被视为 BOURNE SHELL 家族的成员。

1982 年,贝尔实验室的另一位科学家 David Korn 创造了一个 Bourne Shell 的 替代品,称为 KORN SHELL,即 ksh。这个新 Shell 建立在 Korn 和其他研究人员过去几年一直在打造的 工具之上。因此,相对于标准的 Bourne Shell,它是一次巨大的改进。特别值得 一提的是,新的 Korn Shell 提供了历史 文件、命令编辑、别名和作业控制(这些 我们在本书后面都会讲到)。

Korn 确保 ksh 程序与当时的 sh 程序向后兼容,很快 Korn Shell 就成为贝尔实验室事实上的标准。 随着下一个 Unix 版本的发布,Korn Shell 被分发到全世界,并很快成为 Bourne Shell 的永久替代者。从那以后, Korn Shell 又有两个重要的新版本: 1988 年的 Ksh88 和 1993 年的 Ksh93。

20 世纪 90 年代初,要求统一 Unix 的 压力越来越大(见第 2 章)。这种压力 形成了两场运动:一场由机构和委员会 主导,另一场来自大众的需求。对于 "怎样才能一劳永逸地统一 Unix Shell"这个问题,两场运动各有自己的 答案。

"官方的"那场运动制定了一整套 称为 POSIX(发音为 "pause-ix")的规范, 它是标准化操作系统的蓝图。实际上, 你可以把 POSIX 理解为商业力量为统一 Unix 而进行的一次有组织的尝试。

名称的由来

POSIX


统一 Unix 的项目是在一个名为 IEEE 的 组织的旗号下启动的。起初,这个项目叫 IEEE-IX,但这个名字实在糟糕,于是 IEEE 想另找一个更好的。

他们怎么也想不到合适的名字,在最后 关头,自由软件基金会的创始人 Richard Stallman(见第 2 章)提出了 POSIX 这个名字。Stallman 把它选作 "Portable Operating System Interface"(可移植 操作系统界面)的首字母缩写。那个并非 必然的 "X" 则是为了让名字看起来更像 Unix 而加上去的。

POSIX 标准的一个重要部分,就是规定 Shell 基本特性的规范。多年来,这个 标准有过好几个名字,包括 IEEE 1003.2 和 ISO/IEC 9945-2(*)。对于企业、政府 和其他机构来说,1003.2 标准是一个重要 的基准,因为它为所有从事 Shell 开发的 人提供了一个明确的基线目标。例如, Ksh93 Shell 就是按符合 1003.2 标准 来设计的。

* 脚注

如果你喜欢缩写词,这里就是它们的原形: IEEE 是电气与电子工程师学会(Institute of Electrical and Electronics Engineers)。 ISO 是国际标准化组织(International Organization for Standardization)。 (ISO 这个名字并不是缩写词,它来自 希腊语 isos,意思是"相等"。) 最后,IEC 是国际电工委员会(International Electrotechnical Commission)。

然而,个人并不容易拿到 1003.2 标准。 事实上,想得到技术细节的副本是需要 花钱的(*)。在大多数 Unix 程序员中间, 通行的理念并不是去遵循 POSIX 这样 放之四海而皆准的统一标准,而是创造 可以由任何人修改、增强的自由软件。 正如我们在第 2 章所讨论的,自由软件 运动催生了自由软件基金会的成立和 Linux 的诞生。可是,Korn Shell 却无法 随 Linux 一起分发。问题在于,Korn Shell 作为 Unix 的一部分,是属于 AT&T 的商业产品。因此,它并不面向公众。

* 脚注

在 ISO 那里,情况至今仍然如此。不过在 IEEE,你可以在线查看 1003.2 标准, 它是那份称为 IEEE 1003.1 的更大规范的 一部分。在网上,请到 www.unix.org, 寻找指向 "Single UNIX Specification" 的链接。你要找的那部分叫 "Shell & Utilities"。

2000 年,AT&T 终于允许 Korn Shell 成为开源产品,但为时已晚, 已经无济于事了。 20 世纪 90 年代出现了许多自由、开源的 Shell,其中最重要的是 FreeBSD Shell、 Pdksh、Zsh 和 Bash。这些 Shell 全都符合 1003.2 标准,足以替代 Korn Shell。

FREEBSD SHELL 正如其名,是 FreeBSD 的默认 Shell。按照传统,它就叫 sh,也就是 Bourne Shell 家族 成员的标准名称。(换句话说,如果你用的 是 FreeBSD,运行 sh 程序,得到的 就是 FreeBSD Shell。)

PDKSH 是 Korn Shell 的一个现代克隆。 Pdksh 的写作目的是在不附带限制性许可 条款的情况下提供一个 Korn Shell, 名字 "public domain Korn shell"(公有 领域的 Korn Shell)正是由此而来。理解 Pdksh 最好的方式,是把它看成一个现代版 的 Korn Shell,而且在两种意义上都是 自由的(既不花钱,又开源)。最初的 Pdksh 写于 1987 年,作者是一位名叫 Eric Gisin 的程序员,他的工作建立在 Charles Forsyth 所写的 Unix 第七版 Bourne Shell 的公有领域版本之上(*)。多年来,许多人 为 Pdksh 做出过贡献。不过自 20 世纪 90 年代中期以来,这个 Shell 已经稳定 下来,基本上没有再改动。这是因为:(1) 它工作得很好,而(2)开源社区里大多数人 都在用 Bash(见下文)。即便如此,许多 Linux 系统确实把 Pdksh 作为已安装的 Shell 之一,所以如果你的系统上有它, 不妨试一试。

* 脚注

20 世纪 70 年代,我在加拿大的滑铁卢 大学读本科,攻读数学和计算机科学。 有一小段时间,我实际上是和 Charles Forsyth 合租公寓的。他安静、随和, 有点古怪,而且非常、非常聪明。如果我 要形容他,那就是:作为 20 世纪 70 年代中期的一名年轻程序员,他看上去 就是那种迟早有一天会写出自己的 Shell 的家伙。

Bourne Shell 家族中下一个重要的成员 是 Zsh,读作 "zee-shell"(即使在 英格兰和加拿大这些通常把字母 Z 读作 "zed" 的地方也是如此)。Zsh 的 程序名是 zsh

Zsh 由 Paul Falstad 于 1990 年开发, 当时他还是普林斯顿大学的本科生。他的 理念是"把其他每一个 Shell 里我能 搞到的所有有趣的东西都拿过来"。正如 他所解释的:"我想要一个能做任何你 想做之事的 Shell。"其成果是一个既提供 其他 Unix Shell 所有重要特性、又拥有 尚未普及的新能力的 Shell。例如,你可以 让 Zsh 在某个特定用户标识登录时通知你。

那么这个名字是怎么来的?Falstad 开发 这个 Shell 的时候,有一位助教名叫 Zhong Shao,他的 Unix 用户标识就是 zsh。Falstad 觉得这会是个不错 的 Shell 名字,就把它用到了自己的新作 上。

Zsh 发布后不久,就在世界各地形成了一批 狂热的追随者,并在程序员和资深 Unix 用户中广受欢迎。如今 Zsh 的境况与 Pdksh 颇为相似:它能用,它稳定,它是 一个出色的 Shell。不过自 20 世纪 90 年代中期以来,新的开发几乎寸步难行。

在 Bourne Shell 家族的所有成员当中, 迄今为止最重要的无疑是 BASH。Bash 最初由 Brian Fox 创建(1987 年),后来 (从 1990 年起)由 Chet Ramey 维护, 两者都是在自由软件基金会的资助之下。 如今,Bash 由世界各地一个程序员社区 共同支持。正如你可能猜到的,实际程序的 名字是 bash

Bash 以类似于 Korn Shell 的方式扩展了 基本 Bourne Shell 的能力。Bash 不仅是 一个带有强大脚本语言的命令处理器,它还 支持命令行编辑、命令历史、目录栈、命令 补全、文件名补全等等(所有这些你终归 都会觉得理所当然)。

Bash 是自由软件,由自由软件基金会分发。 它是 Linux 以及基于 Unix 的 Macintosh 的默认 Shell,也可以用于 Microsoft Windows(在一个名为 Cygwin 的类 Unix 系统下运行)。事实上,世界上每一个重要 的 Unix 系统,要么自带 Bash,要么有 一个可以从互联网免费下载的 Bash 版本。 由于以上所有原因,Bash 是历史上最 受欢迎的 Shell,全世界有数百万人在 使用它。

名称的由来

Bash


Bash 这个名字代表 "Bourne-again shell"(重生的 Bourne Shell),它既 是一个缩写词,又是一个双关。其含义 在于 — 无论字面上还是精神上 — Bash 建立在一个复活("born again",重生)的标准 Unix Shell 之上。

请注意,虽然我们说 Korn shell、 C-Shell 或 Zsh,我们从不 说 the Bash Shell。我们总是直接 说 "Bash"。

跳至页首

C-Shell 家族:
csh, tcsh
(The C-Shell Family: csh, tcsh)

如上所述,最初的 Bourne Shell 于 1977 年推出。一年之后,1978 年, 加州大学伯克利分校的研究生 Bill Joy 开发了一个全新的 Shell,他所依据的 是 Unix 第六版的 sh 程序, 也就是 Bourne Shell 的前身。然而, Joy 做的不仅仅是照搬已有的功能: 他增加了许多重要的改进,包括别名、 命令历史和作业控制。此外,他彻底 重做了编程功能,把脚本语法的设计改成 接近 C 编程语言的样子。因为这个原因, 他把自己的新 Shell 称为 C-SHELL, 并把程序名从 sh 改为 csh

在 20 世纪 70 年代末和整个 80 年代,C-Shell 变得非常流行。你可能会 想,当时已经有了其他出色的 Shell, 为什么还会如此?原因有几个。

第一,C-Shell 相比标准的 Unix Shell 有重大改进。第二,C-Shell 被包含在 BSD Unix 发行版之中(见第 2 章), 而 BSD 本身非常受欢迎。最后,C-Shell 出自 Bill Joy 之手,他是史上最重要的 Unix 程序员之一。Joy 的工具,比如 vi 编辑器,设计得极为出色, 往往被大量人使用。(关于 Joy 对 Unix 的贡献,见第 2 章。)

很长时间以来,C-Shell 都是有经验 Unix 用户的首选 Shell,在大学和研究 机构尤其如此,那里通常把它设为默认 Shell。我 1976 年第一次使用 Unix, 而 C-Shell 就是我起步时用的 Shell。 直到今天,它依然让我倍感亲切。

不过,C-Shell 有两个重要的问题。 一个是可以解决的;另一个很不幸无法 解决,它导致 C-Shell 在有经验的 用户中间失了宠。

首先,由于 BSD 的许可条款,C-Shell 不能被自由地分发和修改,这对许多 程序员来说是个大问题。因此,在 20 世纪 70 年代末,一位名叫 Ken Greer、 来自卡内基梅隆大学的程序员开始着手 做一个完全自由的 csh 版本, 他称之为 tcsh。20 世纪 80 年代初,TCSH(读作 "Tee sea-shell") 的维护责任移交给了由俄亥俄州立大学 Paul Placeway 带领的一小批程序员。

Tcsh 非常出色。它不仅自由(以公有 领域的形式分发),而且通过提供一系列 高级特性增强了 C-Shell,例如文件名 补全和命令行编辑。Tcsh 吸引了大量 用户,久而久之,形成了一个庞大的 志愿者群体来维护和扩展它。

然而,有一个问题无法解决:C-Shell 和 Tcsh 在编程方面都不如 Bourne 家族的 Shell。尽管类 C 的语法用来 写 C 程序很好,却没那么适合编写 Shell 脚本,尤其是在 I/O(输入/输出)方面。 此外,C-Shell 和 Tcsh 还有许多设计 缺陷,这些都太过晦涩,不值一提, 却令那些在乎晦涩之处的程序员耿耿 于怀。

到了 20 世纪 90 年代,所有流行的 Shell 都可以用在所有 Unix 系统上, 于是围绕哪个 Shell 最好的争论普遍 兴起。C-Shell 就像一位衣裙略显妖艳、 反受其累的年轻女子,在不知不觉之中 开始声名受损。在铁杆 Unix 用户和 想成为铁杆用户的人中间,说一句 "我平时干活喜欢用 C-Shell, 但编程时用 Bourne Shell"成了 一种时髦。

1995 年出现了一个分水岭。那一年, Tom Christiansen —— 一位深受 敬重的 Unix 程序员、Perl 编程语言的 之父之一 —— 写了一篇广为流传的文章, 题为 "Csh Programming Considered Harmful"(《Csh 编程有害》)。这个 标题取自一篇非常有名的计算机论文 "Go To Statement Considered Harmful" (《Go To 语句有害》),那是荷兰 程序员 Edsger Dijkstra 写的一篇短文(*)。 1968 年,Dijkstra 的这篇论文改变了 编程世界,推动了后来所谓结构化编程的 普及。1995 年,Christiansen 的论文 虽然影响没那么开创性,却最终导致人们 不再用 C-Shell 和 Tcsh 编程。

* 脚注

Communications of the ACM(CACM), 第 11 卷第 3 期,1968 年 3 月, 147-148 页。你有空的时候读一读这篇 论文。(在互联网上很容易找到。)读的 时候请想一想:这篇短短 14 段的文章, 对编程世界的改变,超过此前或此后任何 一个单独的举动。如果你有兴趣,不妨再 看看 Dijkstra 那部具有开创意义的著作 A Discipline of Programming (Prentice-Hall PTR, 1976)。

顺便说一句,Dijkstra 论文(因而 也是 Christiansen 论文)的标题其实 出自 Niklaus Wirth 之手,而非 Dijkstra。Wirth 是 Algol W、Pascal 和 Modula-2 编程语言的创造者,当时 是 CACM 的编辑。

如今,C-Shell 和 Tcsh 的使用远不如 从前广泛,而且自 20 世纪 90 年代 中期以来,Tcsh 的开发几乎完全停滞。 尽管如此,C-SHELL 家族在许多 资深 Unix 用户心中仍享有很高的地位, 正因为如此,我为本书专门留出一章, 教你如何使用这个 Shell,如果你愿意 用的话。

在某些系统上,cshtcsh 是两个独立的程序。但在 许多 Unix 系统上,tcsh 已经 完全取代了 csh。也就是说,如果 你运行 csh,实际得到的是 tcsh。你可以通过查看 csh 的手册页(见第 9 章) 来判断你的系统是否如此。

即使在今天,C-Shell 依然重要。事实上, 当你阅读其他 Shell 的介绍时,常会看到 它们纳入了 Bill Joy 多年前设计的 C-Shell 特性。例如,在 Zsh 的网站 上你会读到:"bashkshtcsh 的许多有用特性都被 吸收进了 zsh。"

名称的由来

C-Shell, Tcsh


C-Shell 这个名字来自这样一个事实: Bill Joy 把这个 Shell 的编程功能 设计成与 C 编程语言相似。我猜 Joy 喜欢 "C-Shell" 这个名字, 是因为它听起来像 "sea shell" (海螺壳),而人人都喜欢海螺壳。

那么 Tcsh 又是怎么一回事?

Ken Greer 为 Unix 编写最初的 Tcsh 时,他还在 DEC 的一台 PDP-10 计算机上 使用一个名为 TENEX 的操作系统。TENEX 的命令解释器使用很长的命令名,因为 它们容易理解。可是命令敲起来麻烦, 所以 TENEX 提供了一个叫 "命令补全" (command completion)的功能来代劳 大部分工作。你只需输入几个字母,再 按下 <Esc> 键,命令解释器就会把 你输入的内容扩展成完整的命令。

Greer 把这个特性加到了新的 C-Shell 上,到了该给这个 Shell 起名字的 时候,他把它叫做 tcsh,其中的 "t" 指的就是 TENEX。

名称的由来

C, C++, C#


C-Shell 和 Tcsh 都是以 C 编程语言 命名的。但一门语言怎么会起这么个 古怪的名字?

1963 年,英国开发了一门叫 CPL 的 编程语言,那是一个有剑桥大学和伦敦 大学研究人员参与的项目的一部分。CPL 代表 "Combined Programming Language" (组合编程语言),它以 Algol 60 为 基础,而 Algol 60 是最早设计精良的 现代编程语言之一。

四年之后,1967 年,剑桥一位名叫 Martin Richards 的程序员创造了 BCPL, 即 "Basic CPL"(基础 CPL)。BCPL 本身又催生了另一门语言,只用一个 字母命名:B。

B 语言被带到贝尔实验室,Ken Thompson 和 Dennis Ritchie 对它做了修改,并 重命名为 NB。20 世纪 70 年代初, Thompson(Unix 的最初开发者)用 NB 重写了 Unix 的基本部分,用于第二版。 在此之前,整个 Unix 都是用汇编语言 编写的。不久之后,NB 语言被扩展并 更名为 C。C 很快成为编写新的 Unix 实用工具、应用程序乃至操作系统本身的 首选语言。

人们问道:C 这个名字是从哪儿来的? 是字母表中 B 之后的下一个字母,还是 BCPL 的第二个字母?这个问题有着关乎 宇宙般重要的语源学意义:C 的继任者 会叫 D 还是 P?

事实证明这个问题无关紧要:20 世纪 80 年代初,同样出自贝尔实验室的 Bjarne Stroustrup 设计了 C 最受欢迎 的扩展,一门面向对象的语言,他称之 为 C++,读作 "C-plus-plus"。 (在 C 语言里,++ 是一个给变量 加 1 的运算符。例如,要给变量 total 加 1,你可以使用命令 total++。)

2002 年,微软作为其 .NET 计划的 一部分创建了一个特殊版本的 C++。他们 把新语言称为 C#,读作 "C sharp" (如同音乐术语里的升号)。你愿意的 话,可以想象两个小小的 "++" 上下相叠,构成了 "#" 这个符号。

因此,当你看到 C、C++ 或 C# 这些 名字时,你可以把它们当作那些绝妙的 编程双关语的一个例子 —— 这类双关 足以让人挠头沉思:人类究竟是不是 自然界的终极之作。

跳至页首

你应该使用哪个 Shell?(Which Shell Should You Use?)

Unix 的 Shell 有几十种之多,我们 上面讨论过其中最重要的几种:Bourne shell、Korn shell、FreeBSD Shell、 Pdksh、Zsh、Bash、C-Shell 和 Tcsh。

作为参考,图 11-1 列出了这些 Shell 以及各自程序的名字(*)。要运行 某个 Shell,只要你的系统上有,键入 它的名字即可,例如:

bash
ksh
tcsh

图 11-1(Figure 11-1):Unix 的众多 Shell

Unix Shell 数量众多。这张表列出了 最受欢迎的几种 Shell,以及实际 Shell 程序的名称。

Shell 程序名称
Bashbashsh
Bourne Shellsh
C-Shellcsh
FreeBSD Shellsh
Korn Shellkshsh
Pdkshksh
Tcshtcshcsh
Zshzsh

* 脚注

还有另外两个你可能遇到的常见名字, 它们看上去像普通的 Shell,其实不是: sshrshssh 程序是 "Secure Shell"(安全外壳), 用于连接远程计算机。rsh 程序是 "Remote Shell"(远程外壳) — 一个已不推荐使用的老程序 — 用于在远程计算机上运行单条命令。

在某些 Unix 系统上,各种 Shell 都 以自己的名字安装。sh 程序 不同于 kshbash, csh 也不同于 tcsh。 所以,如果你想用老式的 Bourne shell, 就键入 sh;想用 Bash,就键入 bash。同样,你可以用 csh(标准 C-Shell),也可以用 tcsh(增强版 C-Shell)。

然而在许多系统上,较新的 Shell 已经 取代了旧的,你根本找不到 Bourne shell 或 C-Shell。相反,如果你键入 sh,得到的会是 Bash 或 Korn shell;如果你键入 csh,得到的 是 Tcsh。要确认你的系统是否如此, 查一查相应 Shell 的手册页即可。例如, 在 Linux 系统上,如果你索取 sh 的手册页,得到的是 bash 的手册页;如果你索取 csh 的手册页,得到的是 tcsh 的手册页。

要显示某个特定 Shell 的手册页,使用 man 命令(第 9 章),后面 跟上相应程序的名字。例如:

man sh
man csh

由于 Shell 极其复杂,手册页实际上 会有一本小手册那么长。别被吓住:你看到 的内容有很多是供高级用户查阅的参考 资料。

那么,你应该使用哪个 Shell?如果你 是初学者,其实用哪个都无所谓,因为 所有 Shell 都有相同的基本功能。不过, 随着你作为 Unix 用户不断进步,细节 就开始变得重要,你需要做出一个选择。

如果你喜欢随大流,那就沿用默认设置, 键入 sh 时系统给你什么就用 什么。在 Linux 上很可能是 Bash,在 FreeBSD 上是 FreeBSD Shell,在商业 Unix 上则很可能是 Korn shell。

然而,如果你喜欢冒险,有很多 Shell 供你尝试。例如,虽然 C-Shell 已经不 是默认 Shell,但确实有很多人乐于使用 它,你也可能会发现 tcshcsh 在你的系统上已经可用。 想走得更远,只要在互联网上搜索 Unix 或 Linux shells,我保证你能找到值得 一试的新东西。(如果你有冒险精神 却又拿不定主意,那就试试 Zsh。)

— 提示 —

对于日常工作,你可以用任何合你心意的 Shell,想什么时候换就什么时候换。

但是,如果你编写 Shell 脚本,就应该 坚持使用标准的 Bourne shell 编程 语言,以确保你的脚本足够可移植,能在 其他系统上使用。

接下来我就教你怎样更改你的 Shell。 在那之前,我想先回答一个有趣的问题: 各个 Shell 究竟有多复杂?一个复杂的 程序功能很多,但也会要求你花更多时间 去掌握。而且和许多 Unix 程序一样, Shell 还有很多你永远也用不上的晦涩 特性和选项。这些额外的功能常常是一种 干扰。

衡量程序复杂度的一个粗略办法,是看 文档的长度。图 11-2 中的表格列出了 每种 Shell 手册页的大约字节数(字符数)。 为了便于比较,我对这些数字做了归一化 处理,把最小的那个定为 1.0。(当然, 随着文档新版本的发布,这些数字不时 会有所变化。)

图 11-2(Figure 11-2):Unix 各 Shell 的相对复杂度

估计程序复杂度的一个办法,是看它文档 的规模。下面是反映最受欢迎的几种 Unix Shell 相对复杂度的统计数据。

Shell 名称 手册页大小 相对复杂度
Bourne Shell 38,000 字节 1.0
FreeBSD Shell 57,000 字节 1.5
C-Shell 64,000 字节 1.7
Korn Shell121,000 字节 3.2
Tcsh250,000 字节 6.6
Bash302,000 字节 7.9
Zsh789,000 字节20.8

从这些数字很容易看出,C-Shell 和 FreeBSD Shell 在较老、功能较弱的 Bourne shell 与其他更复杂的 Shell 之间,提供了一个不错的中间选择。

当然,也有人可以说这些都无关紧要, 因为所有现代 Shell 都是向后兼容的, 要么与 Bourne shell 兼容,要么与 C-Shell 兼容。如果你不需要那些附加 功能,完全可以忽略它们,它们也不会 来烦你。

不过,文档是很重要的。较复杂 Shell 的手册页读起来非常耗时,而且很难 理解。事实上,就连 Bourne shell 的 手册页,其篇幅也大得让普通人无法 舒适地通读。所以,再看一下图 11-2 中的数字,想想下面这几个问题:

假设 FreeBSD Shell、Bash 和 Zsh 都具备有见识的 Unix 用户所需要的 大部分现代特性,那么对于一个选择使用 FreeBSD 和 FreeBSD Shell 的人,你 能说出些什么?

那么,一个因为 Bash 是自己系统上的 默认 Shell 而使用它的人呢?

还有,你觉得什么样的人才会乐于下载、 安装并学习一个像 Zsh 这样复杂的工具 (它在任何系统上都不是默认 Shell)?

跳至页首

临时更改你的 Shell(Changing Your Shell Temporarily)

每当你登录时,系统都会自动为你启动 一个 Shell。这个 Shell 称为你的登录 SHELL(LOGIN SHELL)。一个需要回答的 重要问题是:究竟哪个 Shell 是你的 登录 Shell?是 Bash、Korn shell、 C-Shell 还是 Tcsh?

除非你更改过默认设置,否则你的登录 Shell 就是分配给你用户标识的那个 Shell。如果你用 Linux,你的登录 Shell 很可能是 Bash。如果你用商业 Unix,你的登录 Shell 很可能是 Korn shell。如果你用 FreeBSD,那很可能是 Tcsh。

如果你用的是共享系统,你的系统管理员 会为你设定登录 Shell。如你所知,在你 自己的计算机上,你就是管理员(见第 4 章),所以除非你更改过默认 Shell,否则 它就是你安装系统时自动设定的那一个。

更改 Shell 有两种方式。你可能想暂时 使用另一个 Shell,也许是为了试一试。 也可能你发现自己更喜欢某个新 Shell, 想做一个永久性的更改。

举个例子,假设你决定试试 Zsh。你从 互联网下载它并安装到你的系统上。时不 时地,你临时切换到 Zsh,纯粹为了好玩。 最终,你发现自己太喜欢 Zsh 了,想让 它成为你永久的登录 Shell。本节中,我 会教你怎样临时更改 Shell;下一节,我 会教你怎样永久更改。

首先,记住 Shell 只是一个程序,你可以 像运行其他任何程序一样运行它。这意味着 在任何时候,你都可以暂停当前的 Shell, 只需运行新的 Shell,就能启动另一个。 例如,假设你刚登录,你的登录 Shell 是 Bash。你输入了几条命令,然后决定想试试 Tcsh(假设你的系统上有它)。只需输入:

tcsh

你当前的 Shell(Bash)被暂停,新的 Shell(Tcsh)随即启动。现在你可以用 Tcsh 做任何你想做的事。当你准备换回 Bash 时,只需按下 ^D(见第 7 章),表示没有更多数据了。Tcsh 就会 结束,你则回到原来的 Bash Shell。就是 这么简单。

如果你想动手试验,可以用下面这条命令 查看系统上有哪些可用的 Shell:

less /etc/shells

下一节我们会讨论这条命令。

如果你在试验过程中,把自己弄糊涂了, 搞不清自己用的是哪个 Shell,随时可以 用下面这条命令显示当前 Shell 的名字:

echo $0

如果这条不管用,就用:

ps -p $$

— 提示 —

你可以启动一个新 Shell,然后再启动 一个新 Shell,然后再来一个,如此没完 没了。然而,当你要结束工作会话时, 只能从最初的那个登录 Shell 注销。

因此,如果你已经启动了一个或多个新 Shell,就必须一层层退回到登录 Shell, 然后才能注销。

跳至页首

密码文件;
更改你的登录 Shell: chsh
(The Password File;
Changing Your Login Shell: chsh)

Unix 用两个文件来记录系统中所有的 用户标识。第一个文件 /etc/passwd — 密码文件(PASSWORD FILE) — 包含每个用户标识的基本信息。 第二个文件 /etc/shadow — 阴影文件(SHADOW FILE) — 包含 真正的密码(当然,是加密过的)。

当你登录时,Unix 从这些文件中读取 关于你用户标识的信息。具体来说, /etc/passwd 文件中含有你登录 Shell 的名字。因此,要更改你的登录 Shell,你只需要在 /etc/passwd 文件中做一个简单的改动。不过,你不要 直接这么做。那样太危险了,因为把 /etc/passwd 文件搞砸会给你的 系统带来灾难。相反,你要用一个特殊的 命令,我马上就会讲。

在那之前,我想先就文件名说几句。我刚才 提到的那两个文件的书写方式,称为"路径名" (pathname)。路径名显示文件在文件系统 中的确切位置。我们在第 23 章讨论 Unix 文件系统时会详细谈到这个概念。眼下你 只需要知道,路径名 /etc/passwd 指的是 /etc 目录中的 passwd 文件。目录(directory) 就是 Windows 或 Mac 用户所说的文件夹。 (这个概念和许多其他概念一样,都是从 Unix 那里学来的。)

当你更改 Shell 时,需要以路径名的形式 指定 Shell 程序的名字。可用 Shell 的 路径名存放在一个名为 /etc/shells 的文件中(*)。要显示这个文件,使用 less 命令(我们将在第 21 章 正式认识它)。

less /etc/shells

* 脚注

/etc/shells 文件在 Linux 和 FreeBSD 上使用,但某些商业 Unix 系统 (如 AIX 和 Solaris)不用。

下面是一些典型的输出:

/bin/bash
/bin/sh
/bin/tcsh
/bin/csh

从这段输出可以看出,(在本例中)共有 四个可用的 Shell:shbashtcshcsh

要更改你的登录 Shell,你使用 chsh(change shell,更改 shell)命令。其语法(*)是:

chsh [-s shell] [userid]

其中 userid 是你想为之做更改的 用户标识;shell 是新登录 Shell 的路径名。

注意:(1)你只能更改自己用户标识的 Shell。要更改另一个用户标识的 Shell, 你必须是超级用户。(2)在某些系统上, 除非某个 Shell 已经列在 /etc/shells 文件中,否则 chsh 不会允许你切换到它。在 另一些系统上,chsh 允许你做 这样的更改,但会给你一个警告。因此, 如果你自己下载并安装了一个 Shell,最好 把这个 Shell 的路径名写进 /etc/shells 文件。

* 脚注

在本书中,我会教你如何使用大量的命令。 每次我介绍一个新命令,都会先给你看它的 语法。我这样做时,只会展示最重要的选项 和参数。如果你需要更多信息,随时可以从 手册页上获取(见第 9 章)。

正如我在第 10 章所解释的,有些命令在 不同版本的 Unix 之间会有细微的差别。 在本书中,我通常使用某个命令的 GNU/Linux 版本。大多数情况下这样做没问题,因为 重要的选项和参数在大多数类型的 Unix 中 都是一样的。不过,如果你遇到了问题,我 希望你记住:关于一个程序在你的系统上 究竟如何工作,权威的资料来源是你的 联机手册。

默认情况下,chsh 假定你要更改 自己的登录 Shell,所以你不必指定用户 标识。例如,要把你的登录 Shell 改为 /bin/tcsh,使用:

chsh -s /bin/tcsh

如果你省去 -s 选项和 Shell 的 名字,chsh 会提示(询问)你要。 例如,假设你以 harley 登录,并且 输入:

chsh

你会看到:

Changing shell for harley.
New shell [/bin/bash]:

这时 chsh 在告诉你两件事。 第一,你即将更改用户标识 harley 的登录 Shell。第二, 当前的登录 Shell 是 /bin/bash

现在你有两个选择。如果你输入一个新 Shell 的路径名,chsh 就会替你 完成更改。例如,要把你的登录 Shell 改为 Tcsh,输入:

/bin/tcsh

如果你什么也不输入,只是按下 <Enter>,chsh 就不会做 更改。这是查看你当前登录 Shell 名字的 一个好办法。

在 Linux 上,chsh 命令还有一个 很有用的选项。要显示所有可用 Shell 的 列表,你可以使用 -l(list,列出) 选项:

chsh -l

有些 Unix 系统没有 chsh 命令。 在这些系统上,你要通过 passwd 命令的一个变体来更改登录 Shell(我们在 第 4 章讨论过它)。例如, 在 AIX 上使用 passwd ‑s;在 Solaris 上使用 passwd -e。更多细节 请查看你的 passwd 手册页。

如果你是系统管理员,有人请你替别人 更改登录 Shell,你可以使用 usermod -s。同样,详情请查看 手册页。

— 提示 —

当你更改登录 Shell 时,你实际修改的是 /etc/passwd 文件。因此,你所做的 任何更改都要等到下一次登录时才生效 (正如你更改密码时一样)。

— 提示 —

在某些情况下,如果你的系统病得很重, 你需要以超级用户(root)身份 登录来做修复,而有些 Shell 可能无法 正常运行。因此,root 的登录 Shell 必须是那种无论如何都能启动运行 的 Shell。

所以,除非你真的知道自己是在干什么, 否则不要更改用户标识 root 的登录 Shell。如果你改了, 你就冒着某一天系统坏掉却毫无办法登录 的风险。

跳至页首



练习(Exercises)

复习问题 #1:

什么是 Shell?

复习问题 #2:

两大主要的 Shell 家族是什么?说出每个 家族中最常用的那些 Shell 的名字。

复习问题 #3:

"向后兼容"是什么意思?

举一个与另一个 Shell 向后兼容的 Shell 的例子。

复习问题 #4:

什么是 POSIX?它怎么读?

复习问题 #5:

怎样临时更改你的 Shell?怎样永久地 更改你的 Shell?

应用你的知识 #1:

查看你的系统上有哪些可用的 Shell。

显示你的默认 Shell 的名字。

应用你的知识 #2:

把你的默认 Shell 换成另一个 Shell。 注销并再次登录。检查确认你的默认 Shell 已经更改。

再把你的默认 Shell 换回原来的那个。 注销并再次登录。检查确认你的默认 Shell 已正确改回。

进一步思考 #1:

多年来,人们创造了许多不同的 Unix Shell。为什么有必要这样做?为什么不 只用一个主要的 Shell,时不时地加以 增强就好?

进一步思考 #2:

程序 A 被程序 B 取代了。如果程序 B 与程序 A 向后兼容,好处是什么?坏处 又是什么?

跳至页首