Unix 手册页与文件系统全解析
1. 编写 pathfind 手册页
在标记系统的完整文档可能需要多本书来阐述,但我们可以通过学习这里介绍的简单 troff 子集来轻松应对。在开始之前,先了解一下 nroff/troff 标记。nroff 基于早期文本格式化系统(如 DEC 的 runoff)开发,用于 ASCII 打印设备输出;而 troff 是贝尔实验室为照排机创建的程序,是早期基于计算机排版的成功尝试。这两个程序接受相同的输入,所以之后提到 troff 通常也包含 nroff。
早期 Unix 系统运行在小内存的小型计算机上,这限制了格式化程序的设计。troff 命令简短且隐晦,大多以点开头,后面跟着一两个字母或数字。字体选择有限,只有罗马体、粗体、斜体和后来的等宽字体,且尺寸较少。在 troff 文档中,空格和空行很重要,两个输入空格大约产生两个输出空格,这使得输入难以通过缩进和间距来提高可读性。
不过,简单的命令格式便于解析 troff 文档,也有一些前端处理器可用于轻松指定方程、图形、图片和表格。手册页样式(通过 -man 选项选择)的命令较少,通常没有方程、图片,表格也很少见。手册页文档布局简单,有半打标准的顶级章节标题,穿插着格式化的段落文本,偶尔还有缩进和带标签的块。
现在开始编写 pathfind 的手册页。先写注释语句,troff 注释以反斜杠 - 引号开头,到行尾结束,但如果跟在初始点后面,行终止符也不会输出:
.\" = = = = = = = = = = = = = = = = = = = = = = = = =
= =
= = = = = = = = = = = = = = = = = = = = = = = = = = = = =
由于 troff 输入不能缩进,使用等号注释行可以让章节标题更易识别。每个手册页文档以文本标题命令(.TH)开头,最多包含四个参数:大写命令名、手册章节编号(用户命令为 1),以及可选的修订日期和版本号。这些参数用于在格式化输出文档中构建页眉和页脚:
.TH PATHFIND 1 "" "1.00"
2. 手册页语法检查
检查手册页的正确格式通常通过以下方法:
- 打印输出 :
- groff -man -Tps pathfind.man | lp
- troff -man -Tpost pathfind.man | /usr/lib/lp/postscript/dpost | lp
- 屏幕显示 :
- nroff -man pathfind.man | col | more
- groff -man -Tascii pathfind.man | more
- groff -man -TX100 pathfind.man &
col 命令用于处理 nroff 生成的水平和垂直移动的特殊转义序列,groff 输出不需要 col 命令。
一些 Unix 系统有简单的语法检查器 checknr,使用 checknr pathfind.man 命令在某些系统上可能不会报错。checknr 擅长捕捉字体不匹配问题,但对手册页格式了解较少。大多数 Unix 系统有 deroff,可用于去除 troff 标记,进行拼写检查:
deroff pathfind.man | spell
此外,还有一些实用工具,如 双词查找器 和 分隔符平衡检查器 可用于查找文档中难以发现的错误。
3. 手册页格式转换
将手册页转换为 HTML、Texinfo、Info、XML 和 DVI 文件很简单:
- man2html pathfind.man
- man2texi --batch pathfind.man
- makeinfo pathfind.texi
- makeinfo --xml pathfind.texi
- tex pathfind.texi
由于输出文件较长,这里不展示 .html、.texi、.info 和 .xml 文件,你可以自己生成并查看这些标记格式的样子。
4. 手册页安装
历史上,man 命令期望在由环境变量 MANPATH 定义的搜索路径的子目录中找到手册页,通常是 /usr/man:/usr/local/man 。一些新的 man 版本假设程序搜索路径 PATH 中的每个目录可以添加 /../man 后缀来确定对应的手册页目录,从而无需 MANPATH。
在每个手册页目录中,常见以 man 和 cat 为前缀、章节编号为后缀的子目录对。子目录中的文件名也以后缀章节编号结尾。例如, /usr/man/man1/ls.1 是记录 ls 命令的 troff 文件, /usr/man/cat1/ls.1 保存 nroff 的格式化输出。man 命令会使用后者(如果存在)以避免不必要地重新运行格式化程序。
大多数 GNU 软件将可执行文件安装在 $prefix/bin ,手册页安装在 $prefix/man/man1 ,其中 prefix 默认是 /usr/local ,这种方式在各处都适用。系统管理员通常定期运行 catman 或 makewhatis 来更新包含手册页 NAME 部分单行描述的文件,该文件用于 apropos、man -k 和 whatis 命令,提供手册页的简单索引。如果这些方法找不到所需内容,可能需要使用 grep 进行全文搜索。
5. 文件与文件系统概述
有效使用计算机需要了解文件和文件系统。下面将介绍 Unix 文件系统的重要特性,包括文件的定义、命名方式、内容、文件系统层次结构以及文件属性。
6. 文件的定义
简单来说,文件是计算机系统中存储的数据集合,可以在计算机程序中作为单个实体引用。文件提供了一种数据存储机制,即使进程执行结束或计算机重启,数据仍然存在。
早期计算机中,文件位于计算机系统外部,通常存储在磁带、纸带或穿孔卡片上,由用户自行管理。后来,磁盘变得常见,其物理尺寸大幅减小,容量增加了几个数量级,成本和访问时间也大幅下降。如今,磁盘数量与人口数量相当。
光学存储设备(如 CD - ROM 和 DVD)价格便宜且容量大,在 20 世纪 90 年代,CD - ROM 很大程度上取代了可移动软盘和磁带用于商业软件分发。非易失性固态存储设备也已出现,可能最终会取代有机械运动部件的设备,但目前价格较高、容量较小且可重写次数有限。
7. 文件的命名
早期计算机操作系统不给文件命名,文件由用户提交处理,由人工操作员逐个处理。为了实现文件处理自动化,需要为文件命名,以便人类分类管理和计算机识别。
给文件命名后,会遇到同名问题,现代文件系统通过将唯一命名的文件分组到称为目录或文件夹的逻辑集合中来解决这个问题。
文件命名使用主机操作系统字符集的字符。早期计算中,字符集差异很大,后来标准化变得很有必要。1963 年,美国标准协会提出了 7 位 ASCII 字符集,可表示 128 个不同字符,包括大小写字母、数字、特殊符号和标点符号等,还剩余 33 个作为控制字符。ASCII 几乎在所有计算机系统上都支持,可通过 man ascii 命令查看。
然而,ASCII 无法表示世界上大多数语言的文本,因为其字符集太小。大多数计算机系统使用 8 位字节,可表示 256 个字符。系统设计者填充了上半部分字符集,但缺乏国际标准,产生了数百种不同的字符编码,即代码页。ISO 开发了一系列代码页,如 ISO 8859 - 1 等。
20 世纪 90 年代,开始开发通用字符集 Unicode,最终可能需要每个字符约 21 位,目前一些操作系统使用 16 位实现。Unix 系统使用 UTF - 8 可变字节宽度编码,使现有的 ASCII 文件成为有效的 Unicode 文件。
除 IBM 大型机的 EBCDIC 字符集外,当前所有字符集都包含 ASCII 字符的前 128 个位置。因此,将文件名限制为 ASCII 子集可以使文件名在各处更通用,减少重命名的维护工作。
8. Unix 文件的内容
Unix 对文件的简单看法是其巨大成功之一,Unix 文件只是零个或多个匿名字节的数据流。
大多数其他操作系统有不同类型的文件,如二进制与文本数据、定长与变长记录、索引与随机或顺序访问等。这导致复制文件的简单任务因文件类型而异,增加了软件处理文件的复杂性。
Unix 文件复制操作很简单,以下是示例代码:
try-to-get-a-byte
while (have-a-byte)
{
put-a-byte
try-to-get-a-byte
}
这种循环可以在多种编程语言中实现,而且程序无需知道数据来源。如果需要特殊格式的文件,如带有指向早期数据的指针目录且数据加密,只需让应用程序理解该格式,无需让文件系统或操作系统处理这种复杂性。
Unix 对文件有一个细微区分,人类创建的文件通常由文本行组成,以换行符结尾,且大多不含不可打印的 ASCII 控制字符。这类文件可以编辑、显示、打印、通过电子邮件发送和网络传输,数据完整性有保障。处理文本文件的程序可能使用固定大小的缓冲区,因此输入文件的行长过长或包含不可打印字符时,程序可能行为异常。处理文本文件的经验法则是将行长限制在 50 到 70 个字符。
文本文件使用 ASCII 换行符(LF,十进制值 10)标记行边界,许多编程语言用 \n 表示。C 和 C++ 等语言受 Unix 影响,认为文本文件行由单个换行符终止,这比其他一些系统使用的回车/换行对更简单。
在混合操作系统环境和共享文件系统中,需要经常转换文本文件的行终止约定。 dosmacux 包 提供了一套方便的工具来完成此任务,并保留文件时间戳。
9. Unix 分层文件系统
大量文件会带来文件名冲突风险,即使文件名唯一,管理也很困难。Unix 允许将文件分组到目录中,每个目录形成独立的命名空间,还可以为文件提供默认属性。
9.1 文件系统结构
目录可以几乎任意深度嵌套,Unix 文件系统形成树状结构,根目录用 / 表示。斜杠还用作目录嵌套的分隔符。
Unix 目录可以包含任意数量的文件,但大多数当前 Unix 文件系统设计和编程接口假设目录按顺序搜索,因此在大目录中查找文件的时间与文件数量成正比。如果目录包含数百个以上的文件,可能需要将其重新组织到子目录中。
到达文件的完整嵌套目录列表称为路径名,可能包含或不包含文件名本身。历史 Unix 文档未规定文件名完整路径的长度,但 POSIX 定义了常量 PATH_MAX 表示该长度,包括终止的空字符,最小值为 256,X/Open 可移植性指南要求 1024。可以使用 getconf 命令查看系统限制,例如:
$ getconf PATH_MAX . What is longest pathname in current
filesystem?
1023
其他 Unix 系统报告的值可能是 1024 或 4095。ISO C 语言标准将此值称为 FILENAME_MAX,并要求在标准头文件 stdio.h 中定义。不同 Unix 系统的值不同,如惠普 HP - UX 10.20 和 11.23 的 FILENAME_MAX 只有 14,但 getconf 报告 1023 和 1024。
由于 Unix 系统支持多个文件系统,文件名长度限制是文件系统的属性,而不是操作系统的属性,因此使用编译时常量定义这些限制没有意义。高级语言程序员建议使用 pathconf() 或 fpathconf() 库调用获取这些限制,需要传递路径名或打开的文件描述符来确定具体的文件系统。
Unix 目录本身也是文件,但具有特殊属性和受限的访问权限。所有 Unix 系统都遵循这种文件系统结构。
综上所述,Unix 的手册页编写、语法检查、格式转换和安装有其独特的方法和工具,而 Unix 文件系统在文件定义、命名、内容和结构方面也有其特点和优势,了解这些知识有助于更好地使用 Unix 系统。
10. 文件系统结构示例与分析
为了更直观地理解 Unix 文件系统的结构,我们来看一个简单的 mermaid 流程图:
graph TD;
/(根目录 /)-->bin(目录 bin);
/(根目录 /)-->usr(目录 usr);
/(根目录 /)-->home(目录 home);
usr(目录 usr)-->man(目录 man);
usr(目录 usr)-->local(目录 local);
home(目录 home)-->user1(用户目录 user1);
home(目录 home)-->user2(用户目录 user2);
man(目录 man)-->man1(子目录 man1);
man(目录 man)-->man2(子目录 man2);
local(目录 local)-->bin(子目录 bin);
local(目录 local)-->man(子目录 man);
user1(用户目录 user1)-->file1(文件 file1);
user1(用户目录 user1)-->file2(文件 file2);
user2(用户目录 user2)-->file3(文件 file3);
man1(子目录 man1)-->ls.1(文件 ls.1);
man2(子目录 man2)-->cp.2(文件 cp.2);
local(目录 local)/man(子目录 man)-->man1(子子目录 man1);
local(目录 local)/man(子目录 man)/man1(子子目录 man1)-->mycmd.1(文件 mycmd.1);
这个流程图展示了 Unix 文件系统的部分结构。根目录下有 bin 、 usr 和 home 等常见目录。 usr 目录下又包含 man 和 local 等子目录, home 目录下是用户的个人目录。每个目录可以包含文件或进一步的子目录,形成了层次分明的树状结构。
从这个结构中我们可以看出,不同的目录有不同的用途。例如, bin 目录通常存放系统的基本命令, usr 目录用于存放用户程序和文档, home 目录则是用户的个人工作空间。这种结构使得文件的管理和查找更加有序,用户可以根据目录的用途快速定位到所需的文件。
11. 路径名的使用与示例
路径名在 Unix 文件系统中非常重要,它用于指定文件或目录的位置。路径名可以分为绝对路径和相对路径。
绝对路径从根目录 / 开始,包含了从根目录到目标文件或目录的完整路径。例如, /usr/man/man1/ls.1 就是一个绝对路径,它明确地指出了 ls.1 文件在文件系统中的位置。
相对路径则是相对于当前工作目录的路径。假设当前工作目录是 /home/user1 ,那么要访问 file2 文件,可以直接使用文件名 file2 ,或者使用相对路径 ./file2 ( . 表示当前目录)。如果要访问 /usr/man/man1/ls.1 文件,可以使用相对路径 ../../usr/man/man1/ls.1 ,其中 .. 表示上级目录。
下面是一个表格,总结了绝对路径和相对路径的特点:
| 路径类型 | 定义 | 示例 | 特点 |
| ---- | ---- | ---- | ---- |
| 绝对路径 | 从根目录 / 开始的完整路径 | /usr/bin/gcc | 明确、唯一,不受当前工作目录影响 |
| 相对路径 | 相对于当前工作目录的路径 | ../src/main.c | 简洁,依赖当前工作目录 |
在实际使用中,我们可以根据具体情况选择使用绝对路径或相对路径。如果需要在不同的工作目录中都能准确访问文件,建议使用绝对路径;如果只是在当前工作目录及其子目录中操作,相对路径会更加方便。
12. 文件系统性能优化建议
由于大多数 Unix 文件系统设计假设目录按顺序搜索,当目录中的文件数量过多时,查找文件的效率会降低。为了优化文件系统的性能,我们可以采取以下措施:
1. 合理组织目录结构 :当一个目录中的文件数量超过几百个时,将其拆分为子目录。例如,如果 home/user1 目录下有大量的文件,可以根据文件的类型或用途创建子目录,如 documents 、 pictures 、 videos 等,将文件分类存放。
2. 避免在根目录下存放过多文件 :根目录是文件系统的基础,应该保持简洁。将系统文件和用户文件分别存放在不同的目录中,避免根目录过于臃肿。
3. 定期清理无用文件 :删除不再使用的文件和目录,释放磁盘空间。可以使用 find 命令查找并删除指定时间之前的文件,例如:
find /home/user1 -type f -mtime +30 -delete
这个命令会查找 /home/user1 目录下 30 天前修改过的文件并删除。
4. 使用符号链接 :符号链接可以在不移动文件的情况下,为文件创建一个新的访问路径。例如,如果经常需要访问 /usr/local/bin 目录下的某个程序,可以在 home/user1/bin 目录下创建一个符号链接:
ln -s /usr/local/bin/myprogram /home/user1/bin/myprogram
这样就可以在 home/user1/bin 目录下直接访问该程序,而不需要每次都输入完整的路径。
13. 总结
通过对 Unix 手册页和文件系统的详细介绍,我们了解了以下重要内容:
- 手册页相关 :编写手册页时,使用 troff 子集,通过 .TH 命令设置标题,使用注释语句提高可读性。语法检查可以通过打印输出或屏幕显示的方式进行,还可以使用 checknr 和 deroff 等工具。手册页可以方便地转换为多种格式,安装时遵循一定的目录结构和规则。
- 文件系统相关 :文件是计算机系统中存储的数据集合,有多种存储介质。文件命名需要考虑字符集的问题,建议使用 ASCII 子集。Unix 文件是字节流,复制操作简单,文本文件有其特殊的行终止约定。文件系统采用分层结构,目录嵌套形成树状,路径名用于定位文件,同时要注意文件名长度限制。
掌握这些知识,我们可以更好地编写和管理手册页,高效地使用 Unix 文件系统,提高工作效率和系统性能。在实际应用中,我们应该根据具体情况灵活运用这些方法和技巧,不断优化和改进我们的工作流程。
超级会员免费看
1942

被折叠的 条评论
为什么被折叠?



