详解Linux硬链接与软链接(ln命令)

序言

  在Linux中文件需要通过inode号才能识别当前文件数据存储的位置,所以inode号才是文件的唯一标识而不是文件名称 。文件名只是方便人们的记忆和区分,而系统或程序则是通过inode号寻找正确的文件数据块。在了解这个点以后,我们就可以很好地学习Linux中的软链接和硬链接了,因为它是建立在inode号之上的。

  其实链接文件就是为解决文件的共享使用,在Linux系统中引入了两种链接:硬链接(hard link)和软链接(又称符号链接,即soft link或symbolic link)

  不太了解文件系统的可以参考:轻松学Linux文件系统(Ext2/Ext3/Ext4)

一:硬链接(hard link)

  硬链接是指一个文件系统中的多个文件名指向同一个数据块(inode)。也就是说硬链接指向相同的数据文件,但它们的文件名称却不一样。因此,对于硬链接和原文件来说,它们的访问权限、所有者、大小等属性都是相同的。但要注意的是硬链接只能在同一个分区内创建,不能跨越不同的文件系统。

(一):硬链接的创建及删除方法

  在Linux系统中,可以使用ln 源文件 目标文件命令来创建硬链接。例如现在有/home/demo.txt的原文件,现在需要对这个原文件创建一个硬链接/home/demoHard.txt。具体如下:

bash 复制代码
# 对demo.txt创建一个硬链接demoHard.txt  
   > ln /home/demo.txt /home/demoHard.txt  
# 这样就会在/home目录下生成一个名为demoHard.txt的硬链接,它和demo.txt指向同一个数据块。  
# 可以使用ls -li命令来查看文件的inode号和硬链接数。例如:  
   > ls -li  
      1179691 -rw-r--r-- 2 root root 11 12月 12 21:03 demoHard.txt  
      1179691 -rw-r--r-- 2 root root 11 12月 12 21:03 demo.txt  
# 可以看到两个文件的inode号都是1179691,表示它们指向同一个数据块。同时两个文件的硬链接数都是2,  
# 表示有两个文件名指向该数据块。这两个文件的创建时间是一样的,实际上是原始文件的创建时间。

  硬链接一旦被创建,那么这些文件都是指向同一个inode号,即使后面修改了某个文件的数据,那么其它的文件数据也随之发生改变。具体如下:

bash 复制代码
# 首先查询那两个文件信息  
   > cat demo.txt  
      helloWorld  
   > cat demoHard.txt  
      helloWorld  
# 覆盖其中一个文件的信息  
   > echo "my name is ant" > demoHard.txt  
# 再次查询两个文件的信息  
   > cat demoHard.txt  
      my name is ant  
   > cat demo.txt  
      my name is ant

  删除硬链接只需要使用rm命令来即可,例如我们想删除demoHard.txt文件:

bash 复制代码
# 删除硬链接"demoHard.txt"文件  
   > rm demoHard.txt  
# 这样就会删除demoHard.txt这个文件名,而不会影响demo.txt或者该数据块。  
# 只有当所有指向该数据块的文件名都被删除时,该数据块才会被释放。例如:  
   > rm demo.txt

(二):硬链接的优缺点

js 复制代码
优点:  
   1.节省空间:  
      硬链接创建的链接文件与原始文件共享相同的数据块,因此不会占用额外的磁盘空间。  
      这使得硬链接成为一种节省存储空间的有效方式。  
   2.备份:  
      使用硬链接可以轻松地创建文件的备份。  
      如果原始文件发生更改,其对应的硬链接也会自动更新,这样就可以轻松地实现文件备份。  
   3.文件版本控制:  
      通过使用硬链接,可以轻松地创建文件的不同版本,并且每个版本都可以直接访问。  
      这在需要保留文件历史记录或版本控制时非常有用。  
   4.性能:  
      由于硬链接只是文件系统中相同数据块的多个引用,因此在一定程度上可以提高文件访问的性能。  
