ln 是一個很神奇的命令,它可以創建一個文件的影子,也可以通過一個通道進入另一個地方。其實,所有的這些把戲都是通過軟鏈接和硬鏈接來實現的。本文不會花太多篇幅來深入解釋“硬鏈接”和“軟鏈接”兩個概念,而是更側重在 ln 命令本身的功能和使用上。
鏈接也分軟硬
我們先來介紹一下軟鏈接和硬鏈接的概念。
軟鏈接,全稱是軟鏈接文件,英文叫作 symbolic link。這類文件其實非常類似於 Windows 裏的快捷方式,這個軟鏈接文件(假設叫 VA)的內容,其實是另外一個文件(假設叫 B)的路徑和名稱,當打開 A 文件時,實際上系統會根據其內容找到並打開 B 文件。
而硬鏈接,全稱叫作硬鏈接文件,英文名稱是 hard link。這類文件比較特殊,這類文件(假設叫 A)會擁有自己的 inode 節點和名稱,其 inode 會指向文件內容所在的數據塊。與此同時,該文件內容所在的數據塊的引用計數會加 1。當此數據塊的引用計數大於等於 2 時,則表示有多個文件同時指向了這一數據塊。一個文件修改,多個文件都會生效。當刪除其中某個文件時,對另一個文件不會有影響,僅僅是數據塊的引用計數減 1。當引用計數爲 0 時,則系統纔會清除此數據塊。
如果上述內容理解起來非常困難,那麼還請花些時間閱讀一下《UNIX 環境高級編程》的相關章節,要確保理解這部分知識,才更有助於深入掌握 ln 命令。
建立屬於你的第一個硬鏈接
硬盤上已經有了一個文件,叫作 source.txt,我想針對這個文件建一個硬鏈接文件,名字叫作 hardsource.txt:
#我們的原文件 [roc@roclinux ~]$ cat source.txt Hello!Source! #先通過ls看看文件信息, 注意開頭的"-", 表示這是一個普通文件 [roc@roclinux ~]$ ls -l source.txt -rw-rw-r-- 1 roc roc 14 3月 1 00:19 source.txt #用ln命令建立硬鏈接 [roc@roclinux ~]$ ln source.txt hardsource.txt #我們通過ls -i查看兩個文件的inode, 發現是完全相同的, 表示它們指向的是同一數據塊 [roc@roclinux ~]$ ls -il source.txt hardsource.txt 2235010 -rw-rw-r-- 2 roc roc 14 3月 1 00:19 hardsource.txt 2235010 -rw-rw-r-- 2 roc roc 14 3月 1 00:19 source.txt
可以看到,我們建立硬鏈接的命令格式是:
$ ln 源文件名稱 硬鏈接文件名稱
首先,用 ln source.txt hardsource.txt 建立了一個 source.txt 文件的硬鏈接文件。然後,用 ls-il 命令查看了文件的信息。其中,-i
選項表示列出每個文件的 inode 節點 ID,可以發現 source.txt 和 hardsource.txt 的 inode 號完全一致,都是 2235010,這就說明它們都指向了同一個數據塊。
這就是硬鏈接,屬於我們的第一個硬鏈接文件。
有一點要注意,硬鏈接不允許跨分區來建立,也不允許跨文件系統來建立,即使是同一類型的文件系統也不行,這主要是受限於 inode 指向數據塊的名字空間。所以,記住,硬鏈接只能在同一個分區內建立。
建立屬於你的第一個軟鏈接
建立一個 source.txt 文件的軟鏈接,名字叫作 softsource.txt。
#用ln -s來建立軟鏈接 [roc@roclinux ~]$ ln -s source.txt softsource.txt #查看文件i節點信息 [roc@roclinux ~]$ ls -il source.txt softsource.txt 2235009 lrwxrwxrwx 1 roc roc 10 3月 1 00:24 softsource.txt -> source.txt 2235010 -rw-rw-r-- 2 roc roc 14 3月 1 00:19 source.txt
可以看到,建立軟鏈接也是使用 ln 命令,但是必須加上-s
選項,即 --symbolic 選項。建立軟鏈接的命令格式爲:
ln -s 源文件名稱 軟鏈接文件名稱
我們依然使用 ls-il 命令查看,發現軟鏈接文件 softsource.txt 和源文件 source.txt 的 inode 號是不一樣的,這說明它們完全指向兩個不同的數據塊。而且,細心的朋友能夠觀察到軟鏈接文件的權限欄首字符爲 l(L的小寫字母),這也是軟鏈接文件區別於普通文件的地方之一。
如果這個時候,我們刪除了 source.txt 文件,則軟鏈接 softsource.txt 就會變成紅色字體。這表示警告,說明這是一個有問題的文件,無法找到它所標識的目標文件 source.txt 啦。
建立屬於你自己的目錄鏈接
前面的兩個例子都是創建的文件鏈接,那可以創建目錄的鏈接嗎?自從學會了 ln 命令之後,就像手裏有了一把錘子,總覺得哪兒都是釘子。
[roc@roclinux ~]$ ls -F tempdir/ [roc@roclinux ~]$ ln tempdir linkdir ln: "tempdir": 不允許針對目錄建立硬鏈接
我想硬鏈接一個目錄 tempdir,但是報錯了!是的,硬鏈接是不允許鏈接到目錄的。至於原因,賣個關子,稍後再揭曉。
我們來嘗試一下針對目錄建立軟鏈接,看看是否可以:
#嘗試建立針對目錄的軟鏈接 [roc@roclinux ~]$ ln -s tempdir/ linkdir [roc@roclinux ~]$ ls -li 總用量 4 2235009 lrwxrwxrwx 1 roc roc 8 3月 1 00:32 linkdir -> tempdir/ 2235011 drwxrwxr-x 2 roc roc 4096 3月 1 00:30 tempdir
成功了,系統允許我們針對目錄建立軟鏈接,看,我建立了一個 tempdir 目錄的軟鏈接 linkdir,以後我完全可以用 cd linkdir 來“進入”temp 目錄了。
#給大家看看tempdir裏的東西 [roc@roclinux ~]$ ls -F tempdir/ linksource.txt #我們通過剛纔創建的軟鏈接, 進入linkdir [roc@roclinux ~]$ cd linkdir/ #看, 就如同進入tempdir一樣 [roc@roclinux linkdir]$ ls -F linksource.txt
爲什麼 ln 不允許硬鏈接到目錄
Linux 系統中的硬鏈接有兩個限制:
- 不能跨越文件系統。
- 不允許普通用戶對目錄作硬鏈接。
至於第一個限制,很好理解,而第二個就不那麼好理解了。
我們對任何一個目錄用 ls-l 命令都可以看到其鏈接數至少是 2,這也說明了系統中是存在基於目錄的硬鏈接的,而且命令 ln-d(-d選項表示針對目錄建立硬鏈接)也允許 root 用戶嘗試對目錄作硬鏈接。這些都說明了系統限制對目錄進行硬鏈接只是一個硬性規定,並不是邏輯上不允許或技術上不可行。那麼操作系統爲什麼要進行這個限制呢?
這是因爲,如果引入了對目錄的硬連接就有可能在目錄中引入循環鏈接,那麼在目錄遍歷的時候系統就會陷入無限循環當中。也許有人會說,符號連接不也可以引入循環鏈接嗎,那麼爲什麼不限制目錄的符號連接呢?
原因就在於,在 Linux 系統中,每個文件(目錄也是文件)都對應着一個 inode 結構,其中 inode 數據結構中包含了文件類型(目錄、普通文件、符號連接文件等)的信息,也就是說,操作系統在遍歷目錄時可以判斷出其是否是符號連接。既然可以判斷出它是否是符號連接,當然就可以採取一些措施來防範進入過大過深的循環層次,於是大部分系統會規定在連續遇到 8 個符號連接後就停止遍歷。但是對於硬鏈接,由於操作系統中採用的數據結構和算法限制,目前是不能防範這種死循環的。
基於這樣的考慮,系統不允許普通用戶建立目錄硬鏈接。
ln 命令的 -n 選項有點繞
ln 命令裏面有一個-n
選項,它的官方解釋是這樣的:
-n, --no-dereference treat destination that is a symlink to a directory as if it were a normal file.
這個選項理解起來的確有些難度,爲此,我們模擬了一個操作過程,以便讓大家能更好地理解。
第一步:建立兩個文件夾 a 和 b。
[roc@roclinux ~]$ mkdir a b [roc@roclinux ~]$ ls -F a/ b/
第二步:針對 a 目錄創建軟鏈接 c。
[roc@roclinux ~]$ ln -s a c [roc@roclinux ~]$ ls -li 總用量 8 2235012 drwxrwxr-x 2 roc roc 4096 3月 1 00:47 a 2235013 drwxrwxr-x 2 roc roc 4096 3月 1 00:47 b 2235009 lrwxrwxrwx 1 roc roc 1 3月 1 00:48 c -> a
第三步:精髓就在這一步。
#我們再針對b目錄創建軟鏈接c, 造成了軟鏈接c的重複定義 [roc@roclinux ~]$ ln -s b c #軟鏈接c並沒有指向b, 上一條命令似乎並沒有生效 [roc@roclinux ~]$ ls -li 總用量 8 2235012 drwxrwxr-x 2 roc roc 4096 3月 1 00:48 a 2235013 drwxrwxr-x 2 roc roc 4096 3月 1 00:47 b 2235009 lrwxrwxrwx 1 roc roc 1 3月 1 00:48 c -> a #我們進入到軟鏈接c(也就是a目錄)中看一看 [roc@roclinux ~]$ cd c/ #竟然發現了一個軟鏈接b指向目錄b, 而且是死鏈 [roc@roclinux c]$ ls -li 總用量 0 2235010 lrwxrwxrwx 1 roc roc 1 3月 1 00:48 b -> b
可以看到,ln 會在 c 軟鏈接目錄(也就是 a 目錄)裏面創建一個 b 的軟鏈接文件,且指向 b 目錄,但很明顯,這不是你的本意。
如果換成 ln-sn b c,那麼結果就變了,我們一起來看。
#加上-n選項後, 系統發現了軟鏈接重複定義的問題, 於是報錯了 [roc@roclinux ~]$ ln -sn b c ln: 創建符號鏈接 "c": 文件已存在 #我們使用-f(--force)來強制建立軟鏈接, 看看效果 [roc@roclinux ~]$ ln -snf b c #看, 原來指向a的符號鏈接c, 現在已經乖乖地指向b了 [roc@roclinux ~]$ ls -li 總用量 8 2235012 drwxrwxr-x 2 roc roc 4096 3月 1 00:51 a 2235013 drwxrwxr-x 2 roc roc 4096 3月 1 00:47 b 2235009 lrwxrwxrwx 1 roc roc 1 3月 1 00:51 c -> b
這就是-n
選項的作用,相信通過這樣一個生動的例子,你應該可以理解下面這句話的含義了。
-n, --no-dereference treat destination that is a symlink to a directory as if it were a normal file.