1.4 文件與目錄
文件系統(tǒng)
UNIX文件系統(tǒng)是按層次安排目錄和文件的。起始目錄被稱為根(root),它的名字是一個(gè)字符 / 。
目錄是一個(gè)包含目錄項(xiàng)的文件。在邏輯上,可以認(rèn)為每個(gè)目錄項(xiàng)都包含一個(gè)文件名,同時(shí)還包含說(shuō)明該文件屬性的信息。文件屬性是:文件類型,文件長(zhǎng)度,文件所有者,文件的許可權(quán)(例如,其他用戶能否能訪問(wèn)該文件),文件最后的修改時(shí)間等。start和fstat函數(shù)返回一個(gè)包含所有文件屬性的信息結(jié)構(gòu)。第4章將詳細(xì)說(shuō)明文件的各種屬性。
目錄項(xiàng)事實(shí)上存儲(chǔ)在磁盤上,對(duì)此區(qū)別于目錄項(xiàng)的邏輯看法。多數(shù)UNIX文件系統(tǒng)的實(shí)現(xiàn)并不在目錄項(xiàng)中存儲(chǔ)該目錄項(xiàng)自己的屬性,因?yàn)楫?dāng)文件有很多硬連接的時(shí)候,很難做到同步保存該文件的屬性。當(dāng)我們?cè)诘谒恼掠懻撚策B接后,對(duì)此將有清晰的認(rèn)識(shí)。
文件名
目錄中的各個(gè)名字被稱為文件名。唯一兩個(gè)不能出現(xiàn)在文件名中的字符是反斜杠(/)和空字符(null)。反斜杠用來(lái)把文件名從路徑名中區(qū)別出來(lái),空字符用來(lái)結(jié)束一個(gè)路徑名。因此,把文件名中可用的字符限制在一般打印字符的子集中是一個(gè)好習(xí)慣。(我們限制可用字符還因?yàn)椋绻覀冊(cè)谖募惺褂昧?/SPAN>shell的特殊字符,我們就必須使用shell的引號(hào)機(jī)制來(lái)引用文件名,這將導(dǎo)致問(wèn)題復(fù)雜化。)
被反斜桿區(qū)分開(kāi),并且可選的以反斜桿開(kāi)頭一個(gè)或多個(gè)文件名的序列,構(gòu)成了路徑名。以反斜桿起頭的路徑名稱為絕對(duì)路徑;否則,稱為相對(duì)路徑。相對(duì)路徑涉及到的文件相對(duì)于當(dāng)前目錄。文件系統(tǒng)的根(/)的名字是絕對(duì)路徑的特例,它沒(méi)有文件名。
例子
列出一個(gè)目錄中所有文件的名字并不困難。圖1.3展示了ls(1)命令實(shí)現(xiàn)的本質(zhì)。
ls(1)符號(hào)是UNIX系統(tǒng)手冊(cè)的一般表示方法,用來(lái)引用特定的項(xiàng)。它引用第一小節(jié)中的ls項(xiàng)。小節(jié)號(hào)通常用數(shù)字1到8表示,同時(shí)每一小節(jié)中的所有項(xiàng)都是按字母順序排列的。本書中,我們假定你有一份你的UNIX系統(tǒng)手冊(cè)的拷貝。
歷史上,UNIX系統(tǒng)把所有8個(gè)小節(jié)集中在UNIX程序員手冊(cè)中。隨著頁(yè)數(shù)的增加,趨勢(shì)變?yōu)榘迅鞴?jié)安排在不同的手冊(cè)中:例如一份為用戶準(zhǔn)備的,一份為程序員準(zhǔn)備的,一份為系統(tǒng)管理員準(zhǔn)備的。
一些UNIX系統(tǒng)使用大寫字母在已有的小節(jié)中進(jìn)一步細(xì)分手冊(cè)。舉例來(lái)說(shuō),所有AT&T中的標(biāo)準(zhǔn)輸出/輸入(I/O)函數(shù)在3S小節(jié)中,比如fopen(3S)。其它系統(tǒng)用字母來(lái)代替數(shù)字表示小節(jié)號(hào),例如用C表示命令。
今天,許多手冊(cè)用電子形式進(jìn)行發(fā)行。如果你的手冊(cè)是聯(lián)機(jī)手冊(cè),查看手冊(cè)中ls命令的方式或許是這樣的:
man 1 ls
或者
man –s1 ls
圖1.3是一個(gè)程序,其打印出目錄中各個(gè)文件的名字。如果源碼文件的名字是myls.c,我們按照以下方式把它編譯成默認(rèn)的可執(zhí)行文件a.out:
cc myls.c
cc(1)是早期的C編譯器。在支持GNU C編譯器的系統(tǒng)上,gcc(1)是C編譯器。這里,cc通常與gcc相連接(譯者注:原句是Here,cc is often linked to gcc。沒(méi)翻譯好,期待哪位大蝦指教)。
一些輸出例子如下:
$ ./a.out /dev
.
..
console
tty
mem
kmem
null
mouse
stdin
stdout
stderr
zero
省略其它未顯示的行
cdrom
$ ./a.out /var/spool/cron
can’t open /var/spool/cron: Permission denied
$ ./a.out .dev/tty
can’t open /dev/tty: Not a directory
像上面那樣,我們會(huì)以如下的方式展示運(yùn)行的命令和該命令的輸出:輸入的字符以紅色加粗字體顯示,而程序的輸出以紅色字體顯示。如果對(duì)于輸出需要加注釋,我們會(huì)以紅色斜體字體顯示注釋。輸入行前面的美元符號(hào)是shell打印出來(lái)的提示符。我們始終使用美元符號(hào)作為shell提示符。
注意文件名并沒(méi)有按照字母順序輸出。而ls命令會(huì)在打印名字之前現(xiàn)對(duì)名字排序。
在這個(gè)20行的程序中,許多細(xì)節(jié)應(yīng)當(dāng)被考慮:
l 首先,我們包含了一個(gè)我們自己編寫的頭文件:apue.h。幾乎本書中所有的程序都包含這個(gè)頭文件。該頭文件包含了一些標(biāo)準(zhǔn)系統(tǒng)頭文件,并且定義了本書例子中使用的數(shù)值常量和函數(shù)原型。該頭文件的清單在附錄B中。
l main函數(shù)的聲明使用了ISO C標(biāo)準(zhǔn)的風(fēng)格。(下章中我們會(huì)談到更多ISO C標(biāo)準(zhǔn)。)
l 我們從命令行得到參數(shù)argv[1]作為對(duì)象目錄的名字。在第七章,我們將看到main函數(shù)是怎樣被調(diào)用的,同時(shí)看到命令行參數(shù)和環(huán)境變量是如何傳遞給程序的。
l 由于不同UNIX系統(tǒng)的目錄項(xiàng)格式不盡相同,我們使用opendir函數(shù),readdir函數(shù)和closedir函數(shù)來(lái)操作目錄。
l opendir函數(shù)返回DIR結(jié)構(gòu)的指針,并傳遞該指針給readdir函數(shù)。不必關(guān)心DIR結(jié)構(gòu)的細(xì)節(jié)。接著在循環(huán)中調(diào)用readdir函數(shù),用來(lái)讀取每個(gè)目錄項(xiàng)。readdir函數(shù)返回一個(gè)dirent結(jié)構(gòu)的指針,否則,在無(wú)目錄項(xiàng)可讀時(shí)返回null指針。我們只需要檢查dirent結(jié)構(gòu)中每個(gè)目錄項(xiàng)的名字(d_name)。使用這個(gè)名字,我們就可以調(diào)用stat函數(shù)(4.2節(jié)介紹)來(lái)確定文件的所有屬性。
l 我們調(diào)用兩個(gè)我們自己編寫的函數(shù)來(lái)處理錯(cuò)誤:err_sys和err_quit。從圖1.3的輸出中我們可以看到,err_sys函數(shù)打印出了豐富的信息來(lái)描述遇到的錯(cuò)誤(“Permission denied”和“Not a directory”)。附錄B中列出了這兩個(gè)錯(cuò)誤處理函數(shù)。在1.7節(jié)中我們將更詳細(xì)的談到錯(cuò)誤處理。
l 當(dāng)程序完成時(shí),以參數(shù)0調(diào)用exit函數(shù)。exit函數(shù)結(jié)束一個(gè)程序。通常,參數(shù)0意味者正常結(jié)束,而1到255之間的參數(shù)意味著發(fā)生了錯(cuò)誤。8.5節(jié)中,我們將會(huì)學(xué)習(xí)一個(gè)程序(比如shell或者我們自己寫的程序)如何獲得另一個(gè)正在執(zhí)行中的程序的exit狀態(tài)。

圖 1.3 列舉出一個(gè)目錄中的所有文件
工作目錄
每個(gè)進(jìn)程都有一個(gè)工作目錄,有時(shí)又稱為當(dāng)前工作目錄。所有的相對(duì)路徑都從該目錄開(kāi)始。一個(gè)進(jìn)程能夠用chdir函數(shù)改變它的工作目錄。
例如,相對(duì)路徑doc/memo/joe指出memo目錄中的文件或目錄joe,memo目錄又在doc目錄中,而doc一定是工作目錄下的一個(gè)目錄。查看這個(gè)相對(duì)路徑,我們知道doc和memo一定是目錄,但是我們不能確定joe是一個(gè)文件還是一個(gè)目錄。路徑/usr/lib/lint是一個(gè)絕對(duì)路徑,它指出了lib目錄中的文件或目錄lint,lib目錄在usr目錄中,而usr目錄又在根(root)目錄中。
起始(Home)目錄
當(dāng)我們登錄時(shí),工作目錄被設(shè)定為我們的起始目錄。我們的起始目錄是從密碼文件(1.3節(jié)介紹)中我們的登錄項(xiàng)得到的。