对话 UNIX,第 11 部分: 漫谈 UNIX 文件系统
刚刚购买了一个全球定位系统(GPS)导航设备,仅仅使用了几次之后,我就迷上了它。从点 A 到点 B,现在是轻而易举的事情。不再需要到 MapQuest 网站上去查询地图了。不再需要猜测哪边是东。不再需要在远离城市的农村地区中途停车以询问方向。我只需要跳进我的车,指定我的目的地,并遵循语音提示即可。为什么呢?GPS 使我看起来就像一个本地居民,它为 Buckaroo Banzai 的格言“无论您去哪里,您就在那里赋予了新的含义。
本月,让我们纵情满足自己的旅行爱好,并且漫谈 Unix® 文件系统。从 /bin 到 /var,有许多有趣的景点值得一看(一些经常有人走过,还有一些则很隐秘),并且很快您将会像当地居民一样熟悉周围的环境了。
文件名称的含义
UNIX 计算机上的文件采用层次结构进行组织。这个层次结构的最高层是 /,一般称其为“斜线或者“根目录。
如果您将工作目录更改为 /,并运行 ls,那么您将看见几个具有神秘名称的子目录(如 etc、bin、var、home 和 tmp)。尽管 UNIX 现在支持长文件名,但是这些顶层目录名字中的大多数可以追溯到大约 30 年前,即 UNIX 刚刚出现的时候。类似地,根据同样长期存在的约定,包含在 / 中的每个目录都用于某个特殊的目的:
/bin 仅仅是包含应用程序和实用工具的许多目录中的一个。然而,/bin 通常包含那些对于系统操作而言基本的实用工具。因此,Shell 文件操作命令如 cp 和 chmod、压缩和解压缩,以及诊断命令都位于 /bin 中。
/sbin 同样包含那些对于系统操作和维护而言至关重要的实用工具。然而,只有超级用户才能够执行 /sbin 中的程序,因此这个目录称为“superuser-bin或者 /sbin。
/dev 包含您的系统中所安装的所有硬件,包括终端和 USB 设备(以及从物理上连接到这台计算机的其他外围设备)、伪终端(用于与 X 终端窗口进行交互),以及硬盘驱动器,等等。
/etc(常常发音为“etsee)专门用于系统配置。/etc 目录包含用于系统守护进程、启动脚本、系统参数和更多其他方面的配置文件。
/home 包含用户的 home 目录。例如,如果您的登录名是 joe,那么目录 /home/joe 就是您的个人文件存储库。
/lib 用于存储基本的系统库文件。在现代 Unix 中,通常共享系统库,这意味着并不是每个二进制文件都链接和包括这些库(那样的话,至少将会浪费空间),但是当需要该库的时候,按需要加载它,并且同时可以由许多应用程序进行共享。因此,与 UNIX 一同安装的核心应用程序和实用工具的运行都需要使用 /lib 中的库,并且您至少需要拥有少量相应的库文件,以便从源代码创建新的可执行文件。其中所有的文件都是至关重要的,损坏或者删除(无论是有意的还是无意的)某个文件就可能使系统变得无法使用。
/mnt 是“mount的缩写,是装入硬盘驱动器分区和其他设备的标准位置。如果您希望查看当前装入的并且可访问的所有设备,只需要运行 mount 命令。
/tmp 或者“temporary,是系统范围的暂存存储区。您的 Web 服务器可能会将会话数据文件保存在这里,并且其他实用工具将使用 /tmp 中的空间对中间结果进行缓存。通常认为 /tmp 中的文件在使用后即被丢弃。实际上,您的系统管理员可能会在每天晚上删除其中比某个过期时间更早的所有文件。
/usr 用于存储大量文件。最终用户应用程序(从编辑器、游戏和接口,到系统特性)都位于其中,它是 man 页面和其他更多内容的存储库。有些文件很有价值,但并不是系统操作所必须的,那么您很可能会在 /usr 中找到它。
/var 是“variable的简写,它是用于存储那些大小通常随时间而增大的文件的存储库。可以在 /var 中找到邮箱、日志文件、打印机队列和数据库。通常可以将 Web 站点保存在 /var 中,因为 Web 站点可能会在一段时间后异常地累积大量的数据。
以上是一些最常见的目录名,尽管某些 Unix 版本之间存在细微的差异。(例如,在基于 FreeBSD® 的 Mac OS X 上,将包含用户的 home 目录的目录命名为 /Users,而不是 /home。)
保持传统
事实上,名称 etc、bin、lib 和 man 在 UNIX 的文化中是如此根深蒂固,以至于在计算机中的其他地方使用相同的名称来标注类似用途的目录已经成为一种传统。例如,如果您查看一位专家的 home 目录,您很可能会在其中发现 bin 和 lib 目录分别存储个人应用程序以及脚本和个人库。
同样地,/usr/local 中通常包括 etc、bin、lib、和 man。在历史上,曾将 /usr/local 用于存储来自于您的站点或者仅与您的站点有密切关系的应用程序和数据。/usr/local/bin 目录用于存储本地添加的、新的程序,以及标准系统实用工具的本地修改版本。例如,您的系统管理员可能在 /usr/local/bin/perl 中提供了 Perl 的最新和最好的版本,同时保持 /usr/bin/perl 不变,以便进行引用,并且因为其他的核心实用工具可能仍然依赖于它。/usr/local/lib 目录作为 /usr/local/bin 的补充。
/usr/local 目录甚至可能是一个完全独立的分区(甚至是通过网络文件系统从 Network Attached Storage [NAS] 设备装入的分区),这使得可以更容易地对系统进行数据恢复和恢复使用。如果系统中发生了某种情况,管理员可以覆盖操作系统的文件,而无需担心会破坏本地数据。
甚至安装包也是用了类似的目录结构。例如 MySQL:如果使用了选项 --prefix=/usr/local/mysql, 进行配置,那么它将在 /usr/local 中创建它自己的根目录,名为 /usr/local/mysql,并创建子目录 /usr/local/mysql/bin、/usr/local/mysql/lib 等等:
$ ls -1 /usr/local/mysqlbin/configure*data/docs/include/lib/man/...
或者,如果您希望将 MySQL 的内容安装到 /usr/local/bin、/usr/local/lib 和其他地方,可以使用 --prefix=/usr/local。
其他有趣的内容
因为本文只是简要地介绍,所以让我们再安排一些其他有趣的内容。
/etc
/etc 目录是寻找配置文件的地方,这些配置文件通常以后缀 .conf 作为结束。一个较大的包可能拥有它自己的子目录,以便收集用于这个包的所有配置文件。Apache 是一个很好的例子;特别是,Apache V2.2 已经重新组织了它的配置文件,使其更具模块化,并具有更少的独立性。
另一个新颖的内容是 /etc/init.d,其中包含当您的系统启动时运行的许多启动脚本。如果您希望干净地重新启动一个守护进程,例如,在更改它的配置之后,可以在 /etc/init.d 中查找同名的脚本。例如,要重新启动 Postfix 邮件传送代理(MTA),您可以运行:
$ /etc/init.d/postfix restart
/etc/init.d 还包含切换到单用户模式的脚本,以便重新启动并关闭计算机,并禁止登录。
/var/spool
如前所述,/var 保存了那些大小可能随时间增大和缩小的文件。与 / 一样,可以将 /var 划分为若干个子目录,每个子目录都有其自身的方案:
/var/spool/mail 是寻找您和其他用户的传入邮件的地方。您的邮箱是一个简单的平面(连续的、非索引的)文件(除非您的系统管理员正在使用 maildir 格式)。传入邮件追加到文件的尾部。您所丢弃的邮件将从该文件中删除;并且当您读取一条新的消息时,将会更改并重写已有的消息状态字段。您可以读写您自己的邮箱,但是可以通过权限防止您访问其他用户的邮箱。(建议您不要直接编辑您的邮箱。)
/var/log 保存了一套系统日志文件,或者记录系统活动的文件。这些日志记录了所有的活动,从邮件通信到失败的登录尝试。通常,每个守护进程都拥有自己的日志文件,这使得当一个服务失败时很容易搜寻所发生的问题。因为可以显示系统活动,所以对日志文件的访问通常会受到限制,只有超级用户才可以访问。
如果您的系统提供了集中的传真服务,那么 /var/spool 还将对这些请求进行排队。
/usr/man
用于您的 Unix 系统的核心 man 页面位于 /usr/man 中。还可以在 /usr/local/man 和包的 man 目录(如 /usr/local/mysql5/man)中找到 man 页面的扩展集合。
因为 man 页面可能像可执行文件那样存放于许多不同的地方,所以 man 程序支持与 PATH 工作方式相同的环境变量 MANPATH。要在多个位置搜索一个特定的页面,可以将 MANPATH 定义为一系列 man 页面目录:
MANPATH="/usr/man"MANPATH="/usr/local/man:$MANPATH"MANPATH="/usr/local/mysql/man:$MANPATHMANPATH="$HOME/man:$MANPATH"export MANPATH
在该示例中,首先 搜索 $HOME/man(它在最左边,或者最前面),随后是 /usr/local/mysql/man,依此类推。顺便说一下,可以将上面的前四个命令简化为下面的语句:
MANPATH="/usr/man:/usr/local/man:/usr/local/mysql/man:$HOME/man"
然而,将附加的目录隔离开来,将允许您快速地对条目进行重新排序,并轻松地添加新的目录。而且,如果存在许多路径,编辑后面的 MANPATH(通过扩展 PATH)变量将变得使人乏味。
包含文件
包含文件(或者头文件)定义了在操作系统中或特定的库中使用的常量、宏以及其他结构。不需要重新定义一个特定的结构,您只需要将头文件“包含在您的代码(代码重用的一种简单形式)中,并按照头文件中的规范编写代码。(man 中的第 2 部分和第 3 部分就专门用于这样的规范;例如,可以尝试 man 2 signal。)
与 bin 和 lib 类似,include 是一个常见的目录名。如果一个包提供了开发工具包,并且您已经将这个包安装到了它自己的根目录,那么可以在 include 子目录中找到相应的头文件。
或者,如果您已经将包安装到了公共的 /usr/local/{bin、lib、include} 目录中,那么可以在 /usr/local/include 中根据这个包进行命名的子目录中找到包的头文件。这是将所有的内容保存到一个公共地方的例外情况。为什么呢?头文件的命名不是唯一的,所以将所有的内容安装到一个地方将会导致冲突,一个包有可能覆盖另一个包的头文件。
如果您从源代码构建应用程序(您将在后面的部分中对其进行深入研究),并且头文件位于一个非标准的位置,那么您可能需要在编译器命令中添加 -I 选项。作为一个示例,如果您的 ImageMagick 头文件位于 /opt/include/magick 中,添加 -I/opt/include/magick 作为编译器的开关。
非常深入地了解它
即将结束今天的 Unix 旅行。现在,您可以更容易地穿越 UNIX 的小路和背街了。如果您迷路了,只需要说“家,家,家(不要被 猎户星座 所欺骗)或者输入 cd 即可。请记住,您还可以使用 find 和 locate 来查找大多数文件,包括可执行文件、库和包含文件。
下午好,女士们、先生们。下次旅行将在 30 天后启程。
附录 A:选择一个标准,任何标准
您的 UNIX 操作系统附带的软件位于文件系统中适当的位置(可能存储在 /bin 或者 /lib 中的),而本地添加的软件则可能位于许多不同的位置。某些系统管理员将本地软件放在 /usr/local 中,而其他的系统管理员则使用 /opt 或者“optional,因为运行系统并不需要该软件。而且,某些管理员会转储 /usr/local/bin 或 /opt/bin 中所有的可执行文件、/usr/local/lib 或 /opt/lib 中所有的库,等等。
另一种方法(这是我更喜欢的范例)是为每一个本地添加的包创建一个根目录,特别是在这个包很大的情况下。例如,我将 MySQL V5 安装到 /usr/local/mysql5.0,将 Apache V2.2 安装到 /usr/local/apache2.2。每个包的安装程序都会在包的根目录中创建它自己的 bin、lib 和 man 目录。
这种方法有一个缺点,每个最终用户必须向他或她的 PATH 环境变量中添加许多 bin 目录。并且当这一需求并不是特别复杂时,通过在系统范围的 Shell 启动文件中扩展缺省的 PATH 设置,就可以解决这个问题。例如,Bash 系统范围启动脚本 /etc/profile,可能包含:
PATH="/bin:/usr/bin:/usr/local/bin"PATH="$PATH:/usr/local/mysql5.0/bin"PATH="$PATH:/usr/local/perl6/bin"PATH="$PATH:/usr/local/Zend/bin"export PATH
然而,将一个包存储在它自己的“容器中,这是很有好处的:
哪个包提供了特定的应用程序,这是显而易见的。遵循这一分类系统,您可以使用 which 命令找到包的名字:$ which mysql/usr/local/mysql5.0/bin/mysql
您可以同时保留同一个包的不同版本。
例如,如果您希望提供 Perl V5.6 和 Perl V5.8,可以将前者安装到 /usr/local/perl5.6,将后者安装到 /usr/local/perl5.8。每个用户都可以通过改变 PATH 变量,来选择一个 Perl 版本。
您可以同时保留不同的版本,但是可以通过使用符号链接,使得缺省情况下对应于某一个特定的版本。只需创建一个到您希望提供的包的版本的符号链接即可。
例如,假定您提供了前面介绍的两个 Perl 版本。如果您希望将 Perl V5.8 作为缺省值,可以创建一个到 /usr/local/perl5.8 的符号链接,并将它命名为 perl:
$ ls -1 /usr/local/perl*perl5.6perl5.8$ sudo ln -s /usr/local/perl5.8 /usr/local/perl$ ls -1 -F /usr/local/perl*perl5.6/perl5.8/perl@
最终用户现在可以添加 /usr/local/perl/bin 到他或她的 PATH 变量以运行 perl 命令。如果您最后需要或者希望切换到一个更新的或者更旧的 Perl 版本,那么您只需删除该符号链接,并重新创建一个指向不同目录的符号链接即可。
对于这样的维护任务,符号链接是非常重要的。您可以维护变量、变更路径,并为方便访问构建集合。例如,您可以在传统的 /usr/local/bin 目录中填入链接到其他包中的命令的符号链接,如 ln -s /usr/local/perl/bin/perl /usr/local/bin/perl。(是的,您可以创建指向另一个符号链接的符号链接。)
相关文章: