一、删除、移动、复制和文件系统的关联关系
1.删除文件的过程
以/var/log/messages这个文件为例,删除messages这个文件的过程大致如下:
①找到/var/log/messages所在的inode(查找文件的过程见前一章节);
②删除/var/log目录上有关messages的条目;
③清空索引中/var/log/messages对应的inode数据(注意,不是删除inode,而是清空这个inode的数据),将此inode对应的位图改为空闲(如从1改为0)。事实上可以不清除数据,只将位图由1改为0,这样下次使用时会自动覆盖。
④将/var/log/messages所占用的磁盘块重新标记为空闲。其实删除文件并不会对磁盘块做任何操作(清除数据),只会将相应的磁盘块的位图改为空闲,下次使用时仅仅只是覆盖现有磁盘块上的数据。如果没有在这些磁盘块上写入新文件,其数据仍然可以被找回来;但是一旦写入了新文件,就很难再找回原来的数据了。这就是为什么删除文件的过程相较其他操作要快得多。
由此不难理解,为什么不能直接删除非空目录,因为一旦删除了非空目录,其中的文件再也无法找到了。而递归删除非空目录的过程,就是将该目录中的文件所占据的磁盘块逐一归类为空闲磁盘块的过程。
2. 移动文件的过程
还是以/var/log/messages 为例,现在将此文件移动到/var/subsys下,并改名为abc。如果/var/log和/var/subsys都在同一个分区下,其操作过程为:
①在/var/subsys目录上新建一个条目,叫做abc,但是inode号不需要变,仍然指向原来的inode号;
②修改索引中该inode号中的磁盘块信息
③删除/var/log目录上有关messages的条目,到此移动的过程就结束了。
如果/var/log和/var/subsys不在同一个分区,那就意味着/var/log 和/var/subsys的inode列表不一样,其过程要复杂得多:
①在/var/subsys目录上新建一个条目,叫做abc,并为其指定一个新的inode号;
②将/var/log/messages复制到/var/subsys所在的分区上;
③将/var/subsys/abc的磁盘块信息存储到/var/subsys所在分区索引中相应的inode号中;
④删除/var/log目录下messages的条目;
⑤删除/var/log所在分区索引中相应的inode号,将该inode号的位图标记为空闲;
⑥将/var/log/messages所在的磁盘块位图标记为空闲
有此可以看出,不在同一分区下的目录之间移动文件,相当于创建了一个新文件,并删除了一个老文件,其速度可想而知。
3. 复制文件的过程
通过前文的描述,不难理解,为什么在同一个目录下不允许有两个同样的文件名(文件名和inode一一对应)。复制文件的过程,其实就是新建一个文件的过程,其速度也和新建一个文件一样,这就是为什么复制文件的过程通常比较慢。
二、链接文件
在Linux上,链接文件分为两类,一类称为硬链接,一类称为软链接(符号链接: Symbolic link)。
1. 硬链接
硬链接指的是不同的路径,但是指向了同一个inode。如上文中的例子,/var/log/messages 和 /var/subsys/abc是两个完全不同的路径,但他们都指向了同一个inode,而同一个inode则必然对应同一个磁盘块。这种链接类似windows系统中的快捷方式。对于硬链接而言,只要它不是指向具体文件的最后一条路径,那么删除它将不会影响到inode和磁盘块。但如果它是最后一条路径,那么删除了该硬链接后,inode也可以删除了。
使用ls -l 命令,第二段所显示的数字就是指的文件被硬链接的次数,如果该数字为1,删除了它的硬链接,将会清除inode信息,也就是真正删除了该文件。
[root@localhost ~]# ls -l /var/log
total 5116 -rw-------. 1 root root 138642 Jul 9 21:44 anaconda.yum.log # 数字1 表示anaconda.yum.log文件被硬链接了1次 drwxr-x---. 2 root root 4096 Jul 9 21:46 audit -rw-r--r--. 1 root root 2384 Jul 11 13:35 boot.log drwxr-xr-x. 2 root root 4096 Jul 9 21:47 ConsoleKit drwxr-xr-x. 2 root root 4096 Jul 13 00:00 sa drwx------. 3 root root 4096 Jul 9 21:30 samba -rw-------. 1 root root 15219 Jul 13 07:03 secure
硬链接有如下特性:
1. 一个分区上的Inode号不可能指向其他分区上的磁盘块,故硬链接也不可能指向外部分区;
2. 硬链接不能指向目录,否则有可能会导致循环引用,但是目录通常被硬链接的次数都是2,这是由于每个目录内都有一个用点表示的文件.,这表示当前目录,所以通常都有两条路径指向当前目录;
[root@localhost tutor]# ls -al
total 144 drwxr-xr-x. 2 root root 4096 Jul 12 10:24 . # 目录被硬链接的次数通常至少为2 drwxr-xr-x. 3 root root 4096 Jul 11 15:43 .. -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh -rwxr-xr-x. 1 root root 108 Jul 11 16:56 blank_line.sh
3. 删除原文件(硬链接次数大于2),将不影响链接文件的使用,事实上当对某个文件创建了硬链接以后,将无法确定哪一个是原文件,哪一个是链接文件;
4. 所有文件(硬链接和原文件)都指向同一个inode号,因此它们是同一个文件。
创建链接文件使用的命令格式为:
ln SRC_FILE LINK_FILE
例如复制/etc/inittab 到当前目录下,并为其创建硬链接,其过程如下:
[root@localhost tutor]# cp /etc/inittab .
[root@localhost tutor]# ll
total 140 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh -rw-r--r--. 1 root root 884 Jul 13 07:20 inittab -rw-r--r--. 1 root root 117 Jul 11 17:59 maxnum.sh -rw-r--r--. 1 root root 274 Jul 11 22:17 useradd.sh -rw-r--r--. 1 root root 256 Jul 12 04:07 version.sh
[root@localhost tutor]# ln inittab hello
[root@localhost tutor]# ll
total 144 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh -rw-r--r--. 2 root root 884 Jul 13 07:20 hello # 可以看到创建了硬链接hello,两个文件的大小一模一样 -rw-r--r--. 2 root root 884 Jul 13 07:20 inittab -rw-r--r--. 1 root root 117 Jul 11 17:59 maxnum.sh -rw-r--r--. 1 root root 274 Jul 11 22:17 useradd.sh -rw-r--r--. 1 root root 256 Jul 12 04:07 version.sh
[root@localhost tutor]# vim inittab
# inittab is only used by upstart for the default runlevel. # # 删除 inittab中除第一行以外的所有内容
[root@localhost tutor]# cat hello
# inittab is only used by upstart for the default runlevel. # # 查看 hello,会发现里面的内容都被删除了,说明这两者指向了同一个文件
使用ls -i命令,可以显示每个文件的inode号:
[root@localhost tutor]# ls -i hello inittab
1312165 hello 1312165 inittab # 可以看到hello和inittab指向了同一个inode号
下面来尝试对目录创建硬链接:
[root@localhost tutor]# mkdir abc
[root@localhost tutor]# ln abc helloABC
ln: `abc': hard link not allowed for directory # 报错了,说明无法对目录创建硬链接
2. 符号链接(软链接)
软连接是使用ls -l命令,显示文件类型为l的链接:
[root@localhost tutor]# ls -l /etc
total 1764 drwxr-xr-x. 3 root root 4096 Jul 9 21:26 abrt lrwxrwxrwx. 1 root root 56 Jul 9 21:24 favicon.png -> /usr/share/icons/hicolor/16x16/apps/system-logo-icon.png # 文件类型为l,说明这是一个软链接 drwxr-xr-x. 2 root root 4096 Jul 9 21:27 festival lrwxrwxrwx. 1 root root 22 Jul 9 21:43 grub.conf -> ../boot/grub/grub.conf ----------. 1 root root 806 Jul 12 08:46 gshadow
在bash中,测试一个文件是否为链接文件,可以使用-L 或-h,如果结果为真,则为链接文件。
符号链接有如下特性:
1. 可以跨分区,即不受分区限制;
2. 可以对所有文件创建,故可以对目录创建符号链接,如果对目录创建了软链接,那么打开此链接,会看到其指向目录中的文件名列表;
3. 删除了原文件,软链接文件将无法使用;
4. 链接文件和原文件指向了不同的inode号,故它们并非同一个文件,这也是为什么软连接可以跨分区。
创建软链接的命令格式为:
ln -s SRC_FILE LINK_FILE
[root@localhost tutor]# ll
total 144 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh -rw-r--r--. 2 root root 884 Jul 13 07:20 hello # 注意,硬链接hello的文件类型并没有显示为l -rw-r--r--. 2 root root 884 Jul 13 07:20 inittab
[root@localhost tutor]# rm hello
rm: remove regular file `hello'? Y # 删除之前创建的硬链接hello
[root@localhost tutor]# ll
total 144 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh -rw-r--r--. 1 root root 63 Jul 13 07:26 inittab
[root@localhost tutor]# ln -s inittab hello
# 创建了软链接hello
[root@localhost tutor]# ll
total 144 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh lrwxrwxrwx. 1 root root 7 Jul 13 07:48 hello -> inittab # 软连接hello的文件类型为l -rw-r--r--. 1 root root 63 Jul 13 07:26 inittab
[root@localhost tutor]# vim hello
# inittab is only used by upstart for the default runlevel. # Hello, this is new text! # 编辑一下hello,在文件末尾加上一行内容
[root@localhost tutor]# cat inittab
# inittab is only used by upstart for the default runlevel. # Hello, this is new text! # 编辑了符号链接后,会发现原文件也受到影响了
[root@localhost tutor]# ls -i hello inittab
1312231 hello 1312165 inittab # 但是需要注意的是,hello和inittab的inode号不是同一个
[root@localhost tutor]# rm hello
rm: remove symbolic link `hello'? Y # 删除软连接hello
[root@localhost tutor]# cat inittab
# inittab is only used by upstart for the default runlevel. # Hello, this is new text! # 原文件inittab依然存在
[root@localhost tutor]# !ln
ln -s inittab hello # 恢复软连接hello
[root@localhost tutor]# rm inittab
rm: remove regular file `inittab'? Y # 删除了原文件
[root@localhost tutor]# ll
# 再次查看会发现软链接hello失效了
[root@localhost tutor]# cat hello
cat: hello: No such file or directory # hello链接存在,但是仍然报错,说明原文件删除了,软连接也无法使用了
[root@localhost tutor]# cp /etc/fstab ./inittab
# 再复制一个其他的文件,但是命名为inittab,以检测hello是否被修复了
[root@localhost tutor]# cat hello
# # /etc/fstab # Created by anaconda on Wed Jul 9 21:21:40 2014 # # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # /dev/mapper/VolGroup-lv_root / ext4 defaults 1 1 UUID=d9512fb3-8dd6-4613-ae55-8e99ba0ef627 /boot ext4 defaults 1 2 /dev/mapper/VolGroup-lv_swap swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 /dev/sdb3 /mydata ext4 defaults,noatime 0 0 LABEL="NEWSWAP" swap swap defaults 0 0 # 软链接hello可以使用了,但是内容已经变成了新文件的内容了 # 说明符号链接不识别文件内容,只识别文件名
[root@localhost tutor]# ln inittab hi
[root@localhost tutor]# ls -li
1312231 lrwxrwxrwx. 1 root root 7 Jul 13 07:56 hello -> inittab 1312165 -rw-r--r--. 2 root root 932 Jul 13 08:02 hi # 将软连接hello和硬链接hi放在一起对比,可以明显看到hello的体积要小于硬链接,且二者inode号不一样 1312165 -rw-r--r--. 2 root root 932 Jul 13 08:02 inittab
[root@localhost tutor]# rm hi
rm: remove regular file `hi'? y
[root@localhost tutor]# ls -li
1312231 lrwxrwxrwx. 1 root root 7 Jul 13 07:56 hello -> inittab 1312165 -rw-r--r--. 1 root root 932 Jul 13 08:02 inittab # 删除了硬链接hi之后,还会发现inittab被硬链接的次数又变成1了
[root@localhost tutor]# ln -s /u01/tutor/inittab /tmp/hello
# 为当前目录下的inittab文件在/tmp目录下创建软链接hello
[root@localhost tutor]# cat /tmp/hello
# # /etc/fstab # Created by anaconda on Wed Jul 9 21:21:40 2014 # # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # /dev/mapper/VolGroup-lv_root / ext4 defaults 1 1 UUID=d9512fb3-8dd6-4613-ae55-8e99ba0ef627 /boot ext4 defaults 1 2 /dev/mapper/VolGroup-lv_swap swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 /dev/sdb3 /mydata ext4 defaults,noatime 0 0 LABEL="NEWSWAP" swap swap defaults 0 0 # /tmp目录下的hello可以链接到当前目录下的inittab文件
[root@localhost tutor]# ls -li ./hello /tmp/hello
1312231 lrwxrwxrwx. 1 root root 7 Jul 13 07:56 ./hello -> inittab 664919 lrwxrwxrwx. 1 root root 18 Jul 13 08:15 /tmp/hello -> /u01/tutor/inittab # 但是对比当前目录下的hello和/tmp下的hello,会发现二者的大小及inode号都不一样 # 事实上符号链接的大小是其路径的字符串的大小 # 符号链接只有一个inode号,并不占据磁盘块的大小,它指向并不是具体的磁盘块,而是一条路径 # 所以符号链接是一种特殊文件
[root@localhost tutor]# ll
total 148 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh drwxr-xr-x. 2 root root 4096 Jul 13 07:31 abc # abc为目录
[root@localhost tutor]# rm hello
rm: remove symbolic link `hello'? Y # 删除hello
[root@localhost tutor]# ln -s abc hello
[root@localhost tutor]# ll
total 148 -rw-r--r--. 1 root root 114 Jul 11 18:52 3sum.sh drwxr-xr-x. 2 root root 4096 Jul 13 07:31 abc lrwxrwxrwx. 1 root root 3 Jul 13 08:29 hello -> abc
[root@localhost tutor]# cat hello
cat: hello: Is a directory # 无法cat hello
[root@localhost tutor]# cd abc
[root@localhost abc]# touch a.txt
[root@localhost abc]# touch b.txt
[root@localhost ~]# cd /u01/tutor
[root@localhost tutor]# ls hello
a.txt b.txt # 使用ls命令查看hello,实际查看的是abc目录
ln命令还可以配合-v选项,来显示创建链接的过程:
[root@localhost tutor]# ln -sv inittab hi
`hi' -> `inittab' # 显示了hi链接的创建过程