缺点:  
   1.限制:  
      硬链接只能用于链接文件,无法链接目录。  
   2.跨文件系统限制:  
      硬链接无法跨越不同的文件系统,因为硬链接是基于文件系统内的inode进行链接的,  
      不同的文件系统有不同的inode表,所以无法进行跨文件系统的硬链接。  
   3.删除问题:  
      当原始文件被删除时,如果仍然存在指向原始文件的硬链接,那么硬链接依然可以访问原始文件的内容。  
      这可能会导致误删除和数据不一致的问题。  
   4.难以识别:  
      硬链接的存在并不容易被察觉,因为它们看起来就像普通的文件,这可能会导致管理上的混乱。

(三):硬链接的注意事项

  每创建一个文件的硬链接,实质上是多一个指向该inode记录的inode指针,并且硬链接数加1。删除文件实质上是删除该文件所在目录数据块中的对应的inode行,所以也是减少硬链接次数,由于block指针是存储在inode中的,所以不是真的删除数据,如果仍有其它inode号链接到该inode,那么该文件的block指针仍然是可用的。当硬链接次数为1时再删除文件就是真的删除文件了,此时inode记录中block指针也将被删除。

  硬链接只能对文件创建而无法对目录创建硬链接。之所以无法对目录创建硬链接,是因为文件系统已经把每个目录的硬链接创建好了,它们就是相对路径中的./../,分别标识当前目录的硬链接和上级目录的硬链接。每一个目录中都会包含这两个硬链接,它包含了两个信息:

  (1):没有子目录的目录文件的硬链接数为2,是因为第一个硬链接数是目录本身,即当前目录数据块中的./,第二个硬链接数是其父目录数据块中该目录的记录,这两者都指向同一个inode号;
  (2):一个包含子目录的目录文件,其硬链接数是2+子目录数,因为每个子目录都关联一个父目录的硬链接../

  很多人在计算目录的硬链接数时认为由于包含了"."和"..",所以空目录的硬链接数是2,这是错误的,因为".."不是本目录的硬链接。另外,还有一个特殊的目录应该纳入考虑,即"/"目录,它自身是一个文件系统的入口,是自引用的,所以"/"目录下的"."和".."的inode号相同,它自身不占用硬链接,因为其data block中只记录inode号相同的"."和"..",不再像其它目录一样还记录一个名为"/"的目录,所以"/"的硬链接数也是2+子目录数,但这个2是"."和".."的结果。

  为什么文件系统自己创建好了目录的硬链接就不允许人为创建呢?从"."和".."的用法上考虑,如果当前目录为/usr,我们可以使用"./local"来表示/usr/local,但是如果我们人为创建了/usr目录的硬链接/tmp/husr,难道我们也要使用"/tmp/husr/local"来表示/usr/local吗?这其实已经是软链接的作用了。若要将其认为是硬链接的功能,这必将导致硬链接维护的混乱。

二:软链接(symbolic link)

  软链接(也称为符号链接或symbolic link)是一种特殊类型的文件,它是将一个新的文件名关联到另外一个文件上,使得这个新的文件名也可以访原文件;简单说软链接是一个指向另一个对象的快捷方式。软链接与原文件不共享inode。因此对于软链接和原文件来说,它们的访问权限、所有者、大小等属性可能不同;但要注意的是软链接可以跨越不同的分区和文件系统创建。

(一):软链接的创建与删除方法

  在Linux系统中,可以使用ln -s 源文件 目标文件命令来创建文件软链接和目录软链接。例如现在有/home/demo.txt的原文件,现在需要对这个原文件创建一个软链接/home/demoSym.txt。具体如下:

bash 复制代码
# 对demo.txt创建一个软链接demoSym.txt  
   > ln -s /home/demo.txt /home/demoSym.txt  
# 这样我们就会获得一个demoSym.txt的软链接文件,这个文件的类型为"l",就代表它是一个软链接文件。  
# 可以查看软链接的文件信息,也可以使用'readlink 链接文件'查看具体的源文件位置  
   > ls -li  
      1179683 lrwxrwxrwx 1 root root 14 12月 14 20:55 demoSym.txt -> /home/demo.txt  
      1179687 -rw-r--r-- 1 root root 19 12月 14 20:54 demo.txt  
