對話 UNIX,第 11 部分: 漫談 UNIX 文件系統(tǒng)
剛剛購買了一個(gè)全球定位系統(tǒng)(GPS)導(dǎo)航設(shè)備,僅僅使用了幾次之后,我就迷上了它。從點(diǎn) A 到點(diǎn) B,現(xiàn)在是輕而易舉的事情。不再需要到 MapQuest 網(wǎng)站上去查詢地圖了。不再需要猜測哪邊是東。不再需要在遠(yuǎn)離城市的農(nóng)村地區(qū)中途停車以詢問方向。我只需要跳進(jìn)我的車,指定我的目的地,并遵循語音提示即可。為什么呢?GPS 使我看起來就像一個(gè)本地居民,它為 Buckaroo Banzai 的格言“無論您去哪里,您就在那里賦予了新的含義。
本月,讓我們縱情滿足自己的旅行愛好,并且漫談 Unix® 文件系統(tǒng)。從 /bin 到 /var,有許多有趣的景點(diǎn)值得一看(一些經(jīng)常有人走過,還有一些則很隱秘),并且很快您將會像當(dāng)?shù)鼐用褚粯邮煜ぶ車沫h(huán)境了。
文件名稱的含義
UNIX 計(jì)算機(jī)上的文件采用層次結(jié)構(gòu)進(jìn)行組織。這個(gè)層次結(jié)構(gòu)的最高層是 /,一般稱其為“斜線或者“根目錄。
如果您將工作目錄更改為 /,并運(yùn)行 ls,那么您將看見幾個(gè)具有神秘名稱的子目錄(如 etc、bin、var、home 和 tmp)。盡管 UNIX 現(xiàn)在支持長文件名,但是這些頂層目錄名字中的大多數(shù)可以追溯到大約 30 年前,即 UNIX 剛剛出現(xiàn)的時(shí)候。類似地,根據(jù)同樣長期存在的約定,包含在 / 中的每個(gè)目錄都用于某個(gè)特殊的目的:
/bin 僅僅是包含應(yīng)用程序和實(shí)用工具的許多目錄中的一個(gè)。然而,/bin 通常包含那些對于系統(tǒng)操作而言基本的實(shí)用工具。因此,Shell 文件操作命令如 cp 和 chmod、壓縮和解壓縮,以及診斷命令都位于 /bin 中。
/sbin 同樣包含那些對于系統(tǒng)操作和維護(hù)而言至關(guān)重要的實(shí)用工具。然而,只有超級用戶才能夠執(zhí)行 /sbin 中的程序,因此這個(gè)目錄稱為“superuser-bin或者 /sbin。
/dev 包含您的系統(tǒng)中所安裝的所有硬件,包括終端和 USB 設(shè)備(以及從物理上連接到這臺計(jì)算機(jī)的其他外圍設(shè)備)、偽終端(用于與 X 終端窗口進(jìn)行交互),以及硬盤驅(qū)動(dòng)器,等等。
/etc(常常發(fā)音為“etsee)專門用于系統(tǒng)配置。/etc 目錄包含用于系統(tǒng)守護(hù)進(jìn)程、啟動(dòng)腳本、系統(tǒng)參數(shù)和更多其他方面的配置文件。
/home 包含用戶的 home 目錄。例如,如果您的登錄名是 joe,那么目錄 /home/joe 就是您的個(gè)人文件存儲庫。
/lib 用于存儲基本的系統(tǒng)庫文件。在現(xiàn)代 Unix 中,通常共享系統(tǒng)庫,這意味著并不是每個(gè)二進(jìn)制文件都鏈接和包括這些庫(那樣的話,至少將會浪費(fèi)空間),但是當(dāng)需要該庫的時(shí)候,按需要加載它,并且同時(shí)可以由許多應(yīng)用程序進(jìn)行共享。因此,與 UNIX 一同安裝的核心應(yīng)用程序和實(shí)用工具的運(yùn)行都需要使用 /lib 中的庫,并且您至少需要擁有少量相應(yīng)的庫文件,以便從源代碼創(chuàng)建新的可執(zhí)行文件。其中所有的文件都是至關(guān)重要的,損壞或者刪除(無論是有意的還是無意的)某個(gè)文件就可能使系統(tǒng)變得無法使用。
/mnt 是“mount的縮寫,是裝入硬盤驅(qū)動(dòng)器分區(qū)和其他設(shè)備的標(biāo)準(zhǔn)位置。如果您希望查看當(dāng)前裝入的并且可訪問的所有設(shè)備,只需要運(yùn)行 mount 命令。
/tmp 或者“temporary,是系統(tǒng)范圍的暫存存儲區(qū)。您的 Web 服務(wù)器可能會將會話數(shù)據(jù)文件保存在這里,并且其他實(shí)用工具將使用 /tmp 中的空間對中間結(jié)果進(jìn)行緩存。通常認(rèn)為 /tmp 中的文件在使用后即被丟棄。實(shí)際上,您的系統(tǒng)管理員可能會在每天晚上刪除其中比某個(gè)過期時(shí)間更早的所有文件。
/usr 用于存儲大量文件。最終用戶應(yīng)用程序(從編輯器、游戲和接口,到系統(tǒng)特性)都位于其中,它是 man 頁面和其他更多內(nèi)容的存儲庫。有些文件很有價(jià)值,但并不是系統(tǒng)操作所必須的,那么您很可能會在 /usr 中找到它。
/var 是“variable的簡寫,它是用于存儲那些大小通常隨時(shí)間而增大的文件的存儲庫。可以在 /var 中找到郵箱、日志文件、打印機(jī)隊(duì)列和數(shù)據(jù)庫。通常可以將 Web 站點(diǎn)保存在 /var 中,因?yàn)?Web 站點(diǎn)可能會在一段時(shí)間后異常地累積大量的數(shù)據(jù)。
以上是一些最常見的目錄名,盡管某些 Unix 版本之間存在細(xì)微的差異。(例如,在基于 FreeBSD® 的 Mac OS X 上,將包含用戶的 home 目錄的目錄命名為 /Users,而不是 /home。)
保持傳統(tǒng)
事實(shí)上,名稱 etc、bin、lib 和 man 在 UNIX 的文化中是如此根深蒂固,以至于在計(jì)算機(jī)中的其他地方使用相同的名稱來標(biāo)注類似用途的目錄已經(jīng)成為一種傳統(tǒng)。例如,如果您查看一位專家的 home 目錄,您很可能會在其中發(fā)現(xiàn) bin 和 lib 目錄分別存儲個(gè)人應(yīng)用程序以及腳本和個(gè)人庫。
同樣地,/usr/local 中通常包括 etc、bin、lib、和 man。在歷史上,曾將 /usr/local 用于存儲來自于您的站點(diǎn)或者僅與您的站點(diǎn)有密切關(guān)系的應(yīng)用程序和數(shù)據(jù)。/usr/local/bin 目錄用于存儲本地添加的、新的程序,以及標(biāo)準(zhǔn)系統(tǒng)實(shí)用工具的本地修改版本。例如,您的系統(tǒng)管理員可能在 /usr/local/bin/perl 中提供了 Perl 的最新和最好的版本,同時(shí)保持 /usr/bin/perl 不變,以便進(jìn)行引用,并且因?yàn)槠渌暮诵膶?shí)用工具可能仍然依賴于它。/usr/local/lib 目錄作為 /usr/local/bin 的補(bǔ)充。
/usr/local 目錄甚至可能是一個(gè)完全獨(dú)立的分區(qū)(甚至是通過網(wǎng)絡(luò)文件系統(tǒng)從 Network Attached Storage [NAS] 設(shè)備裝入的分區(qū)),這使得可以更容易地對系統(tǒng)進(jìn)行數(shù)據(jù)恢復(fù)和恢復(fù)使用。如果系統(tǒng)中發(fā)生了某種情況,管理員可以覆蓋操作系統(tǒng)的文件,而無需擔(dān)心會破壞本地?cái)?shù)據(jù)。
甚至安裝包也是用了類似的目錄結(jié)構(gòu)。例如 MySQL:如果使用了選項(xiàng) --prefix=/usr/local/mysql, 進(jìn)行配置,那么它將在 /usr/local 中創(chuàng)建它自己的根目錄,名為 /usr/local/mysql,并創(chuàng)建子目錄 /usr/local/mysql/bin、/usr/local/mysql/lib 等等:
$ ls -1 /usr/local/mysqlbin/configure*data/docs/include/lib/man/...
或者,如果您希望將 MySQL 的內(nèi)容安裝到 /usr/local/bin、/usr/local/lib 和其他地方,可以使用 --prefix=/usr/local。
其他有趣的內(nèi)容
因?yàn)楸疚闹皇呛喴亟榻B,所以讓我們再安排一些其他有趣的內(nèi)容。
/etc
/etc 目錄是尋找配置文件的地方,這些配置文件通常以后綴 .conf 作為結(jié)束。一個(gè)較大的包可能擁有它自己的子目錄,以便收集用于這個(gè)包的所有配置文件。Apache 是一個(gè)很好的例子;特別是,Apache V2.2 已經(jīng)重新組織了它的配置文件,使其更具模塊化,并具有更少的獨(dú)立性。
另一個(gè)新穎的內(nèi)容是 /etc/init.d,其中包含當(dāng)您的系統(tǒng)啟動(dòng)時(shí)運(yùn)行的許多啟動(dòng)腳本。如果您希望干凈地重新啟動(dòng)一個(gè)守護(hù)進(jìn)程,例如,在更改它的配置之后,可以在 /etc/init.d 中查找同名的腳本。例如,要重新啟動(dòng) Postfix 郵件傳送代理(MTA),您可以運(yùn)行:
$ /etc/init.d/postfix restart
/etc/init.d 還包含切換到單用戶模式的腳本,以便重新啟動(dòng)并關(guān)閉計(jì)算機(jī),并禁止登錄。
/var/spool
如前所述,/var 保存了那些大小可能隨時(shí)間增大和縮小的文件。與 / 一樣,可以將 /var 劃分為若干個(gè)子目錄,每個(gè)子目錄都有其自身的方案:
/var/spool/mail 是尋找您和其他用戶的傳入郵件的地方。您的郵箱是一個(gè)簡單的平面(連續(xù)的、非索引的)文件(除非您的系統(tǒng)管理員正在使用 maildir 格式)。傳入郵件追加到文件的尾部。您所丟棄的郵件將從該文件中刪除;并且當(dāng)您讀取一條新的消息時(shí),將會更改并重寫已有的消息狀態(tài)字段。您可以讀寫您自己的郵箱,但是可以通過權(quán)限防止您訪問其他用戶的郵箱。(建議您不要直接編輯您的郵箱。)
/var/log 保存了一套系統(tǒng)日志文件,或者記錄系統(tǒng)活動(dòng)的文件。這些日志記錄了所有的活動(dòng),從郵件通信到失敗的登錄嘗試。通常,每個(gè)守護(hù)進(jìn)程都擁有自己的日志文件,這使得當(dāng)一個(gè)服務(wù)失敗時(shí)很容易搜尋所發(fā)生的問題。因?yàn)榭梢燥@示系統(tǒng)活動(dòng),所以對日志文件的訪問通常會受到限制,只有超級用戶才可以訪問。
如果您的系統(tǒng)提供了集中的傳真服務(wù),那么 /var/spool 還將對這些請求進(jìn)行排隊(duì)。
/usr/man
用于您的 Unix 系統(tǒng)的核心 man 頁面位于 /usr/man 中。還可以在 /usr/local/man 和包的 man 目錄(如 /usr/local/mysql5/man)中找到 man 頁面的擴(kuò)展集合。
因?yàn)?man 頁面可能像可執(zhí)行文件那樣存放于許多不同的地方,所以 man 程序支持與 PATH 工作方式相同的環(huán)境變量 MANPATH。要在多個(gè)位置搜索一個(gè)特定的頁面,可以將 MANPATH 定義為一系列 man 頁面目錄:
MANPATH="/usr/man"MANPATH="/usr/local/man:$MANPATH"MANPATH="/usr/local/mysql/man:$MANPATHMANPATH="$HOME/man:$MANPATH"export MANPATH
在該示例中,首先 搜索 $HOME/man(它在最左邊,或者最前面),隨后是 /usr/local/mysql/man,依此類推。順便說一下,可以將上面的前四個(gè)命令簡化為下面的語句:
MANPATH="/usr/man:/usr/local/man:/usr/local/mysql/man:$HOME/man"
然而,將附加的目錄隔離開來,將允許您快速地對條目進(jìn)行重新排序,并輕松地添加新的目錄。而且,如果存在許多路徑,編輯后面的 MANPATH(通過擴(kuò)展 PATH)變量將變得使人乏味。
包含文件
包含文件(或者頭文件)定義了在操作系統(tǒng)中或特定的庫中使用的常量、宏以及其他結(jié)構(gòu)。不需要重新定義一個(gè)特定的結(jié)構(gòu),您只需要將頭文件“包含在您的代碼(代碼重用的一種簡單形式)中,并按照頭文件中的規(guī)范編寫代碼。(man 中的第 2 部分和第 3 部分就專門用于這樣的規(guī)范;例如,可以嘗試 man 2 signal。)
與 bin 和 lib 類似,include 是一個(gè)常見的目錄名。如果一個(gè)包提供了開發(fā)工具包,并且您已經(jīng)將這個(gè)包安裝到了它自己的根目錄,那么可以在 include 子目錄中找到相應(yīng)的頭文件。
或者,如果您已經(jīng)將包安裝到了公共的 /usr/local/{bin、lib、include} 目錄中,那么可以在 /usr/local/include 中根據(jù)這個(gè)包進(jìn)行命名的子目錄中找到包的頭文件。這是將所有的內(nèi)容保存到一個(gè)公共地方的例外情況。為什么呢?頭文件的命名不是唯一的,所以將所有的內(nèi)容安裝到一個(gè)地方將會導(dǎo)致沖突,一個(gè)包有可能覆蓋另一個(gè)包的頭文件。
如果您從源代碼構(gòu)建應(yīng)用程序(您將在后面的部分中對其進(jìn)行深入研究),并且頭文件位于一個(gè)非標(biāo)準(zhǔn)的位置,那么您可能需要在編譯器命令中添加 -I 選項(xiàng)。作為一個(gè)示例,如果您的 ImageMagick 頭文件位于 /opt/include/magick 中,添加 -I/opt/include/magick 作為編譯器的開關(guān)。
非常深入地了解它
即將結(jié)束今天的 Unix 旅行。現(xiàn)在,您可以更容易地穿越 UNIX 的小路和背街了。如果您迷路了,只需要說“家,家,家(不要被 獵戶星座 所欺騙)或者輸入 cd 即可。請記住,您還可以使用 find 和 locate 來查找大多數(shù)文件,包括可執(zhí)行文件、庫和包含文件。
下午好,女士們、先生們。下次旅行將在 30 天后啟程。
附錄 A:選擇一個(gè)標(biāo)準(zhǔn),任何標(biāo)準(zhǔn)
您的 UNIX 操作系統(tǒng)附帶的軟件位于文件系統(tǒng)中適當(dāng)?shù)奈恢茫赡艽鎯υ?/bin 或者 /lib 中的),而本地添加的軟件則可能位于許多不同的位置。某些系統(tǒng)管理員將本地軟件放在 /usr/local 中,而其他的系統(tǒng)管理員則使用 /opt 或者“optional,因?yàn)檫\(yùn)行系統(tǒng)并不需要該軟件。而且,某些管理員會轉(zhuǎn)儲 /usr/local/bin 或 /opt/bin 中所有的可執(zhí)行文件、/usr/local/lib 或 /opt/lib 中所有的庫,等等。
另一種方法(這是我更喜歡的范例)是為每一個(gè)本地添加的包創(chuàng)建一個(gè)根目錄,特別是在這個(gè)包很大的情況下。例如,我將 MySQL V5 安裝到 /usr/local/mysql5.0,將 Apache V2.2 安裝到 /usr/local/apache2.2。每個(gè)包的安裝程序都會在包的根目錄中創(chuàng)建它自己的 bin、lib 和 man 目錄。
這種方法有一個(gè)缺點(diǎn),每個(gè)最終用戶必須向他或她的 PATH 環(huán)境變量中添加許多 bin 目錄。并且當(dāng)這一需求并不是特別復(fù)雜時(shí),通過在系統(tǒng)范圍的 Shell 啟動(dòng)文件中擴(kuò)展缺省的 PATH 設(shè)置,就可以解決這個(gè)問題。例如,Bash 系統(tǒng)范圍啟動(dòng)腳本 /etc/profile,可能包含:
PATH="/bin:/usr/bin:/usr/local/bin"PATH="$PATH:/usr/local/mysql5.0/bin"PATH="$PATH:/usr/local/perl6/bin"PATH="$PATH:/usr/local/Zend/bin"export PATH
然而,將一個(gè)包存儲在它自己的“容器中,這是很有好處的:
哪個(gè)包提供了特定的應(yīng)用程序,這是顯而易見的。遵循這一分類系統(tǒng),您可以使用 which 命令找到包的名字:$ which mysql/usr/local/mysql5.0/bin/mysql
您可以同時(shí)保留同一個(gè)包的不同版本。
例如,如果您希望提供 Perl V5.6 和 Perl V5.8,可以將前者安裝到 /usr/local/perl5.6,將后者安裝到 /usr/local/perl5.8。每個(gè)用戶都可以通過改變 PATH 變量,來選擇一個(gè) Perl 版本。
您可以同時(shí)保留不同的版本,但是可以通過使用符號鏈接,使得缺省情況下對應(yīng)于某一個(gè)特定的版本。只需創(chuàng)建一個(gè)到您希望提供的包的版本的符號鏈接即可。
例如,假定您提供了前面介紹的兩個(gè) Perl 版本。如果您希望將 Perl V5.8 作為缺省值,可以創(chuàng)建一個(gè)到 /usr/local/perl5.8 的符號鏈接,并將它命名為 perl:
$ ls -1 /usr/local/perl*perl5.6perl5.8$ sudo ln -s /usr/local/perl5.8 /usr/local/perl$ ls -1 -F /usr/local/perl*perl5.6/perl5.8/perl@
最終用戶現(xiàn)在可以添加 /usr/local/perl/bin 到他或她的 PATH 變量以運(yùn)行 perl 命令。如果您最后需要或者希望切換到一個(gè)更新的或者更舊的 Perl 版本,那么您只需刪除該符號鏈接,并重新創(chuàng)建一個(gè)指向不同目錄的符號鏈接即可。
對于這樣的維護(hù)任務(wù),符號鏈接是非常重要的。您可以維護(hù)變量、變更路徑,并為方便訪問構(gòu)建集合。例如,您可以在傳統(tǒng)的 /usr/local/bin 目錄中填入鏈接到其他包中的命令的符號鏈接,如 ln -s /usr/local/perl/bin/perl /usr/local/bin/perl。(是的,您可以創(chuàng)建指向另一個(gè)符號鏈接的符號鏈接。)
相關(guān)文章:
1. 對話 UNIX: Squirrel--可移植的 shell 和腳本語言2. 對話 UNIX,第 3 部分: 在命令行中完成所有的工作3. 對話 UNIX,第 12 部分: 自己動(dòng)手完成項(xiàng)目4. 對話 UNIX,第 9 部分: 正則表達(dá)式5. 對話 UNIX: !$#@*%6. 對話 UNIX: 掌握強(qiáng)大的命令行7. 對話 UNIX,第 8 部分: UNIX 進(jìn)程8. 對話 UNIX: 更多 shell 腳本技術(shù)9. 對話 UNIX: 啟動(dòng)10. 對話 UNIX,第 5 部分: 操縱數(shù)據(jù)與文件
