|
Harley Hahn 的
|
|
各章...
命令
教师 |
第 23 章... Unix 文件系统 (The Unix Filesystem)
在下面的三章里,我们将讨论 Unix 文件系统,也就是 操作系统中为你和你的程序服务的那一部分:它负责存储 并组织你系统上的所有数据。本章先讲基本概念, 随后在第 24 章讨论目录的具体用法, 在第 25 章讨论文件的具体用法。 本章的目标是回答三个关键问题。第一,什么是 Unix 文件?不难想象,文件可以是存放在磁盘上的数据仓库。 但你会看到,它的含义远不止于此。第二个问题关乎组织 方式。一台 Unix 系统上常常有几十万个文件,如何才能把 这么多条目组织得井井有条、易于理解?最后,一个统一 的系统怎么可能透明地支持许多不同类型的数据存储设备? 我们的讨论从一个简单的问题开始,它的答案却复杂得 令人吃惊:什么是文件?
在还没有计算机的旧时代,“文件”一词指的是一摞纸张。 通常,文件放在硬纸板文件夹里,再加以整理,存进档案 柜。如今,大多数数据都已计算机化,文件的定义也随之 改变。从最简单的意义上说,文件就是被起了名字的一堆 数据(*)。多数情况下,文件存放在数字媒体上:硬盘、 CD、DVD、软盘、U 盘、存储卡等等。 * 脚注 一个 Unix 文件实际上可以有不止一个名字。我们将在 第 25 章讨论链接时讲到这一点。 在 Unix 内部,文件的定义要宽泛得多。文件(FILE)是 任何有名字、可以从中读取数据的来源;也是任何有名字、 可以往里写入数据的去向。因此,当你使用 Unix 或 Linux 时,“文件”不仅指磁盘文件这类数据仓库,还指任何物理 设备。例如,键盘可以作为文件来访问(一个输入来源), 显示器同样如此(一个输出去向)。还有一些文件毫无实体 形态,却能接受输入或产生输出,以提供特定的服务。 以如此通用的方式定义文件,其重要性怎么强调都不为过: 这意味着 Unix 程序可以用简单的过程从任何输入来源读取 数据,并向任何输出去向写入数据。例如,大多数 Unix 程序被设计成从标准输入读取、向标准输出写入(见第 18 章和第 19 章)。从程序员的角度看,I/O(输入/输出)很 容易实现,因为无论数据实际来自何处、去往何处,读写 数据都能以简单而标准的方式完成。从用户的角度看,则 拥有极大的灵活性,因为他可以在运行程序的当下指定输入 来源和输出去向。 可以想见,Unix 文件系统——或任何文件系统——的内部 细节是复杂的。本章我们只讲基本概念,等你读完,就会 发现 Unix 文件系统是一种令人着迷的精美之物:这种美 只存在于一切都说得通的复杂系统之中。
Unix 文件有很多种类型,但都归入三大类:普通文件、 目录和伪文件。在伪文件之中,最常见的又有三种:特殊 文件、命名管道和 Proc 文件。本节我们先快速浏览一番 这些最重要的文件类型,后面的各节再分别详细讨论每一 种文件。 普通文件(ORDINARY FILE)或规则文件(REGULAR FILE) 就是大多数人听到“文件”一词时所想到的东西。普通文件 存有数据,驻留在某类存储设备上,例如硬盘、CD、DVD、 U 盘、存储卡或软盘。因此,普通文件是你平时打交道最 多的文件类型。例如,当你用文本编辑器写一个 Shell 脚本时,这个 Shell 脚本和编辑器程序本身都存放在普通 文件里。 如我们在第 19 章所讨论的,粗略地说,普通文件分为两 类:文本文件和二进制文件。文本文件包含一行行可打印 字符组成的数据(字母、数字、标点符号、空格、制表 符),每行末尾有一个换行字符。文本文件用来存放文本 数据:纯数据、Shell 脚本、源程序、配置文件、HTML 文件等等。 二进制文件包含非文本数据,这类数据只有被执行或被某个 程序解释时才有意义。常见的例子有可执行程序、目标文 件、图像、音乐文件、视频文件、文字处理文档、电子表 格、数据库等等。例如,文本编辑器程序本身是一个二进制 文件,而你所编辑的那个文件是文本文件。 由于你遇到的文件几乎都是普通文件,掌握基本的文件操作 技能至关重要。具体来说,你必须学会如何创建、复制、 移动、重命名和删除这类文件。我们将在第 25 章详细 讨论这些主题。 第二种文件类型是目录(DIRECTORY)。与普通文件一样, 目录也驻留在某类存储设备上。然而目录不存放常规数据, 它们用于组织并访问其他文件。从概念上说,目录“包含” 其他文件。例如,你可能有一个名为 vacation 的 目录,里面存放着你即将前往 Syldavia 旅行所需的全部 文件。 目录还可以包含其他目录。这让你能够把文件组织成一个 层次化的系统。你在本章后面会看到,整个 Unix 文件系统 就是按一棵巨大的层次树组织的,目录套着目录,目录里再 套目录。在这棵树中属于你的那部分里,你可以随心所欲地 创建和删除目录。这样,你就能按自己的意愿组织文件,并 随需求的变化而调整。 (你还记得吗,在第 9 章讨论 Info 系统时,我们谈到过 树。严格地说,树(TREE)是一种数据结构,由节点、叶和 分支组成的集合,其组织方式保证任意两个节点之间至多有 一条分支。) 你有时会看到用“文件夹(FOLDER)”来代替“目录”一词, 尤其在图形用户界面工具中。这种说法来自 Windows 和 Macintosh 世界,因为这两个系统都用文件夹来组织文件。 Windows 的文件夹很像 Unix 的目录,但没有那么强大。 Macintosh 的文件夹则就是 Unix 的目录,因为 Mac 的操作系统 OS X 是运行在 Unix 之上的(见 第 2 章)。 最后一种文件类型是伪文件(PSEUDO FILE)。与普通文件 和目录不同,伪文件不用于存放数据。因此,伪文件本身 不占任何空间,尽管它们被视为文件系统的一部分,并且 同样被组织在目录之中。伪文件的用途是提供一种服务, 而访问这种服务的方式与访问常规文件的方式相同。多数 情况下,伪文件用来访问由内核——操作系统的核心部分 ——提供的服务(见第 2 章)。 最重要的一类伪文件是特殊文件(SPECIAL FILE),有时 称为设备文件(DEVICE FILE)。特殊文件是物理设备的 内部表示。例如,你的键盘、显示器、打印机、磁盘驱动 器,实际上你计算机里的或网络上的每一台设备——都可以 作为特殊文件来访问。 下一种伪文件是命名管道(NAMED PIPE)。命名管道是我们 在第 15 章讨论过的管道机制的延伸,因此它能把一个程序 的输出接到另一个程序的输入。 最后,Proc 文件让你可以访问内核内部的信息。在少数 特定情形下,你甚至能用 Proc 文件修改内核里的数据。 (显然,这只有非常内行的人才该做。)最初创建这些文件 是为了提供进程运行时信息,因此得名“proc”。 名称的由来 File(文件) 当你看到或听到“file”这个词时,必须依上下文判断它的 含义。有时它指任何类型的文件;有时它只指包含数据的 文件,也就是普通文件。 例如,假设你读到这句话:“ls 程序会列出目录中 所有文件的名字。”此处“file”指任何类型的文件:普通 文件、目录、特殊文件、命名管道或虚拟文件。这五种文件 都可能出现在目录里,因而都能被 ls 程序列出。 然而,假如你读到的是:“要用 cmp 程序把一个文件 与另一个文件比较。”此处“file”指的是普通文件,因为只有 这种文件包含可比较的数据。
我们用目录把文件组织成一个层次化的树状系统。为此, 我们把文件收集成一个个组,每个组存放在自己的目录里。 由于目录本身也是文件,一个目录就能包含其他目录,层次 由此形成。 举个例子。你是西海岸一所声望很高的大学的学生,本学期 选了三门课——历史、文学和冲浪——每门课都写了不少 论文。为了把这一切作业组织好,你建了一个叫 essays 的目录(暂时别管具体怎么做)。在这个 目录里,你又建了三个目录:history、 literature 和 surfing,用来存放论文。 每篇论文都存在一个文本文件里,文件名字起得很贴切。 Figure 23-1 展示了这整个结构的样子。注意,这张图 看上去像一棵倒过来的树。 |
| |||||||
|
|
通常情况下,除非你是系统管理员,否则你永远不必去看 Proc 文件。大体而言,Proc 文件只被那些需要从内核获取高度技术 性信息的程序使用。例如,在第 26 章我们将讨论 ps (process status,进程状态)程序,它会显示你系统上各进程 的信息。ps 程序正是通过读取相应的 Proc 文件来 收集它所需的数据的。 有一个格外引人入胜的 Proc 文件,我没有列在 Figure 23-3 里,那就是 /proc/kcore。这个文件 表示你计算机的实际物理内存。你可以用带 -l 选项的 ls 程序显示它的大小(见第 24 章): ls -l /proc/kcore 这个文件看上去会大得吓人:实际上,它的大小与你计算机全 部内存(RAM)的容量相同。但要记住,这是一个伪文件:它并 不真的占用空间。 提示 Linux 用户:我鼓励你去探索一下系统里的 Proc 文件。看看 这些文件的内部,能让你对自己的系统如何配置、机制如何运作 增长不少见识。为了不出乱子,请确保你不是超级用户, 哪怕你只是看一看。
在接下来几节里,我们要谈谈 Unix 文件系统以及它的组织 方式。讨论中我以标准的 Linux 文件系统为例。细节在不同 的 Unix 系统之间会有差别,所以你的系统可能与这里写的 有些不同。但基本概念,包括大多数目录名字,都是一样的。 一台典型的 Unix 系统含有远超十万个文件(*),存放在目录 和子目录中。所有这些文件都被组织进一个文件系统 (FILESYSTEM),其中的目录以一棵树的结构组织,树根是一个 称为主目录的目录,即“根目录”。文件系统的职责是存储和 组织数据,并向用户和程序提供对这些数据的访问。 Figure 23-4 给出了文件系统组织方式的图示。根目录 ——直接或间接地——是系统中所有其他目录的父目录。 * 脚注 不,我没有夸大其词。有些基本的 Unix 系统自带超过二十万 个文件。要估算你系统上文件和目录的数量,请以超级用户身份 运行下面这条命令: ls -R / | wc -l |
| |||||||
|
第一次查看 Unix 文件系统的组织方式,你或许会有些发怵。 毕竟那些名字古怪而神秘,几乎看不出什么道理。然而,如同 Unix 世界的大部分内容一样,一旦你明白了这些模式以及它们 如何运作,Unix 文件系统就很好懂了。本章后面我们会把 Figure 23-4 里的子目录逐个过一遍,届时我会解释它们 的用途以及名字的由来。 不过在开始之前,我想花点时间说说 Unix 文件系统为什么会 组织成这个样子。如我们在第 2 章所讨论的,第一个 Unix 系统是 1970 年代初在贝尔实验室开发的。Figure 23-5 展示了最初那个 Unix 系统的结构,它本来就是按层次树设计 的。别担心那些名字,后面都会说得明白。我只想让你注意一 点:最初的文件系统与如今的文件系统(Figure 23-4) 的某个子集极其相似。 |
| |||||||
|
随着 Unix 逐年演进,文件系统的组织方式也跟着变化,以反 映各路 Unix 开发者的需求与偏好。虽然基本格式没变,细节 却因 Unix 的版本而异。这造成了相当的混乱,尤其是当用户 在 System V Unix 和 BSD 之间来回迁移的时候(见 第 2 章)。到了 1990 年代,各 Linux 发行版的创造者开始 引入自己的变体,混乱于是加剧。 1993 年 8 月,一群 Linux 用户成立了一个小组织,制定标准 的 Linux 目录结构。第一份这样的标准于 1994 年 2 月发布。 1995 年初,随着 BSD 社区成员加入这项工作,该组织把目标 进一步扩大。从那以后,他们致力于能为所有 Unix 系统—— 而不只是 Linux——制定标准的文件系统组织方式。这套新的 体系被称为文件系统层次标准(FILESYSTEM HIERARCHY STANDARD,FHS)。当然,由于并不存在 Unix 警察,这个标准 是自愿采用的。尽管如此,许多 Unix 和 Linux 开发者还是 选择采纳了 FHS 的大部分内容。 尽管许多 Unix 系统在某些方面与 FHS 不同,但 FHS 是一个 深思熟虑的方案,确实抓住了现代 Unix 和 Linux 文件系统 组织方式的精髓。理解了 FHS,你会发现与任何其他 Unix 系统打交道都很容易。因此,在我们讨论 Unix 文件系统的 细节时,我将以 FHS 为样板。如果你想看看 FHS 的基本模样, 请看 Figure 23-4。 提示 如你在 Figure 23-4 中所见,除根目录以外,所有目录 都位于另一个目录之内。所以严格来说,除根目录以外,所有 目录都是子目录。 然而日常说法里,我们通常只说目录。例如,我们可能提到 “/bin 目录”。只有当我们想强调某个目录位于另一个 目录之内时,才使用“子目录”这个词,例如“/bin 是 根目录的一个子目录。”
从一开始,Unix 文件系统就被组织成一棵树。我们在第 9 章 把树当作抽象数据结构讨论过,当时我解释过,一棵树的主要 节点称为根(详见第 9 章)。因此,我们把 Unix 文件系统的 主目录称为根目录(ROOT DIRECTORY)。 由于根目录如此重要,它的名字常常必须作为命令的一部分写 出来。每次都要输入 “root” 这几个字母实在太麻烦。于是, 根目录用一个单独的 /(斜杠)来表示。这里举个简单 例子。要列出某个指定目录中的文件,你用 ls 程序 (第 24 章):输入 ls,后面跟上目录名即可。列出 根目录中所有文件的命令是: ls / 当你要指明某个位于根目录之内的目录或文件时,就写一个 /,后面跟上名字。例如,根目录里有一个名为 bin 的子目录。要列出这个目录中的所有文件,你用 这条命令: ls /bin 严格地说,它的意思是“位于 /(根)目录之内、名为 bin 的那个目录”。 要表示某个目录或文件位于另一个目录之内,就用 / 把名字隔开。例如,在 /bin 目录里,你会找到存放 ls 程序本身的文件。这个文件的正式名字是 /bin/ls。同样,在 /etc 目录里,你会找到 Unix 的口令文件 passwd(见第 11 章),它正式的 名字是 /etc/passwd。 谈论这类名字时,我们把 / 字符读作 “slash”(斜 杠)。因此,/bin/ls 这个名字读作 “slash-bin- slash-L-S”。 提示 在你习惯这套术语之前,/ 字符的用法可能让人发 晕。这是因为 / 有两个彼此毫不相干的含义。 在文件名的开头,/ 代表根目录;在文件名中间, / 充当分隔符。(花点时间想想看。) 名称的由来 root 在第 4 章我解释过,要成为超级用户,你要用 root 这个用户 ID 登录。现在你明白这个名字从何而来了:超级 用户的用户 ID 取自根目录之名,而根目录是文件系统中首要 的目录。
在 Unix 文件系统里,几十万个文件被组织成一棵巨大的树, 树的基部就是根目录。多数情况下,这些文件并不存放在同一 个物理设备上,而是存放在若干不同的设备上,其中包括多个 磁盘分区。(如我前面解释的,每个磁盘分区都被视为一个独立 的设备。) 每个存储设备都有自己的本地文件系统,其中的目录和子目录 按标准的 Unix 方式组织成一棵树。然而,在能够访问某个本 地文件系统之前,必须把它的树接到主树上。做法是把较小文 件系统的根目录连接到主文件系统中某个指定的目录上。我们 这样把一个较小的文件系统接上来,就叫挂载(MOUNT)它。 主树中用来承接该文件系统的那个目录称为挂载点(MOUNT POINT)。最后,当我们断开一个文件系统时,就叫卸载 (UNMOUNT)它。 Unix 系统每次启动时,都会作为启动过程的一部分自动挂载 若干本地文件系统。因此,等到系统运行起来、可以使用时, 主文件系统早已被其他几个文件系统扩充过了。 有时你可能需要手工挂载一个设备。为此你使用 mount 程序;要卸载一个设备,你用 umount。作为一种总体 上的预防措施,只有超级用户才被允许挂载文件系统。不过为 了方便,有些系统被配置成允许普通用户挂载某些预先设定的 设备,例如 CD 或 DVD。 这里举一条挂载命令的例子。在这个例子里,我们挂载设备 /dev/fd0 上找到的软盘驱动器文件系统,把它在主树 上的 /media/floppy 位置接上: mount /dev/fd0 /media/floppy 这条命令的效果是,用户就能通过 /media/floppy 目录访问软盘上的文件。 挂载与卸载是需要超级用户身份的系统管理工作,所以我不深 究其细节。请查阅联机手册(man mount)。不过 作为普通用户,你可以列出系统上当前挂载的全部文件系统, 只要单独输入一条 mount 命令: mount 粗略地说,存储设备分两类。固定媒体(FIXED MEDIA)如硬 盘,永久连接在计算机上。可移动媒体(REMOVABLE MEDIA)则 可以在系统运行时更换:CD、DVD、软盘、磁带、U 盘、存储卡 等等。在系统层面,这一区分很重要,因为一旦某个文件系统 有可能真的凭空消失,Unix 就必须确保对它做妥善管理。例 如,在允许你弹出 CD 之前,Unix 必须确认所有待完成的输出 操作都已完成。 因此,文件系统层次标准规定了挂载文件系统应使用的特定目 录。对于没有挂载在其他位置的固定媒体(例如额外的硬盘), 该目录是 /mnt;对于可移动媒体,该目录是 /media。 名称的由来 Mount, Unmount(挂载,卸载) 在 Unix 早期(大约 1970 年),磁盘驱动器是又大又贵的 设备,以今天的标准看,它们能存的数据相当少(撑死四十 兆字节)。与如今作为完整整体的现代硬盘不同,当年的磁盘 驱动器使用可更换的“磁盘组”,每一组都有自己的文件系统。 每当用户需要更换磁盘组时,系统管理员必须在物理上卸下当 前那个磁盘组,再装上新的一组。这就是直到今天我们还说 “挂载”和“卸载”文件系统的原因。当我们使用 mount 程序时,所做的正是“把磁盘组装进驱动器”这一动作的软件 版本。
要对你计算机上的文件系统建立基本理解,最快的办法就是看 看根目录,把里面所有子目录检查一遍。这些目录构成了整个 系统的骨干,因此有时被称为顶级目录(TOP-LEVEL DIRECTORIES)。 Figure 23-6 总结了文件系统层次标准(FHS,本章前面 讨论过)所规定的根目录标准内容。尽管细节因 Unix 系统而 异,但所有现代文件系统都可视为 FHS 的变体。所以,一旦 你理解了 FHS,就能看懂你碰巧遇到的任何 Unix 文件系统。 Figure 23-6: 根目录的内容 Unix 文件系统的骨架是由顶级目录,也就是根目录的 子目录搭起来的。下面是文件系统层次标准(FHS)规定的 全部顶级目录的清单。由于某些 Unix 和 Linux 系统并不 严格遵循 FHS,你看到的可能与这里有所不同。即便如此, 你仍可把这份清单当作起点,用以理解你自己的系统。
我们这里的目标是从根目录开始,把顶级目录的清单逐个走 一遍。每讨论一个目录,你都可以用 ls 程序 (第 24 章)在自己的系统上查看它。例如,要显示 /bin 目录的内容,可用下面两条命令之一:
ls /bin
你用不带选项的 ls 时,只会看到文件名字。如果用 上 -l(long,详细)选项,就会看到更多细节。要是 输出太多、刷得太快,你可以把它用管道送给 less (第 21 章),一屏一屏地看:
ls -l / | less
根目录
/bin
/boot
ls -l /boot | less
如果你升级过系统,你会发现内核不止一个版本。多数情况 下,在用的是最新的那一个,看名字就能认出来。(版本号 是名字的一部分。)
/dev
/etc
/home
/lib
/lost+found
/media
/mnt
/opt
/root
/sbin
/srv
/tmp
/usr
/var
名称的由来 dev, etc, lib, mnt, opt, src, srv, tmp, usr, var Unix 有个传统:文件系统的顶级目录用三个字母的名字。理由 是这样的名字短、好敲。然而说起来,这些名字念起来有些拧 巴。因此,每个三字母名字都有一个大家认可的读法。
dev: "dev"
一般规则是:如果你在谈论与 Unix 有关的事情,碰上一个缺 了一两个字母的名字,念出来时就把缺的字母补上。例如, /etc/passwd 文件的名字念作 “slash et-cetera slash password”。文件 /usr/lib/X11 念作 “slash user slash libe slash x-eleven”。 你有时会听人说 etc 代表 “extended tool chest” (扩展工具箱),或者说 usr 的意思是 “Unix system resources”(Unix 系统资源),云云。这些说法都不真实。 这些名字全都是缩写,不是首字母缩略词。
如本章前面所讨论的,/usr 和 /var 两个目录 是各自独立文件系统的挂载点,这些文件系统被整合进主文件 系统。/usr 文件系统存放静态数据,/var 存 放变动数据。这两个目录装的都是系统数据,与之相对,用户 数据存放在 /home 目录中。 此外,这两个目录都包含若干标准子目录。不过 /var 文件系统主要是给系统管理员用的,对普通用户没那么重要。 /usr 文件系统就有趣得多了:它包含对普通用户和程 序员都有用的文件。因此,我要带你把 /usr 简短地 逛一圈,给你看看文件系统层次标准所描述的最重要的子目录。 作为参考,Figure 23-7 汇总了这些目录。如前所述,你 可能会发现标准布局与你的系统之间存在一些差异。 Figure 23-7: /usr 目录的内容 /usr 目录是一个第二文件系统的挂载点,其中存放用 户和程序员感兴趣的静态数据。按文件系统层次标准,下面是 你在这个目录里会找到的最重要的子目录。细节见正文。
/usr/bin
/usr/games
/usr/include
/usr/lib
/usr/local
/usr/sbin
/usr/share
/usr/src
/usr/X11
如我们所讨论的,有两个不同的目录用来存放通用的可执行 程序:/bin 和 /usr/bin。你也许正在纳闷, Unix 为什么要有两个这样的目录?为什么不干脆把所有程序 存放在一个目录里?答案是:这两个 bin 目录是一笔 历史遗产。 1970 年代初,最早几个版本的 Unix 是在贝尔实验室一台 PDP 11/45 小型机上开发的(见第 2 章)。Unix 的开发人员用的 那台 PDP 11/45 有两个数据存储设备。主设备是一个定 头磁盘,常被称作磁鼓(drum)。磁鼓相对较快,因为读写头 不必随磁盘转动而移动。但它的数据存储量有限,不到 3 兆 字节。 次设备是一块叫 RP03 的常规磁盘。RP03 上的读写头可以在 一条磁道与另一条磁道之间来回移动,这让它能存多得多的 数据,最多 40 兆字节。不过,由于读写头要动,这块磁盘 比磁鼓慢得多。 为了在一台计算机上容纳多个存储设备,Unix 的开发人员采 用了一种设计:每个设备都有自己的文件系统。主设备(磁 鼓)存放所谓根文件系统;次设备(磁盘)存放所谓 usr 文件系统。 理想情况下,把整个 Unix 系统都放在磁鼓上当然最好,因为 它比磁盘快得多。可就是没那么大的地方。于是 Unix 的开 发人员把所有文件分成两组。第一组是启动过程以及运行基 础操作系统所必需的文件,这些文件存放在磁鼓上的根文件 系统里。其余文件则存放在磁盘上的 usr 文件系统 中。 启动时,Unix 从磁鼓引导。这就让操作系统能立即访问根文 件中那些必备的文件。Unix 运行起来之后,再挂载 usr 文件系统,从而可以访问其余文件。 这两个文件系统中各有一个 bin 目录用来存放可执行 程序:根文件系统有 /bin,usr 文件系统有 /usr/bin。在启动过程中,也就是 usr 文件系 统挂载之前,Unix 只能访问根文件系统那块相对狭小的存储 区。因此必备程序存放在 /bin 中,其他程序存放在 /usr/bin 中。同样,库文件也分成两个目录:/lib 和 /usr/lib;临时文件则放在 /tmp 和 /usr/tmp 中。所有情形都是一个道理:根文件系统只 放最重要的文件,即引导和排除故障所必需的文件,其余一切 都放进 usr 文件系统。 如今存储设备又快又便宜,还能存海量数据。除少数情况外, 已经没有令人信服的理由非要把 Unix 的核心拆分到存放于多 个设备的多个文件系统里。的确,有些 Unix 系统把所有通用 二进制文件放在一个巨大的目录里。不过,仍有许多 Unix 系 统使用各自独立的文件系统,合成一棵大树。这样设计的原因, 我们将在本章后面讨论虚拟文件系统时再讲。 一般规则是,现代 Unix 系统区分三类软件:任何人都可能用 到的通用程序;只有超级用户才用的系统管理程序;以及需要 许多文件和目录的大型第三方应用程序。如本章前面所讨论 的,这三类程序各自存放在自己的目录里。作为参考, Figure 23-8 汇总了你可能找到 Unix 程序文件的各个 位置。 Figure 23-8: 存放程序文件的目录 Unix 文件系统为程序文件设置了不少不同的存放位置。通用 程序存放在名为 bin(“binary files”,二进制文件) 的目录中;系统管理程序存放在名为 sbin(“system binaries”,系统二进制程序)的目录中;大型第三方应用存放 在名为 opt(“optional software”,可选软件)的目 录中。程序还被进一步分为必备与非必备两类。必备程序是启 动系统或执行关键系统管理所必需的程序,其余的都是非必备 程序。 你在这里看到的细节以文件系统层次标准为依据,你的系统 可能略有不同。
系统目录里有这么多塞满重要文件的地方,显然我们需要一套 有序的制度来管住用户把个人文件存在哪里。当然,像你我这 样聪明的人,如果允许我们把个人程序存进 /bin 目 录、把个人数据文件存进 /etc,也未必会把事情搞 糟。但总的来说,我们不能让芸芸众生随心所欲地把文件乱放 在任何地方——我们需要条理。 解决办法是给每个用户一个属于自己的主目录(HOME DIRECTORY),一个他可以在里面为所欲为的目录。当你的 Unix 账户被创建时(见第 4 章),系统就为你创建了一个主目录。 你主目录的名字记在口令文件里(第 11 章),你一登录,系统 就自动把你放进这个目录。(“在”一个目录里是什么主意,等 你读完第 24 章就会明白得更透彻。)在你的主目录里,你可以 随心所欲地存放文件、创建其他子目录。的确,许多人自己就 有一套庞大精妙的树形结构,全都挂在自己的主目录之下。 文件系统层次标准建议主目录建在 /home 目录里。在 小型系统上,主目录的名字就是用户 ID,例如 /home/harley、/home/linda 等等。在用户 ID 众多的大型系统上,可能多加一层子目录,把主目录按类 别组织起来。例如,在一所大学里,主目录可能放在名为 undergrad、grad、professors 和 staff 的子目录里;在一家房地产公司,你可能会看到 agents、managers 和 admin。意思你 懂了。 唯一一个主目录不在 /home 之下的用户 ID 就是超级用户(root)。因为管理员必须随时都能控制 系统,超级用户的主目录必须始终可用,即使在系统引导时或 系统在单用户模式下运行时也不例外(见第 6 章)。许多系统 上,/home 目录位于一个第二文件系统之中,而它在 被挂载之前是不可用的。相反,/root 目录始终是根 文件系统的一部分,因而始终可用。 每次你登录时,环境变量 HOME 都会被设成你主目录 的名字。因此,显示主目录名字的一个办法,就是用 echo 程序显示 HOME 变量的值: echo $HOME (echo 程序只是显示它参数的值。关于它和环境变量 的讨论在第 12 章。) 作为捷径,符号 ~(波浪号)可以作为你主目录的缩写。 例如,你可以用下面这条命令显示主目录的名字: echo ~ 不管它叫什么名字,主目录要紧的地方在于:它是你的,由你 做主。你该做的头一件事,就是建一个 bin 子目录, 用来存放你自己的程序和 Shell 脚本。然后你可以把这个目录 的名字——例如 /home/harley/bin——放进你的搜索 路径。 (搜索路径是存放在 PATH 环境变量里的一串目录。每 当你输入一个并非 Shell 内置的程序名字时,Unix 就会到搜 索路径指定的那些目录里去找该执行的程序。详见第 13 章。) Figure 23-9 展示了一个以 /home/harley 主目录 为基础的典型目录结构。这个主目录有三个子目录: bin、essays 和 games。essays 目录自己又有三个子目录:history、 literature 和 surfing。所有这些目录都含有 文件,只是图中没有画出来。你在第 24 章会看到,创建和删除 子目录很容易。因此,随着需求变化,扩大或修剪你的目录树都 是轻而易举的事。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
/home 目录是文件系统层次标准的一部分,在 Linux 系统上被广泛使用。但如果你用的是另一类 Unix,你的主目录 也许在别处。经典的设置——用了很多年——是把主目录放在 /usr 目录里。例如,用户 ID 为 harley 的主 目录就是 /usr/harley。还有的系统用 /u、 /user(带 “e”)、/var/home 或 /export/home。作为参考,下面是你可能在不同系统 上看到的主目录位置示例:
/usr/harley
在大型系统上,尤其是文件存放在网络上的系统,主目录的确 切位置可能复杂得多;很大程度取决于系统管理员决定如何组织 文件系统。例如,我在一台计算机上有账户,我的主目录是一个 五层深的子子子子子目录: /usr/local/psa/home/vhosts/harley 提示 在任何系统上,你都可以用下面两条命令中的任意一条查出 主目录的位置:
echo $HOME
在这一章里,你我一起覆盖了不少材料。如果你在意这类东 西,这些细节多少会有些意思。然而,这片森林的内容远不止 树上的叶子。Unix 文件系统是由几位极其聪明的人创造的, 多年来又经许许多多经验丰富的程序员和系统管理员之手不断 增强。最终的产品不仅实用,而且优美。 本节我想帮你体会这套系统的不凡之处,不只是它的有用,还 有它的美。为此,我要解释:存放在各种不同存储设备上的多 个文件系统,是如何被合并成一个巨大的树形结构的。 本章前面我解释过,每个存储设备都有自己的本地文件系统, 其中目录和子目录按标准 Unix 方式组织成一棵树。在你能够 访问这样一个文件系统之前,它必须先连到主文件系统上,这 个过程我们称为挂载。用技术术语说,我们是通过把一个文件 系统的根目录连接到一个挂载点——主文件系统内的某个目录 ——来挂载它的。 我希望你注意到,我们谈论这些概念时,“文件系统”一词有 两种不同用法。别被绕糊涂。第一种是“Unix 文件系统”,那 个包罗万象的巨大结构,整个系统里每个文件、每个目录都在 其中。第二种是较小的、独立的“设备文件系统”,驻留在各 个存储设备上。Unix 文件系统正是由这些较小的文件系统连接 成一个巨大结构而形成的。 要为了解释这一切如何运作,我得从头说起,先回答一个问题: 系统启动时会发生什么?当你打开计算机时,一连串复杂的事件 被启动起来,这就是引导过程(第 2 章有描述)。加电自检之后, 一个叫做引导加载程序(boot loader)的特殊程序接管控制权, 并从引导设备(BOOT DEVICE)读取数据,以便把操作系统装入 内存。多数情况下,引导设备是本地硬盘上的一个分区;但它也 可以是一个网络设备、一张 CD、一个 U 盘等等。 引导设备上的数据之中,藏着那个最初的 Unix 文件系统,即 根文件系统(ROOT FILESYSTEM)。根文件系统是自动挂载的, 它保存启动 Unix 所需的全部程序和数据文件,也保存一旦出 乱子系统管理员会用到的工具。因此,根文件系统至少包含下 面这些目录(本章前面都讨论过): /bin /boot /dev /etc /lib /root /sbin /tmp 一旦根文件系统挂载完毕、内核启动起来,其他设备文件系统 就会被自动挂载。有关这些文件系统的信息保存在一个配置文 件 /etc/fstab(*)里,系统管理员可以修改它。(名字 代表 “file system table”,文件系统表。)要查看你系统上 的这个文件,用命令: less /etc/fstab * 脚注 在 Solaris 上,这个文件叫 /etc/vfstab。 根文件系统总是存放在引导设备上。不过还有三个文件系统可 能驻留在各自的设备上:usr、var 和 home。如果这些文件系统有自己独立的设备,就把它们 接到相应的子目录上,从而连入 Unix 文件系统。usr 文件系统挂载在 /usr;var 文件系统挂载在 /var;依此类推。这一切都是自动完成的,所以等到你 看到登录提示符时,所有文件系统都已挂载,Unix 文件系统已 就绪运行。 每种设备都使用适合该类设备的文件系统。硬盘上的一个分区 使用适合硬盘的文件系统;CD-ROM 使用适合 CD-ROM 的文件系 统,如此等等。可以想见,读写数据所涉及的细节会因设备类 型不同而差别很大,也会因文件系统是本地(在你计算机上) 还是远程(在网络上)而不同。最后,有些文件系统——例如用 于 Proc 文件的 procfs——使用伪文件,而伪文件并不 驻留在存储设备上。作为参考,Figure 23-10 列出了你 最可能遇到的那些文件系统。 Figure 23-10: 最常见的文件系统 作为参考,这里列出你使用 Unix 或 Linux 系统时最常遇到 的文件系统。基于磁盘的文件系统在硬盘、CD、DVD 或其他设 备上存储数据;网络文件系统支持通过网络共享资源;专用文 件系统提供对系统资源(例如伪文件)的访问。
各种文件系统之间差异如此之大,这就引出一个重要问题。 想想下面两条 cp(复制)命令:
cp /media/cd/essays/freddy-the-pig /home/harley/essays
我们在第 25 章会讲 cp。眼下我只想让你体会到的 是:第一条命令把 CD 上某个目录里的文件复制到硬盘某个分 区的目录里;第二条命令把伪文件(由内核生成)里的信息复 制到硬盘某个分区的一个文件里。两种情况下,你都只是输入 一条简单命令,那么细节由谁来操心? 细节由一个特殊的设施负责,叫做虚拟文件系统(VIRTUAL FILE SYSTEM,VFS)。VFS 是一个 API(应用程序接口),在你 的程序与各个文件系统之间充当中间人。每当一个程序需要一 次 I/O 操作时,它就向虚拟文件系统发出请求。VFS 找到合适 的文件系统,通过指示设备驱动程序执行 I/O 来与之通信。就 这样,VFS 让你和你的程序能够面对单一、统一的树形结构 (Unix 文件系统)工作,尽管实际上数据来自种种彼此不同的 独立文件系统。 在我们的第一个例子里,数据必须从 CD 读出。cp 程 序发出一个读请求,由虚拟文件系统处理。VFS 把它自己的请 求发给 CD 文件系统,CD 文件系统再向 CD 设备驱动程序发出 相应的命令,由驱动程序读取数据。这样,你不必知道任何细 节,你的程序也不必。在你看来,Unix 文件系统就跟你想象的 那样存在,并且完全按你希望的方式工作。 你看出它的美了吗?在每一次文件操作的一端,虚拟文件系统 用你的语言与你交谈;在另一端,VFS 用各个设备文件系统自己 的语言与它们交谈。结果就是,你和你的程序能够与任何一个 文件系统打交道,而无须直接与它们通信。 再想一个问题。每当开发出一种新的文件系统(比如为新设备 开发的),它怎样才能与 Unix 协同工作?答案在概念上很简 单。新设备的所有开发者要做的,只是教会这个新文件系统说 “VFS 语”。这样它就能加入 Unix 的世界,并且天衣无缝地融 入其中。 妙处就在这里:无论你是什么时候学的 Unix——35 年前还是 35 分钟前——Unix 文件系统看上去一样,用起来也一样。而 且,随着岁月推移,新设备、更好的文件系统不断出现,它们 都会平滑而轻松地融入你的世界。这就是为什么那个在学生还 戴爱情珠、上街反战的时代设计出来的操作系统,在学生已经 戴着手机、上街反战的今天依然运作良好。 那么未来呢?我们无法预知在即将到来的岁月里会出现什么样 稀奇古怪的新设备和信息来源。毕竟,说到技术,谁也不敢许 诺什么。然而我能向你承诺的是:无论出现什么新技 术,它都能与 Unix 一起工作。我还可以承诺:多年以后,你 会把 Unix 教给你的孩子(*)。 * 脚注 所以把这本书留好。
复习问题 #1: 什么是 Unix 文件? 文件的三种主要类型是什么?分别描述每一种。 复习问题 #2: 说明文本文件与二进制文件的区别。各举三个例子。 复习问题 #3: 什么是文件系统层次标准(FHS)?按 FHS,简要说明下列 各项的内容: 1. 根目录(/) 2. 下列顶级目录: /bin /boot /dev /etc /home /lib /sbin /tmp /usr /var复习问题 #4: 在 FHS 中,哪些目录存放通用程序? 哪些目录存放系统管理程序? 复习问题 #5: 什么是主目录?按 FHS,主目录在哪里找到? 唯一一个主目录在别处的用户 ID 是谁?为什么? 假设你的用户 ID 是 weedly,你是一所大型大学的 本科生。给出你的主目录两个可能的名字。 应用你的知识 #1: 下面这条命令会列出根目录的所有子目录: ls -F / | grep '/' 用这条命令看看你系统上顶级目录的名字。把你看到的与 文件系统层次标准的基本布局比较一下。有哪些不同? 应用你的知识 #2: 如我们将在第 24 章讨论的,你可以用 cd 从一个目录 换到另一个目录,用 ls 列出目录的内容。例如,要切 到 /bin 目录并列出其内容,你可以用: cd /bin; ls 探索你的系统,找出下列文件存放在哪里:
• 用户的主目录
提示:你会发现 whereis 程序很有用(见第 25 章)。 应用你的知识 #3: 输入下面这条命令: cp /dev/tty tempfile 输入几行文本,然后按 ^D。 你刚才做了什么?它是怎么起作用的? 提示:为了收拾自己留下的摊子,你应当输入下面这条命令, 删除名为 tempfile 的文件: rm tempfile 进一步思考 #1: Unix 用非常通用的方式定义“文件”。给出这种制度的三个 优点,再给出三个缺点。 进一步思考 #2: 至于各 Unix 系统在多大程度上必须遵循文件系统层次标准, 并没有统一的规定。有些系统相当贴近这个理想模型,有些 则差别很大。 如果要求所有 Unix 系统使用同一套基本的文件系统层次, 这是好事还是坏事? 讨论一下优点与缺点。
© 本书全部内容,2026 年版权所有,Harley Hahn
| |||||||||||||||||||||||||||||||||||||||