概述
在本篇中,學習創建和管理硬鏈接和符號鏈接。學習:
創建硬或軟鏈接識別鏈接並知道它們的類型理解復制與鏈接文件之間的區別使用鏈接執行系統管理任務
鏈接簡介
在存儲設備上,文件或目錄包含在一些數據塊中。有關某個文件的信息包含在一個 inode 中,它記錄了所有者、最後訪問該文件的時間、文件的大小、它是否是目錄,以及誰可以讀取或寫入它等信息。inode 編號也稱為文件序列號 ,該編號在特定文件系統內是唯一的。一個 目錄條目 包含一個文件或目錄的名稱,以及用來存儲該文件或目錄的信息的 inode 的指針。
創建鏈接
硬鏈接 是指向 inode 的目錄條目,而 軟鏈接 或 符號鏈接 是指向提供另一個目錄條目的名稱的 inode 的目錄條目。存儲第二個名稱的准確機制可能依賴於文件系統和名稱的長度。符號鏈接也稱為symlink 。
您可以只為文件創建硬鏈接,而不為目錄創建硬鏈接。一個例外是一個包含該目錄和它的父目錄(. 和 ..)的目錄中的特殊目錄條目,它們是維護子目錄數量的硬鏈接。因為硬鏈接指向 inode,而且 inode 僅在特定的文件系統內是唯一的,所以硬鏈接不能跨文件系統使用。如果一個文件有多個硬鏈接,那麼只在指向該 inode 的最後一個鏈接被刪除,而且鏈接數量變為 0 時,才會刪除該文件。
軟鏈接或 symlink 僅按名稱指向另一個文件或目錄,而不是按 inode。軟鏈接可以跨越文件系統邊界進行使用。刪除軟鏈接不會刪除目標文件或目錄,刪除目標文件或目錄也不會自動刪除任何軟鏈接。
首先讓我們看看如何創建硬和軟鏈接。在本教程後面,我們將介紹識別和使用我們在這裡創建的鏈接的方式。
硬鏈接
使用 ln 命令創建現有文件的額外的硬鏈接(但不能是目錄,即使系統將 . 和 .. as 設置為硬鏈接)。
清單 1 展示了如何創建一個包含兩個文件和一個子目錄的目錄,其中包含 file1 的兩個硬鏈接,一個位於同一個目錄中,另一個位於子目錄中。我們向 file1 添加一個詞,然後向 file3 添加另一個詞,並在子目錄中顯示該鏈接的內容,以表明所有鏈接確實都指向相同的數據。
清單 1. 創建硬鏈接
[ian@atticf22 ~]$ mkdir -p lpi104-6/subdir
[ian@atticf22 ~]$ touch lpi104-6/file1
[ian@atticf22 ~]$ touch lpi104-6/file2
[ian@atticf22 ~]$ ln lpi104-6/file1 lpi104-6/file3
[ian@atticf22 ~]$ ln lpi104-6/file1 lpi104-6/subdir/file3sub
[ian@atticf22 ~]$ echo "something" > lpi104-6/file1
[ian@atticf22 ~]$ echo "else" >> lpi104-6/file3
[ian@atticf22 ~]$ cat lpi104-6/subdir/file3sub
something
else
如果嘗試創建跨文件系統或針對目錄的硬鏈接,則會獲得錯誤。清單 2 顯示我的主目錄和 research 目錄在不同的文件系統上,而且跨這些文件系統創建硬鏈接的嘗試失敗了,與創建 lpi104-6 目錄的硬鏈接的嘗試一樣。
清單 2. 硬鏈接創建失敗
[ian@atticf22 ~]$ df . research
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 71168700 31642752 35887712 47% /
/dev/sdb3 60326992 30677592 26578276 54% /home/ian/research
[ian@atticf22 ~]$ mkdir -p research/lpi104-6/
[ian@atticf22 ~]$ ln lpi104-6/file1 research/lpi104-6/file3
ln: failed to create hard link ‘ research/lpi104-6/file3 ’ =>
‘ lpi104-6/file1 ’ : Invalid cross-device link
[ian@atticf22 ~]$ ln lpi104-6 lpidir104-6
ln: ‘ lpi104-6 ’ : hard link not allowed for directory
軟鏈接
使用 ln 命令和 -s 選項來創建軟鏈接。軟鏈接使用文件或目錄名稱,這些名稱可能是相對或絕對的。如果使用相對名稱,您可能希望當前工作目錄是您創建鏈接的目錄。否則,您創建的鏈接將是文件系統中的另一個位置相對的鏈接。
清單 3 展示了為我們剛創建的 file1 創建軟鏈接的兩種方式,以及如何創建軟鏈接,而不是創建在 清單 2中失敗的兩個硬鏈接。
清單 3. 創建軟鏈接
[ian@atticf22 ~]$ # Create symlink using absolute paths
[ian@atticf22 ~]$ ln -s ~/lpi104-6/file1 ~/lpi104-6/file4
[ian@atticf22 ~]$ # Create symlink using relative paths
[ian@atticf22 ~]$ cd lpi104-6/
[ian@atticf22 lpi104-6]$ ln -s file1 file5
[ian@atticf22 lpi104-6]$ cd ..
[ian@atticf22 ~]$ # Create symlink across file systems
[ian@atticf22 ~]$ mkdir -p ~ian/research/lpi104-6
[ian@atticf22 ~]$ ln -s ~/lpi104-6/file1 ~ian/research/lpi104-6/file4
[ian@atticf22 ~]$ # Create symlink for directory
[ian@atticf22 ~]$ ln -s lpi104-6 lpidir104-6
與之前一樣,您可以使用任何鏈接或目標文件名來引用該文件或目錄。清單 4 顯示了一些例子。
清單 4. 使用軟鏈接
[ian@atticf22 ~]$ echo "another line" >> ~ian/research/lpi104-6/file
[ian@atticf22 ~]$ # cat a symlink
[ian@atticf22 ~]$ cat lpi104-6/file5
something
else
[ian@atticf22 ~]$ # cat a hard link
[ian@atticf22 ~]$ cat lpi104-6/file1
something
else
[ian@atticf22 ~]$ # display directory contents using symlink
[ian@atticf22 ~]$ ls lpidir104-6
file1 file2 file3 file4 file5 subdir
在創建鏈接時,讓我們在工作目錄 不是我們想要存放鏈接的目錄時使用相對路徑創建一個鏈接。下一節將介紹如何實現此目的。
清單 5. 創建不良的軟鏈接
[ian@atticf22 ~]$ ln -s lpi104-6/file1 lpi104-6/file6
識別鏈接
在上一節中,您了解了如何創建鏈接,但不知道如何區分您創建的鏈接。現在讓我們討論一下這個主題。
查找信息
在許多系統上,ls 命令等同於 ls --color=auto ,它以不同顏色打印不同類型的文件系統對象。如果使用此選項,可能使用藍綠色文本來顯示 symlink,如 圖 1中所示。
圖 1. 使用 ls 的 --colors 選項來識別鏈接
在舊配置上,可能使用深藍色背景來顯示硬鏈接。這些顏色可使用 dircolors 程序來配置。如果要自定義您的終端外觀,您可能希望更改ls 的一些輸出的顏色。清單 6顯示了一種在 Fedora 22 系統上獲得硬鏈接的藍色背景的方式,而 圖 2 則顯示了結果。使用手冊頁進一步理解該示例。
清單 6. 使用 dircolors 為硬鏈接設置一種藍色背景
[ian@atticf22 ~]$ # Save a copy of dircolors defaults
[ian@atticf22 ~]$ dircolors -p > dircolors-defaults
[ian@atticf22 ~]$ grep MULTI dircolors-defaults
MULTIHARDLINK 00 # regular file with more than one link
[ian@atticf22 ~]$ # Change MULTIHARDLINK to blue background
[ian@atticf22 ~]$ sed -e'/MULTI/s/00/00;44/' dircolors-defaults > dircolors-new
[ian@atticf22 ~]$ grep MULTI dircolors-new
MULTIHARDLINK 00;44 # regular file with more than one link
[ian@atticf22 ~]$ # Set the new colors for the current terminal session
[ian@atticf22 ~]$ eval $(dircolors dircolors-new )
圖 2. 使用藍色背景來標識硬鏈接
對於能夠區分顏色的視力正常的人而言,顏色可能很方便,但它們對其他人沒多大用處,對 shell 腳本或程序肯定也沒多大用處。沒有顏色,就需要更多的信息,比如使用ls -l 通過一個長清單所提供的信息。在 清單 7中,我們為第一個示例顯式禁用了顏色輸出,但您也可以像我們對另外兩個示例所做的一樣顯式調用/bin/ls 命令。
清單 7. 識別鏈接
[ian@atticf22 ~]$ ls --color=none -lR lpi104-6
lpi104-6:
total 12
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file1
-rw-rw-r--. 1 ian ian 0 Aug 9 14:19 file2
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file3
lrwxrwxrwx. 1 ian ian 24 Aug 9 14:26 file4 -> /home/ian/lpi104-6/file1
lrwxrwxrwx. 1 ian ian 5 Aug 9 14:26 file5 -> file1
lrwxrwxrwx. 1 ian ian 14 Aug 9 14:34 file6 -> lpi104-6/file1
drwxrwxr-x. 2 ian ian 4096 Aug 9 14:19 subdir
lpi104-6/subdir:
total 4
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file3sub
[ian@atticf22 ~]$ /bin/ls -l ~ian/research/lpi104-6/file4
lrwxrwxrwx. 1 ian ian 24 Aug 9 14:27 /home/ian/research/lpi104-6/file4 -> /home/ian/lpi104-6/file1
[ian@atticf22 ~]$ /bin/ls -l lpidir104-6
lrwxrwxrwx. 1 ian ian 8 Aug 9 14:27 lpidir104-6 -> lpi104-6
輸出的第二列是一個鏈接計數,顯示了此文件的硬鏈接數,所以我們知道 file1、file3 和 file3sub 都擁有多個指向它們表示的對象的硬鏈接。我們仍沒有足夠的信息來知道它們都表示同一個對象。如果您刪除一個鏈接數大於 1 的文件,inode 中的鏈接數會減 1,但該文件只在鏈接數變為 0 時才會刪除。同一個文件的其他所有硬鏈接將顯示一個現在減去了 1 的鏈接數。
在輸出的第一列中,您會看到第一個字符是表示符號鏈接的 “l”(L 的小寫形式)。您還會看到在 -> 字符後顯示了鏈接的目標。例如,file4 -> /home/ian/lpi104-6/file1。另一個提示是,該大小是鏈接目標的名稱中的字符數。請注意,對於符號鏈接,目錄清單中的鏈接數沒有更新。刪除該鏈接不會影響目標文件。Symlink 不會阻止文件被刪除。如果目標文件被移動或刪除,那麼 symlink 將被破壞。出於這個原因,許多系統在目錄清單中使用了顏色,通常使用淡藍色表示正常鏈接,使用紅色表示被破壞的鏈接。
您可以使用 ls 命令的 -i 選項來顯示文件和目錄條目的 inode 數量。清單 8同時給出了我們的 lpi104-6 目錄的短和長輸出。
清單 8. 顯示 inode 信息
[ian@atticf22 ~]$ ls -i lpi104-6
1988884 file1 1988884 file3 1988892 file5 1988605 subdir
1988886 file2 1988885 file4 1988891 file6
[ian@atticf22 ~]$ ls -il lpi104-6
total 12
1988884 -rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file1
1988886 -rw-rw-r--. 1 ian ian 0 Aug 9 14:19 file2
1988884 -rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file3
1988885 lrwxrwxrwx. 1 ian ian 24 Aug 9 14:26 file4 -> /home/ian/lpi104-6/file1
1988892 lrwxrwxrwx. 1 ian ian 5 Aug 9 14:26 file5 -> file1
1988891 lrwxrwxrwx. 1 ian ian 14 Aug 9 14:34 file6 -> lpi104-6/file1
1988605 drwxrwxr-x. 2 ian ian 4096 Aug 9 14:19 subdir
您還可以使用 find 命令,使用 -type l 查找表達式來搜索符號鏈接,如 清單 9中所示。
清單 9. 使用 find 查找 symlink
[ian@atticf22 ~]$ find lpi104-6 research/lpi104-6 -type l
lpi104-6/file4
lpi104-6/file6
lpi104-6/file5
research/lpi104-6/file4
破壞的 symlink
在 清單 5 中,我們聲明要創建一個不良的軟鏈接。這是破壞的 symlink 的一個示例。因為硬鏈接始終指向一個表示文件的 inode,所以它們始終有效。但是,symlink 可能出於許多原因而遭到破壞,包括:
在創建鏈接時,鏈接的原始文件或目標不存在(就像 清單 5 中一樣)。鏈接的目標被刪除或重命名。目標的路徑中的某個元素被刪除或重命名。
所有這些條件都不會拋出錯誤,所以您需要仔細考慮您在創建 symlink 時可能發生了什麼情況。具體地講,對於絕對或相對路徑的選擇,可能受到您希望鏈接的對象在鏈接生存期中發生什麼的影響。
如果您使用顏色輸出,破壞的 symlink 可能在黑色背景上顯示為紅色文本,就像 圖 1 中的 file6 的情況一樣。否則,您需要使用 ls 的 -H 或 -L 選項來取消引用該鏈接,並提供有關目標的信息。-H 選項在命令行上取消引用鏈接,-L 選項取消引用顯示中包含的附加鏈接。清單 10演示了來自這兩個選項的輸出中的區別。
清單 10. 使用 ls -H 和 ls -L 取消引用鏈接
[ian@atticf22 ~]$ /bin/ls -lH lpidir104-6
total 12
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file1
-rw-rw-r--. 1 ian ian 0 Aug 9 14:19 file2
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file3
lrwxrwxrwx. 1 ian ian 24 Aug 9 14:26 file4 -> /home/ian/lpi104-6/file1
lrwxrwxrwx. 1 ian ian 5 Aug 9 14:26 file5 -> file1
lrwxrwxrwx. 1 ian ian 14 Aug 9 14:34 file6 -> lpi104-6/file1
drwxrwxr-x. 2 ian ian 4096 Aug 9 14:19 subdir
[ian@atticf22 ~]$ /bin/ls -lL lpidir104-6
/bin/ls: cannot access lpidir104-6/file6: No such file or directory
total 20
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file1
-rw-rw-r--. 1 ian ian 0 Aug 9 14:19 file2
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file3
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file4
-rw-rw-r--. 3 ian ian 15 Aug 9 14:19 file5
l?????????? ? ? ? ? ? file6
drwxrwxr-x. 2 ian ian 4096 Aug 9 14:19 subdir
請注意,錯誤消息表明 file6 不存在,另請注意針對它的包含所有 “?” 字符的輸出,它們同樣表明該文件不存在。
關於破壞的符號鏈接,還要說明最後一點。讀取該文件的嘗試將失敗,因為它不存在。但是,如果您擁有目標文件的合適權限,寫入它的嘗試將有效,如 清單 11中所示。請注意,我們需要在寫入該文件之前創建 lpi104-6/lpi104-6。
清單 11. 讀取和寫入一個破壞的 symlink
[ian@atticf22 ~]$ cat lpi104-6/file6
cat: lpi104-6/file6: No such file or directory
[ian@atticf22 ~]$ echo "Testing file6" > lpi104-6/file6
bash: lpi104-6/file6: No such file or directory
[ian@atticf22 ~]$ mkdir lpi104-6/lpi104-6
[ian@atticf22 ~]$ cat lpi104-6/file6
cat: lpi104-6/file6: No such file or directory
[ian@atticf22 ~]$ echo "Testing file6" > lpi104-6/file6
[ian@atticf22 ~]$ cat lpi104-6/file6
Testing file6
[ian@atticf22 ~]$ ls lpi104-6/lpi104-6
file1
[ian@atticf22 ~]$ ls -l lpi104-6/file6
lrwxrwxrwx. 1 ian ian 14 Aug 9 14:34 lpi104-6/file6 -> lpi104-6/file1
誰鏈接到我?
要確定哪些文件是一個特定 inode 的硬鏈接,可以使用 find 命令和 -samefile 選項及一個文件名,或者-inum 選項及一個 inode 編號,如 清單 12 中所示。
清單 12. 查找同一個文件的硬鏈接
[ian@atticf22 ~]$ find lpi104-6 -samefile lpi104-6/file1
lpi104-6/file1
lpi104-6/file3
lpi104-6/subdir/file3sub
[ian@atticf22 ~]$ ls -i lpi104-6/file1
1988884 lpi104-6/file1
[ian@atticf22 ~]$ find lpi104-6 -inum 1988884
lpi104-6/file1
lpi104-6/file3
lpi104-6/subdir/file3sub
要查找哪些文件通過符號鏈接而鏈接到一個特定文件,可以使用 find 命令和 -lname 選項及一個文件名,如 清單 13 所示。鏈接可以使用相對或絕對路徑,所以您可能希望在名稱中放入一個前導的星號來找到所有匹配結果。
清單 13. 查找一個文件或目錄的符號鏈接
[ian@atticf22 ~]$ find lpi104-6 research/lpi104-6 -lname "*file1"
lpi104-6/file4
lpi104-6/file6
lpi104-6/file5
research/lpi104-6/file4
復制還是鏈接
根據您想要完成的任務,有時會使用鏈接,有時復制一個文件可能會更好一些。主要區別在於,鏈接提供了一個文件的多個名稱,而副本會在兩個不同的名稱下創建兩組相同的數據。對於備份和測試用途,肯定會使用副本,您希望試驗一個新程序而不讓您的操作數據處於風險之中。在需要某個文件(或目錄)的別名時(可能用於提供更方面或更短的路徑),可以使用鏈接。在下一節中,我們將介紹鏈接的其他一些用法。
您已經看到,在更新一個文件時,它所有的鏈接都會看到更新信息,而復制文件不會這樣。您還看到,符號鏈接可以破壞,後續寫入操作可以創建新的文件。請小心使用鏈接。
鏈接和系統管理
鏈接(尤其是符號鏈接)通常用在 Linux 系統管理中。命令通常具有別名,所以用戶不需要知道當前命令的版本號,但在必要的時候,可以使用更長的名稱來訪問其他版本。如 清單 14所示,python 命令是python2 的 symlink,python2 本身是 2.7 版的 python2.7 的 symlink。
清單 14. 將命令別名化為一個特定版本
[ian@atticf22 ~]$ which python
/usr/bin/python
[ian@atticf22 ~]$ ls -l /usr/bin/python
lrwxrwxrwx. 1 root root 7 May 27 14:12 /usr/bin/python -> python2
[ian@atticf22 ~]$ ls -l /usr/bin/python2
lrwxrwxrwx. 1 root root 9 May 27 14:12 /usr/bin/python2 -> python2.7
[ian@atticf22 ~]$ ls -l /usr/bin/python2.7
-rwxr-xr-x. 1 root root 7120 May 27 14:12 /usr/bin/python2.7
在多個命令名稱使用相同的基礎代碼時,比如存儲和重新啟動系統的各種命令,其他用途就可以派上用場。有時,一個新命令名稱(比如 genisoimage )將取代舊命令名稱,但舊名稱 (mkisofs) 保持為新命令的鏈接。一些替代性 工具會廣泛使用鏈接,所以您可以在多個替代性工具中選擇一個來用於某條命令,比如java 。清單 15顯示了一些示例。
清單 15. 命令別名的示例
[ian@atticf22 ~]$ which halt
/usr/sbin/halt
[ian@atticf22 ~]$ ls -l /usr/sbin/halt
lrwxrwxrwx. 1 root root 16 Jun 9 09:16 /usr/sbin/halt -> ../bin/systemctl
[ian@atticf22 ~]$ find /usr/sbin /usr/bin -lname "*/systemctl"
/usr/sbin/halt
/usr/sbin/telinit
/usr/sbin/shutdown
/usr/sbin/runlevel
/usr/sbin/poweroff
/usr/sbin/reboot
[ian@atticf22 ~]$ which mkisofs
/usr/bin/mkisofs
[ian@atticf22 ~]$ ls -l /usr/bin/mkisofs
lrwxrwxrwx. 1 root root 25 Jun 15 08:02 /usr/bin/mkisofs -> /etc/alternatives/mkisofs
[ian@atticf22 ~]$ alternatives --display mkisofs
mkisofs - status is auto.
link currently points to /usr/bin/genisoimage
/usr/bin/genisoimage - priority 50
slave mkisofs-mkhybrid: /usr/bin/genisoimage
slave mkisofs-mkhybridman: /usr/share/man/man1/genisoimage.1.gz
slave mkisofs-mkisofsman: /usr/share/man/man1/genisoimage.1.gz
Current `best' version is /usr/bin/genisoimage.
庫名稱通常也使用 symlink 來管理,無論是允許程序在獲取當前版本時鏈接到一般名稱,還是管理系統,比如能夠運行 32 位程序的 64 位系統。清單 16顯示了一些示例。請注意,一些情況會使用絕對路徑,而另一些情況會使用相對路徑。
清單 16. 庫鏈接
[ian@atticf22 ~]$ ls -l /usr/lib*/libm.so*
lrwxrwxrwx. 1 root root 21 Feb 23 10:31 /usr/lib64/libm.so -> ../../lib64/libm.so.6
lrwxrwxrwx. 1 root root 12 Feb 23 10:33 /usr/lib64/libm.so.6 -> libm-2.21.so
lrwxrwxrwx. 1 root root 12 Feb 23 10:35 /usr/lib/libm.so.6 -> libm-2.21.so
[ian@atticf22 ~]$ find /usr/lib/ /usr/lib64/ -lname "*libstdc++*"
/usr/lib/gcc/x86_64-redhat-linux/5.1.1/libstdc++.so
/usr/lib/gcc/x86_64-redhat-linux/5.1.1/32/libstdc++.so
/usr/lib/gcc/x86_64-redhat-linux/5.1.1/32/libstdc++.a
/usr/lib64/libstdc++.so.6
[ian@atticf22 ~]$ ls -l /usr/lib64/libstdc++.so.6
lrwxrwxrwx. 1 root root 19 Jun 18 06:52 /usr/lib64/libstdc++.so.6 -> libstdc++.so.6.0.21
[ian@atticf22 ~]$ ls -l /usr/lib64/libwbclient*
lrwxrwxrwx. 1 root root 19 Jul 1 10:37 /usr/lib64/libwbclient.so.0 -> libwbclient.so.0.12
lrwxrwxrwx. 1 root root 40 Jul 1 10:37 /usr/lib64/libwbclient.so.0.12 ->
/etc/alternatives/libwbclient.so.0.12-64
累死了,大概這些就夠了吧,有興趣的可以多去了解了解!Linux是很有魅力的!