如果要想說清楚 ln 命令,則必須先解釋下 ext 文件系統(tǒng)(linux 文件系統(tǒng))是如何工作的。我們在前面講解了分區(qū)的格式化就是寫入文件系統(tǒng),而我們的 Linux 目前使用的是 ext4 文件系統(tǒng)。如果用一張示意圖來描述 ext4 文件系統(tǒng),則可以參考圖 1。

圖 1 ext4 文件系統(tǒng)示意圖
ext4 文件系統(tǒng)會把分區(qū)主要分為兩大部分(暫時不提超級塊):小部分用于保存文件的 inode (i 節(jié)點)信息;剩余的大部分用于保存 block 信息。
inode 的默認大小為 128 Byte,用來記錄文件的權(quán)限(r、w、x)、文件的所有者和屬組、文件的大小、文件的狀態(tài)改變時間(ctime)、文件的最近一次讀取時間(atime)、文件的最近一次修改時間(mtime)、文件的數(shù)據(jù)真正保存的 block 編號。每個文件需要占用一個 inode。大家如果仔細查看,就會發(fā)現(xiàn) inode 中是不記錄文件名的,那是因為文件名記錄在文件所在目錄的 block 中。
block 的大小可以是 1KB、2KB、4KB,默認為 4KB。block 用于實際的數(shù)據(jù)存儲,如果一個 block 放不下數(shù)據(jù),則可以占用多個 block。例如,有一個 10KB 的文件需要存儲,則會占用 3 個 block,雖然最后一個 block 不能占滿,但也不能再放入其他文件的數(shù)據(jù)。這 3 個 block 有可能是連續(xù)的,也有可能是分散的。
由此,我們可以知道以下 2 個重要的信息:- 每個文件都獨自占用一個 inode,文件內(nèi)容由 inode 的記錄來指向;
- 如果想要讀取文件內(nèi)容,就必須借助目錄中記錄的文件名找到該文件的 inode,才能成功找到文件內(nèi)容所在的 block 塊;
了解了 Linux 系統(tǒng)底層文件的存儲狀態(tài)后,接下來學(xué)習(xí) ln 命令。
ln 命令用于給文件創(chuàng)建鏈接,根據(jù) Linux 系統(tǒng)存儲文件的特點,鏈接的方式分為以下 2 種:- 軟鏈接:類似于 Windows 系統(tǒng)中給文件創(chuàng)建快捷方式,即產(chǎn)生一個特殊的文件,該文件用來指向另一個文件,此鏈接方式同樣適用于目錄。
- 硬鏈接:我們知道,文件的基本信息都存儲在 inode 中,而硬鏈接指的就是給一個文件的 inode 分配多個文件名,通過任何一個文件名,都可以找到此文件的 inode,從而讀取該文件的數(shù)據(jù)信息。
ln 命令的基本格式如下:
[root@localhost ~]# ln [選項] 源文件 目標文件
選項:
- -s:建立軟鏈接文件。如果不加 "-s" 選項,則建立硬鏈接文件;
- -f:強制。如果目標文件已經(jīng)存在,則刪除目標文件后再建立鏈接文件;
【例 1】創(chuàng)建硬鏈接:
[root@localhost ~]# touch cangls
[root@localhost ~]# ln /root/cangls /tmp
#建立硬鏈接文件,目標文件沒有寫文件名,會和原名一致
#也就是/tmp/cangls 是硬鏈接文件
【例 2】創(chuàng)建軟鏈接:
[root@localhost ~]# touch bols
[root@localhost ~]# In -s /root/bols /tmp
#建立軟鏈接文件
這里需要注意,軟鏈接文件的源文件必須寫成絕對路徑,而不能寫成相對路徑(硬鏈接沒有這樣的要求);否則軟鏈接文件會報錯。這是初學(xué)者非常容易犯的錯誤。
ln創(chuàng)建鏈接的深度剖析
建立硬鏈接和軟鏈接非常簡單,那這兩種鏈接有什么區(qū)別?它們都有什么作用?這才是鏈接文件最不容易理解的地方,我們分別來講講。ln創(chuàng)建硬鏈接
我們再來建立一個硬鏈接文件,然后看看這兩個文件的特點。
[root@localhost ~]# touch test
#建立源文件
[root@localhost ~]# ln /root/test /tmp/test-hard
#給源文件建立硬鏈接文件 /tmp/test-hard
[root@localhost ~]# ll -i /root/test /tmp/test-hard
262147 -rw-r--r-- 2 root root 0 6月 19 10:06 /root/test
hard
262147 -rw-r--r-- 2 root root 0 6月 19 10:06 /tmp/test-hard
#查看兩個文件的詳細信息,可以發(fā)現(xiàn)這兩個文件的 inode 號是一樣的,"ll"等同于"ls -l"。
這里有一件很奇怪的事情,我們之前在講 inode 號的時候說過,每個文件的 inode 號都應(yīng)該是不一樣的。inode 號就相當于文件 ID,我們在查找文件的時候,要先查找 inode 號,才能讀取到文件的內(nèi)容。
但是這里源文件和硬鏈接文件的 inode 號居然是一樣的,那我們在查找文件的時候,到底找到的是哪一個文件呢?我們來畫一張示意圖,如圖 2 所示。