# 可以看出软链接文件的后面往往多出一个箭头并指向原文件或者目录的位置

  上面我们创建了一个软链接,要知道软链接就是字符链接,链接文件默认指的就是字符链接文件(注意不是字符设备),使用"l"表示其类型。之前硬链接不能跨文件系统创建,否则inode号可能会冲突。于是实现了软链接以便跨文件系统建立链接。既然是跨文件系统,那么软链接必须得有自己的inode号。软链接在功能上等价于Windows系统中的快捷方式,它指向原文件,原文件损坏或消失,软链接文件就损坏。所以可以认为软链接的inode记录中指针内容是目标路径的字符串。

bash 复制代码
# 查看文件信息发现demoSym.txt的文件大小为14,其实是"/home/demo.txt"字符的长度
    > ll
        lrwxrwxrwx  1 root root   14 12月 14 20:55 demoSym.txt -> /home/demo.txt
        -rw-r--r--  1 root root   19 12月 14 20:54 demo.txt
# 我们再查看源文件的内容信息
    > cat demo.txt
        helloWorld ninhao!
# 追加一些信息到源文件内部后会发现链接文件的大小并没有变,所以就验证了它存储的是原文件的路径信息
    > echo 'mynameisjack' >> demo.txt
    > ll
        lrwxrwxrwx  1 root root   14 12月 14 20:55 demoSym.txt -> /home/demo.txt
        -rw-r--r--  1 root root   32 12月 14 21:43 demo.txt
# 查看它们的文件信息内容(其实都是一样的,只不过链接文件它本质上类似快捷方式)
    > cat demo.txt 
        helloWorld ninhao!
        mynameisjack
    > cat demoSym.txt 
        helloWorld ninhao!
        mynameisjack

  删除软链接只需要使用rm命令删除即可,比如rm demoSym.txt

(二):软链接的优缺点

js 复制代码
优点:
    1.跨文件系统支持:
        软链接可以跨越不同的文件系统,因为它们是基于路径名的,而不是基于 inode 的。
    2.灵活性:
        软链接是一种非常灵活的链接方式,可以链接到任何类型的文件或目录。
    3.易于识别:
        软链接可以很容易地被识别出来,并且在文件系统中显示为一个单独的文件。
    4.删除安全:
        当原始文件被删除时,软链接将失效,不会产生误删除和数据不一致的问题。
缺点:
    1.性能开销:
        与硬链接相比,软链接需要额外的系统调用来解析路径名,因此可能会导致一些性能开销。
    2.空间占用:
        软链接需要占用一定的磁盘空间,因为它们是单独的文件。
    3.指向错误路径:
        如果源文件或目录移动或重命名,那么软链接将指向错误的路径,这可能会导致应用程序或脚本出现错误。
    4.安全漏洞:
        软链接可能会被用于欺骗应用程序或脚本,例如通过创建指向恶意文件的软链接来执行恶意代码或攻击系统。

(三):软链接的注意事项

  在设置软链接的时候,它是以软链接的路径为主,去寻找指向的文件,源文件虽然不要求是绝对路径,但建议给绝对路径 。是否还记得软链接文件的大小?它是根据软链接所指向路径的字符数计算的,例如某个软链接的指向方式为rmt --> ../sbin/rmt,那么rmt文件大小为11字节,也就是说只要建立了软链接后,软链接的指向路径是不会改变的,仍然是../sbin/rmt。如果此时移动软链接文件本身,它的指向是不会改变的,仍然是11个字符的../sbin/rmt,但此时该软链接父目录下可能根本就不存在/sbin/rmt,也就是说此时该软链接是一个被破坏的软链接。

三:ln链接命令其它用法

txt 复制代码
我们可以通过ln --help 命令来获取帮助
ln基本语法:
    ln [参数] 源文件或目录 目标文件或目录
ln命令可选参数:
    -b:如果目标目录中已有同名的文件,那么在覆盖之前先进行备份(通常备份的文件后面加"~")
    -f:如果目标目录中已经有同名的文件,无需提示,直接覆盖
    -i:如果目标目录中已经有同名的文件,则提示是否进行覆盖(y/n)
    -s:创建软链接
    -n:把软链接视为一般目录(后面有案例)
    -v:详细显示操作进行的步骤,告诉我们谁链接了谁
    -S:需要携带值如"-S=xx";是替换通常使用的备份文件后缀

