Subsections

2 深入文件

现在您已经知道关于文件的基本知识,该学些更加深入的东西了。


1 文件的本质:硬连接和资料结点 (Hard Links and Inodes)

系统中的每个文件是以资料结点 (inode: Information Node; 发音 ``eye-node'') 表示的,一个资料结点含有一个文件的所有信息。但是,资料结点不能直接看到,每个资料结点通过一个或多个的硬连接跟文件系统联系起来。硬连接含有一个文件的文件名和资料结点序号 (inode number)。而资料结点含有那个文件本身,就是文件在磁盘上储存的位置,它的访问权限,文件的类型等等。如果一个资料结点有它的资料结点序号 (inode number),那么系统总能把它找到。

一个文件可以有超过一个的硬连接,就是说多个不同的文件名可以指向同一个文件(它们都和同一个资料结点需要结合)。但您不能做跨越文件系统的硬连接:所有的对某一个文件(资料结点)做直接参考必需在同一个文件系统上,这是因为每个文件系统都有它自己的一套资料结点,不同的文件系统间的资料结点序号可能会重复。

因为所有指向同一个资料结点的硬连接都是参照同一个文件,您可以用一个文件名来修改一个文件,用指向同一个资料结点但使用一个不同的文件名来查看您的更改结果。试一下这个:

cd; echo "hello" > firstlink
cd 到您的家目录,建立一个有单词 ``hello'' 的叫 firstlink 的文件,您实际上是把 echo 命令的输出重新定向,把输出放到 firstlink 里,echo 命令仅仅重复您传给它的任何东西。细节请参考有关 shell 的章节。

cat firstlink
确定文件 firstlink 的内容。

ln firstlink secondlink
建立一个硬连接:secondlink 现在指向和 firstlink 相同的资料结点。

cat secondlink
确定 secondlink 的内容和 firstlink 一样。

ls -l
注意列出的 firstlinksecondlink 文件的资料结点联合的硬连接数目是 2。

echo "change" >> secondlink
这个另外一个 shell 重新定向诀窍(现在不用考虑细节部分)。您实际上是把单词 ``change'' 附加在 secondlink 的最后。可以用 cat secondlink 来确定。

cat firstlink
firstlink 现在后面也有了单词 ``change''!这是因为 firstlinksecondlink 指的是同一个文件。当您修改它的时候,它叫什么名字是没有关系的。

chmod a+rwx firstlink
改变文件 firstlink 的访问权限。键入命令 ls -l 以确定文件 secondlink 的访问权限也被改变了,这说明访问权限的资料是存在资料结点里而不是硬连接里的。

rm firstlink
删除这个连接,这是 rm 命令的微妙之处:它实际上删除的是连接而不是真正的文件。现在键入 ls -l,您会看到 secondlink 还在。注意现在 secondlink 的硬连接数降到了 1 个。

rm secondlink
删除另外一个连接。当一个文件没有任何连接的时候,Linux 本身会删除真正的文件,即它的资料结点。

所有的文件都是这样的──即使是像设备文件这样的特殊文件(例如 /dev/hda)。

一个目录只是一个文件名和资料结点序号的列表,也就是说是一个硬连接的列表。当您建立一个硬连接时,您只是在一个目录上加入了一个“文件名─序号”对。当您删除一个文件,您只是从目录中删除了一个硬连接。


2 文件类型

到目前为止,我们隐藏了一个细节:Linux 核心把所有东西都看成是一个文件。这包括目录和各种设备,它们只是一些特殊的文件罢了。

您可能记得,ls -l 显示的第一个字符代表的是该文件的类型,对于一个普通的文件来说,这个字符就是个简单的 -。其它可能的字符包括一下:

d
目录 (directory)
l
符号连接 (symbolic link)
b
块设备 (block device)
c
字符设备 (character device)
p
具名管道 (named pipe)
s
套接口 (socket)


1 符号连接 (Symbolic Links)

符号连接(也叫 ``symlinks'' 或软连接 ``soft links'')是除硬连接以外的另外一种连接。一个符号连接是个特殊的文件,它“指向”任意一个加载了的文件系统上的一个硬连接。当您读取一个符号连接的内容时,它给出它所指向的文件的内容而不是这个符号连接本身的内容。因为目录,设备,以及其它的符号连接都是各种类型的文件,所以您可以使用一个符号连接指向所有这些文件。

