ln命令_Linux ln命令:建立檔案連結

2020-07-16 10:04:30
ln 是一個很神奇的命令,它可以建立一個檔案的影子,也可以通過一個通道進入另一個地方。其實,所有的這些把戲都是通過軟連結和硬連結來實現的。本文不會花太多篇幅來深入解釋“硬連結”和“軟連結”兩個概念,而是更側重在 ln 命令本身的功能和使用上。

連結也分軟硬

我們先來介紹一下軟連結和硬連結的概念。

軟連結,全稱是軟連結檔案,英文叫作 symbolic link。這類檔案其實非常類似於 Windows 裡的快捷方式,這個軟連結檔案(假設叫 VA)的內容,其實是另外一個檔案(假設叫 B)的路徑和名稱,當開啟 A 檔案時,實際上系統會根據其內容找到並開啟 B 檔案。

而硬連結,全稱叫作硬連結檔案,英文名稱是 hard link。這類檔案比較特殊,這類檔案(假設叫 A)會擁有自己的 inode 節點和名稱,其 inode 會指向檔案內容所在的資料塊。與此同時,該檔案內容所在的資料塊的參照計數會加 1。當此資料塊的參照計數大於等於 2 時,則表示有多個檔案同時指向了這一資料塊。一個檔案修改,多個檔案都會生效。當刪除其中某個檔案時,對另一個檔案不會有影響,僅僅是資料塊的參照計數減 1。當參照計數為 0 時,則系統才會清除此資料塊。

如果上述內容理解起來非常困難,那麼還請花些時間閱讀一下《UNIX 環境高階程式設計》的相關章節,要確保理解這部分知識,才更有助於深入掌握 ln 命令。

建立屬於你的第一個硬連結

硬碟上已經有了一個檔案,叫作 source.txt,我想針對這個檔案建一個硬連結檔案,名字叫作 hardsource.txt:
#我們的原檔案
[[email protected] ~]$ cat source.txt
Hello!Source!
 
#先通過ls看看檔案資訊, 注意開頭的"-", 表示這是一個普通檔案
[[email protected] ~]$ ls -l source.txt
-rw-rw-r-- 1 roc roc 14 3月   1 00:19 source.txt
 
#用ln命令建立硬連結
[[email protected] ~]$ ln source.txt hardsource.txt
 
#我們通過ls -i檢視兩個檔案的inode, 發現是完全相同的, 表示它們指向的是同一資料塊
[[email protected] ~]$ 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來建立軟連結
[[email protected] ~]$ ln -s source.txt softsource.txt
 
#檢視檔案i節點資訊
[[email protected] ~]$ 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 命令之後,就像手裡有了一把錘子,總覺得哪兒都是釘子。
[[email protected] ~]$ ls -F
tempdir/
 
[[email protected] ~]$ ln tempdir linkdir
ln: "tempdir": 不允許針對目錄建立硬連結

我想硬連結一個目錄 tempdir,但是報錯了!是的,硬連結是不允許連結到目錄的。至於原因,賣個關子,稍後再揭曉。

我們來嚐試一下針對目錄建立軟連結,看看是否可以:
#嘗試建立針對目錄的軟連結
[[email protected] ~]$ ln -s tempdir/ linkdir
[[email protected] ~]$ 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裡的東西
[[email protected] ~]$ ls -F tempdir/
linksource.txt
 
#我們通過剛才建立的軟連結, 進入linkdir
[[email protected] ~]$ cd linkdir/
 
#看, 就如同進入tempdir一樣
[[email protected] linkdir]$ ls -F
linksource.txt

為什麼 ln 不允許硬連結到目錄

Linux 系統中的硬連結有兩個限制:
  1. 不能跨越檔案系統。
  2. 不允許普通使用者對目錄作硬連結。

至於第一個限制,很好理解,而第二個就不那麼好理解了。

我們對任何一個目錄用 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。
[[email protected] ~]$ mkdir a b
[[email protected] ~]$ ls -F
a/  b/

第二步:針對 a 目錄建立軟連結 c。
[[email protected] ~]$ ln -s a c
[[email protected] ~]$ 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的重複定義
[[email protected] ~]$ ln -s b c
 
#軟連結c並沒有指向b, 上一條命令似乎並沒有生效
[[email protected] ~]$ 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目錄)中看一看
[[email protected] ~]$ cd c/
 
#竟然發現了一個軟連結b指向目錄b, 而且是死鏈
[[email protected] 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選項後, 系統發現了軟連結重複定義的問題, 於是報錯了
[[email protected] ~]$ ln -sn b c
ln: 建立符號連結 "c": 檔案已存在
 
#我們使用-f(--force)來強制建立軟連結, 看看效果
[[email protected] ~]$ ln -snf b c
 
#看, 原來指向a的符號連結c, 現在已經乖乖地指向b了
[[email protected] ~]$ 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.

好了,有關 ln 命令的種種知識和範例,就講到這裡了。如果你對-n選項的作用理解得還不是非常透徹的話,就多看幾遍吧,確實挺難理解的,哈哈。