参数 − b 、 − f 、 − i 、 − v 示例: \color{#f00}{参数-b、-f、-i、-v示例:} 参数−b、−f、−i、−v示例:

bash 复制代码
# 插入两个文件并查看文件inode号
> echo 'aaa' > aaa.txt
> echo 'bbb' > bbb.txt
> ls -li
    1048596 -rw-r--r-- 1 root root 4 12月 19 21:16 aaa.txt
    1048597 -rw-r--r-- 1 root root 4 12月 19 21:16 bbb.txt
# 创建带参数的硬链接(使用-b参数覆盖目标文件前先备份,并看出备份的文件带后面"~",多次覆盖则多个"~")
> ln -b aaa.txt bbb.txt
> ls -li
    1048596 -rw-r--r-- 2 root root 4 12月 19 21:16 aaa.txt
    1048596 -rw-r--r-- 2 root root 4 12月 19 21:16 bbb.txt
    1048597 -rw-r--r-- 1 root root 4 12月 19 21:16 bbb.txt~
# 创建硬链接并交互式的(这里交互 "ln: 是否替换 'bbb.txt~'?"我选择'n'不同意)
> ln -i aaa.txt bbb.txt~
# 使用-f强行覆盖目标已经存在的文件,并打印操作步骤
> ln -fv aaa.txt bbb.txt~
    'bbb.txt~' => 'aaa.txt'
# 此时3个文件都被硬链接到一个地方了

参数 − s 、 − n 示例: \color{#f00}{参数-s、-n示例:} 参数−s、−n示例:

bash 复制代码
# 创建两个目录aaa和bbb,并指定ccc目录软链接到aaa
> ln -s aaa ccc
> ls -li
    1048596 drwxr-xr-x 2 root root 4096 12月 19 21:34 aaa
    1048597 drwxr-xr-x 2 root root 4096 12月 19 21:34 bbb
    1048599 lrwxrwxrwx 1 root root    3 12月 19 21:35 ccc -> aaa
# 指定ccc目录软链接到bbb(因为ccc已经是指向aaa的软链接目录了,所以创建失败)
>  ls -s bbb ccc # 这个执行不管有没有输出都不会成功
# 使用-n参数来把软链接当成一个普通的文件或者目录来操作,并强行链接过去
> ln -fns bbb ccc

参数 − S 、 − t 示例: \color{#f00}{参数-S、-t示例:} 参数−S、−t示例:

bash 复制代码
# 覆盖文件时的后缀可以自己指定,不在是"~"
> ln -b -S=yz aaa.txt bbb.txt
> ls -li
    1048596 -rw-r--r-- 2 root root 4 12月 19 22:04  aaa.txt
    1048596 -rw-r--r-- 2 root root 4 12月 19 22:04  bbb.txt
    1048597 -rw-r--r-- 1 root root 4 12月 19 22:04 'bbb.txt=yz'
相关推荐
EMTime8 小时前
Docker运行OpenWRT
运维·docker·容器
lolo大魔王8 小时前
Linux 文件系统超全面详解(原理、结构、挂载、分区、inode、日志、管理命令)
linux·运维·服务器
磊 子9 小时前
详细讲解一下epoll
linux·io·epoll·io多路复用
printfLILEI10 小时前
php中的类与对象以及反序列化
linux·开发语言·php
zyl8372110 小时前
Docker 使用手册
运维·docker·容器
古月方枘Fry11 小时前
MGRE实验
运维·服务器
叠叠乐11 小时前
redmi k90 pro max 强解BL,刷海外rom, 并刷入sukisu ultra
linux
stolentime11 小时前
FreeDomain 本地开发环境快速搭建指南
运维·服务器·网络
xiaoye-duck12 小时前
《Linux系统编程》Linux 进程间通信之管道基础解析:从匿名管道原理到基于管道的进程池实现
linux