對於 Linux 新手,或者那些想要重新審視或改進自己對基本 Linux 概念(比如:復制和移動文件、創建符號和硬鏈接、設置文件系統對象所有權和權限以及同管道和重定向一起使用 Linux 的標准文本處理命令)的理解的人來說,本系列連載文章之一是理想的教材。沿著這個方向,我們將一起分享很多心得、技巧和竅門,使該教程甚至對於那些具有豐富經驗的 Linux 老手來說都是“有血有肉”,並且是實用的。
對於初學者而言,本系列文章的許多內容都很新穎,而更有經驗的 Linux 用戶可能會發現本教程是使他們基本的 Linux 技能“爐火純青”的有效途徑。
介紹 bash
shell
如果您使用過 Linux 系統,那麼您知道當登錄時,將會看到像這樣的提示符:
$
$ echo $SHELL/bin/bash
如果上面的命令行報錯或者不會類似地響應我們的示例,那麼您可能正在運行一個不同於 bash 的 shell。
關於 bash
Bash 是“Bourne-again shell”的首字母縮寫,它是大多數 Linux 系統缺省的 shell。shell 的任務是執行您的命令,使您能夠與 Linux 系統進行交互。當您輸完命令,您可以通知 shell 執行 exit 或 logout 命令,在此您將返回到登錄提示符。順便提一下,您還可以通過在 bash 提示符下按 control-D 來注銷。
使用“cd”
您可能已經發現,目不轉睛地盯著bash提示符可不是世界上最讓人感到有勁的事。那麼,讓我們來開始用 bash 來浏覽我們的文件系統。在提示符下,輸入下面的命令(不包括 $):
$ cd /
我們只告訴 bash 您想在 /(也稱為根目錄)中工作;系統上的所有目錄形成一棵樹,/ 被認為是這棵樹的頂部,或者是根。cd設置當前您正在工作的目錄,也稱為“當前工作目錄”。
路徑
要看 bash 的當前工作目錄,您可以輸入:
$ pwd /
在上面的示例中,cd 的 / 參數叫做路徑。它告訴 cd 我們要轉到什麼地方。特別是,/ 參數是一個絕對路徑,意味著它指定了相對於文件系統樹的根的位置。絕對路徑這裡有幾個其它的絕對路徑:
/dev /usr /usr/bin /usr/local/bin
您可以看到,所有絕對路徑有一個共同點就是,它們都以/開頭。通過路徑/usr/local/bin,我們告訴 cd 進入 / 目錄,接著進入這個目錄之下的usr目錄,然後再進入 local 和 bin。絕對路徑總是通過是否以 / 開頭來判斷。
相對路徑
另一種路徑叫相對路徑。在 Bash 中,cd 以及其它命令總是解釋那些相對於當前目錄的路徑。相對路徑絕不會以 / 開頭。這樣,如果我們在 /usr 中:
$ cd /usr
那麼,我們可以使用相對路徑來轉到 /usr/local/bin 目錄:
$ cd local/bin $ pwd /usr/local/bin
使用“..”
相對路徑還可以包含一個或多個 .. 目錄。.. 目錄是指向父目錄的專門目錄。那麼,繼續前面的示例:
$ pwd /usr/local/bin $ cd .. $ pwd /usr/local
您可以看到,現在我們的當前目錄是 /usr/local。我們能夠“後退”到相對於我們所在的當前目錄的一個目錄。此外,我們還可以將 \\\\\"..\\\\\\" 添加到一個現有的相對路徑中,使我們可以進入與我們已在目錄並排的目錄,例如:
$ pwd /usr/local $ cd ../share $ pwd /usr/share
相對路徑示例
相對路徑可以變得相當復雜。這裡有幾個示例,所有的都沒有顯示出結果的目標路徑。請試著推斷一下,輸入這些命令後,您最終將會轉到什麼地方:
$ cd /bin $ cd ../usr/share/zoneinfo$ cd /usr/X11R6/bin $ cd ../lib/X11$ cd /usr/bin $ cd ../bin/../bin
現在,試驗一次,看看您的推斷是否正確。
理解“.”
在我們結束 cd 的介紹之前,我們還需要討論一些更多的內容。首先,還有另一個叫 . 的專門的目錄。它表示“當前目錄”。然而該目錄不為 cd 命令使用,它通常用來執行一些當前目錄中的程序,如下所示:
$ ./myprog
在上面的示例中,駐留在當前工作目錄中的 myprog 可執行文件將被執行。
cd 和主目錄
如果我們想要轉到主目錄,我們可以輸入:
$ cd
沒有參數,cd 將轉到主目錄,對於超級用戶來說是 /root,對於一般用戶來說通常是
/home/username。但是,如果我們想要指定一個主目錄中的文件,將會怎樣呢?可能我們想要將一個文件參數傳給 myprog 命令。如果該文件在主目錄中,我們可以輸入:
$ ./myprog /home/drobbins/myfile.txt
但是,使用像這樣的絕對路徑並不總是很方便。幸好,我們可以使用 ~(代字符)字符來完成同樣的事:
$ ./myprog ~/myfile.txt
其他用戶的主目錄Bash 將把單獨的 ~ 擴展為指向主目錄,然而您還可以用它來指向其他用戶的主目錄。例如,如果我們想要引用 fred 的主目錄中的名為 fredsfile.txt 的文件,可以輸入:
$ ./myprog ~fred/fredsfile.txt
$ ls -i /usr1409 X11R6 314258 i686-linux 43090 libexec 13394 sbin1417 bin 1513 i686-pc-linux-gnu 5120 local 13408 share8316 distfiles 1517 include 776 man 23779 src43 doc 1386 info 93892 portage 36737 ssl70744 gentoo-x86 1585 lib 5132 portage.old 784 tmp
理解索引節點,第 1 部分
文件系統的每個對象都分配到一個獨一無二的索引,叫做索引節點號。這可能看起來微不足道,但是理解索引節點對於理解許多文件系統操作來說很重要。例如,請考慮出現在每個目錄中的 . 和 .. 鏈接。為了完全理解 .. 目錄實際上是什麼,我們將先來看一看 /usr/local 的索引節點號:
$ ls -id /usr/local5120 /usr/local/usr/local
目錄有一個 5120 索引節點號。現在,我們來看一 看 /usr/local/bin/.. 的索引節點號:
$ ls -id /usr/local/bin/..5120 /usr/local/bin/..
您可以看到,/usr/local/bin/..具有和/usr/local相同的索引節點號!這就是我們抓住的問題的實質。過去,我們認為 /usr/local 是這個目錄本身。
現在,我們發現索引節點 5120實際上是這個目錄,並且我們發現了指向該索引節點的兩個目錄條目(叫做“鏈接”)。/usr/local 和 /usr/local/bin/..都鏈接到索引節點 5120。雖然索引節點 5120 只在磁盤中的一地方存在,但是多個目錄條目都鏈接到它上面。事實上,通過使用 ls -dl 命令,我們可以看到索引節點 5120 被引用的總次數
$ ls -dl /usr/localdrwxr-xr-x 8 root root 240 Dec 22 20:57 /usr/local
如果我們看一看從左起的第二欄,我們可以看到目錄 /usr/local(索引節點 5120)被引用了 8 次。在我的系統中,引用該索引節點的不同路徑有這些:
/usr/local/usr/local/./usr/local/bin/../usr/local/games/../usr/local/lib/../usr/local/sbin/../usr/local/share/../usr/local/src/..
使用 Linux 命令
mkdir
我們來快速地看一看 mkdir 命令,它可以用來創建新目錄。下面的示例創建了三個新目錄:tic、tac 和 toe,都在 /tmp 下:
$ cd /tmp$ mkdir tic tac toe
缺省情況下,mkdir 不會為您創建父目錄;鄰接的上一元素的完整路徑必須存在。因此,如果您想要創建目錄 won/der/ful,您將需要發出三個單獨的 mkdir 命令:
$ mkdir won/der/fulmkdir: cannot create directory`won/der/ful': No such file or directory$ mkdir won$ mkdir won/der$ mkdir won/der/ful
mkdir -p
然而,mkdir有一個很方便的-p選項,該選項告訴mkdir創建所有缺少的父目錄,如下所示:
$ mkdir -p easy/as/pie
總之,非常簡單。要學習更多關於 mkdir 命令的知識,請輸入 man mkdir 來閱讀手冊頁。除 cd(它內置在 bash 中)之外,這幾乎適用於這裡所涉及的所有命令(比如 man ls)。
touch
現在,我們將要快速地看一看 cp 和 mv 命令,這些命令用來復制、重命名以及移動文件和目錄。為了開始該概述,我們將首先用 touch 命令在 /tmp 中創建一個文件:
$ cd /tmp$ touch copyme
如果文件存在,touch 命令將更新文件的“mtime”(請回想 ls -l 輸出中的第六欄)。如果文件不存在,那麼將創建一個新的空文件。現在您應該有一個大小為零的 /tmp/copyme 文件。
echo 和重定向
既然文件存在,我們來把一些數據添加到文件中。我們可以使用echo命令來完成,它帶有自己參數,並且把這些參數打印到標准輸出。首先,單獨的 echo 命令是這樣的:
$ echo \"firstfile\"firstfile
帶有輸出重定向的同樣的 echo 命令為:
$ echo \"firstfile\" > copyme
大於符號告訴 shell 將 echo 的輸出寫到名為 copyme 的文件中。如果該文件不存在,將創建這個文件;如果該文件存在,將覆蓋這個文件。通過輸入 ls -l,我們可以看到 copyme 文件為 10 個字節長,因為它包括 firstfile 這個詞和換行符:
$ ls -l copyme-rw-r--r-- 1 root root 10 Dec 28 14:13 copyme
cat 和 cp
為了在終端顯示文件的內容,要使用 cat 命令:
$ cat copymefirstfile
現在,我們可以使用 cp 命令的基本調用來由原始的 copyme 文件創建 copiedme 文件:
$ cp copyme copiedme
通過觀察,我們發現它們確實是相互獨立的文件;它們的索引節點號不同:
$ ls -i copyme copiedme648284 copiedme 650704 copyme
mv
現在,我們來用“mv”命令將“copiedme”重命名為“movedme”。其索引節點號將仍然是同一個;但是,指向該索引節點的文件名將改變。
$ mv copiedme movedme$ ls -i movedme648284 movedme
只要目標文件和源文件駐留在同一文件系統上,被移動的文件的索引節點號就將仍然不變。在本教程系列的第 3 部分,我們將進一步看一下文件系統。
創建鏈接和刪除文件
硬鏈接
當談及目錄條目和索引節點之間關系時,我們提到了鏈接這個術語。Linux 實際有兩種鏈接。到此為止我們所討論的這種鏈接叫硬鏈接。一個給定的索引節點可以有任意數目的硬鏈接,該索引節點一直存在於文件系統,直到所有的硬鏈接消失。可以使用 ln 命令來創建新的硬鏈接
$ cd /tmp$ touch firstlink$ ln firstlink secondlink$ ls -i firstlink secondlink15782 firstlink 15782 secondlink
您可以看到,硬鏈接工作於索引節點級別,指向特殊的文件。在 Linux 系統上,硬鏈接有幾個局限性。第一,您只能給文件建立硬鏈接,而不能給目錄建立硬鏈接。的確如此;即便 . 和 .. 是系統給目錄創建的硬鏈接,也不允許您(“root”用戶也不行)創建任何您自己的硬鏈接。
硬鏈接的第二個局限性是它們不能跨文件系統。這意味著,如果您的 / 和 /usr 存在於不同的文件系統,您不能創建從 /usr/bin/bash 到 /bin/bash 的鏈接。
符號鏈接
實際上,符號鏈接(symbolic link,或“symlinks”)比硬鏈接更常用到。符號鏈接是一種專門的文件類型,在這種文件類型中,鏈接通過名稱引用另一個文件,而不是直接引用索引節點。符號鏈接不阻止文件被刪除;如果目標文件消失,那麼符號鏈接僅僅是不可用,或“被破壞”。
通過將 -s 選項傳給 ln,可以創建符號鏈接。
$ ln -s secondlink thirdlink$ ls -l firstlink secondlink thirdlink-rw-rw-r-- 2 agriffis agriffis 0 Dec 31 19:08 firstlink-rw-rw-r-- 2 agriffis agriffis 0 Dec 31 19:08 secondlinklrwxrwxrwx 1 agriffis agriffis 10 Dec 31 19:39 thirdlink -> secondlink
在 ls -l 輸出中,可以用三種方式區分符號鏈接和一般文件。第一,請注意第一欄包含一個 l 字符的輸出表明是符號鏈接。第二,符號鏈接的大小是目標文件(本例是 secondlink)的字符數。第三,輸出的最後一欄顯示目標文件名。
符號鏈接通常比硬鏈接更靈活。您可以給任何類型的文件系統對象(包括目錄)創建符號鏈接。又因為符號鏈接的實現是基於路徑的(而不是索引節點),所以創建指向另一個文件系統上的對象的符號鏈接是完全可行的。但是,這一事實也使符號鏈接理解起來很復雜。請考慮我們想要在/tmp中創建一個指向/usr/local/bin的鏈接的情況。我們應該輸入:
$ ln -s /usr/local/bin bin1$ ls -l bin1lrwxrwxrwx 1 root root 14 Jan 1 15:42 bin1 -> /usr/local/bin
或者還可以輸入:
$ ln -s ../usr/local/bin bin2$ ls -l bin2lrwxrwxrwx 1 root root 16 Jan 1 15:43 bin2 -> ../usr/local/bin
您可以看到,兩個符號鏈接都指向同一目錄。但是,如果我們的第二個符號鏈接在任何時刻被移動到另一個目錄,由於相對路徑的緣故,它將遭到“破壞”。
$ ls -l bin2lrwxrwxrwx 1 root root 16 Jan 1 15:43 bin2 -> ../usr/local/bin$ mkdir mynewdir$ mv bin2 mynewdir$ cd mynewdir$ cd bin2bash: cd: bin2: No such file or directory
因為/tmp/usr/local/bin這個目錄不存在,我們不能再把目錄轉到bin2;換句話說,bin2 現在被破壞了。
由於這個原因,有時避免用相對路徑信息來創建符號鏈接是個好主意。但是,在許多情況下,相對的符號鏈接很管用。請考慮一個示例,在這個示例中您想要給 /usr/bin 中的一個程序創建一個別名:
# ls -l /usr/bin/keychain -rwxr-xr-x 1 root root 10150 Dec 12 20:09 /usr/bin/keychain
作為 root 用戶,您可能想要給“keychain”創建一個別名,比如“kc”。在這個示例中,我們有 root 訪問權,由 bash 提示符改變為“#”可以證明。我們之所以需要 root 訪問權是因為一般用戶不能在 /usr/bin 中創建文件。作為 root 用戶,我們可以像下面這樣給 keychain 創建一個別名:
# cd /usr/bin# ln -s /usr/bin/keychain kc
當這個解決方法起作用時,如果我們想要把兩個文件都移到 /usr/local/bin 時,它將會出現問題。
# mv /usr/bin/keychain /usr/bin/kc /usr/local/bin
因為在符號鏈接中,我們使用了絕對路徑,而我們的kc符號鏈接仍然指向/usr/bin/keychain,它已不存在了——另一個被破壞的符號鏈接。符號鏈接中的相對路徑和絕對路徑都各具優點,您應該使用適合於您的特殊應用的路徑類型。一般情況下,相對路徑或絕對路徑都能工作得很好。在這種情況下,下面的示例將起作用:
# cd /usr/bin# ln -s keychain kc# ls -l kclrwxrwxrwx 1 root root 8 Jan 5 12:40 kc -> keychain
$ cd /tmp$ touch file1 file2$ ls -l file1 file2-rw-r--r-- 1 root root 0 Jan 1 16:41 file1-rw-r--r-- 1 root root 0 Jan 1 16:41 file2$ rm file1 file2$ ls -l file1 file2ls: file1: No such file or directoryls: file2: No such file or directory
$ mkdir mydir$ touch mydir/file1$ rm mydir/file1$ rmdir mydir
$ rm -rf mydir
$ rm file[1-8]
$ rm file*
$ ls -d /etc/g*/etc/gconf /etc/ggi /etc/gimp /etc/gnome/etc/gnome-vfs-mime-magic /etc/gpm/etc/group /etc/group-
$ ls -d /usr/bin/asdf*jklls: /usr/bin/asdf*jkl: No such file or directory