因此一个硬连接是一个文件名和一个资料结点序号。一个文件其实是一个资料结点:在磁盘上的地址,文件类型,允许模式等等。一个符号连接是一个资料结点,它的内容包含一个硬连接的名字。一个符号连接把一个文件名和另外一个文件名配对,而一个硬连接把一个文件名和一个资料结点配对。

所有的指向同一个文件的硬连接有相同的形态,就是说任何一个跟其他的都是一样的,如果您在其中一个上面进行操作,其效果跟再其它的连接上进行操作是一样的。而在符号连接上的操作,有时候会影响这个符号连接自己的资料结点(含有硬连接名字的那个结点)的资料,有时候影响的是它指向的那个硬连接的内容。

符号连接和硬连接之间有几个重要的分别。

符号连接可以跨越文件系统,因为它们含有从根目录开始的完整的文件名,而所有的完整的文件名都是唯一的。但硬连接指向的是资料结点序号,资料结点序号仅仅在一个文件系统内是唯一的,如果不知道文件系统,则这个序号就会不明确。

您可以建立目录的符号连接,但不能建立目录的硬连接。每个目录都有它的硬连接──在它的母目录中以 . 列出,在它的所有子目录中以 .. 列出──但为了在文件系统中强制次序,不允许有其它的目录硬连接存在。因而一个目录中的文件数目等于该目录的所有硬连接的数目减 2 (减去目录名和 . 连接)。比较符号连接和硬连接,您只能跟一个存在的文件建立硬连接,因为它必需指向一个资料结点序号,但您可以把符号连接连到任何文件名,不论这个文件名的文件是否存在。

删除一个符号连接只删除这个连接,这对于连到的那个目标文件没有影响,而删除一个文件的最后的那个硬连接,则会把那个文件完全删除。

范例:

cd; ln -s /tmp/me MyTmp
cd 到您的家目录,命令 ln-s 选项建立一个符号连接。这里建立的是一个叫 MyTmp 的文件指向文件名 /tmp/me

ls -l MyTmp
输出结果应该类似:

lrwxrwxrwx 1 havoc havoc 7 Dec 6 12:50 MyTmp -> /tmp/me 
当然日期和用户 / 群体名在您的系统上是不一样的。注意文件类别是 l,指示着这是一个符号连接,另外注意它的许可状态:符号连接的许可状态总是这样的。如果您尝试改变一个符号连接的状态(使用 chmod 命令),您改变的是它所指向的那个文件的状态。

chmod 700 MyTmp
您会得到 No such file or directory(没有这个文件或目录)的错误讯息,这是因为文件 /tmp/me 并不存在,虽然您仍然可以就这么建立一个符号连接。

mkdir /tmp/me
建立目录 /tmp/me

chmod 700 MyTmp
这个命令现在应该可以成功。

touch MyTmp/myfile
MyTmp 下建立一个文件。

ls /tmp/me
这个文件其实是在目录 /tmp/me 下建立的。

rm MyTmp
删除这个符号连接,主要这只删除了连接,而不是那个它指向的目录,所以使用的是 rm 而不是 rmdirrmdir 用来删除目录)。

rm /tmp/me/myfile; rmdir /tmp/me
现在您自己清扫一下。

2 设备文件 (Device Files)

设备文件指向您的系统里的物理设备或者虚拟设备,例如您的硬盘、显卡、屏幕和键盘。虚拟设备则包括控制台 (console),以 /dev/console 来表示。

设备分为两种:字符式 (character) 和块式 (block)。字符设备可以每次访问一个字符,记住从这种设备中可以读取和写入的最小单位是一个字符(一个字节)。

块设备的存取必需以一个大的单位进行,我们叫作‘块’。一块里包含了一些字符。硬盘就是一个块设备。

您可以像对其它文件一样对设备文件进行读写,不过这些设备文件里可能含有一些您根本看不懂的乱七八糟的东西。一般来说往这些文件里随便写入数据不是什么好事儿,但又是却会有用,例如,您可以把一个 postscript 文件直接倾倒进打印机设备文件 /dev/lp0 或者把一些调制解调器 (modem) 指令传给相应的串连埠的设备文件。

