1.简介
操作机某软件异常,进行重装时。对软链接理解存在偏差导致误删除目录问题详细参考 2.3.5 删除目录的软链。
因为未移除感觉软链接,导致安装失败;
尝试删除软链接
/root/bin -> /bin
。执行命令
rm /root/bin/
时,报错Is a directory
。想当然的执行
rm -rf /root/bin/
导致将其link的目录/bin
删除。目录软链接的删除,应为
rm /root/bin
,而非rm -rf /root/bin/
。
本文详细记录由链接引伸出来的一系列概念。
2.说明
2.0 基础知识
inode的相关说明:注1
- 跨文件系统(磁盘分区),inode不唯一;
- 每个文件都会占用一个 inode ,文件内容由 inode 来指向blok获取;
- inode与文件名为一对多关系;
系统内部读取文件步骤:注1
- 系统找到
文件名
对应的inode
- 通过
inode
号码,获取inode
信息 - 根据
inode
信息,找到文件数据所在的block
,读出数据。
链接: UNIX文件系统提供的一种将不同文件链接至同一个文件的机制;实际上是一种文件共享的方式,是 POSIX 中的概念,主流文件系统都支持链接文件。
查看文件信息的命令
ls命令
示例:
1 2 3 4
hex@hex-PC:/tmp/ln-test$ ls -li total 4 60822147 -rw-rw-r-- 1 hex hex 12 Oct 25 17:36 test 60822175 lrwxrwxrwx 1 hex hex 4 Oct 25 17:36 test-sl -> test
参数:
-i
查看inode
输出:
- 第一列:inode号
- 第二列:文件权限
- 第三列:链接数目,指一共多少个文件名指向这个inode
- 第四列:文件拥有者
- 第五列:文件所属group
- 第六列:文件大小
- 第七列:文件内容上一次变动的时间
- 第八列:文件名
stat命令
示例:
1 2 3 4 5 6 7 8 9
hex@hex-PC:/tmp/ln-test$ stat test-sl File: test-sl -> test Size: 4 Blocks: 0 IO Block: 4096 symbolic link Device: 10302h/66306d Inode: 60822175 Links: 1 Access: (0777/lrwxrwxrwx) Uid: ( 1000/ hex) Gid: ( 1000/ hex) Access: 2022-10-25 17:36:18.216885854 +0800 Modify: 2022-10-25 17:36:16.184873570 +0800 Change: 2022-10-25 17:36:16.184873570 +0800 Birth: 2022-10-25 17:36:16.184873570 +0800
参数: 无
输出:
File:显示文件名
Size:显示文件大小
Blocks:文件使用的数据块总数
IO Block:IO块大小
symbolic link:文件类型(软链接)
Inode:inode 号
Links:链接数,即有多少文件名指向这个 inode
Uid:文件拥有者的 Uid
Gid:文件所属group的 Gid
Access:文件的读、写、执行权限
文件的时间戳,共有三个:
- Change:简写为ctime,文件状态(链接数、大小、权限、Blocks数)改变时间。
- Modify:简写为mtime,文件内容的修改时间,文件内容被修改时更新。
- Access:简写为atime,文件内容的访问时间。文件内容被访问时更新。
- Birth: 文件创建时间。
2.1 软链接、硬链接区别
功能项 | 软链接 | 硬链接 |
---|---|---|
使用对象 | 文件、目录 | 文件 |
inode是否相同 | 不同 | 相同 |
是否跨文件系统(磁盘分区) | 是 | 否 |
原文件删除 | 软链接不可用 | 不受影响 |
与原文件的关联项 | 执行命令时,原文件名参数 | 原文件inode |
原文件是否必须存在 | 否 | 是 |
执行命令 | ln -s <src> <file-sl> | ln <src> <file-hl> |
2.2 软链接
软链接只是一个符号链接,其实就是新建立一个文件,这个文件就是专门用来指向别的文件。大小很小,权限是777,而真正的信息是由指向的原文件决定;
- 删除软链接文件,不影响原文件;
- 删除原文件,则相应的软链接不可用(cat那个软链接文件,则提示“没有该文件或目录“);
2.3 硬链接
硬链接实际上是为文件建一个别名,指向同一个inode。
- 创建硬链接时,不会建立inode,只是在原文件的
inode link count
域再增加1; - 删除硬链接时,在原文件的
inode link count
域再减1;
系统调用会检查inode link count
的数值,如果>=1
,那么inode不会被回收,文件的内容不会被删除。
2.4 引申问题
2.4.1 软链接跳转靠的是文件名而非inode
验证思路:设置软链接时,原文件参数传递为相对路径;再将软链接移动到其他目录下;如果报错
Not Found
则说明成立软链接查找使用的文件名,为
ln
执行命令时传入的原文件,如果是相对路径,则根据软链接路径进行查找。
准备测试环境
1 2 3 4 5
# 创建测试目录 mkdir /tmp/ln-test/ cd /tmp/ln-test/ # 生成测试 原文件 echo "source file" > test
设置软链接
1
ln -s test test-sl
查看文件状态
执行命令
ls -li
(i参数为查看文件inode
)1 2 3 4
hex@hex-PC:/tmp/ln-test$ ls -li total 4 60822147 -rw-rw-r-- 1 hex hex 12 Oct 25 17:36 test 60822175 lrwxrwxrwx 1 hex hex 4 Oct 25 17:36 test-sl -> test
执行命令
stat <filename>
1 2 3 4 5 6 7 8 9
hex@hex-PC:/tmp/ln-test$ stat test-sl File: test-sl -> test Size: 4 Blocks: 0 IO Block: 4096 symbolic link Device: 10302h/66306d Inode: 60822175 Links: 1 Access: (0777/lrwxrwxrwx) Uid: ( 1000/ hex) Gid: ( 1000/ hex) Access: 2022-10-25 17:36:18.216885854 +0800 Modify: 2022-10-25 17:36:16.184873570 +0800 Change: 2022-10-25 17:36:16.184873570 +0800 Birth: 2022-10-25 17:36:16.184873570 +0800
移动软链接至其他目录
1
mv test-sl ../
通过软链接
cat
文件内容stat 查看软链接属性,
File: test-sl -> test
显示软链接指向当前目录test
文件,但test
文件不存在。1 2 3 4 5 6 7 8 9 10 11 12
hex@hex-PC:/tmp/ln-test$ cd ../ hex@hex-PC:/tmp$ stat test-sl File: test-sl -> test Size: 4 Blocks: 0 IO Block: 4096 symbolic link Device: 10302h/66306d Inode: 60822175 Links: 1 Access: (0777/lrwxrwxrwx) Uid: ( 1000/ hex) Gid: ( 1000/ hex) Access: 2022-10-25 17:40:57.608602008 +0800 Modify: 2022-10-25 17:36:16.184873570 +0800 Change: 2022-10-25 17:40:34.131967367 +0800 Birth: 2022-10-25 17:36:16.184873570 +0800 hex@hex-PC:/tmp$ cat test-sl cat: test-sl: No such file or directory
软链接所在新目录创建新的
test
文件,再查看1 2 3 4 5 6
hex@hex-PC:/tmp$ echo "Other test file" > test hex@hex-PC:/tmp$ ls -li test* 60822202 -rw-rw-r-- 1 hex hex 16 Oct 25 17:47 test 60822175 lrwxrwxrwx 1 hex hex 4 Oct 25 17:36 test-sl -> test hex@hex-PC:/tmp$ cat test-sl Other test file
软链接移动前后,inode为60822175
,未改变;但前后的原文件test
的inode已发生改变60822147 -> 60822202
。说明软链接是通过File: test-sl -> test
记录所跳转的原文件,而非inode。
2.4.2 硬链接无法跨分区,而软链接可以的原因
硬盘格式化的时候,操作系统自动将硬盘分为两个区域:
数据区:存放文件内容
inode 区:存放 inode 包含的信息,也叫作 inode table
硬链接通过与原文件共用同一inode访问blok读取文件内容。跨分区无法共享inode,所以硬链接无法跨分区。
软链接记录的是原文件的文件名
, 而非inode。可以跨分区。
2.4.3 硬链接不支持目录的原因
系统限制对目录进行硬链接只是一个硬性规定,并不是逻辑上不允许、技术上不可行。
其实使用
ln -d
命令也允许 root 用户尝试建立目录硬链接,且.
与..
都是目录的硬链接。
由于 Linux 操作系统中的目录是以
/
为节点的树状结构,对目录的硬链接有可能破坏这种结构,甚至形成循环如:/usr/bin -> /usr/
,在使用遍历目录的命令时(如:ls -R
)系统就会陷入无限循环中。如果使用 hard link 链接到目录时, 链接的数据需要连同被链接目录下面的所有数据都创建链接。因此造成环境相当大的复杂度。
举例来说,如果要将
/etc
使用实体链接创建一个/etc_hd
的目录时,那么在/etc_hd
下面的所有文件名同时都与/etc
下面的文件名要创建 hard link 的,而不是仅链接到/etc_hd
与/etc
而已。 并且,未来如果需要在/etc_hd
下面创建新文件时,连带的,/etc
下面的数据又得要创建一次hard link
。
2.3.4 .
与..
是目录的硬链接,特殊在哪里
创建目录时,默认会生成两个目录项: .
和 ..
。
.
相当于当前目录的硬链接;..
相当于父目录的硬链接。
目录硬链接总数:
- 空目录的硬链接总数,等于2(
.
和<file-name>
); - 目录的硬链接总数,等于 2 + 它的子目录总数(子目录的
..
);
2.3.5 目录软链接删除,注意区分 软链接/
与 软链接
目录的软链接=文件,而非目录文件;例如
目录文件:
/tmp/ln-test/test-dir
等同于/tmp/ln-test/test-dir/
目录的软链接:
/tmp/ln-test/test-dir-sl
<不等于>/tmp/ln-test/test-dir-sl/
rm 前者 == 删除软链接; rm后者 == 删除原目录。
验证:
准备环境
1 2 3 4
# 创建目录 mkdir -p /tmp/ln-test/test-dir cd /tmp/ln-test/test-dir
设置软链接
1
ln -s test-dir/ test-dir-sl
查看文件状态
1 2 3 4
hex@hex-PC:/tmp/ln-test$ ls -li total 4 60822338 drwxrwxr-x 2 hex hex 4096 Oct 26 10:22 test-dir 60822339 lrwxrwxrwx 1 hex hex 9 Oct 26 10:23 test-dir-sl -> test-dir/
软链接
stat1 2 3 4 5 6 7 8 9
hex@hex-PC:/tmp/ln-test$ stat test-dir-sl File: test-dir-sl -> test-dir/ Size: 9 Blocks: 0 IO Block: 4096 symbolic link Device: 10302h/66306d Inode: 60822339 Links: 1 Access: (0777/lrwxrwxrwx) Uid: ( 1000/ hex) Gid: ( 1000/ hex) Access: 2022-10-26 10:23:12.046192861 +0800 Modify: 2022-10-26 10:23:06.810155908 +0800 Change: 2022-10-26 10:23:06.810155908 +0800 Birth: 2022-10-26 10:23:06.810155908 +0800
软链接/
的stat1 2 3 4 5 6 7 8 9
hex@hex-PC:/tmp/ln-test$ stat test-dir-sl/ File: test-dir-sl/ Size: 4096 Blocks: 8 IO Block: 4096 directory Device: 10302h/66306d Inode: 60822338 Links: 2 Access: (0775/drwxrwxr-x) Uid: ( 1000/ hex) Gid: ( 1000/ hex) Access: 2022-10-26 10:23:12.046192861 +0800 Modify: 2022-10-26 10:22:18.821817214 +0800 Change: 2022-10-26 10:22:18.821817214 +0800 Birth: 2022-10-26 10:22:18.821817214 +0800
可尝试执行
stat test-dir
和stat test-dir/
,会发现与stat test-dir-sl/
的inode
一致。测试删除
通过上一步stat查看
软链接/
和软链接
已足够说明问题,通过删除再二次验证删除
软链接/
1 2
hex@hex-PC:/tmp/ln-test$ rm test-dir-sl/ rm: cannot remove 'test-dir-sl/': Is a directory
删除
软链接
1 2 3 4
hex@hex-PC:/tmp/ln-test$ rm test-dir-sl hex@hex-PC:/tmp/ln-test$ ls -li total 4 60822338 drwxrwxr-x 2 hex hex 4096 Oct 26 10:22 test-dir
2.3.6 应用场景
软链接:
灵活切换不同版本的目标程序
在开发的过程中,对于同一个工具软件,可能要安装多个不同的版本,例如:
Python2
和Python3
。当在终端窗口中输入:
python
时,启动的是python2.7
版本。如果有一天需要使用
python3.5
版本,只需要把软链接python
指向python3.5
即可。动态库版本管理
场景描述: 想象这样一个情景,一个程序需要使用
foo_1.1
文件中的共享资源,由于foo
经常改变版本号。每次升级后都得将使用foo_1.1
的所有程序更新到foo_1.2
文件,那么每次更新foo
版本后,都要重复上边的工作。解决方案:创建一个
foo
的软链接指向foo_1.2
。这时,当一个程序访问foo
时,实际上是访问foo_1.2
。当升级到foo_1.3
时,只需要更新软链接指向。这不仅解决了版本升级问题,而且还允许在系统中保存两个不同的版本,如果foo_1.3
有错误,再更新回原来的foo_1.2
链接就可以。快捷方式,将目录层次较深的文件链接到一个更易访问的目录中。
硬链接:
- 不同角度对文件进行分类
- 文件多人共享
- 文件备份
3.总结
- 目录的软链接比较特殊,尤其删除时注意区分带与不带的
/
的区别。<软链接>/
是原目录本身,后<软链接>
是软链接文件; - 硬链接无法跨分区是实现机制决定的,无法创建目录的硬链接是硬性规定(
.
与..
都是目录的硬链接); - 硬链接共用同一
inode
,增加硬链接相当于文件inode
的新的别名; - 软链接通过创建时的原文件参数查找原文件,而非原文件
inode
(原文件参数==绝对路径,软链接可到处移动。否则不可以);
4.参考
[注1]: linux-inode说明
[注2]: “醉卧沙场:计算机专业性文章及回答总索引-存储和文件系统”
[注3]:Linux是如何跨分区寻找inode
[注4]: “鸟哥私房菜-链接ln说明”