Linux中的軟鏈接、硬鏈接:都用在哪些場合?
時間:2021-09-10 16:35:41
手機看文章
掃描二維碼
隨時隨地手機看文章
[導讀]來源|IOT物聯(lián)網(wǎng)小鎮(zhèn)作者|道哥最近,看到很多文章都在介紹Linux中的文件系統(tǒng),其中就包括:inode節(jié)點、軟鏈接、硬鏈接等重要的概念。于是就有小伙伴私信問我:這些概念我都懂,但是我能利用他們來完成什么工作呢?或者說,在哪些情況下,軟鏈接和硬鏈接能夠提供提供更好的解決方案呢?這...
來源 | IOT物聯(lián)網(wǎng)小鎮(zhèn)作者 | 道哥
最近,看到很多文章都在介紹
Linux
中的文件系統(tǒng),其中就包括:inode 節(jié)點、軟鏈接、硬鏈接等重要的概念。于是就有小伙伴私信問我:這些概念我都懂,但是我能利用他們來完成什么工作呢?或者說,在哪些情況下,軟鏈接和硬鏈接能夠提供提供更好的解決方案呢?這篇文章我們就來簡單梳理一下,軟鏈接和硬鏈接的幾個使用場景。什么是索引節(jié)點
什么是硬鏈接
什么是軟鏈接
軟鏈接應用之:靈活切換不同版本的目標程序
軟鏈接應用之:動態(tài)庫版本管理
軟鏈接應用之:快捷方式
硬鏈接應用之:從不同角度對文件進行分類
硬鏈接應用之:文件多人共享
硬鏈接應用之:文件備份
在
Linux
系統(tǒng)中,我們可以把一個文件看做 3 個組成部分:可以簡單的做一個類比:文件本身的內(nèi)容,可以看做一個實實在在的人。文件的描述信息,可以看做是派出所里的戶籍卡。戶籍卡上記錄了一個人的姓名、年齡、住址等信息,警察叔叔通過這個戶籍卡,就知道這個人的一切描述信息,除了你腦袋里的知識。回到計算機中,文件的所有信息都需要存儲在硬盤上,因此就要對硬盤進行區(qū)域劃分:不同的區(qū)域存儲不同類型的數(shù)據(jù),這就是文件系統(tǒng)的重要作用。在
- 文件名:從用戶角度來描述一個文件;
- 文件內(nèi)容:也就是文件中存儲的那些數(shù)據(jù);
- 文件的描述信息:文件的類型、所有者、創(chuàng)建時間等等,可以稱之為元信息;
Linux
系統(tǒng)使用的 ext2/ext3
文件系統(tǒng)中,從硬盤上劃分一塊區(qū)域,用來存放文件本身的內(nèi)容(數(shù)據(jù)),這塊區(qū)域按照一個最小單位:塊(block)來進行劃分。然后從硬盤上劃分出另一塊區(qū)域,專門用來存放所有文件的描述信息。每一個文件的描述信息,都用一個名為索引節(jié)點(inode)的數(shù)據(jù)結構來表示,所有文件的 inode
就統(tǒng)一放在這塊硬盤區(qū)域中。就像戶籍卡上記錄了一個人的住址一樣,一個文件的索引節(jié)點(inode)中,也記錄了這個文件的所有描述信息,包括:文件類型、所有者、創(chuàng)建時間等待,當然也包括文件內(nèi)容存儲在硬盤的哪些塊(block)中。當我們調(diào)用打開文件 API
函數(shù)的時候,操作系統(tǒng)首先根據(jù)傳入的文件路徑,找到這個文件的 inode
,然后進行一系列的權限檢查操作,最后從 inode
中獲得這個文件的內(nèi)容存儲在哪些塊(block)中,從而可以對文件的內(nèi)容進行讀取、寫入操作。文件名稱只是給我們用戶來使用的,操作系統(tǒng)只是通過 inode
節(jié)點,來對文件進行管理的。當我們創(chuàng)建一個新文件的時候,就同時創(chuàng)建了這個文件對應的 inode
節(jié)點。當我們刪除一個文件的時候,就同時刪除了這個文件對應的 inode
節(jié)點。此時,文件本身內(nèi)容所在的那個塊中,數(shù)據(jù)并不會被抹除掉,因此有些數(shù)據(jù)恢復軟件就是利用這個特點來進行數(shù)據(jù)找回。一句話總結:索引節(jié)點(inode)就像戶籍卡,操作系統(tǒng)通過 inode 來管理所有的文件。剛才已經(jīng)說到,每一個文件都對應一個
inode
節(jié)點。例如有一個文件 a.txt
,文件內(nèi)容長度是 1024
個字節(jié),存放在硬盤上的某個塊(block
)中,假設就是第 10000
個塊吧。那么這個文件對應的 inode
節(jié)點中,就會把 10000
這個塊記錄下來。同時,它還有一個 links
字段,表示:當前這個 inode
對應一個文件,此時 inode.links
的值為 1。此時,如果我們用另一個文件名 a_hard_link.txt
,也來表示 a.txt
這個文件。也就是說:雖然我們用了 2
個文件名稱,但是本質(zhì)上指向同一個文件,內(nèi)容都指向第 10000
個塊中存儲的文件內(nèi)容。Linux
系統(tǒng)中提供了硬鏈接來支持這樣的目的,它僅僅是把 inode
節(jié)點中的 links
字段的值 加1 即可,也就是 inode.links 的值變成了 2。硬鏈接的操作指令是:$ ln a.txt b.txt
基于硬鏈接,用戶就可以用不同的文件名來訪問同一個文件,所有的操作最終修改的都是同一個文件。如果僅僅從用戶的角度來看,好像我們是在操作不同的文件,但是這些文件具有自動同步的功能。這個行為有點類似于網(wǎng)盤:在云存儲中有一個文件 hello.txt
,然后我有兩臺電腦 A
和 B
,這兩臺電腦會把云端的文件 hello.txt
都創(chuàng)建一個鏡像文件在本地,就好像這個文件就在自己的硬盤上一樣。當我在電腦 A
上操作 hello.txt
時,電腦 B
中的同名文件會自動更新。因此,從行為上來看,硬鏈接就相當于是:文件拷貝 自動同步。再來看一下硬鏈接文件的刪除操作。在執(zhí)行 $ ln a.txt a_hard_link.txt
指令之后,該文件對應的 inode
節(jié)點中,links
的值為 2。如果我們刪除 a.txt
,操作系統(tǒng)會把該文件對應的 inode
中的 links
值減1,結果為 1
,操作系統(tǒng)發(fā)現(xiàn)不為 0,因此并不會刪掉這個 inode。如果我們再刪除 a_hard_link.txt
,操作系統(tǒng)再次執(zhí)行 inode.links
減1 動作,發(fā)現(xiàn)值變成了 0,于是就把這個 inode
刪除了,于是這個文件就徹底不存在了。這就相當于把一個人的戶籍卡給注銷掉了,從戶籍管理角度看,這個人就不存在了。即使存在,也是一個黑戶。硬鏈接存在 2 個限制:
- 不允許用戶給目錄創(chuàng)建硬鏈接,即:用戶不可以,操作系統(tǒng)可以(想一下每個目錄下的 . 和 ..);
- 只有在同一個文件系統(tǒng)中的文件,才能創(chuàng)建硬鏈接,也就是說:不能跨文件系統(tǒng);
為了克服硬鏈接的
2
個限制,軟鏈接被引入進來了。軟鏈接也叫符號鏈接,它是一個獨立的文件。軟鏈接文件的內(nèi)容是一個文本字符串,存儲的是目標文件(即:鏈接到的文件)的路徑名。這個路徑名可以指向任意一個文件系統(tǒng)的任意文件或者目錄,甚至可以指向一個不存在的文件。與創(chuàng)建硬鏈接不同的是:當我們創(chuàng)建了一個軟鏈接之后,操作系統(tǒng)會創(chuàng)建一個新的 inode 來表示這個軟鏈接文件。例如有一個文件 a.txt
,我們創(chuàng)建一個軟鏈接 a_soft_link.txt
來指向它:$ ln -s a.txt a_soft_link.txt
此時,a.txt
和 a_soft_link.txt
各自都有自己的 inode
節(jié)點。圖中的綠色虛線,就表示軟鏈接文件中的文件路徑。正因為軟鏈接文件中存儲的僅僅是目標文件的路徑字符串,所以可以表示任意一個文件系統(tǒng)中的文件,或者是目錄。當我們打開文件軟鏈接 a_soft_link.txt
時,操作系統(tǒng)從 a_soft_link.txt
對應的 inode
數(shù)據(jù)結構中發(fā)現(xiàn):這是一個軟鏈接文件。于是操作系統(tǒng)就根據(jù)其中的路徑信息,找到 a.txt
的 inode
節(jié)點,從而對最終的目標文件進行操作。再來看一下軟鏈接文件的刪除操作。如果我們把目標文件 a.txt
刪除掉之后,inode
節(jié)點會被刪除掉,就相當于它的戶籍卡被注銷掉了。此時再次打開軟鏈接 a_soft_link.txt
時,雖然其中的路徑信息仍然存在,但是系統(tǒng)此時卻找不到 a.txt
對應的 inode
節(jié)點了。因此,軟鏈接就類似于與 Windows
系統(tǒng)中的快捷方式。當真正的目標文件被刪除之后,快捷方式也就沒有存在的意義了。在開發(fā)的過程中,對于同一個工具軟件,可能要安裝多個不同的版本,例如:
Python2
和 Python3
, JDK8
和 JDK9
等等。此時就可以通過軟鏈接來指定當前使用哪個版本。例如在我的電腦中:$ ll -l /usr/bin/python*
lrwxrwxrwx 1 root root 9 12月 31 08:19 /usr/bin/python -> python2.7*
lrwxrwxrwx 1 root root 9 12月 31 08:19 /usr/bin/python2 -> python2.7*
-rwxr-xr-x 1 root root 3492624 3月 2 04:47 /usr/bin/python2.7*
lrwxrwxrwx 1 root root 9 12月 31 08:19 /usr/bin/python3 -> python3.5*
-rwxr-xr-x 2 root root 4456208 1月 27 02:48 /usr/bin/python3.5*
當在終端窗口中輸入:python
時,啟動的是 python2.7
版本。如果有一天我需要使用 python3.5
版本,只需要把軟鏈接 python
指向 python3.5
即可。在
Linux
系統(tǒng)的動態(tài)庫版本管理中,有一個 SONAME
的概念。我們在編譯一個動態(tài)鏈接庫時,一般使用如下編譯命令:$ gcc -fPIC -shared -o libhello.so hello.c
在使用這個動態(tài)庫時,需要鏈接這個庫:-llibhello
。簡單的 demo
可以這么來寫,但是如果遇到一些比較大的項目,需要執(zhí)行嚴格的版本管理,那應該怎么來操作呢?Linux
系統(tǒng)已經(jīng)為我們想到了問題的解決方案,利用 SO-NAME
。首先,在編譯動態(tài)鏈接庫文件時,就指定產(chǎn)生 SO-NAME
,它會被存儲在動態(tài)鏈接庫 ELF
文件中。我們來直接看一個優(yōu)秀的開源工具 libevent
的例子:$ ll /usr/lib/libevent-2.1.so*
lrwxrwxrwx 1 root root 17 Jul 27 2020 /usr/lib/libevent-2.1.so -> libevent-2.1.so.7
lrwxrwxrwx 1 root root 21 Jul 27 2020 /usr/lib/libevent-2.1.so.7 -> libevent-2.1.so.7.0.1
-rw-r--r-- 1 root root 412016 Jul 27 2020 /usr/lib/libevent-2.1.so.7.0.1
此時使用 readelf
命令來查看生成的動態(tài)庫文件 libevent-2.1.so.7.0.1
:$ readelf -a libevent-2.1.so.7.0.1 | grep SONAME
0x000000000000000e (SONAME) Library soname: [libevent-2.1.so.7]
它這么做有什么好處呢?Linux
系統(tǒng)在查找動態(tài)鏈接庫文件時,會到下面這 3
個默認目錄下查找(當然然還有其他目錄,比如:當前目錄,LD_LIBRARY_PATH
指定的目錄)/lib: 存放操作系統(tǒng)最關鍵和基礎的庫文件;/usr/lib: 存放一些非系統(tǒng)運行時所需要的關鍵庫文件;/usr/local/lib: 存放用戶自己安裝的一些第三方庫文件;系統(tǒng)中安裝的所有動態(tài)鏈接庫,借助
ldconfig
這個程序,會自動的創(chuàng)建、更新或者刪除對應的 SONAME
(它是一個軟鏈接,鏈接到 實際的庫文件),并把這些 SONAME
匯總到一個文件 /etc/ld.so.cache
中緩存起來。這樣,當動態(tài)庫加載器查找動態(tài)庫文件時,就可以直接在這個緩存文件中進行查找,加快了動態(tài)庫的查找速度。利用軟鏈接的快捷方式功能就比較好理解了,想一想:我們?yōu)槭裁丛?
Windows
的桌面上創(chuàng)建很多軟件的快捷方式啊?在 Linux
中同樣如此!比如:最近一段時間的工作,每次都要打開一個路徑很深的文件。如果在資源管理器中,一層一層的點擊鼠標,是不是比較浪費時間。此時,就可以在桌面上創(chuàng)建一個軟鏈接,每次直接雙擊就打開所鏈接的目標文件了。比如我有一個文件夾,存儲了10 個G的照片。這些照片中的人物、拍照地點、拍照時間都是不一樣的。現(xiàn)在,我既想根據(jù)照片中的人物進行分類,也想根據(jù)拍照地點進行分類,還想根據(jù)拍照時間進行分類,那該怎么辦?因為一張照片可能同時屬于多個不同的分類,難道每個分類中都復制一張照片?這樣也太浪費硬盤空間了!解決方案是:所有的照片仍舊放在一個總的文件夾中,然后創(chuàng)建不同的分類文件夾,在每個分類文件夾中,創(chuàng)建硬鏈接到目標照片文件。這樣的話,不僅對照片進行了分類,而且一點都不占用硬盤空間。
當很多人同時對同一個文件進行維護的時候,如果大家都直接操作這個文件,萬一不小心把文件刪除了,大家就都玩完了!此時,可以在每個人自己的私人目錄中,創(chuàng)建一個硬鏈接。每次只需要對這個硬鏈接文件進行操作,所有的改動會自動同步到目標文件中。由于每個人都是操作硬鏈接文件,即使不小心刪除了,也不會導致文件的丟失。因為刪除硬鏈接文件,僅僅是把該文件的
inode
節(jié)點中的 links
值減 1 而已,只要不為 0
,就不會真正的刪除文件。一些小伙伴有定期備份文件、清理文件的好習慣。在備份的時候,如果是實實在在的拷貝一份,那真的是太浪費磁盤空間,特別是對于我這種只有 256G 硬盤空間的筆記本。此時,就可以利用硬鏈接功能,既實現(xiàn)文件備份的目的,又節(jié)省了大量的硬盤空間,一舉兩得!很多備份工具利用的就是硬鏈接的功能,包括
git
工具,當克隆本地的一個倉庫時,執(zhí)行 clone
指令:git clone --reference
git
并不會把倉庫中的所有文件拷貝到本地,而僅僅是創(chuàng)建文件的硬鏈接,幾乎是零拷貝!來源整理于網(wǎng)絡素材,版權歸原作者所有,如有侵權,請聯(lián)系刪除,謝謝。???????????????? ?END ?????????????????關注我的微信公眾號,回復“加群”按規(guī)則加入技術交流群。