1 /dev/null

/dev/null 是一个特殊的设备文件,您写入它的任何东西都会被丢弃。如果您不想要什么了,把它扔进 /dev/null。它基本上就是个无底深渊,如果您从 /dev/null 里读入,您立刻会得到一个文件结束 (EOF : end-of-file) 字符。/dev/zero 是另一个类似的设备文件,只是如果您从这里读取,您得到的是一个 \0 字符(这是一个空 (null) 字符,代表什么也不是,与数字 0 是不同的)。

3 具名管道 (Named Pipes, FIFOs)

一个管道是一个作用象个管道的文件。您放东西进这个文件,您放的东西从文件的另一端出来,因此它也叫 FIFO(First-In-First-Out 缩写,即先入先出),您放进去的第一个东西也是最先从另外一端出来的那个。

如果对一个具名的管道进行写入,这个写入的进程不到所有写入的资料被从管道中都读走了是不会结束的。如果您从一个管道中读取,读取进程会一直等到读到一些东西以后才结束。管道的大小总是 0:它不储存任何数据,它只是把两个进程连接起来,就像 shell 里的 | 一样。但是因为这个管道是有名字的,所以那两个被连的进程不需要总同一个命令行出现,它们甚至不需要是属于同一个用户的。

您可以试一下这个例子:

cd; mkfifo mypipe
做一个管道。

echo "hello" > mypipe &
echo 把 ``hello'' 写入管道 mypipe,同时把这个进程放到后台。注意这个进程在后台并不返回,因为它在等待有人从它的管道把数据读出。

cat mypipe
这时候,echo 的进程将会返回,因为 cat 把管道里的资料都读了,而 cat 命令会印出单词 hello

rm mypipe
您可以用一般方式删除这个管道。

4 套接口 (Sockets)

套接口 (sockets) 类似于管道 (pipes) 但它是在网络上面工作的。您到计算机就是靠它来做网络处理的。您可能听说过 ``Winsock'',那是 Windows 的套接口。

我们在这里不深入谈有关套接口,因为如果您不写程序,您不会用到它,但如果您看到您系统里有个文件类型是 s,您知道它是什么就行了。

3 proc 文件系统 (The proc Filesystem)

Linux 的核心会建立一个特别的文件系统,在 Debian 系统上,这个文件系统加载于 /proc 目录下。这是一个“伪文件系统” (``pseudo-filesystem''),因为它不在任何一个物理设备上。

proc 文件系统包含系统和执行中的进程的资料。/proc 下的“文件”,有些是可以读懂的简单文本格式(试着键入 cat /proc/meminfocat /proc/cpuinfo),另外一些是一些神秘的数字组合。系统会有一些工具可以读取这些资料,然后翻译成一些您看的懂的东西。

有些人当看到一个特别的文件时常会觉得紧张,就是 /proc/kcore 文件。这个文件一般来说都很大,它是用来对核心进行除错用的。它其实根本不存在您的物理设备里(记住 /proc 下是一个伪文件系统),所以用不着担心它的大小。

如果您想知道所有关于 /proc 的资料,参看它的手册,键入man 5 proc

4 大规模复制

有时候您会要把一个目录复制 (copy) 到另外一个地方,可能是因为您加了一个新硬盘,您要把您的 /usr/local 复制到它上面。有几个方法都可以达到这个目的。

第一个是用复制命令 cp。命令 cp -a 告诉 cp 在复制的时候,尽量保存可能保存的资料(这个 a 有 all 的意思)。因此,您可以用

cp -a /usr/local /destination
但是有些东西即使 cp -a 也不能保存下来[*]。因此,进行大规模复制工作的最好方法是使用两个连在一起的 tar 命令,像是:
tar -cSpf - /usr/local | tar -xvSpf - -C /destination
第一个 tar 命令会把想要的目录归档,然后通过管道把它送给第二个 tar 命令。第二个命令把归好的档解开,放到 -C 所指定的目的地。

John Goerzen / Ossama Othman / Debian 中文计划