圖 2 硬鏈接示意圖
在 inode 信息中,是不會記錄文件名稱的,而是把文件名記錄在上級目錄的 block 中。也就是說,目錄的 block 中記錄的是這個目錄下所有一級子文件和子目錄的文件名及 inode 的對應(yīng);而文件的 block 中記錄的才是文件實際的數(shù)據(jù)。
當我們查找一個文件,比如 /root/test 時,要經(jīng)過以下步驟:- 首先找到根目錄的 inode(根目錄的 inode 是系統(tǒng)已知的,inode 號是 2),然后判斷用戶是否有權(quán)限訪問根目錄的 block。
- 如果有權(quán)限,則可以在根目錄的 block 中訪問到 /root 的文件名及對應(yīng)的 inode 號。
- 通過 /root/ 目錄的 inode 號,可以查找到 /root/ 目錄的 inode 信息,接著判斷用戶是否有權(quán)限訪問 /root/ 目錄的 block。
- 如果有權(quán)限,則可以從 /root/ 目錄的 block 中讀取到 test 文件的文件名及對應(yīng)的 inode 號。
- 通過 test 文件的 inode 號,就可以找到 test 文件的 inode 信息,接著判斷用戶是否有權(quán)限訪問 test 文件的 block。
- 如果有權(quán)限,則可以讀取 block 中的數(shù)據(jù),這樣就完成了 /root/test 文件的讀取與訪問。
按照這個步驟,在給源文件 /root/test 建立了硬鏈接文件 /tmp/test-hard 之后,在 /root/ 目錄和 /tmp/ 目錄的 block 中就會建立 test 和 test-hard 的信息,這個信息主要就是文件名和對應(yīng)的 inode 號。但是我們會發(fā)現(xiàn) test 和 test-hard 的 inode 信息居然是一樣的,那么,我們無論訪問哪個文件,最終都會訪問 inode 號是 262147 的文件信息。
這就是硬鏈接的原理。硬鏈接的特點如下:- 不論是修改源文件(test 文件),還是修改硬鏈接文件(test-hard 文件),另一個文件中的數(shù)據(jù)都會發(fā)生改變。
- 不論是刪除源文件,還是刪除硬鏈接文件,只要還有一個文件存在,這個文件(inode 號是 262147 的文件)都可以被訪問。
- 硬鏈接不會建立新的 inode 信息,也不會更改 inode 的總數(shù)。
- 硬鏈接不能跨文件系統(tǒng)(分區(qū))建立,因為在不同的文件系統(tǒng)中,inode 號是重新計算的。
- 硬鏈接不能鏈接目錄,因為如果給目錄建立硬鏈接,那么不僅目錄本身需要重新建立,目錄下所有的子文件,包括子目錄中的所有子文件都需要建立硬鏈接,這對當前的 Linux 來講過于復(fù)雜。
硬鏈接的限制比較多,既不能跨文件系統(tǒng),也不能鏈接目錄,而且源文件和硬鏈接文件之間除 inode 號是一樣的之外,沒有其他明顯的特征。這些特征都使得硬鏈接并不常用,大家有所了解就好。
我們通過實驗來測試一下。[root@localhost ~]# echo 1111 >>/root/test
#向源文件中寫入數(shù)據(jù)
[root@localhost ~]# cat /root/test
1111
[root@localhost ~]# cat /tmp/test-hard
1111
#源文件和硬鏈接文件都會發(fā)生改變
[root@localhost ~]# echo 2222 >> /tmp/test-hard
#向硬鏈接文件中寫入數(shù)據(jù)
[root@localhost ~]# cat /root/test
1111
2222
[root@localhost ~】# cat /tmp/test-hard
1111
2222
#源文件和硬鏈接文件也都會發(fā)生改變
[root@localhost ~]# rm -rf/root/test
#刪除源文件
[root@localhost ~]# cat /tmp/test-hard
1111 2222
#硬鏈接文件依然可常讀取
ln創(chuàng)建軟鏈接
軟鏈接也稱作符號鏈接,相比硬鏈接來講,軟鏈接就要常用多了。我們先建立一個軟鏈接,再來看看軟鏈接的特點。
[root@localhost ~]# touch check
#建立源文件
[root@localhost ~]# ln -s /root/check /tmp/check-soft
#建立軟鏈接文件
[root@localhost ~]# ll -id /root/check /tmp/check-soft
262154 -rw-r--r-- 1 root root 0 6月 19 11:30 /root/check
917507 lrwxrwxrwx 1 root root 11 6月 19 11:31 /tmp/ check-soft -> /root/check
#軟鏈接和源文件的 inode 號不一致,軟鏈接通過 -> 明顯地標識出源文件的位置
#在軟鏈接的權(quán)限位 lrwxrwxrwx 中,l 就代表軟鏈接文件
再強調(diào)一下,軟鏈接的源文件必須寫絕對路徑,否則建立的軟鏈接文件就會報錯,無法正常使用。
軟鏈接的標志非常明顯,首先,權(quán)限位中"l"表示這是一個軟鏈接文件;其次,在文件的后面通過 "->" 顯示出源文件的完整名字。所以軟鏈接比硬鏈接的標志要明顯得多,而且軟鏈接也不像硬鏈接的限制那樣多,比如軟鏈接可以鏈接目錄,也可以跨分區(qū)來建立軟鏈接。
軟鏈接完全可以當作 Windows 的快捷方式來對待,它的特點和快捷方式一樣,我們更推薦大家使用軟鏈接,而不是硬鏈接。
大家在學(xué)習(xí)軟鏈接的時候會有一些疑問:Windows 的快捷方式是由于源文件放置的位置過深,不容易找到,建立一個快捷方式放在桌面,方便查找,那 Linux 的軟鏈接的作用是什么呢?
筆者個人覺得,軟鏈接主要是為了照顧管理員的使用習(xí)慣。比如,有些系統(tǒng)的自啟動文件 /etc/rc.local 放置在 /etc 目錄中,而有些系統(tǒng)卻將其放置在 /etc/rc.d/rc.local 中,那么干脆對這兩個文件建立軟鏈接,不論你習(xí)慣操作哪一個文件,結(jié)果都是一樣的。
如果你比較細心,則應(yīng)該已經(jīng)發(fā)現(xiàn)軟鏈接和源文件的 inode 號是不一致的,我們也畫一張示意圖來看看軟鏈接的原理,如圖 3 所示。

圖 3 軟鏈接示意圖
軟鏈接和硬鏈接在原理上最主要的不同在于:硬鏈接不會建立自己的 inode 索引和 block(數(shù)據(jù)塊),而是直接指向源文件的 inode 信息和 block,所以硬鏈接和源文件的 inode 號是一致的;而軟鏈接會真正建立自己的 inode 索引和 block,所以軟鏈接和源文件的 inode 號是不一致的,而且在軟鏈接的 block 中,寫的不是真正的數(shù)據(jù),而僅僅是源文件的文件名及 inode 號。
我們來看看訪問軟鏈接的步驟和訪問硬鏈接的步驟有什么不同。
- 首先找到根目錄的 inode 索引信息,然后判斷用戶是否有權(quán)限訪問根目錄的 block。
- 如果有權(quán)限訪問根目錄的 block,就會在 block 中查找到 /tmp/ 目錄的 inode 號。
- 接著訪問 /tmp/ 目錄的 inode 信息,判斷用戶是否有權(quán)限訪問 /tmp/ 目錄的 block。
- 如果有權(quán)限,就會在 block 中讀取到軟鏈接文件 check-soft 的 inode 號。因為軟鏈接文件會真正建立自己的 inode 索引和 block,所以軟鏈接文件和源文件的 inode 號是不一樣的。
- 通過軟鏈接文件的 inode 號,找到了 check-soft 文件 inode 信息,判斷用戶是否有權(quán)限訪問 block。
- 如果有權(quán)限,就會發(fā)現(xiàn) check-soft 文件的 block 中沒有實際數(shù)據(jù),僅有源文件 check 的 inode 號。
- 接著通過源文件的 inode 號,訪問到源文件 check 的 inode 信息,判斷用戶是否有權(quán)限訪問 block。
- 如果有權(quán)限,就會在 check 文件的 block 中讀取到真正的數(shù)據(jù),從而完成數(shù)據(jù)訪問。
通過這個過程,我們就可以總結(jié)出軟鏈接的特點(軟鏈接的特點和 Windows 中的快捷方式完全一致)。
- 不論是修改源文件(check),還是修改硬鏈接文件(check-soft),另一個文件中的數(shù)據(jù)都會發(fā)生改變。
- 刪除軟鏈接文件,源文件不受影響。而刪除原文件,軟鏈接文件將找不到實際的數(shù)據(jù),從而顯示文件不存在。
- 軟鏈接會新建自己的 inode 信息和 block,只是在 block 中不存儲實際文件數(shù)據(jù),而存儲的是源文件的文件名及 inode 號。
- 軟鏈接可以鏈接目錄。
- 軟鏈接可以跨分區(qū)。
我們測試一下軟鏈接的特性。[root@localhost ~]# echo 111>>/root/check
#修改源文件
[root@localhost ~]# cat /root/check
111
[root@localhost ~]# cat /tmp/check-soft
111
#不論是源文件還是軟鏈接文件,數(shù)據(jù)都發(fā)生改變
[root@localhost ~]# echo 2222 >>/tmp/check-soft
#修改軟鏈接文件
[root@localhost ~]# cat /tmp/check-soft
111
2222
[root@localhost ~]# cat /root/check
111
2222
#不論是源文件還是軟鏈接文件,數(shù)據(jù)也都會發(fā)生改變
[root@localhost ~]# rm -rf/root/check
#刪除源文件
[root@localhost ~]# cat /tmp/check-soft
cat: /tmp/check-soft:沒有那個文件或目錄
#軟鏈接無法正常使用
軟鏈接是可以鏈接目錄的,例如:
[root@localhost ~]# mkdir test
#建立源目錄
[root@localhost ~]# ln -s /root/test/ /tmp/
[root@localhost ~]# ll -d /tmp/test
lrwxrwxrwx 1 root root 11 6月 19 12:43 /tmp/test->/root/test/
#軟鏈接可以鏈接目錄