鳥哥的 Linux 私房菜

第零章、計算機概論

第一章、Linux是什麼

第二章、Linux如何學習

第三章、主機規劃與磁碟分割

第四章、安裝CentOS5.x與多重開機小技巧

第五章、首次登入與線上求助manpage

第六章、Linux的檔案權限與目錄配置

第七章、Linux檔案與目錄管理

第八章、Linux磁碟與檔案系統管理

第九章、檔案與檔案系統的壓縮與打包

第十章、vim 程式編輯器

第十一章、認識與學習 BASH

第十二章、正規表示法與文件格式化處理

第十三章、學習 Shell Scripts

第十四章、Linux 帳號管理與 ACL 權限設定

第十五章、磁碟配額(Quota)與進階檔案系統管理

第十六章、例行性工作排程 (crontab)

第十七章、程序管理與 SELinux 初探

第十八章、認識系統服務 (daemons)

第十九章、認識與分析登錄檔

第二十章、開機流程、模組管理與 Loader

第二十一章、系統設定工具(網路與印表機)與硬體偵測

第二十二章、軟體安裝：原始碼與 Tarball

第二十三章、軟體安裝： RPM, SRPM 與 YUM 功能

第二十四章、 X Window 設定介紹

第二十五章、 Linux 備份策略

第二十六章、Linux 核心編譯與管理

基礎學習篇快速索引

附錄A:GPL條文

附錄B:ext2/ext3

一個簡單的 SPFdisk 分割實例

第零章、計算機概論

切換解析度為 800x600

最近更新日期：2009/08/03

這幾年鳥哥開始在大學任教了，在教學的經驗中發現到，由於對 Linux 有興趣的朋友很多可能並非資訊相關科系出身， 因此對於電腦硬體及計算機方面的概念不熟。然而作業系統這種咚咚跟硬體有相當程度的關連性， 所以，如果不瞭解一下計算機概論，要很快的瞭解 Linux 的概念是有點難度的。因此，鳥哥就自作聰明的新增一個小章節來談談計概囉！ 因為鳥哥也不是資訊相關學門出身，所以，寫的不好的地方請大家多多指教啊！^_^

1. 電腦：輔助人腦的好工具

1.1 電腦硬體的五大單元

1.2 CPU的種類

1.3 周邊設備

1.4 運作流程

1.5 電腦分類

1.6 電腦上面常用的計算單位 (容量、速度等)

2. 個人電腦架構與周邊設備

2.1 CPU： CPU的外頻與倍頻, 32位元與64位元, CPU等級

2.2 記憶體

2.3 顯示卡

2.4 硬碟與儲存設備

2.5 PCI介面卡

2.6 主機板

2.7 電源供應器

2.8 選購須知

3. 資料表示方式

3.1 數字系統

3.2 文字編碼系統

4. 軟體程式運作

4.1 機器程式與編譯程式

4.2 作業系統

4.3 應用程式

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=31574

電腦：輔助人腦的好工具

進入二十一世紀的現在，沒有用過電腦的朋友應該算很少了吧？但是，你瞭解電腦是什麼嗎？ 電腦的機殼裡面含有什麼元件？不同的電腦可以作什麼事情？你生活周遭有哪些電器用品內部是含有電腦相關元件的？ 底下我們就來談一談這些東西呢！

所謂的電腦就是一種計算機，而計算機其實是：『接受使用者輸入指令與資料， 經由中央處理器的數學與邏輯單元運算處理後，以產生或儲存成有用的資訊』。 因此，只要有輸入設備 (不管是鍵盤還是觸控式螢幕)及輸出設備(螢幕或直接列印出來)，讓你可以輸入資料使該機器產生資訊的， 那就是一部計算機了。

圖1.1.1、計算機的功能

根據這個定義你知道哪些東西是計算機了嗎？包括一般商店用的簡易型加減乘除計算機、打電話用的手機、開車用的衛星定位系統 (GPS)、提款用的提款機 (ATM)、你常使用的桌上型個人電腦、可攜帶的筆記型電腦還有這兩年 (2008, 2009) 很火紅的 Eee PC (或稱為 netbook) 等等，這些都是計算機！

那麼計算機主要的組成元件是什麼呢？底下我們以常見的個人電腦來作為說明。

電腦硬體的五大單元

關於電腦的組成部分，其實你可以觀察你的桌上型電腦分析一下，依外觀來說這傢伙主要分為三部分：

- 輸入單元：包括鍵盤、滑鼠、讀卡機、掃描器、手寫板、觸控螢幕等等一堆；

- 主機部分：這個就是系統單元，被主機機殼保護住了，裡面含有 CPU 與主記憶體等；

- 輸出單元：例如螢幕、印表機等等

我們主要透過輸入設備如滑鼠與鍵盤來將一些資料輸入到主機裡面，然後再由主機的功能處理成為圖表或文章等資訊後， 將結果傳輸到輸出設備，如螢幕或印表機上面。重點在於主機裡面含有什麼元件呢？如果你曾經拆開過電腦主機機殼， 會發現其實主機裡面最重要的就是一片主機板，上面安插了中央處理器 (CPU) 以及主記憶體還有一些介面卡裝置而已。

整部主機的重點在於中央處理器 (Central Processing Unit, CPU)，CPU 為一個具有特定功能的晶片， 裡頭含有微指令集，如果你想要讓主機進行什麼特異的功能，就得要參考這顆 CPU 是否有相關內建的微指令集才可以。 由於 CPU 的工作主要在於管理與運算，因此在 CPU 內又可分為兩個主要的單元，分別是： 算數邏輯單元與控制單元。(註1) 其中算數邏輯單元主要負責程式運算與邏輯判斷，控制單元則主要在協調各周邊元件與各單元間的工作。

既然 CPU 的重點是在進行運算與判斷，那麼要被運算與判斷的資料是從哪裡來的？ CPU 讀取的資料都是從主記憶體來的！ 主記憶體內的資料則是從輸入單元所傳輸進來！而 CPU 處理完畢的資料也必須要先寫回主記憶體中， 最後資料才從主記憶體傳輸到輸出單元。

綜合上面所說的，我們會知道其實電腦是由幾個單元所組成的，包括輸入單元、 輸出單元、CPU內部的控制單元、算數邏輯單元與主記憶體五大部分。 相關性如下所示：

圖1.1.2、電腦的五大單元(註2)

上面圖示中的『系統單元』其實指的就是電腦機殼內的主要元件，而重點在於CPU與主記憶體。 特別要看的是實線部分的傳輸方向，基本上資料都是流經過主記憶體再轉出去的！ 至於資料會流進/流出記憶體則是CPU所發佈的控制命令！而CPU實際要處理的資料則完全來自於主記憶體！ 這是個很重要的概念喔！

而由上面的圖示我們也能知道，所有的單元都是由CPU內部的控制單元來負責協調的，因此CPU是整個電腦系統的最重要部分！ 那麼目前世界上有哪些主流的CPU呢？是否剛剛我們談到的硬體內全部都是相同的CPU種類呢？底下我們就來談一談。

CPU的種類

如前面說過的，CPU其實內部已經含有一些小指令集，我們所使用的軟體都要經過CPU內部的微指令集來達成才行。 那這些指令集的設計主要又被分為兩種設計理念，這就是目前世界上常見到的兩種主要CPU種類： 分別是精簡指令集(RISC)與複雜指令集(CISC)系統。底下我們就來談談這兩種不同CPU種類的差異囉！

- 精簡指令集(Reduced Instruction Set Computer, RISC)：(註3)

這種CPU的設計中，微指令集較為精簡，每個指令的執行時間都很短，完成的動作也很單純，指令的執行效能較佳； 但是若要做複雜的事情，就要由多個指令來完成。常見的RISC微指令集CPU主要例如昇陽(Sun)公司的SPARC系列、 IBM公司的Power Architecture(包括PowerPC)系列、與ARM系列等。

在應用方面，SPARC架構的電腦常用於學術領域的大型工作站中，包括銀行金融體系的主要伺服器也都有這類的電腦架構； 至於PowerPC架構的應用上，例如新力(Sony)公司出產的Play Station 3(PS3)就是使用PowerPC架構的Cell處理器； 那ARM呢？你常使用的各廠牌手機、PDA、導航系統、網路設備(交換器、路由器等)等，幾乎都是使用ARM架構的CPU喔！ 老實說，目前世界上使用範圍最廣的CPU可能就是ARM呢！ (註4)

- 複雜指令集(Complex Instruction Set Computer, CISC)：(註5)

與RISC不同的，CISC在微指令集的每個小指令可以執行一些較低階的硬體操作，指令數目多而且複雜， 每條指令的長度並不相同。因為指令執行較為複雜所以每條指令花費的時間較長， 但每條個別指令可以處理的工作較為豐富。常見的CISC微指令集CPU主要有AMD、Intel、VIA等的x86架構的CPU。

由於AMD、Intel、VIA所開發出來的x86架構CPU被大量使用於個人電腦(Personal computer)用途上面， 因此，個人電腦常被稱為x86架構的電腦！那為何稱為x86架構(註6)呢？ 這是因為最早的那顆Intel發展出來的CPU代號稱為8086，後來依此架構又開發出80286, 80386...， 因此這種架構的CPU就被稱為x86架構了。

在2003年以前由Intel所開發的x86架構CPU由8位元升級到16、32位元，後來AMD依此架構修改新一代的CPU為64位元， 為了區別兩者的差異，因此64位元的個人電腦CPU又被統稱為x86_64的架構喔！

那麼不同的x86架構的CPU有什麼差異呢？除了CPU的整體結構(如第二層快取、每次運作可執行的指令數等)之外， 主要是在於微指令集的不同。新的x86的CPU大多含有很先進的微指令集， 這些微指令集可以加速多媒體程式的運作，也能夠加強虛擬化的效能，而且某些微指令集更能夠增加能源效率， 讓CPU耗電量降低呢！由於電費越來越高，購買電腦時，除了整體的效能之外， 節能省電的CPU特色也可以考慮喔！

例題：

最新的Intel/AMD的x86架構中，請查詢出多媒體、虛擬化、省電功能各有哪些重要的微指令集？(僅供參考)

答：

- 多媒體微指令集：MMX, SSE, SSE2, SSE3, SSE4, AMD-3DNow!

- 虛擬化微指令集：Intel-VT, AMD-SVM

- 省電功能：Intel-SpeedStep, AMD-PowerNow!

- 64/32位元相容技術：AMD-AMD64, Intel-EM64T

周邊設備

單有CPU也無法運作電腦的，所以電腦還需要其他的周邊設備才能夠實際運作。 除了前面稍微提到的輸入/輸出設備，以及CPU與主記憶體之外，還有什麼周邊設備呢？ 其實最重要的周邊設備是主機板！因為主機板負責將所有的設備通通連接在一起，讓所有的設備能夠進行協調與溝通。 而主機板上面最重要的元件就是主機板晶片組！這個晶片組可以將所有的設備匯集在一起！

其他重要的設備還有：

- 儲存裝置：儲存裝置包括硬碟、軟碟、光碟、磁帶等等；

- 顯示裝置：顯示卡對於玩3D遊戲來說是非常重要的一環，他與顯示的精緻度、色彩與解析度都有關係；

- 網路裝置：沒有網路活不下去啊！所以網路卡對於電腦來說也是相當重要的！

更詳細的各項周邊裝置我們將在下個小節進行介紹！在這裡我們先來瞭解一下各元件的關係囉！ 那就是，電腦是如何運作的呢？

運作流程

如果不是很瞭解電腦的運作流程，鳥哥拿個簡單的想法來思考好了∼ 假設電腦是一個人體，那麼每個元件對應到那個地方呢？可以這樣思考：

圖1.4.1、各元件運作

- CPU=腦袋瓜子：每個人會作的事情都不一樣(微指令集的差異)， 但主要都是透過腦袋瓜子來進行判斷與控制身體各部分的活動；

- 主記憶體=腦袋中的記錄區塊：在實際活動過程中，我們的腦袋瓜子能夠將外界的互動暫時記錄起來， 提供CPU來進行判斷；

- 硬碟=腦袋中的記憶區塊：將重要的資料記錄起來，以便未來將這些重要的經驗再次的使用；

- 主機板=神經系統：好像人類的神經一樣，將所有重要的元件連接起來，包括手腳的活動都是腦袋瓜子發佈命令後， 透過神經(主機板)傳導給手腳來進行活動啊！

- 各項周邊設備=人體與外界溝通的手、腳、皮膚、眼睛等：就好像手腳一般，是人體與外界互動的重要關鍵！

- 顯示卡=腦袋中的影像：將來自眼睛的刺激轉成影響後在腦袋中呈現，所以顯示卡所產生的資料來源也是CPU控制的。

- 電源供應器 (Power)=心臟：所有的元件要能運作得要有足夠的電力供給才行！這電力供給就好像心臟一樣，如果心臟不夠力， 那麼全身也就無法動彈的！心臟不穩定呢？那你的身體當然可能斷斷續續的∼不穩定！

由這樣的關係圖當中，我們知道整個活動中最重要的就是腦袋瓜子！ 而腦袋瓜子當中與現在正在進行的工作有關的就是CPU與主記憶體！任何外界的接觸都必須要由腦袋瓜子中的主記憶體記錄下來， 然後給腦袋中的CPU依據這些資料進行判斷後，再發佈命令給各個周邊設備！如果需要用到過去的經驗， 就得由過去的經驗(硬碟)當中讀取囉！

也就是說，整個人體最重要的地方就是腦袋瓜子，同樣的，整部主機當中最重要的就是CPU與主記憶體， 而CPU的資料來源通通來自於主記憶體，如果要由過去的經驗來判斷事情時， 也要將經驗(硬碟)挪到目前的記憶(主記憶體)當中，再交由CPU來判斷喔！這點得要再次的強調啊！ 下個章節當中，我們就對目前常見的個人電腦各個元件來進行說明囉！

電腦分類

知道了電腦的基本組成與周邊裝置，也知道其實電腦的CPU種類非常的多，再來我們想要瞭解的是，電腦如何分類？ 電腦的分類非常多種，如果以電腦的複雜度與運算能力進行分類的話，主要可以分為這幾類：

- 超級電腦(Supercomputer)

超級電腦是運作速度最快的電腦，但是他的維護、操作費用也最高！主要是用於需要有高速計算的計畫中。 例如：國防軍事、氣象預測、太空科技，用在模擬的領域較多。詳情也可以參考： 國家高速網路與計算中心http://www.nchc.org.tw的介紹！ 至於全世界最快速的前500大超級電腦，則請參考：http://www.top500.org。

- 大型電腦(Mainframe Computer)

大型電腦通常也具有數個高速的CPU，功能上雖不及超級電腦，但也可用來處理大量資料與複雜的運算。 例如大型企業的主機、全國性的證券交易所等每天需要處理數百萬筆資料的企業機構， 或者是大型企業的資料庫伺服器等等。

- 迷你電腦(Minicomputer)

迷你電腦仍保有大型電腦同時支援多使用者的特性，但是主機可以放在一般作業場所， 不必像前兩個大型電腦需要特殊的空調場所。通常用來作為科學研究、工程分析與工廠的流程管理等。

- 工作站(Workstation)

工作站的價格又比迷你電腦便宜許多，是針對特殊用途而設計的電腦。在個人電腦的效能還沒有提升到目前的狀況之前， 工作站電腦的性能/價格比是所有電腦當中較佳的，因此在學術研究與工程分析方面相當常見。

- 微電腦(Microcomputer)

又可以稱為個人電腦，也是我們這裡主要探討的目標！體積最小，價格最低，但功能還是五臟俱全的！ 大致又可分為桌上型、筆記型等等。

若光以效能來說，目前的個人電腦效能已經夠快了，甚至已經比工作站等級以上的電腦運算速度還要快！ 但是工作站電腦強調的是穩定不當機，並且運算過程要完全正確，因此工作站以上等級的電腦在設計時的考量與個人電腦並不相同啦！ 這也是為啥工作站等級以上的個人電腦售價較貴的原因。

電腦上面常用的計算單位 (容量、速度等)

電腦的運算能力是由速度來決定的，而存放在電腦儲存設備當中的資料容量也是有單位的。

- 容量單位

電腦依有沒有通電來記錄資訊，所以理論上它只認識 0 與 1 而已。0/1 的單位我們稱為 bit。但 bit 實在太小了， 並且在儲存資料時每份簡單的資料都會使用到 8 個 bits 的大小來記錄，因此定義出 byte 這個單位，他們的關係為：

1 Byte = 8 bits

不過同樣的，Byte 還是太小了，在較大的容量情況下，使用 byte 相當不容易判斷資料的大小，舉例來說，1000000 bytes 這樣的顯示方式你能夠看得出有幾個零嗎？所以後來就有一些常見的簡化單位表示法，例如 K 代表 1024，M 代表 1024K 等。 而這些單位在不同的進位制下有不同的數值表示，底下就列出常見的單位與進位制對應：

進位制

K

M

G

T

P

二進位

1024

1024K

1024M

1024G

1024T

十進位

1000

1000K

1000M

1000G

1000T

一般來說，檔案容量使用的是二進位的方式，所以 1 GBytes 的檔案大小實際上為：1024x1024x1024 Bytes 這麼大！ 速度單位則常使用十進位，例如 1GHz 就是 1000x1000x1000 Hz 的意思。

- 速度單位

CPU的運算速度常使用 MHz 或者是 GHz 之類的單位，這個 Hz 其實就是秒分之一。而在網路傳輸方面，由於網路使用的是 bit 為單位，因此網路常使用的單位為 Mbps 是 Mbits per second，亦即是每秒多少 Mbit。舉例來說，大家常聽到的 8M/1M ADSL 傳輸速度，如果轉成檔案容量的 byte 時，其實理論最大傳輸值為：每秒 1Mbyte/ 每秒125Kbyte的上傳/下載容量喔！

例題：

假設你今天購買了500GB的硬碟一顆，但是格式化完畢後卻只剩下460GB左右的容量，這是什麼原因？

答：

因為一般硬碟製造商會使用十進位的單位，所以500GByte代表為500*1000*1000*1000Byte之意。 轉成檔案的容量單位時使用二進位(1024為底)，所以就成為466GB左右的容量了。

硬碟廠商並非要騙人，只是因為硬碟的最小物理量為512Bytes，最小的組成單位為磁區(sector)， 通常硬碟容量的計算採用『多少個sector』，所以才會使用十進位來處理的。相關的硬碟資訊在這一章後面會提到的！

個人電腦架構與周邊設備

一般消費者常說的電腦通常指的就是x86的個人電腦架構，因此我們有必要來瞭解一下這個架構的各個元件。 事實上，Linux最早在發展的時候，就是依據個人電腦的架構來發展的，所以，真的得要瞭解一下呢！ 另外，因為兩大主流x86開發商(Intel, AMD)的CPU架構並不相容，而且設計理念也有所差異， 所以兩大主流CPU所需要的主機板晶片組設計也就不太相同。目前(2009)最新的主機板架構主要是這樣的：

圖2.1.1、Intel晶片架構

就如同前一小節提到的，整個主機板上面最重要的就是晶片組了！而晶片組通常又分為兩個橋接器來控制各元件的溝通， 分別是：(1)北橋：負責連結速度較快的CPU、主記憶體與顯示卡等元件；(2)南橋：負責連接速度較慢的周邊介面， 包括硬碟、USB、網路卡等等。(晶片組的南北橋與三國的大小喬沒有關係 @_@)至於AMD的晶片組架構如下所示：

圖2.1.2、AMD晶片架構

與Intel不同的地方在於主記憶體是直接與CPU溝通而不透過北橋！從前面的說明我們可以知道CPU的資料主要都是來自於主記憶體提供， 因此AMD為了加速這兩者的溝通，所以將記憶體控制元件整合到CPU當中， 理論上這樣可以加速CPU與主記憶體的傳輸速度！這是兩種CPU在架構上面主要的差異點。

畢竟目前世界上x86的CPU主要供應商為Intel，所以底下鳥哥將以Intel的主機板架構說明各元件囉！ 我們以技嘉公司出的主機板，型號：Gigabyte GA-X48-DQ6作為一個說明的範例，主機板各元件如下所示：

圖2.1.3、技嘉主機板各元件(圖片為各公司所有)

主要的元件為：CPU、主記憶體、磁碟裝置(IDE/SATA)、匯流排晶片組(南橋/北橋)、顯示卡介面(PCI-Express)與其他介面卡(PCI)。 底下的各項元件在講解時，請參考Intel晶片組架構與技嘉主機板各元件來印證喔！

CPU

如同技嘉主機板示意圖上最上方的中央部分，那就是CPU插槽。 由於CPU負責大量運算，因此CPU通常是具有相當高發熱量的元件。所以如果你曾經拆開過主機板， 應該就會看到CPU上頭通常會安插一顆風扇來主動散熱的。

x86個人電腦的CPU主要供應商為Intel與AMD，目前(2009)主流的CPU都是雙核以上的架構了！ 原本的單核心CPU僅有一個運算單元，所謂的多核心則是在一顆CPU封裝當中嵌入了兩個以上的運算核心， 簡單的說，就是一個實體的CPU外殼中，含有兩個以上的CPU單元就是了。

不同的CPU型號大多具有不同的腳位(CPU上面的插腳)，能夠搭配的主機板晶片組也不同， 所以當你想要將你的主機升級時，不能只考慮CPU，你還得要留意你的主機板上面所支援的CPU型號喔！ 不然買了最新的CPU也不能夠安插在你的舊主機板上頭的！目前主流的CPU有Intel的Core 2 Duo與AMD的Athlon64 X2雙核CPU， 高階產品則有Intel的Core i7 與AMD的Phenom II 四核心CPU喔！

圖2.1.4、不同的CPU腳位

我們前面談到CPU內部含有微指令集，不同的微指令集會導致CPU工作效率的優劣。除了這點之外， CPU效能的比較還有什麼呢？那就是CPU的時脈了！什麼是時脈呢？簡單的說， 時脈就是CPU每秒鐘可以進行的工作次數。 所以時脈越高表示這顆CPU單位時間內可以作更多的事情。舉例來說，Intel的Core 2 Duo型號E8400的CPU時脈為3.0GHz， 表示這顆CPU在一秒內可以進行3.0x10^9次工作，每次工作都可以進行少數的指令運作之意。

Tips:

注意，不同的CPU之間不能單純的以時脈來判斷運算效能喔！這是因為每顆CPU的微指令集不相同，架構也不見得一樣， 每次時脈能夠進行的工作指令數也不同之故！所以，時脈目前僅能用來比較同款CPU的速度！

- CPU的『外頻』與『倍頻』

我們可以看到圖2.1.1的晶片架構圖當中各個元件都是透過北橋與南橋所連接在一起。 但就像一群人共同在處理一個連續作業一般，如果這一群人裡面有個人的動作特別快或特別慢， 將導致前面或者是後面的人事情一堆處理不完！也就是說，這一群人最好能夠速度一致較佳！ 所以，CPU與外部各元件的速度理論上應該要一致才好。但是因為CPU需要較強大的運算能力， 因為很多判斷與數學都是在CPU內處理的，因此CPU開發商就在CPU內再加上一個加速功能， 所以CPU有所謂的外頻與倍頻！

所謂的外頻指的是CPU與外部元件進行資料傳輸時的速度，倍頻則是 CPU 內部用來加速工作效能的一個倍數， 兩者相乘才是CPU的時脈速度。我們以剛剛Intel Core 2 Duo E8400 CPU來說，他的時脈是3.0GHz， 而外頻是333MHz，因此倍頻就是9倍囉！(3.0G=333Mx9, 其中1G=1000M)

Tips:

很多電腦硬體玩家很喜歡玩『超頻』，所謂的超頻指的是： 將CPU的倍頻或者是外頻透過主機板的設定功能更改成較高頻率的一種方式。但因為CPU的倍頻通常在出廠時已經被鎖定而無法修改， 因此較常被超頻的為外頻。

舉例來說，像上述3.0GHz的CPU如果想要超頻， 可以將他的外頻333MHz調整成為400MHz，但如此一來整個主機板的各個元件的運作頻率可能都會被增加成原本的1.333倍(4/3)， 雖然CPU可能可以到達3.6GHz，但卻因為頻率並非正常速度，故可能會造成當機等問題。

- 32位元與64位元

前面談到CPU運算的資料都是由主記憶體提供的，主記憶體與CPU的溝通速度靠的是外部頻率， 那麼每次工作可以傳送的資料量有多大呢？那就是匯流排的功能了。一般主機板晶片組有分北橋與南橋， 北橋的匯流排稱為系統匯流排，因為是記憶體傳輸的主要通道，所以速度較快。 南橋就是所謂的輸入輸出(I/O)匯流排，主要在聯繫硬碟、USB、網路卡等周邊設備。

目前北橋所支援的頻率可高達333/400/533/800/1066/1333/1600MHz等不同頻率，支援情況依晶片組功能而有不同。 北橋所支援的頻率我們稱為前端匯流排速度(Front Side Bus, FSB)， 而每次傳送的位元數則是匯流排寬度。 那所謂的匯流排頻寬則是：『FSBx匯流排寬度』亦即每秒鐘可傳送的最大資料量。 目前常見的匯流排寬度有32/64位元(bits)。

而如圖 2.1.1中的圖示，在該架構中前端匯流排最高速度可達1600MHz。 我們看到記憶體與北橋的頻寬為12.8GBytes/s，亦即是1600MHz*64bits = 1600MHz*8Bytes = 12800MByes/s = 12.8GBytes/s

與匯流排寬度相似的，CPU每次能夠處理的資料量稱為字組大小(word size)， 字組大小依據CPU的設計而有32位元與64位元。我們現在所稱的電腦是32或64位元主要是依據這個 CPU解析的字組大小而來的！早期的32位元CPU中，因為CPU每次能夠解析的資料量有限， 因此由主記憶體傳來的資料量就有所限制了。這也導致32位元的CPU最多只能支援最大到4GBytes的記憶體。

Tips:

字組大小與匯流排寬度是可以不同的！舉例來說，在Pentium Pro時代，該CPU是32位元的處理器， 但當時的晶片組可以設計出64位元的匯流排寬度。在這樣的架構下我們通常還是以CPU的字組大小來稱呼該架構。 個人電腦的64位元CPU是到2003年由AMD Athlon64後才出現的。

- CPU等級

由於x86架構的CPU在Intel的Pentium系列(1993年)後就有不統一的腳位與設計，為了將不同種類的CPU規範等級， 所以就有i386,i586,i686等名詞出現了。基本上，在Intel Pentium MMX與AMD K6年代的CPU稱為i586等級， 而Intel Celeron與AMD Athlon(K7)年代之後的32位元CPU就稱為i686等級。 至於目前的64位元CPU則統稱為x86_64等級。

目前很多的程式都有對CPU做最佳化的設計，萬一哪天你發現一些程式是註明給686的CPU使用時， 就不要將他安裝在586以下等級的電腦中，否則可是會無法執行該軟體的！ 不過，在686倒是可以安裝386的軟體喔！也就是說，這些東西具有向下相容的能力啦！

記憶體

如同圖2.1.3、技嘉主機板示意圖中的右上方部分的那四根插槽，那就是主記憶體的插槽了。 主記憶體插槽中間通常有個突起物將整個插槽稍微切分成為兩個不等長的距離， 這樣的設計可以讓使用者在安裝主記憶體時，不至於前後腳位安插錯誤，是一種防呆的設計喔。

前面提到CPU所使用的資料都是來自於主記憶體(main memory)，不論是軟體程式還是資料，都必須要讀入主記憶體後CPU才能利用。 個人電腦的主記憶體主要元件為動態隨機存取記憶體(Dynamic Random Access Memory, DRAM)， 隨機存取記憶體只有在通電時才能記錄與使用，斷電後資料就消失了。因此我們也稱這種RAM為揮發性記憶體。

DRAM根據技術的更新又分好幾代，而使用上較廣泛的有所謂的SDRAM與DDR SDRAM兩種。 這兩種記憶體的差別除了在於腳位與工作電壓上的不同之外，DDR是所謂的雙倍資料傳送速度(Double Data Rate)， 他可以在一次工作週期中進行兩次資料的傳送，感覺上就好像是CPU的倍頻啦！ 所以傳輸頻率方面比SDRAM還要好。新一代的PC大多使用DDR記憶體了。 下表列出SDRAM與DDR SDRAM的型號與頻率及頻寬之間的關係。

SDRAM/DDR

型號

資料寬度(bit)

外頻(MHz)

頻率速度

頻寬(頻率x寬度)

SDRAM

PC100

64

100

100

800MBytes/sec

SDRAM

PC133

64

133

133

1064MBytes/sec

DDR

DDR266

64

133

266

2.1GBytes/sec

DDR

DDR400

64

200

400

3.2GBytes/sec

DDR

DDRII800

64

200

800

6.4GBytes/sec

DDR SDRAM又依據技術的發展，有DDR, DDRII, DDRIII等等，其中，DDRII 的頻率倍數則是 4 倍喔！

Tips:

主記憶體型號的挑選與CPU及晶片組有關，所以主機板、CPU與記憶體在購買的時候必須要考慮其相關性喔。 並不是任何主機板都可以安插DDR III的記憶體呢！

主記憶體除了頻率/頻寬與型號需要考慮之外，記憶體的容量也是很重要的喔！ 因為所有的資料都得要載入記憶體當中才能夠被CPU判讀，如果記憶體容量不夠大的話將會導致某些大容量資料無法被完整的載入， 此時已存在記憶體當中但暫時沒有被使用到的資料必須要先被釋放，使得可用記憶體容量大於該資料，那份新資料才能夠被載入呢！ 所以，通常越大的記憶體代表越快速的系統，這是因為系統不用常常釋放一些記憶體內部的資料。 以伺服器來說，主記憶體的容量有時比CPU的速度還要來的重要的！

- 雙通道設計

由於所有的資料都必須要存放在主記憶體，所以主記憶體的資料寬度當然是越大越好。 但傳統的匯流排寬度一般大約僅達64位元，為了要加大這個寬度，因此晶片組廠商就將兩個主記憶體彙整在一起， 如果一支記憶體可達64位元，兩支記憶體就可以達到128位元了，這就是雙通道的設計理念。

如上所述，要啟用雙通道的功能你必須要安插兩支(或四支)主記憶體，這兩支記憶體最好連型號都一模一樣比較好， 這是因為啟動雙通道記憶體功能時，資料是同步寫入/讀出這一對主記憶體中，如此才能夠提升整體的頻寬啊！ 所以當然除了容量大小要一致之外，型號也最好相同啦！

你有沒有發現圖 2.1.3、技嘉主機板示意圖上那四根記憶體插槽的顏色呢？是否分為兩種顏色，且兩兩成對？ 為什麼要這樣設計？答出來了嗎？是啦！這種顏色的設計就是為了雙通道來的！要啟動雙通道的功能時， 你必須要將兩根容量相同的主記憶體插在相同顏色的插槽當中喔！

- CPU時脈與主記憶體的關係

理論上，CPU與主記憶體的外頻應該要相同才好。不過，因為技術方面的提升，因此這兩者的頻率速度不會相同， 但外頻則應該是一致的較佳。舉例來說，上面提到的Intel E8400 CPU外頻為333MHz，則應該選用DDR II 667這個型號， 因為該記憶體型號的外頻為333MHz之故喔！

- DRAM與SRAM

除了主記憶體之外，事實上整部個人電腦當中還有許許多多的記憶體存在喔！最為我們所知的就是CPU內的第二層快取記憶體。 我們現在知道CPU的資料都是由主記憶體提供，但主記憶體的資料畢竟得經由北橋送到CPU內。 如果某些很常用的程式或資料可以放置到CPU內部的話，那麼CPU資料的讀取就不需要透過北橋了！ 對於效能來說不就可以大大的提升了？這就是第二層快取的設計概念。第二層快取與主記憶體及CPU的關係如下圖所示：

圖2.2.1、記憶體相關性

因為第二層快取(L2 cache)整合到CPU內部，因此這個L2記憶體的速度必須要CPU時脈相同。 使用DRAM是無法達到這個時脈速度的，此時就需要靜態隨機存取記憶體(Static Random Access Memory, SRAM)的幫忙了。 SRAM在設計上使用的電晶體數量較多，價格較高，且不易做成大容量，不過由於其速度快， 因此整合到CPU內成為快取記憶體以加快資料的存取是個不錯的方式喔！新一代的CPU都有內建容量不等的L2快取在CPU內部， 以加快CPU的運作效能。

- 唯讀記憶體(ROM)

主機板上面的元件是非常多的，而每個元件的參數又具有可調整性。舉例來說，CPU與記憶體的時脈是可調整的； 而主機板上面如果有內建的網路卡或者是顯示卡時，該功能是否要啟動與該功能的各項參數， 是被記錄到主機板上頭的一個稱為CMOS的晶片上，這個晶片需要藉著額外的電源來發揮記錄功能， 這也是為什麼你的主機板上面會有一顆電池的緣故。

那CMOS內的資料如何讀取與更新呢？還記得你的電腦在開機的時候可以按下[Del]按鍵來進入一個名為BIOS的畫面吧？ BIOS(Basic Input Output System)是一套程式，這套程式是寫死到主機板上面的一個記憶體晶片中， 這個記憶體晶片在沒有通電時也能夠將資料記錄下來，那就是唯讀記憶體(Read Only Memory, ROM)。 ROM是一種非揮發性的記憶體。另外，BIOS對於個人電腦來說是非常重要的， 因為他是系統在開機的時候首先會去讀取的一個小程式喔！

另外，韌體(firmware)(註7)很多也是使用ROM來進行軟體的寫入的。 韌體像軟體一樣也是一個被電腦所執行的程式，然而他是對於硬體內部而言更加重要的部分。例如BIOS就是一個韌體， BIOS雖然對於我們日常操作電腦系統沒有什麼太大的關係，但是他卻控制著開機時各項硬體參數的取得！ 所以我們會知道很多的硬體上頭都會有ROM來寫入韌體這個軟體。

BIOS 對電腦系統來講是非常重要的，因為他掌握了系統硬體的詳細資訊與開機設備的選擇等等。但是電腦發展的速度太快了， 因此 BIOS 程式碼也可能需要作適度的修改才行，所以你才會在很多主機板官網找到 BIOS 的更新程式啊！但是 BIOS 原本使用的是無法改寫的 ROM ，因此根本無法修正 BIOS 程式碼！為此，現在的 BIOS 通常是寫入類似快閃記憶體 (flash) 或 EEPROM (註8) 中。(註9)

顯示卡

顯示卡插槽如同圖 2.1.3、技嘉主機板示意圖所示，是在中央較長的插槽！ 這張主機板中提供了兩個顯示卡插槽喔！

顯示卡又稱為VGA(Video Graphics Array)，他對於圖形影像的顯示扮演相當關鍵的角色。 一般對於圖形影像的顯示重點在於解析度與色彩深度，因為每個圖像顯示的顏色會佔用掉記憶體， 因此顯示卡上面會有一個記憶體的容量，這個顯示卡記憶體容量將會影響到最終你的螢幕解析度與色彩深度的喔！

除了顯示卡記憶體之外，現在由於三度空間遊戲(3D game)與一些3D動畫的流行，因此顯示卡的『運算能力』越來越重要。 一些3D的運算早期是交給CPU去運作的，但是CPU並非完全針對這些3D來進行設計的，而且CPU平時已經非常忙碌了呢！ 所以後來顯示卡廠商直接在顯示卡上面嵌入一個3D加速的晶片，這就是所謂的GPU稱謂的由來。

顯示卡主要也是透過北橋晶片與CPU、主記憶體等溝通。如前面提到的，對於圖形影像(尤其是3D遊戲)來說， 顯示卡也是需要高速運算的一個元件，所以資料的傳輸也是越快越好！因此顯示卡的規格由早期的PCI導向AGP， 近期AGP又被PCI-Express規格所取代了。如前面技嘉主機板圖示當中看到的就是PCI-Express的插槽。 這些插槽最大的差異就是在資料傳輸的頻寬了！如下所示：

規格

寬度

速度

頻寬

PCI

32 bits

33 MHz

133 MBytes/s

PCI 2.2

64 bits

66 MHz

533 MBytes/s

PCI-X

64 bits

133 MHz

1064 MBytes/s

AGP 4x

32 bits

66x4 MHz

1066 MBytes/s

AGP 8x

32 bits

66x8 MHz

2133 MBytes/s

PCIe x1

無

無

250 MBytes/s

PCIe x8

無

無

2 GBytes/s

PCIe x16

無

無

4 GBytes/s

比較特殊的是，PCIe(PCI-Express)使用的是類似管線的概念來處理，每條管線可以具有250MBytes/s的頻寬效能， 管線越大(最大可達x32)則總頻寬越高！目前顯示卡大多使用x16的PCIe規格，這個規格至少可以達到4GBytes/s的頻寬！ 比起AGP是快很多的！此外，新的PCIe 2.0規格也已經推出了，這個規格又可將每個管線的效能提升一倍呢！ 好可怕的傳輸量....

如果你的主機是用來打3D遊戲的，那麼顯示卡的選購是非常重要喔！如果你的主機是用來做為網路伺服器的， 那麼簡單的入門級顯示卡對你的主機來說就非常夠用了！因為網路伺服器很少用到3D與圖形影像功能。

例題：

假設你的桌面使用1024x768解析度，且使用全彩(每個像素佔用3bytes的容量)，請問你的顯示卡至少需要多少記憶體才能使用這樣的彩度？

答：

因為1024x768解析度中會有786432個像素，每個像素佔用3bytes，所以總共需要2.25MBytes以上才行！ 但如果考慮螢幕的更新率(每秒鐘螢幕的更新次數)，顯示卡的記憶體還是越大越好！

硬碟與儲存設備

電腦總是需要記錄與讀取資料的，而這些資料當然不可能每次都由使用者經過鍵盤來打字！所以就需要有儲存設備咯。 電腦系統上面的儲存設備包括有：硬碟、軟碟、MO、CD、DVD、磁帶機、隨身碟(快閃記憶體)、還有新一代的藍光光碟機等， 乃至於大型機器的區域網路儲存設備(SAN, NAS)等等，都是可以用來儲存資料的。而其中最常見的應該就是硬碟了吧！

- 硬碟的物理組成

大家應該都看過硬碟吧！硬碟依據桌上型與筆記型電腦而有分為3.5吋及2.5吋的大小。我們以3.5吋的桌上型電腦使用硬碟來說明。 在硬碟盒裡面其實是由許許多多的圓形磁碟盤、機械手臂、 磁碟讀取頭與主軸馬達所組成的，整個內部如同下圖所示：

圖2.4.1、硬碟物理構造(圖片取自維基百科)

實際的資料都是寫在具有磁性物質的磁碟盤上頭，而讀寫主要是透過在機械手臂上的讀取頭(head)來達成。 實際運作時， 主軸馬達讓磁碟盤轉動，然後機械手臂可伸展讓讀取頭在磁碟盤上頭進行讀寫的動作。 另外，由於單一磁碟盤的容量有限，因此有的硬碟內部會有兩個以上的磁碟盤喔！

- 磁碟盤上的資料

既然資料都是寫入磁碟盤上頭，那麼磁碟盤上頭的資料又是如何寫入的呢？ 其實磁碟盤上頭的資料有點像下面的圖示所示：

圖2.4.2、磁碟盤上的資料格式

整個磁碟盤上頭好像有多個同心圓繪製出的圓形圖，而由圓心以放射狀的方式分割出磁碟的最小儲存單位，那就是磁區(Sector)， 在物理組成分面，每個磁區大小為512Bytes，這個值是不會改變的。而磁區組成一個圓就成為磁軌(track)， 如果是在多碟的硬碟上面，在所有磁碟盤上面的同一個磁軌可以組成一個磁柱(Cylinder)， 磁柱也是一般我們分割硬碟時的最小單位了！

在計算整個硬碟的儲存量時，簡單的計算公式就是：『header數量 * 每個header負責的磁柱數量 * 每個磁柱所含有的磁區數量 * 磁區的容量』，單位換算為『header * cylinder/header * secter/cylinder * 512bytes/secter』，簡單的寫法如下： Head x Cylinder x Sector x 512 Bytes。 不過要注意的是，一般硬碟製造商在顯示硬碟的容量時，大多是以十進位來編號，因此市售的500GB硬碟， 理論上僅會有460GBytes左右的容量喔！

- 傳輸介面

由於傳輸速度的需求提升，目前硬碟與主機系統的聯繫主要有幾種傳輸介面規格：

圖2.4.3、兩款硬碟介面(左邊為IDE介面，右邊為SATA介面)

- IDE介面：

如同圖 2.1.3、技嘉主機板圖示右側的較寬的插槽所示，那就是IDE的介面插槽。 IDE介面插槽所使用的排線較寬，每條排線上面可以接兩個IDE裝置，由於可以接兩個裝置，那為了判別兩個裝置的主/從架構， 因此這種磁碟機上面需要調整跳針(Jump)成為Master或slave才行喔！這種介面的最高傳輸速度為Ultra 133規格， 亦即每秒理論傳輸速度可達133MBytes。

圖2.4.4、IDE 介面的排線 (圖示取自 Seagate 網站)

- SATA介面：

如同技嘉主機板圖示右下方所示為SATA硬碟的連接介面插槽。 我們可以看到該插槽要比IDE介面的小很多，每條SATA連接線僅能接一個SATA裝置。SATA介面除了速度較快之外， 由於其排線較細小所以有利於主機機殼內部的散熱與安裝！目前SATA已經發展到了第二代， 其速度由SATA-1的每秒150MBytes提升到SATA-2每秒300MBytes的傳輸速度喔， 也因此目前主流的個人電腦硬碟已經被SATA取代了。SATA的插槽示意圖如下所示：

圖2.4.5、SATA 介面的排線 (圖示取自 Seagate 網站)

由於SATA一條排線僅接一顆硬碟，所以妳不需要調整跳針。不過一張主機板上面SATA插槽的數量並不是固定的， 且每個插槽都有編號，在連接SATA硬碟與主機板的時候，還是需要留意一下。

- SCSI介面：

另一種常見於工作站等級以上的硬碟傳輸介面為SCSI介面，這種介面的硬碟在控制器上含有一顆處理器， 所以除了運轉速度快之外，也比較不會耗費CPU資源喔！在個人電腦上面這種介面的硬碟不常見啦！

- 選購與運轉須知

如果你想要增加一顆硬碟在你的主機裡頭時，除了需要考慮你的主機板可接受的插槽介面(IDE/SATA)之外， 還有什麼要注意的呢？

- 容量

通常首先要考量的就是容量的問題！目前(2009)主流市場硬碟容量已經到達320GB以上，甚至有的廠商已經生產高達 2TB 的產品呢！硬碟可能可以算是一種消耗品，要注意重要資料還是得常常備份出來喔！

- 緩衝記憶體

硬碟上頭含有一個緩衝記憶體，這個記憶體主要可以將硬碟內常使用的資料快取起來，以加速系統的讀取效能。 通常這個緩衝記憶體越大越好，因為緩衝記憶體的速度要比資料從硬碟盤中被找出來要快的多了！ 目前主流的產品可達16MB左右的記憶體大小喔。

- 轉速

因為硬碟主要是利用主軸馬達轉動磁碟盤來存取，因此轉速的快慢會影響到效能。 主流的桌上型電腦硬碟為每分鐘7200轉，筆記型電腦則是5400轉。有的廠商也有推出高達10000轉的硬碟， 若有高效能的資料存取需求，可以考慮購買高轉速硬碟。

- 運轉須知

由於硬碟內部機械手臂上的磁頭與硬碟盤的接觸是很細微的空間， 如果有抖動或者是髒污在磁頭與硬碟盤之間就會造成資料的損毀或者是實體硬碟整個損毀∼ 因此，正確的使用電腦的方式，應該是在電腦通電之後，就絕對不要移動主機，並免抖動到硬碟， 而導致整個硬碟資料發生問題啊！另外，也不要隨便將插頭拔掉就以為是順利關機！因為機械手臂必須要歸回原位， 所以使用作業系統的正常關機方式，才能夠有比較好的硬碟保養啊！因為他會讓硬碟的機械手臂歸回原位啊！

Tips:

可能因為環境的關係，電腦內部的風扇常常會卡灰塵而造成一些聲響。很多朋友只要聽到這種聲響都是二話不說的 『用力拍幾下機殼』就沒有聲音了∼現在你知道了，這麼做的後果常常就是你的硬碟容易壞掉！ 下次千萬不要再這樣做囉！

PCI介面卡

PCI介面卡的插槽就如同圖2.1.3、技嘉主機板示意圖所示的左下方那個白色的插槽， 這種PCI插槽通常會提供多個給使用者，如果使用者有額外需要的功能卡， 就能夠安插在這種PCI介面插槽上。

我們在前面顯示卡的部分稍微談過PCI介面，事實上有相當多的元件是使用PCI介面作為傳輸的， 例如網路卡、音效卡、特殊功能卡等等。但由於PCI Express規格的發展，很多製造商都往PCIe介面開發硬體了。 不過還是有很多硬體使用PCI介面啦，例如大賣場上面常見的網路卡就是一個。

目前在個人電腦上面常見到的網路卡是一種稱為乙太網路(Ethernet)的規格，目前乙太網路卡速度輕輕鬆鬆的就能到達10/100/1000 Mbits/second的速度，但同樣速度的乙太網路卡所支援的標準可能不太一樣，因此造成的價差是非常大的。 如果想要在伺服器主機上面安裝新的網路卡時，得要特別注意標準的差異呢！

由於各元件的價格直直落，現在主機板上面通常已經整合了相當多的設備元件了！ 常見整合到主機板的元件包括音效卡、網路卡、USB控制卡、顯示卡、磁碟陣列卡等等。 你可以在主機板上面發現很多方形的晶片，那通常是一些個別的設備晶片喔。 由於主機板已經整合了很多常用的功能晶片，所以現在的主機板上面所安插的PCI介面卡就少很多了！

主機板

主機板可以說是整部主機相當重要的一個部分，因為上面我們所談到的所有元件都是安插在主機板上面的呢！ 而主機板上面負責溝通各個元件的就是晶片組，如同圖2.1.1、Intel晶片組圖示所示， 圖中我們也可以發現晶片組一般分為北橋與南橋喔！北橋負責CPU/RAM/VGA等的連接，南橋則負責PCI介面與速度較慢的I/O裝置。

由於晶片組負責所有設備的溝通，所以事實上晶片組(尤其是北橋)也是一個可能會散發出高熱量的元件。 因此在主機板上面常會發現一些外接的小風扇或者是散熱片在這組晶片上面。在本章所附的主機板圖示中， 技嘉使用較高散熱能力的熱導管技術，因此你可以發現圖中的南橋與北橋上面覆蓋著黃銅色的散熱片， 且連接著數根圓形導管，主要就是為了要散熱的。

- 晶片組功能

所有的晶片組幾乎都是參考CPU的能力去規劃的，而CPU能夠接受的主記憶體規格也不相同，因此在新購買或升級主機時，CPU、主機板、主記憶體與相關的周邊設備都需要同時考慮才行 ！此外，每一種晶片組的功能可能都不太相同， 有的晶片組強調的是全功能，因此連顯示卡、音效、網路等都整合了，在這樣的整合型晶片中， 你幾乎只要購買CPU、主機板、主記憶體再加上硬碟，就能夠組裝成一部主機了。不過整合型晶片的效能通常比較弱， 對於愛玩3D遊戲的玩家以及強調高效能運算的主機來說，就不是這麼適合了。

至於獨立型晶片組雖然可能具有較高的效能，不過你可能必須要額外負擔周邊設備的CoCo呢！ 例如顯示卡、網路卡、音效卡等等。但獨立型晶片組也有一定程度的好處，那就是你可以隨時抽換周邊設備。

- 設備I/O位址與IRQ中斷通道

主機板是負責各個電腦元件之間的溝通，但是電腦元件實在太多了，有輸出/輸入/不同的儲存裝置等等， 主機板晶片組怎麼知道如何負責溝通吶？這個時候就需要用到所謂的I/O位址與IRQ囉！

I/O位址有點類似每個裝置的門牌號碼，每個裝置都有他自己的位址，一般來說，不能有兩個裝置使用同一個I/O位址， 否則系統就會不曉得該如何運作這兩個裝置了。而除了I/O位址之外，還有個IRQ中斷(Interrupt)這個咚咚。

如果I/O位址想成是各裝置的門牌號碼的話，那麼IRQ就可以想成是各個門牌連接到郵件中心(CPU)的專門路徑囉！ 各裝置可以透過IRQ中斷通道來告知CPU該裝置的工作情況，以方便CPU進行工作分配的任務。 老式的主機板晶片組IRQ只有15個，如果你的周邊介面太多時可能就會不夠用， 這個時候你可以選擇將一些沒有用到的周邊介面關掉，以空出一些IRQ來給真正需要使用的介面喔！ 當然，也有所謂的sharing IRQ的技術就是了！

- CMOS與BIOS

前面記憶體的地方我們有提過CMOS與BIOS的功能，在這裡我們再來強調一下： CMOS主要的功能為記錄主機板上面的重要參數， 包括系統時間、CPU電壓與頻率、各項設備的I/O位址與IRQ等，由於這些資料的記錄要花費電力，因此主機板上面才有電池。 BIOS為寫入到主機板上某一塊 flash 或 EEPROM 的程式，他可以在開機的時候執行，以載入CMOS當中的參數， 並嘗試呼叫儲存裝置中的開機程式，進一步進入作業系統當中。BIOS程式也可以修改CMOS中的資料， 每種主機板呼叫BIOS設定程式的按鍵都不同，一般桌上型電腦常見的是使用[del]按鍵進入BIOS設定畫面。

- 連接周邊設備的介面

主機板與各項輸出/輸入設備的連結主要都是在主機機殼的後方，主要有：

- PS/2介面：這是常見的鍵盤與滑鼠的介面，不過漸漸有被USB介面取代的趨勢；

- USB介面：目前相當流行的一個介面，支援隨插即用。 主流的USB版本為USB 2.0，這個規格的速度可達480Mbps，相對之下的USB 1.1僅達12Mbps差異很大，購買周邊設備要注意啊！ 不然copy一些資料到USB硬碟時，會吐血....

- 聲音輸出、輸入與麥克風：這個是一些圓形的插孔， 而必須你的主機板上面有內建音效晶片時，才會有這三個東西；

- RJ-45網路頭：如果有內建網路晶片的話，那麼就會有這種接頭出現。 這種接頭有點類似電話接頭，不過內部有八蕊線喔！接上網路線後在這個接頭上會有燈號亮起才對！

- 其他過時介面：包括早期的用來連結滑鼠的九針序列埠(com1)，以及連結印表機的25針並列埠(LPT1)等等。

我們以技嘉主機板的連結介面來看的話，主要有這些：

圖2.6.1、連接周邊介面

電源供應器

除了上面這些元件之外，其實還有一個很重要的元件也要來談一談，那就是電源供應器(Power)。 在你的機殼內，有個大大的鐵盒子，上頭有很多電源線會跑出來，那就是電源供應器了。 我們的CPU/RAM/主機板/硬碟等等都需要用電，而近來的電腦元件耗電量越來越高，以前很古早的230W電源已經不夠用了， 有的系統甚至得要有500W以上的電源才能夠運作∼真可怕∼

電源供應器的價差非常大！貴一點的300W可以到4000 NT，便宜一點的300W只要500 NT不到！ 怎麼差這麼多？沒錯∼因為Power的用料不同，電源供應的穩定度也會差很多。如前所述，電源供應器相當於你的心臟， 心臟差的話，活動力就會不足了！所以， 穩定度差的電源供應器甚至是造成電腦不穩定的元兇呢！所以，盡量不要使用太差的電源供應器喔！

- 能源轉換率

電源供應器本身也會吃掉一部份的電力的！如果你的主機系統需要 300W 的電力時，因為電源供應器本身也會消耗掉一部份的電力， 因此你最好要挑選400W以上的電源供應器。電源供應器出廠前會有一些測試數據，最好挑選高轉換率的電源供應器。 所謂的高轉換率指的是『輸出的功率/輸入的功率』。意思是說，假如你的主機板用電量為250W， 但是電源供應器其實已經使用掉320W的電力，則轉換率為：250/320=0.78的意思。 這個數值越高表示被電源供應器『玩掉』的電力越少，那就符合能源效益了！^_^

- 連接介面

目前主機板與電源供應器的連接介面主要有20pin與24pin兩種規格，購買時也需要考慮你的主機板所需要的規格喔！

選購須知

在購買主機時應該需要進行整體的考量，很難依照某一項標準來選購的。 老實說，如果你的公司需要一部伺服器的話，建議不要自行組裝，買品牌電腦的伺服器比較好！ 這是因為自行組裝的電腦雖然比較便宜，但是每項設備之間的適合性是否完美則有待自行檢測。

另外，在效能方面並非僅考量CPU的能力而已，速度的快慢與『整體系統的最慢的那個設備有關！』，如果你是使用最快速的Intel Core 2 Duo，使用最快的DDR II記憶體， 但是配上一個慢慢的過時顯示卡，那麼整體的3D速度效能將會卡在那個顯示卡上面喔！所以，在購買整套系統時， 請特別留意需要全部的介面都考慮進去喔！尤其是當您想要升級時，要特別注意這個問題， 並非所有的舊的設備都適合繼續使用的。

- 系統不穩定的可能原因

除此之外，到底那個元件特別容易造成系統的不穩定呢？有幾個常見的系統不穩定的狀態是：

- 系統超頻：這個行為很不好！不要這麼做！

- 電源供應器不穩： 這也是個很嚴重的問題，當您測試完所有的元件都沒有啥大問題時，記得測試一下電源供應器的穩定度！

- 記憶體無法負荷：現在的記憶體品質差很多，差一點的記憶體，可能會造成您的主機在忙碌的工作時， 產生不穩定或當機的現象喔！

- 系統過熱：『熱』是造成電子零件運作不良的主因之一，如果您的主機在夏天容易當機， 冬天卻還好，那麼考慮一下加幾個風扇吧！有助於機殼內的散熱，系統會比較穩定喔！ 『 這個問題也是很常見的系統當機的元凶！』(鳥哥之前的一台伺服器老是容易當機， 後來拆開機殼研究後才發現原來是北橋上面的小風扇壞掉了，導致北橋溫度太高。後來換掉風扇就穩定多了。)

Tips:

事實上，要瞭解每個硬體的詳細架構與構造是很難的！這裡鳥哥僅是列出一些比較基本的概念而已。 另外，要知道某個硬體的製造商是哪間公司時，可以看該硬體上面的資訊。 舉例來說，主機板上面都會列出這個主機板的開發商與主機板的型號，知道這兩個資訊就可以找到驅動程式了。 另外，顯示卡上面有個小小的晶片，上面也會列出顯示卡廠商與晶片資訊喔。

資料表示方式

事實上我們的電腦只認識0與1，記錄的資料也是只能記錄0與1而已，所以電腦常用的資料是二進位的。 但是我們人類常用的數值運算是十進位，文字方面則有非常多的語言，台灣常用的語言就有英文、中文(又分正體與簡體中文)、日文等。 那麼電腦如何記錄與顯示這些數值/文字呢？就得要透過一系列的轉換才可以啦！底下我們就來談談數值與文字的編碼系統囉！

數字系統

早期的電腦使用的是利用通電與否的特性的真空管，如果通電就是1，沒有通電就是0， 後來沿用至今，我們稱這種只有0/1的環境為二進位制，英文稱為binary的哩。所謂的十進位指的是逢十進一位， 因此在個位數歸為零而十位數寫成1。所以所謂的二進位，就是逢二就前進一位的意思。

那二進位怎麼用呢？我們先以十進位來解釋好了。如果以十進位來說，3456的意義為：

3456 = 3x10^3 + 4x10^2 + 5x10^1 + 6x10^0

特別注意：『任何數值的零次方為1』所以10^0的結果就是1囉。 同樣的，將這個原理帶入二進位的環境中，我們來解釋一下1101010的數值轉為十進位的話，結果如下：

1101010=1x2^6 + 1x2^5 + 0x2^4 + 1x2^3 + 0x2^2 + 1x2^1 + 0x2^0

= 64 + 32 + 0x16 + 8 + 0x4 + 2 + 0x1 = 106

這樣你瞭解二進位的意義了嗎？二進位是電腦基礎中的基礎喔！瞭解了二進位後，八進位、十六進位就依此類推啦！ 那麼知道二進位轉成十進位後，那如果有十進位數值轉為二進位的環境時，該如何計算？ 剛剛是乘法，現在則是除法就對了！我們同樣的使用十進位的106轉成二進位來測試一下好了：

圖3.1.1、十進位轉二進位的方法

最後的寫法就如同上面的紅色箭頭，由最後的數字向上寫，因此可得到1101010的數字囉！ 這些數字的轉換系統是非常重要的，因為電腦的加減乘除都是使用這些機制來處理的！ 有興趣的朋友可以再參考一下其他計算計概論的書籍中，關於1的補數/2的補數等運算方式喔！

文字編碼系統

既然電腦都只有記錄0/1而已，甚至記錄的資料都是使用byte/bit等單位來記錄的，那麼文字該如何記錄啊？ 事實上文字檔案也是被記錄為0與1而已，而這個檔案的內容要被取出來查閱時，必須要經過一個編碼系統的處理才行。 所謂的『編碼系統』可以想成是一個『字碼對照表』，他的概念有點像底下的圖示：

圖3.2.1、資料參考編碼表的示意圖

當我們要寫入檔案的文字資料時，該文字資料會由編碼對照表將該文字轉成數字後，再存入檔案當中。 同樣的，當我們要將檔案內容的資料讀出時，也會經過編碼對照表將該數字轉成對應的文字後，再顯示到螢幕上。 現在你知道為何瀏覽器上面如果編碼寫錯時，會出現亂碼了嗎？這是因為編碼對照表寫錯， 導致對照的文字產生誤差之故啦！

常用的英文編碼表為ASCII系統，這個編碼系統中， 每個符號(英文、數字或符號等)都會佔用1bytes的記錄， 因此總共會有2^8=256種變化。至於中文字當中的編碼系統目前最常用的就是big5這個編碼表了。 每個中文字會佔用2bytes，理論上最多可以有2^16=65536，亦即最多可達6萬多個中文字。 但是因為big5編碼系統並非將所有的位元都拿來運用成為對照，所以並非可達這麼多的中文字碼的。 目前big5僅定義了一萬三千多個中文字，很多中文利用big5是無法成功顯示的∼所以才會有造字程式說。

big5碼的中文字編碼對於某些資料庫系統來說是很有問題的，某些字碼例如『許、蓋、功』等字， 由於這幾個字的內部編碼會被誤判為單/雙引號，在寫入還不成問題，在讀出資料的對照表時， 常常就會變成亂碼。不只中文字，其他非英語系國家也常常會有這樣的問題出現啊！

為了解決這個問題，由國際組織ISO/IEC跳出來制訂了所謂的Unicode編碼系統， 我們常常稱呼的UTF8或萬國碼的編碼就是這個咚咚。因為這個編碼系統打破了所有國家的不同編碼， 因此目前網際網路社會大多朝向這個編碼系統在走，所以各位親愛的朋友啊，記得將你的編碼系統修訂一下喔！

軟體程式運作

鳥哥在上課時常常會開玩笑的問：『我們知道沒有插電的電腦是一堆廢鐵，那麼插了電的電腦是什麼？』 答案是：『一堆會電人的廢鐵』！這是因為沒有軟體的運作，電腦的功能就無從發揮之故。 就好像沒有了靈魂的軀體也不過就是行屍走肉，重點在於軟體/靈魂囉！所以底下咱們就得要瞭解一下『軟體』是什麼。

一般來說，目前的電腦系統將軟體分為兩大類，一個是系統軟體，一個是應用程式。但鳥哥認為我們還是得要瞭解一下什麼是程式， 尤其是機器程式，瞭解了之後再來探討一下為什麼現今的電腦系統需要『作業系統』這玩意兒呢！

機器程式與編譯程式

我們前面談到電腦只認識0與1而已，而且電腦最重要的運算與邏輯判斷是在CPU內部， 而CPU其實是具有微指令集的。因此，我們需要CPU幫忙工作時，就得要參考微指令集的內容， 然後撰寫讓CPU讀的懂得指令碼給CPU執行，這樣就能夠讓CPU運作了。

不過這樣的流程有幾個很麻煩的地方，包括：

- 需要瞭解機器語言：機器只認識0與1，因此你必須要學習直接寫給機器看的語言！ 這個地方相當的難呢！

- 需要瞭解所有硬體的相關功能函數：因為你的程式必須要寫給機器看， 當然你就得要參考機器本身的功能，然後針對該功能去撰寫程式碼。例如，你要讓DVD影片能夠放映， 那就得要參考DVD光碟機的硬體資訊才行。萬一你的系統有比較冷門的硬體，光是參考技術手冊可能會昏倒∼

- 程式不具有可攜性：每個CPU都有獨特的微指令集，同樣的，每個硬體都有其功能函數。 因此，你為A電腦寫的程式，理論上是沒有辦法在B電腦上面運作的！而且程式碼的修改非常困難！ 因為是機器碼，並不是人類看的懂得程式語言啊！

- 程式具有專一性：因為這樣的程式必須要針對硬體功能函數來撰寫， 如果已經開發了一支瀏覽器程式，想要再開發檔案管理程式時，還是得從頭再參考硬體的功能函數來繼續撰寫， 每天都在和『硬體』挑戰！可能需要天天喝蠻牛了！@_@

那怎麼解決啊？為了解決這個問題，電腦科學家設計出一種讓人類看的懂得程式語言， 然後創造一種『編譯器』來將這些人類能夠寫的程式語言轉譯成為機器能看懂得機器碼， 如此一來我們修改與撰寫程式就變的容易多了！目前常見的編譯器有C, C++, Java, Fortran等等。 機器語言與高階程式語言的差別如下所示：

圖4.1.1、編譯器的角色

從上面的圖示我們可以看到高階程式語言的程式碼是很容易察看的！鳥哥已經將程式碼(英文)寫成中文說∼ 這樣比較好理解啦！所以這樣已經將程式的修改問題處理完畢了。 問題是，在這樣的環境底下我們還是得要考量整體的硬體系統來設計程式喔！

舉例來說，當你需要將運作的資料寫入記憶體中，你就得要自行分配一個記憶體區塊出來讓自己的資料能夠填上去， 所以你還得要瞭解到記憶體的位址是如何定位的，啊！眼淚還是不知不覺的流了下來... 怎麼寫程式這麼麻煩啊！

為了要克服硬體方面老是需要重複撰寫控制碼的問題，所以就有作業系統(Operating System, OS)的出現了！ 什麼是作業系統呢？底下就來談一談先！

作業系統

如同前面提到的，在早期想要讓電腦執行程式就得要參考一堆硬體功能函數，並且學習機器語言才能夠撰寫程式。 同時每次寫程式時都必須要重新改寫，因為硬體與軟體功能不見得都一致之故。那如果我能夠將所有的硬體都驅動， 並且提供一個發展軟體的參考介面來給工程師開發軟體的話，那發展軟體不就變的非常的簡單了？那就是作業系統啦！

- 作業系統核心(Kernel)

作業系統(Operating System, OS)其實也是一組程式， 這組程式的重點在於管理電腦的所有活動以及驅動系統中的所有硬體。 我們剛剛談到電腦沒有軟體只是一堆廢鐵，那麼作業系統的功能就是讓CPU可以開始判斷邏輯與運算數值、 讓主記憶體可以開始載入/讀出資料與程式碼、讓硬碟可以開始被存取、讓網路卡可以開始傳輸資料、 讓所有周邊可以開始運轉等等。總之，硬體的所有動作都必須要透過這個作業系統來達成就是了。

上述的功能就是作業系統的核心(Kernel)了！你的電腦能不能做到某些事情，都與核心有關！ 只有核心有提供的功能，你的電腦系統才能幫你完成！舉例來說，你的核心並不支援TCP/IP的網路協定， 那麼無論你購買了什麼樣的網卡，這個核心都無法提供網路能力的！

但是單有核心我們使用者也不知道能作啥事的∼因為核心主要在管控硬體與提供相關的能力(例如網路功能)， 這些管理的動作是非常的重要的，如果使用者能夠直接使用到核心的話，萬一使用者不小心將核心程式停止或破壞， 將會導致整個系統的崩潰！因此核心程式所放置到記憶體當中的區塊是受保護的！ 並且開機後就一直常駐在記憶體當中。

Tips:

所以整部系統只有核心的話，我們就只能看著已經準備好運作(Ready)的電腦系統，但無法操作他！ 好像有點望梅止渴的那種感覺啦！這個時候就需要軟體的幫忙了！

- 系統呼叫(System Call)

既然我的硬體都是由核心管理，那麼如果我想要開發軟體的話，自然就得要去參考這個核心的相關功能！ 唔！如此一來不是從原本的參考硬體函數變成參考核心功能，還是很麻煩啊！有沒有更簡單的方法啊！

為了解決這個問題，作業系統通常會提供一整組的開發介面給工程師來開發軟體！ 工程師只要遵守該開發介面那就很容易開發軟體了！舉例來說，我們學習C程式語言只要參考C程式語言的函式即可， 不需要再去考量其他核心的相關功能，因為核心的系統呼叫介面會主動的將C程式語言的相關語法轉成核心可以瞭解的任務函數， 那核心自然就能夠順利運作該程式了！

如果我們將整個電腦系統的相關軟/硬體繪製成圖的話，他的關係有點像這樣：

圖4.2.1、作業系統的角色

電腦系統主要由硬體構成，然後核心程式主要在管理硬體，提供合理的電腦系統資源分配(包括CPU資源、記憶體使用資源等等)， 因此只要硬體不同(如x86架構與RISC架構的CPU)，核心就得要進行修改才行。 而由於核心只會進行電腦系統的資源分配，所以在上頭還需要有應用程式的提供，使用者才能夠操作系統的。

為了保護核心，並且讓程式設計師比較容易開發軟體，因此作業系統除了核心程式之外，通常還會提供一整組開發介面， 那就是系統呼叫層。軟體開發工程師只要遵循公認的系統呼叫參數來開發軟體，該軟體就能夠在該核心上頭運作。 所以你可以發現，軟體與核心有比較大的關係，與硬體關係則不大！硬體也與核心有比較大的關係！ 至於與使用者有關的，那就是應用程式啦！

Tips:

在定義上，只要能夠讓電腦硬體正確無誤的運作，那就算是作業系統了。所以說， 作業系統其實就是核心與其提供的介面工具，不過就如同上面講的，因為最陽春的核心缺乏了與使用者溝通的親和介面， 所以在目前，一般我們提到的『作業系統』都會包含核心與相關的使用者應用軟體呢！

簡單的說，上面的圖示可以帶給我們底下的概念：

- 作業系統的核心層直接參考硬體規格寫成， 所以同一個作業系統程式不能夠在不一樣的硬體架構下運作。舉例來說，個人電腦版的Windows XP不能直接在RISC架構的電腦下運作。 所以您知道為何Windows XP又分為32位元及64位元的版本了吧？因為32/64位元的CPU指令集不太相同， 所以當然要設計不同的作業系統版本了。

- 作業系統只是在管理整個硬體資源，包括CPU、記憶體、輸入輸出裝置及檔案系統檔。 如果沒有其他的應用程式輔助，作業系統只能讓電腦主機準備妥當(Ready)而已！並無法運作其他功能。 所以你現在知道為何Windows XP上面要達成網頁影像的運作還需要類似PhotoImpact或Photoshop之類的軟體安裝了吧？

- 應用程式的開發都是參考作業系統提供的開發介面， 所以該應用程式只能在該作業系統上面運作而已，不可以在其他作業系統上面運作的。 現在您知道為何去購買線上遊戲的光碟時，光碟上面會明明白白的寫著該軟體適合用於哪一種作業系統上了吧？ 也該知道某些遊戲為何不能夠在Linux上面安裝了吧？

- 核心功能

既然核心主要是在負責整個電腦系統相關的資源分配與管理，那我們知道其實整部電腦系統最重要的就是CPU與主記憶體， 因此，核心至少也要有這些功能的：

- 系統呼叫介面(System call interface)

剛剛談過了，這是為了方便程式開發者可以輕易的透過與核心的溝通，將硬體的資源進一步的利用， 於是需要有這個簡易的介面來方便程式開發者。

- 程序管理(Process control)

總有聽過所謂的『多工環境』吧？一部電腦可能同時間有很多的工作跑到CPU等待運算處理， 核心這個時候必須要能夠控制這些工作，讓CPU的資源作有效的分配才行！另外， 良好的CPU排程機制(就是CPU先運作那個工作的排列順序)將會有效的加快整體系統效能呢！

- 記憶體管理(Memory management)

控制整個系統的記憶體管理，這個記憶體控制是非常重要的，因為系統所有的程式碼與資料都必須要先存放在記憶體當中。 通常核心會提供虛擬記憶體的功能，當記憶體不足時可以提供記憶體置換(swap)的功能哩。

- 檔案系統管理(Filesystem management)

檔案系統的管理，例如資料的輸入輸出(I/O)等等的工作啦！還有不同檔案格式的支援啦等等， 如果你的核心不認識某個檔案系統，那麼您將無法使用該檔案格式的檔案囉！例如：Windows 98就不認識NTFS檔案格式的硬碟；

- 裝置的驅動(Device drivers)

就如同上面提到的，硬體的管理是核心的主要工作之一，當然囉，裝置的驅動程式就是核心需要做的事情啦！ 好在目前都有所謂的『可載入模組』功能，可以將驅動程式編輯成模組，就不需要重新的編譯核心啦！ 這個也會在後續的第二十章當中提到的！

Tips:

事實上，驅動程式的提供應該是硬體廠商的事情！硬體廠商要推出硬體時，應該要自行參考作業系統的驅動程式開發介面， 開發完畢後將該驅動程式連同硬體一同販賣給使用者才對！舉例來說，當你購買顯示卡時， 顯示卡包裝盒都會附上一片光碟，讓你可以在進入Windows之後進行驅動程式的安裝啊！

- 作業系統與驅動程式

老實說，驅動程式可以說是作業系統裡面相當重要的一環了！不過，硬體可是持續在進步當中的！ 包括主機板、顯示卡、硬碟等等。那麼比較晚推出的較新的硬體，例如顯示卡，我們的作業系統當然就不認識囉！ 那作業系統該如何驅動這塊新的顯示卡？為了克服這個問題，作業系統通常會提供一個開發介面給硬體開發商， 讓他們可以根據這個介面設計可以驅動他們硬體的『驅動程式』，如此一來，只要使用者安裝驅動程式後， 自然就可以在他們的作業系統上面驅動這塊顯示卡了。

圖4.2.2、驅動程式與作業系統的關係

由上圖我們可以得到幾個小重點：

- 作業系統必須要能夠驅動硬體，如此應用程式才能夠使用該硬體功能；

- 一般來說，作業系統會提供開發介面，讓開發商製作他們的驅動程式；

- 要使用新硬體功能，必須要安裝廠商提供的驅動程式才行；

- 驅動程式是由廠商提供的，與作業系統開發者無關。

所以，如果妳想要在某個作業系統上面安裝一張新的顯示卡，那麼請要求該硬體廠商提供適當的驅動程式吧！ ^_^！ 為什麼要強調『適當的驅動程式』呢？ 因為驅動程式仍然是依據作業系統而開發的， 所以，給Windows用的驅動程式當然不能使用於Linux的環境下了。

應用程式

應用程式是參考作業系統提供的開發介面所開發出來軟體，這些軟體可以讓使用者操作，以達到某些電腦的功能利用。 舉例來說，辦公室軟體(Office)主要是用來讓使用者辦公用的；影像處理軟體主要是讓使用者用來處理影音資料的； 瀏覽器軟體主要是讓使用者用來上網瀏覽用的等等。

需要注意的是，應用程式是與作業系統有關係的，如同上面的圖示當中的說明喔。因此，如果你想要購買新軟體， 請務必參考軟體上面的說明，看看該軟體是否能夠支援你的作業系統啊！舉例來說，如果你想要購買線上遊戲光碟， 務必參考一下該光碟是否支援你的作業系統，例如是否支援Windows XP/Windows Vista/MAC/Linux等等。 不要購買了才發現該軟體無法安裝在你的作業系統上喔！

我們拿常見的微軟公司的產品來說明。妳知道Windows XP, Office 2007之間的關係了嗎？

- Windows XP是一套作業系統，他必須先安裝到個人電腦上面，否則電腦無法開機運作；

- Windows 98與Windows XP是兩套不同的作業系統，所以能在Win 98上安裝的軟體不見得可在WinXP上安裝；

- Windows XP安裝好後，就只能擁有很少的功能，並沒有辦公室軟體；

- Office 2007是一套應用程式，要安裝前必須要瞭解他能在哪些作業系統上面運作。

重點回顧

- 計算機的定義為：『接受使用者輸入指令與資料，經由中央處理器的數學與邏輯單元運算處理後，以產生或儲存成有用的資訊』；

- 電腦的五大單元包括：輸入單元、 輸出單元、CPU內部的控制單元、算數邏輯單元與主記憶體五大部分；

- 資料會流進/流出記憶體是CPU所發佈的控制命令，而CPU實際要處理的資料則完全來自於主記憶體；

- CPU依設計理念主要分為：精簡指令集(RISC)與複雜指令集(CISC)系統；

- 關於CPU的時脈部分：外頻指的是CPU與外部元件進行資料傳輸時的速度，倍頻則是CPU內部用來加速工作效能的一個倍數， 兩者相乘才是CPU的時脈速度；

- 一般主機板晶片組有分北橋與南橋，北橋的匯流排稱為系統匯流排，因為是記憶體傳輸的主要通道，所以速度較快。 南橋就是所謂的輸入輸出(I/O)匯流排，主要在聯繫硬碟、USB、網路卡等周邊設備；

- 北橋所支援的頻率我們稱為前端匯流排速度(Front Side Bus, FSB)，而每次傳送的位元數則是匯流排寬度。

- CPU每次能夠處理的資料量稱為字組大小(word size)，字組大小依據CPU的設計而有32位元與64位元。 我們現在所稱的電腦是32或64位元主要是依據這個 CPU解析的字組大小而來的！

- 個人電腦的主記憶體主要元件為動態隨機存取記憶體(Dynamic Random Access Memory, DRAM)， 至於CPU內部的第二層快取則使用靜態隨機存取記憶體(Static Random Access Memory, SRAM)；

- BIOS(Basic Input Output System)是一套程式，這套程式是寫死到主機板上面的一個記憶體晶片中， 這個記憶體晶片在沒有通電時也能夠將資料記錄下來，那就是唯讀記憶體(Read Only Memory, ROM)；

- 顯示卡的規格有PCI/AGP/PCIe，目前的主流為PCIe介面；

- 硬碟的組成為：圓形磁碟盤、機械手臂、 磁碟讀取頭與主軸馬達所組成的，其中磁碟盤的組成為磁區、磁軌與磁柱；

- 作業系統(Operating System, OS)其實也是一組程式， 這組程式的重點在於管理電腦的所有活動以及驅動系統中的所有硬體。

- 電腦主要以二進位作為單位，常用的磁碟容量單位為bytes，其單位換算為1 Byte = 8bits。

- 最陽春的作業系統僅在驅動與管理硬體，而要使用硬體時，就得需要透過應用軟體或者是殼程式(shell)的功能， 來呼叫作業系統操縱硬體工作。目前稱為作業系統的，除了上述功能外，通常已經包含了日常工作所需要的應用軟體在內了。

本章習題

- 動動手實作題：假設你不知道你的主機內部的各項元件資料，請拆開你的主機機殼，並將內部所有的元件拆開，並且依序列出：

- CPU的廠牌、型號、最高時脈；

- 主記憶體的容量、介面 (DDR/DDR II等)；

- 顯示卡的介面 (AGP/PCIe/內建) 與容量

- 主機板的廠牌、南北橋的晶片型號、BIOS的廠牌、有無內建的網卡或音效卡等

- 硬碟的連接介面 (IDE/SATA等)、硬碟容量、轉速、緩衝記憶體容量等。

然後再將他組裝回去。注意，拆裝前務必先取得你主機板的說明書，因此你可能必須要上網查詢上述的各項資料。

- 利用軟體：假設你不想要拆開主機機殼，但想瞭解你的主機內部各元件的資訊時，該如何是好？ 如果使用的是Windows作業系統，可使用CPU-Z(http://www.cpuid.com/cpuz.php)這套軟體，如果是Linux環境下，可以使用『cat /proc/cpuinfo』 及使用『lspci』來查閱各項元件的型號；

- 依據文末的延伸閱讀連結，自行搜尋出 BIOS 的主要任務，以及目前在個人電腦上面常見的 BIOS 製造商有哪幾家？

參考資料與延伸閱讀

- 註1：對於CPU的原理有興趣的讀者，可以參考維基百科的說明：

英文CPU(http://en.wikipedia.org/wiki/CPU)

中文CPU(http://zh.wikipedia.org/wiki/中央處理器)。

- 註2：圖片參考：作者：陳錦輝，『計算機概論-探索未來2008』，金禾資訊，2007出版

- 註3：更詳細的RISC架構可以參考維基百科：

http://zh.wikipedia.org/w/index.php?title=精簡指令集&variant=zh-tw

- 註4：關於ARM架構的說明，可以參考維基百科：

http://zh.wikipedia.org/w/index.php?title=ARM架構&variant=zh-tw

- 註5：更詳細的CISC架構可參考維基百科：

http://zh.wikipedia.org/w/index.php?title=CISC&variant=zh-tw

- 註6：更詳細的x86架構發展史可以參考維基百科：

http://zh.wikipedia.org/w/index.php?title=X86&variant=zh-tw

- 註7：相關的韌體說明可參考維基百科：

http://zh.wikipedia.org/w/index.php?title=韌體&variant=zh-hant

- 註8：相關 EEPROM 可以參考維基百科：

http://zh.wikipedia.org/w/index.php?title=EEPROM&variant=zh-tw

- 註9：相關 BIOS 的說明可以參考維基百科：

http://zh.wikipedia.org/w/index.php?title=BIOS&variant=zh-tw

- 感謝：本章當中出現很多圖示，很多是從Tom's Hardware(http://www.tomshardware.tw/)網站取得的，在此特別感謝！

2008/07/22：利用暑假期間足足寫了快要兩個星期這篇才寫完！好多圖示都不知道如何呈現比較漂亮∼@_@

2008/07/29：又加入了SATA/IDE的連線排線，還有一些額外的圖示。

2009/08/03：加入電源供應器是心臟一詞的說明

2009/08/03：更正原本 BIOS 只放於 ROM 的資料，新的 BIOS 通常放於 EEPROM 或 Flash 記憶體中。

2010/10/19：感謝討論區網友 186003415a 兄的回報，發現 DDR II 的外頻寫錯了！是 200MHz 才對喔！

2008/07/22以來統計人數

第二章、 Linux 如何學習

切換解析度為 800x600

最近更新日期：2009/08/06

目前Linux上頭有兩種主要的操作模式，分別是圖形介面與文字介面，那麼學習Linux要用X-Window(圖形介面)好還是Command Line(文字介面)好？這兩種學習心態有什麼優缺點呢？此外，有沒有良好的入門文件可供參考？ Linux學習有困擾的時候應該要如何發問？要到哪裡去搜尋網路資源？還有，怎樣進行有智慧的提問？嗯！ 在這一章裡面，就讓我們好好談一談！

1. Linux當前的應用角色

1.1 企業環境的利用

1.2 個人環境的使用

2. 鳥哥的Linux苦難經驗全都錄

2.1 鳥哥的Linux學習之路

2.2 學習心態的分別

2.3 X window的學習

3. 有心朝Linux作業系統學習者的學習態度

3.1 從頭學習Linux基礎

3.2 選擇一本易讀的工具書

3.3 實作再實作

3.4 發生問題怎麼處理啊？建議流程是這樣...

4. 鳥哥的建議(重點在solution的學習)

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23872

Linux當前的應用角色

在第一章Linux是什麼當中，我們談到了Linux相關的歷史， 與簡單的介紹了一下Linux這個『Kernel』與Linux distributions等等。 而在開始進入Linux的基礎學習之前，我們有必要瞭解一下應該要如何有效的學習Linux！ 但在談到Linux如何學習之前，我們得就Linux目前的一般應用來說明一下，因為每種應用你所需要的Linux技能都不相同！ 瞭解Linux的應用後，你才好理解你需要的是什麼樣的學習方式！

由於Linux kernel實在是非常的小巧精緻，可以在很多強調省電以及較低硬體資源的環境底下執行； 此外，由於Linux distributions整合了非常多非常棒的軟體(不論是專利軟體或自由軟體)， 因此也相當適合目前個人電腦的使用呢！當前的Linux常見的應用可約略分為企業應用與個人應用兩方面來說：

企業環境的利用

企業對於數位化的目標在於提供消費者或員工一些產品方面的資訊 (例如網頁介紹)，以及整合整個企業內部的資料統一性 (例如統一的帳號管理/文件管理系統等)。另外，某些企業例如金融業等，則強調在資料庫、安全強化等重大關鍵應用。 學術單位則很需要強大的運算能力等。所以企業環境運用Linux作些什麼呢？

- 網路伺服器：

這是Linux當前最熱門的應用了！ 承襲了Unix高穩定性的良好傳統，Linux上面的網路功能特別的穩定與強大！ 此外，由於GNU計畫與Linux的GPL授權模式，讓很多優秀的軟體都在Linux上面發展， 且這些在Linux上面的伺服器軟體幾乎都是自由軟體！因此，做為一部網路伺服器，例如WWW, Mail Server, File Server等等，Linux絕對是上上之選！當然，這也是Linux的強項！ 目前很多硬體廠商甚至搭配自家的硬體來銷售Linux呢！例如底下的連結看看先：

- HP公司的產品：http://h18000.www1.hp.com/products/servers/byos/linuxservers.html

- IBM公司的產品：http://www-07.ibm.com/systems/tw/power/

- 關鍵任務的應用(金融資料庫、大型企業網管環境)：

由於個人電腦的效能大幅提昇且價格便宜，所以金融業與大型企業的環境為了要精實自己機房的機器設備， 因此很多企業漸漸的走向Intel相容的x86主機環境。而這些企業所使用的軟體大多使用Unix作業系統平台的軟體， 總不能連過去發展的軟體都一口氣全部換掉吧！所以囉， 這個時候符合Unix作業系統標準並且可以在x86上運作的Linux就漸漸嶄露頭角了！^_^

目前很多金融業界都已經使用Linux做為他們的關鍵任務應用。所謂的關鍵任務就是該企業最重要的業務啦！ 舉例來說，金融業最重要的就是那些投資者、帳戶的資料了，這些資料大多使用資料庫系統來作為存取介面， 這些資料很重要吧！很多金融業將這麼重要的任務交給了Linux了！你說Linux厲不厲害啊？(註1)

- 學術機構的高效能運算任務：

學術機構的研究常常需要自行開發軟體，所以對於可作為開發環境的作業系統需求非常的迫切！舉例來說， 非常多技職體系的科技大學就很需要這方面的環境，好進行一些畢業專題的製作呢！ 又例如工程界流體力學的數值模式運算、娛樂事業的特效功能處理、軟體開發者的工作平台等等。 由於Linux的創造者本身就是個電腦性能癖，所以Linux有強大的運算能力；並且Linux具有支援度相當廣泛的GCC編譯軟體， 因此Linux在這方面的優勢可是相當明顯的！

舉個鳥哥自己的案例好了，鳥哥之前待的研究室有跑一套空氣品質模式的數值模擬軟體。 這套軟體原本只能在Sun的SPARC機器上面跑。後來該軟體轉向Linux作業系統平台發展， 鳥哥也將自己實驗室的數值模式程式由Sun的Solaris平台移植到Linux上面呢！ 據美國環保署內部人員的測試，發現Linux平台的整體硬體費用不但比較便宜(x86系統嘛！)而且速度還比較快呢！

另外，為了加強整體系統的效能，叢集電腦系統(Cluster)的平行運算能力在近年來一直被拿出來討論(註2)。 所謂的平行運算指的是『將原本的工作分成多份，然後交給多部主機去運算，最終再將結果收集起來』的一種方式。 由於透過高速網路使用到多部主機，將能夠讓原本需要很長運算時間的工作，大幅的降低等待的時間！ 例如中央氣象局的氣象預報就很需要這樣的系統來幫忙！而Linux作業系統則是這種架構下相當重要的一個環境平台呢！

Tips:

目前鳥哥所在的崑山科技大學資訊傳播系，我們系上就有一套由12部雙核心個人電腦組成的叢集電腦架構； 這一整組配備組起來差不多30萬左右，不過卻可以讓我們的數值模式大幅降低等待時間！這12部主機裝的就是Linux啦！

個人環境的使用

你知道你平時接觸的電子用品中，哪些咚咚裡面有Linux系統存在呢？其實相當的多呢！我們就來談一談吧！

- 桌上型電腦：

所謂的桌上型電腦，其實就是你我在辦公室使用的電腦啦。一般我們稱之為Desktop的系統。那麼這個 Desktop 的系統平時都在做什麼呢？大概都是這些工作吧：

- 上網瀏覽+即時通訊(MSN, Skype, Yahoo...)；

- 文書處理；

- 網路介面之公文處理系統；

- 辦公室軟體(Office Software)處理資料；

- 收發電子郵件；

想進行這些電腦工作時，你的Desktop環境需要什麼咚咚？很簡單，『就是需要視窗』！ 因為上網瀏覽、文書編排的所見即所得介面，以及電子公文系統等等， 如果沒有視窗介面的輔助，那麼將對使用者造成很大的困擾。而眾所皆知的， Linux早期都是由工程師所發展的，對於視窗介面並沒有很需要，所以造成Linux不太親和的印象。

好在，為了要強化桌上型電腦的使用率，Linux與X Window System結合了！ 要注意的是，X Window System僅只是Linux上面的一套軟體， 而不是核心喔！所以即使X Window掛了，對Linux也可能不會有直接的影響呢！ 更多關於 X window system 的詳細資訊我們留待第二十四章再來介紹。

近年來在各大社群的團結合作之下，Linux的視窗系統上面能夠跑的軟體實在是多的嚇人！而且也能夠應付的了企業的辦公環境！ 例如美觀的KDE與GNOME視窗介面，搭配可相容微軟Office的Open Office軟體， Open Office包含了文書處理、電子試算表、簡報軟體等等，功能齊全啊！然後配合功能強大速度又快的Firefox瀏覽器， 以及可下載信件的雷鳥(ThunderBird)軟體(類似微軟的Outlook Express)，還有可連上多種即時通訊的Pidgin！ Linux能夠做到企業所需要的各項功能啦！

- 手持系統(PDA、手機)：

別跟我說在台灣你沒有用過手機！你知道嗎，很多的手機、PDA、導航系統都可能使用的是Linux作業系統喔！ 而為了加強Linux作業系統在手機上面的統一標準，很多國際廠商合作了一個LiMo的計畫(Linux Mobile phone)，也有Linux的手機論壇，你可以參考一下底下的連結：

- LiMo基金會：http://www.limofoundation.org/

- Linux手機論壇：http://www.lipsforum.org/

除此之外，還有社群以及Google這個高超的傢伙也在玩Linux手機喔！例如底下的連結說明：

- OpenMoKo網站：http://www.openmoko.com/

- Google的手機平台：http://code.google.com/android/

瞭解了吧？在你天天碰的手機裡頭可能就含有Linux作業系統呢！很有趣的發現吧！ ^_^

- 嵌入式系統：

在第零章當中我們談到過硬體系統， 而要讓硬體系統順利的運作就得要撰寫合適的作業系統才行。那硬體系統除了我們常看到的電腦之外， 其實家電產品、PDA、手機、數位相機以及其他微型的電腦配備也是硬體系統啦！ 這些電腦配備也都是需要作業系統來控制的！而作業系統是直接嵌入於產品當中的，理論上你不應該會更動到這個作業系統， 所以就稱為嵌入式系統啦！

包括路由器、防火牆、手機、PDA、IP分享器、交換器、家電用品的微電腦控制器等等，都可以是Linux作業系統喔！ 酷學園內的Hoyo大大就曾經介紹過如何在嵌入式設備上面載入Linux！ 目前火紅的netbook中，很多也是使用Linux哩！

雖然嵌入式設備很多，大家也想要轉而使用Linux作業系統，不過在台灣，這方面的人才還是太少了！ 要玩嵌入式系統必須要很熟悉Linux Kernel與驅動程式的結合才行！這方面的學習可就不是那麼簡單喔！ ^_^

總之，網路伺服器、工作站電腦、桌上型電腦等等，就是Linux目前最常被應用的環境了。 而您如果想要針對桌上型電腦，或者是網路伺服器主機來學習的話，對於Linux， 您應該如何進行學習的課題呢？底下我們就來談一談。

鳥哥的Linux苦難經驗全都錄

為什麼鳥哥要先介紹Linux的應用，並且還要寫這一章『如何學習』呢？原因就是.....鳥哥曾經受過傷害啊！ 瞎密？什麼傷害呢？是要看外科還是精神科？都不是啦！因為鳥哥玩Linux初期曾經犯了『天下新手都可能容易犯的錯』∼@_@ 所以這裡才先要跟大家耳提面命一番嘛！

鳥哥的Linux學習之路

- 接觸Linux的原因

大約在1999年左右，鳥哥因為學業上的需要，『被迫』得去學習Unix系統，那個時候我們使用的Unix系統是Sun 的SPARC+Solaris作業系統，當時的Sun Unix可不是一般人玩的起的，鳥哥也是一般人，所以當然也就玩不起Sun Unix囉！ 然而學業上所需要完成的計畫案還是需要進行的，那怎麼辦呢？這個時候就得要想一些替代方案啦！

咦！聽說有另外一種可以在PC上頭跑的Unix-Like系統，叫做Linux的，他的介面、功能以及基本的檔案架構都跟Unix差不多， 甚至連系統穩定性也可以說是一模一樣，而且對於硬體配備的要求並不高。嗯！既然玩不起幾十萬起跳的Unix系統， 那麼使用一些即將淘汰的電腦配備來架設一部Linux主機吧！

在經過了一些時候的努力之後，呵呵！竟然真的給鳥哥架起來了(當時的版本是Red Hat 6.1)！哇！好高興！ 那麼就趕快先來熟悉他，然後等到有了一定的經驗值『升級』成老手級之後， 再來玩Unix吧， 以免玩壞了幾十萬的大電腦！嗯！這似乎是不錯的方式，所以就開始了鳥哥的Linux學習之路啦！

- 錯誤的學習方針階段

由於鳥哥之前連Unix是啥都沒聽過，當然就更別提Linux這套作業系統，更可怕的是，聽說Linux還需要使用到指令列模式！ 剛開始碰還真的有點緊張。還好，鳥哥玩電腦的歷史可以追溯之前的DOS年代，所以對於指令列模式多多少少還有點概念， 這過去的經驗或許應該可以撐上一陣子吧？但是沒想到Linux的指令真是『博大精深』吶！早期的DOS概念簡直就是不夠用啊∼ 因此，為了偷懶，一開始鳥哥就捨棄指令列模式，直接在X-Window上面玩起來了！

在還沒有安裝Linux之前，鳥哥就買了兩三本書，每本都看了N遍，發現到每一本書的前半段， 在Linux的基礎方面的介紹談的不多，了不起就是以一些工具教你如何設定一些很重要的參數檔案， 但偏偏沒有告訴你這些工具到底做了什麼事情或修改了哪些檔案？不過書的後半段卻放上了很多的架站文件， 然而卻都有點『點到為止』，所以當時總覺得Linux很有點朦朦朧朧的感覺， 而且在當時最嚴重的現象是『只要一出現問題，身為使用者的鳥哥完全無法解決， 所以只好選擇重新安裝，重新設定與書本教的內容完全一模一樣的環境！』不過，即使如此， 很多時候仍然解決不了發生問題的窘境！

Tips:

那個時候真的很好笑，由於鳥哥並非資訊科系出身，所以身旁並沒有懂電腦/作業系統的朋友，也就不知道怎麼發問！ 曾經為了要安裝光碟機裡面的資料，放進光碟機後，利用X Window的自動掛載將光碟掛載起來， 用完之後卻發現無法退出光碟機，最終竟然用迴紋針將光碟強制退片∼唔！這樣光碟就無法再使用∼@_@只好又重新開機....

在當時，由於知道Linux可以用來做為很多功能的伺服器，而鳥哥的研究室當時又需要一部電子郵件伺服器， 所以鳥哥就很高興的藉由書上的說明，配合Red Hat 6.1提供的一些工具程式，例如：Linuxconf, netcfg等等的工具來架設。 然而由於工具程式的整合度並不見得很好，所以常常修改一個小地方會搞上一整天！

好不容易使用了所有的知道的工具來架設好了鳥哥的電子郵件伺服器，哈哈！真高興， 請注意呦！這個時候鳥哥的Linux主機上面開了多少的ports/services其實當時的鳥哥並不清楚， 當時認為『俺的機器就只有我認識的一些朋友知道而已， 所以反正機器能跑就好了，其他的設定似乎也就不這麼重要』。

- 惡夢的開始.....

然而事實上，這種學習心態卻造成了後來鳥哥惡夢的開端！怎麼說呢？雖然Linux號稱需要的硬體等級不高， 不過X-Window卻是很耗系統資源的一項軟體，因為只要涉及到圖形介面的話，需要親和力嘛！就需要多一點RAM啦、 多一些硬碟空間啦、顯示卡與CPU要好一點啦等等的，且早期的圖形介面整合度不是很高，所以造成X-Window死掉的機會是很高的。

在鳥哥當時安裝的Linux主機當中，使用的是舊舊的電腦，系統的配備並不高，在跑了X-Window之後， 剩下可以使用的實體記憶體其實已經不多了，再跑其他的服務，例如mail server，實際上很有點吃力！ 所以當時的一些同仁常常抱怨我們的機器怎麼老是服務不良？怪怪！這個Linux怎麼跟『號稱穩定』的名號不符？ 而在鳥哥登入系統檢查之後，才發現，哇！X-Window又掛了？當時還不清楚原來可以使用ps及kill等指令將X-Window殺掉即可讓 Linux恢復正常，竟然是用reset的方式來重新啟動Linux，現在想起來，當時真糗....

後來再重新安裝一次，並選擇了文字介面登入系統，呵呵！果然系統是穩定多了！服務上面似乎也就安定了許多。 不過，你以為惡夢這樣就解決了嗎？當然不是！在鳥哥的機器服務了一陣子之後，我老闆竟然接到上層單位的來信， 信中說明『貴單位的主機可能有嘗試入侵國外主機之嫌，敬請妥善改善！』 哇！這不就是警告信嗎？還好不是律師存證信函∼當時至少還知道有所謂的系統登錄檔案可以分析確切日期有誰在線上， 沒想到一登入之後才發現，搞了老半天，原來我們的機器被入侵了！而身為管理者的鳥哥竟然還茫然不知∼這真是一大敗筆....

Tips:

瞎密？由圖形介面轉到文字介面竟然用『重新安裝』來處理？不要懷疑，當初沒有學好Linux的時候， 就是以為需要重新安裝，尤其Windows的經驗告訴我們，這樣做『才是對的！』@_@

在趕快重新安裝，並且重新參考很多文件，架設好了防火牆之後，以為終於從此就可以高枕無憂了！ 唉∼結果還是不盡然的，因為我們的電子郵件伺服器早就被當成垃圾轉信站，造成區域網路內網路流量的大量提高， 導致常常會無法連上網際網路....

- 一個貴人的出現

在經過了一年多以及經歷那麼多事件後，鳥哥還是沒有覺悟ㄟ！真糟糕！ 後來因為某些小事情無法解決而上網搜尋，竟然找到Study Area(酷學園)， 並主動發出email給站長網中人(netman)先生，網中人完全沒有就我的問題來回答，竟然是大發雷霆的臭罵鳥哥一頓∼ 唔！怎麼會這樣∼鳥哥從小到大唸書幾乎沒有被唸過∼竟然讀到這麼大了還被人家罵！真可悲∼ 於是乎痛定思痛，遵循網中人大哥的教誨，從他的網站(http://www.study-area.org)的內容出發，並將鳥哥原本的網站全部砍掉重練！

花了兩三個月在網中人的網站上學習到Linux最基礎的檔案架構、指令模式與腳本(Shell and shell scripts)、 軟體管理方式和資源與帳號管理等等，而在將這些基礎的架構理解之後，再回頭看一下各式各樣的server啟動服務與相關的技巧， 發現『哇！原來如此呀！怎麼這麼簡單的東西當初搞了我幾天幾夜睡不好！』 尤其最重要的登錄資訊的追蹤，幫鳥哥避免了很多不必要的系統傷害行為。

此外，而為了方便鳥哥本身的管理，於是開始了一些腳本(shell scripts)的編寫，讓日常的管理變的更輕鬆而有效率！ 當然，這些工作幾乎都是在文字介面底下完成的，圖形介面之下的工作畢竟還是有限的。

- 撰寫文件的有趣經驗

後來鳥哥為了想要趕快畢業，但希望能夠讓我在實驗室的努力不被學弟妹所搞爛，所以開始撰寫一些FAQ的文件。 但是沒想到越寫越發現自己懂得竟然是那麼少，於是乎就越寫越多，資料也越查閱多，漸漸的就有『鳥哥的Linux私房菜』網站的出現！ 而在寫了這個網站之後發現到更多的朋友其實與鳥哥有相同的經驗，他們也在討論區上面提供非常多有用的意見， 於是網站就越來越熱鬧了！

從撰寫文件的經驗裡面也接觸到很多業界的朋友，才發現到一部Linux主機其實是做不了什麼大事的！ 重點是『我們要讓Linux解決什麼問題』，而不是單純的只是去學習架站而已！ 尤其酷學園的ZMAN對鳥哥網站關於伺服器方面的資料影響很大！我們不能夠讓Linux死板板的定位在那邊， 還有更多可用的功能可以讓我們去思考呢！

- 鳥哥的忠言，希望不會逆耳

經過上面鳥哥學習之路的經驗分享之後，我想，您應該也慢慢的瞭解鳥哥想要提出這本經驗談的書籍最主要的目的了， 那就是想『讓想要學習Linux的玩家可以快速且以較為正確的心態來進入Linux的世界！』 而不要像鳥哥在Linux的環境中打轉了一年多之後才來正確的建立概念。希望我這老傢伙的苦口婆心不要讓您誤會啊！

但是玩Linux並不一定要很辛苦的！因為『你玩Linux的目的跟我又不一樣』！ 鳥哥是為了要學習Linux上面的功能，好應用在未來學術研究領域上，所以才這樣接觸他∼ 那難道你不能只為了要使用Linux的桌上辦公環境嗎？是的！所以鳥哥想來談一談Linux的學習者心態！

學習心態的分別

- 架不架站有所謂：

大家都知道Linux最強項的地方在於網路，而Windows是贏在使用者介面較為親善。 然而很多使用者還是常常會比較Linux與Windows這兩套相當流行的作業系統，初次接觸Linux的人比到最後的結果都是 『Linux怎麼都要使用文字介面來架站，怎麼這麼麻煩，還是Windows比較好用』， 事實上這麼比較實在是有點不公平且沒有意義， 為什麼呢？基本上，Windows是很普及的一個作業系統，這點我們都無法否認，但是，一般使用Windows的使用者用Windows來做什麼？

- 上網、即時通訊、打屁聊天打發時間；

- 做做文書工作，處理電子試算表；

- 玩Game及其他休閒娛樂；

當然啦，Windows的工作環境還有很多可以發展的空間，不過這裡我們主要以一般使用者的角度來看。 OK！說了上面這幾個工作，請問一下，『一般使用者誰有在使用Windows玩架站！』？ 很少對不對！是的！真的是很少人在玩Windows的架站！那麼如何可以說Linux無法普及是文字介面惹的禍呢？ 鳥哥相信，如果是一般使用者，應該不至於想要使用Linux來架設網站，所以美美的X-Window對於一般使用者已經相當的好用了， 實在沒有必要來學習架站的原理與過程，還有防火牆的注意事項等等的。

話再說回來，那麼你幹嘛要使用Linux架站呢？『因為Linux的網路功能比較強呀！』 說的沒錯，但是，相對的，比較強的項目可能也具有比較『危險』的指數，當你一開始學習Linux就只想滿腦子的玩架站， 卻又不好好的弄懂一點Linux與網路基礎的話，Windows底下了不起是被攻擊到您的Windows死掉， 但是在Linux底下，卻有可能讓你吃上官司的！像上面提到的鳥哥的慘痛教訓！

- 只是圖形介面，可以嗎？

而如果你已經習慣以圖形化介面來管理你的Linux主機時，請特別留意，因為Linux的軟體是由多個團隊研發出來的， 圖形介面也僅是一個團隊的研發成果，你認為，一個團隊的東西可以將所有團隊的內容都完整無缺的表現出來嗎？ 如果你依賴圖形久了，呵呵！那如果你的系統出問題，看來就只能求助於外面的工程師了，如此一來，有學跟沒有學有何不同？

曾經有個朋友問我說『唉！Linux怎麼這麼麻煩？架設一個DNS真是不容易呀！不像Windows，簡單的很， 按幾個按鈕就搞定了！』這個時候鳥哥就回答了一句話『不會呀！如果你只是想要安裝DNS的話， 網路上面一大堆按部就班的設定方式教學，照著做，一樣可以在十分鐘之內就完成一個DNS主機的設定呀！』 他想一想，確實有道理！同時鳥哥又反問的一件事：『你以為學Windows就不需要瞭解DNS的概念嗎？ 你有嘗試過使用Windows架設DNS卻無法讓他實地跑的問題嗎？果真如此的話，這個時候你怎麼解決？』 他愣住了！因為在Windows上面他確實也沒有辦法解決！所以說，不論是學哪一套系統， 『基礎的理論都是不變的』，也只有瞭解了基礎的咚咚之後，其他的技能才能夠『觸類旁通』呀！

網路上一些老手不太喜歡搞圖形介面，是因為覺得圖形介面預設的設定常常不合他們的意， 尤其是圖形化介面軟體為了方便使用者，常常自己加入一些設定，但是這些設定卻往往是因地制宜的， 所以反而常常會導致架設的網站無法正常工作！這點在網路新聞群組上面討論的已經相當清楚了！ 與其如此，何不一開始就玩文字介面，去弄懂他呢？

- 學習Linux還是學習Distributions：

此外，很多玩過Linux的朋友大概都會碰到這樣的一個問題，就是Linux distributions事實上是非常多的！ 而每個distribution所提供的軟體內容雖然大同小異，然而其整合的工具卻都不一樣，同時， 每種軟體在不同的distribution上面擺放的目錄位置雖然也是大同小異，然而某些設定檔就是擺在不同的目錄下， 這個時候您怎麼找到該資訊？難道非得來一套distribution就學他的主要內容嗎？這麼一來， 市面上少說也有數十套Linux distributions，每一套都學？如果您時間多到如此地步， 那鳥哥也不知道該說什麼好了！如果是我的話，那麼我會乾脆直接學習一些Linux的基本技巧， 可以讓我很輕易的就找到不同版本之間的差異性，而且學習之路也會變的更寬廣呢！

鳥哥的觀念不見得一定適合你，不過就只是以一個過來人的身份給個小建議， 要麼就不要拿Linux來架站，跟Windows一樣，玩玩X-Window就很開心了，要嘛真的得花一點時間來玩一玩比較深入的東西， 中國話不是說過嗎：『要怎麼收穫就怎麼栽』雖然努力不一定有成果，但最起碼，有成果的時候，成果肯定是自己的！

X window的學習

如果你只是想要拿Linux來取代原本的Windows桌面(Desktop)的話，那麼你幾乎不需要通過『嚴格的學習』啦！ 目前的Linux distribution絕大部分預設就是以Desktop的角度來安裝所需要的軟體，也就是說，你只要將Linux安裝好， 接下來就能夠進入Linux玩弄啦！根本就不需要什麼學習的哩！你只需要購買一本介紹Linux桌面設定的書籍， 裡面有說明輸入法、印表機設定、網際網路設定的書籍就很夠用了！鳥哥建議的distributions包括有：

- Ubuntu下載: http://www.ubuntu.com/getubuntu/download

- OpenSuSE下載: http://software.opensuse.org/

- Fedora下載： http://fedoraproject.org/en/get-fedora, 台灣Fedora社群： http://fedora.tw/

- Mandriva下載: http://www.mandriva.com/en/download/free

另外還有一些網路上面的桌面調教文章也可以參考的！包括有：

- 楊老師的圖解桌面 http://apt.nc.hcc.edu.tw/docs/FC3_X/

- Ubuntu 中文指南 http://ubuntuguide.org/wiki/Ubuntu:Hardy_tw

如果想知道更多關於圖形使用者介面能夠使用的軟體資訊，可以參考底下的連結(感謝崑山計中提供的連結資訊)：

- Open Office(http://www.latex-project.org/)：

就是辦公室軟體，包含有電子試算表、文書處理與簡報軟體等；

- Free Maid(http://freemind.sourceforge.net/wiki/index.php/Main_Page)：

可繪製組織圖的軟體，酷學園裡的SAKANA曾用過，鳥哥覺得挺好看；

- AbiWord(http://www.abisource.com/)：

非常類似微軟的Word的文書處理軟體；

- Tex/LaTeX(http://www.latex-project.org/)：

可進行文件排版的軟體(很多自由軟體文件使用此編輯器喔！)；

- Dia(http://dia-installer.de/index_en.html)：

非常類似微軟Visio的軟體，可繪製流程圖；

- Scribus(http://www.scribus.net/)：

專業的排版軟體，老實說，鳥哥確實不會用∼@_@；

- GanttProject(http://ganttproject.biz/)：

可繪製甘特圖(就是時程表)的軟體；

- GIMP(http://www.gimp.org/)：

在業界相當有名的繪圖自由軟體！

更多的可用軟體，可以參考教育部自由軟體諮詢中心網頁的介紹：

- http://ossacc.moe.edu.tw/modules/tinyd1/index.php?id=21

如果你不需要很特別的專業軟體的支援，那麼一般的辦公環境中，上面的這些軟體通通免費！ 而且相信已經足以應付你日常所需的工作環境啦！不過，千萬記得，玩X window就好，不要搞架站的東西！ 不論是Windows/Linux/Mac/Unix還是什麼的，只要是玩到架站，他就不是這麼安全的東西！ 所以，很多東西都需要學習啦！底下我們就來談談，如果有心想要朝Linux作業系統學習的話，最好可以具備什麼心態呢？

有心朝Linux作業系統學習者的學習態度

為什麼大家老是建議學習Linux最好能夠先捨棄X Window的環境呢？ 這是因為X window了不起也只是Linux內的『一套軟體』而不是『Linux核心』。 此外，目前發展出來的X-Window對於系統的管理上還是有無法掌握的地方，舉個例子來說，如果 Linux本身捉不到網路卡的時候，請問如何以X Window來捉這個硬體並且驅動他呢？

還有，如果需要以Tarball(原始碼)的方式來安裝軟體並加以設定的時候，請以X Window 來架設他！這可能嗎？當然可能，但是這是在考驗『X Window開發商』的技術能力， 對於瞭解Linux架構與核心並沒有多大的幫助的！所以說，如果只是想要『會使用Linux』的角度來看， 那麼確實使用X Window也就足夠了，反正搞不定的話，花錢請專家來搞定即可；但是如果想要更深入 Linux的話，那麼指令列模式才是不二的學習方式！

以伺服器或者是嵌入式系統的應用來說，X Window是非必備的軟體，因為伺服器是要提供用戶端來連線的， 並不是要讓使用者直接在這部伺服器前面按鍵盤或滑鼠來操作的！所以圖形介面當然就不是這麼重要了！ 更多的時候甚至大家會希望你不要啟動X window在伺服器主機上，這是因為X Window通常會吃掉很多系統資源的緣故！

再舉個例子來說，假如你是個軟體服務的工程師，你的客戶人在台北，而你人在遠方的台南。某一天客戶來電說他的Linux伺服器出了問題， 要你馬上解決他，請問：要您親自上台北去修理？還是他搬機器下來讓你修理？或者是直接請他開個帳號給你進去設定即可？ 想當然爾，就會選擇開帳號給你進入設定即可囉！因為這是最簡單而且迅速的方法！這個方法通常使用文字介面會較為單純， 使用圖形介面則非常麻煩啦！所以啦！這時候就得要學學文字介面來操作Linux比較好啦！

另外，在伺服器的應用上，檔案的安全性、人員帳號的管理、軟體的安裝/修改/設定、 登錄檔的分析以及自動化工作排程與程式的撰寫等等，都是需要學習的， 而且這些東西都還未涉及伺服器軟體呢！對吧！這些東西真的很重要，所以，建議你得要這樣學習才好：

從頭學習Linux基礎

其實，不論學什麼系統，『從頭學起』是很重要的！還記得你剛剛接觸微軟的Windows都在幹什麼？ 還不就是由檔案總管學起，然後慢慢的玩到控制台、玩到桌面管理， 然後還去學辦公室軟體，我想，你總該不會直接就跳過這一段學習的歷程吧？那麼 Linux的學習其實也差不多，就是要從頭慢慢的學起啦！不能夠還不會走路之前就想要學飛了吧！^_^！

常常有些朋友會寫信來問鳥哥一些問題，不過，信件中大多數的問題都是很基礎的！ 例如：『為什麼我的使用者個人網頁顯示我沒有權限進入？』、 『為什麼我下達一個指令的時候，系統告訴我找不到該指令？』、 『我要如何限制使用者的權限』等等的問題，這些問題其實都不是很難的，只要瞭解了 Linux的基礎之後，應該就可以很輕易的解決掉這方面的問題呢！ 所以請耐心的，慢慢的，將後面的所有章節內容都看完。自然你就知道如何解決了！

此外，網路基礎與安全也很重要，例如TCP/IP的基礎知識，網路路由的相關概念等等。 很多的朋友一開始問的問題就是『為什麼我的郵件伺服器主機無法收到信件？』 這種問題相當的困擾，因為發生的原因太多了，而朋友們常常一接觸Linux就是希望 『架站！』根本沒有想到要先瞭解一下Linux的基礎！這是相當傷腦筋的！ 尤其近來電腦怪客(Cracker)相當多，(真奇怪，閒閒沒事幹的朋友還真是不少....) ，一個不小心您的主機就被當成怪客跳板了！ 甚至發生被警告的事件也層出不窮！這些都是沒能好好的注意一下網路基礎的原因呀！

所以，鳥哥希望大家能夠更瞭解Linux，好讓他可以為你做更多的事情喔！ 而且這些基礎知識是學習更深入的技巧的必備條件呀！因此建議：

1. 計算機概論與硬體相關知識：

因為既然想要走Linux這門路，資訊相關的基礎技能也不能沒有啊！ 所以先理解一下基礎的硬體知識，不用一定要全懂啦！又不是真的要你去組電腦∼^_^， 但是至少要『聽過、有概念』即可；

2. 先從Linux的安裝與指令學起：

沒有Linux怎麼學習Linux呢？所以好好的安裝起一套你需要的Linux吧！雖然說Linux distributions很多， 不過基本上架構都是大同小異的，差別在於介面的親和力與軟體的選擇不同罷了！ 選擇一套你喜歡的就好了，倒是沒有哪一套特別好說∼

3. Linux作業系統的基礎技能：

這些包含了『使用者、群組的概念』、『權限的觀念』，『程序的定義』等等，尤其是權限的概念， 由於不同的權限設定會妨礙你的使用者的便利性，但是太過於便利又會導致入侵的可能！ 所以這裡需要瞭解一下你的系統呦！

4. 務必學會vi文書編輯器：

Linux的文書編輯器多到會讓你數到生氣！不過，vi卻是強烈建議要先學習的！ 這是因為vi會被很多軟體所呼叫，加上所有的Unix like系統上面都有vi，所以你一定要學會才好！

5. Shell與Shell Script的學習：

其實鳥哥上面一直談到的『文字介面』說穿了就是一個名為shell的軟體啦！既然要玩文字介面，當然就是要會使用shell的意思。 但是shell上面的資料太多了，包括『正規表示法』、『管線命令』與『資料流重導向』等等，真的需要瞭解比較好呦！ 此外，為了幫助你未來的管理伺服器的便利性，shell scripts也是挺重要的！要學要學！

6. 一定要會軟體管理員：

因為玩Linux常常會面臨得要自己安裝驅動程式或者是安裝額外軟體的時候，尤其是嵌入式設備或者是學術研究單位等。 這個時候Tarball/RPM/DPKG等軟體管理員的安裝方式的瞭解，對你來說就重要到不行了！

7. 網路基礎的建立：

如果上面你都通過了，那麼網路的基礎就是下一階段要接觸的咚咚，這部份包含了『IP概念』『路由概念』等等；

8. 如果連網路基礎都通過了，那麼網站的架設對你來說，簡直就是『太簡單啦！』

在一些基礎知識上，可能的話，當然得去書店找書來讀啊！ 如果您想要由網路上面閱讀的話，那麼這裡推薦一下由Netman大哥主筆的Study-Area裡面的基礎文章，相當的實用！

- 電腦基礎 (http://www.study-area.org/compu/compu.htm)

- 網路基礎 (http://www.study-area.org/network/network.htm)

選擇一本易讀的工具書

一本好的工具書是需要的，不論是未來作為查詢之用，還是在正確的學習方法上。 可惜的是，目前坊間的書大多強調速成的Linux教育，或者是強調Linux的網路功能， 卻欠缺了大部分的Linux基礎管理∼鳥哥在這裡還是要再次的強調，Linux的學習歷程並不容易， 他需要比較長的時間來適應、學習與熟悉，但是只要能夠學會這些簡單的技巧， 這些技巧卻可以幫助您在各個不同的OS之間遨遊！

您既然看到這裡了，應該是已經取得了鳥哥的 Linux 私房菜 -- 基礎學習篇了吧！ ^_^ 。 希望這本書可以幫助您縮短基礎學習的歷程，也希望能夠帶給您一個有效的學習觀念！ 而在這本書看完之後，或許還可以參考一下Netman推薦的相關網路書籍：

- 請推薦有關網路的書： http://linux.vbird.org/linux_basic/0120howtolinux/0120howtolinux_1.php

不過，要強調的是，每個人的閱讀習慣都不太一樣，所以，除了大家推薦的書籍之外， 您必須要親眼看過該本書籍，確定您可以吸收的了書上的內容，再下去購買喔！

實作再實作

要增加自己的體力，就是只有運動；要增加自己的知識，就只有讀書；當然，要增加自己對於Linux的認識， 大概就只有實作經驗了！所以，趕快找一部電腦，趕快安裝一個Linux distribution，然後快點進入Linux的世界裡面晃一晃！ 相信對於你自己的Linux能力必然大有斬獲！除了自己的實作經驗之外，也可以參考網路上一些善心人士整理的實作經驗分享喔！ 例如最有名的Study-Area(http://www.study-area.org)等網站。

此外，人腦不像電腦的硬碟一樣，除非硬碟壞掉了或者是資料被你抹掉了， 否則儲存的資料將永遠而且立刻的記憶在硬碟中！在人類記憶的曲線中， 你必須要『不斷的重複練習』才會將一件事情記得比較熟！同樣的，學習Linux也一樣， 如果你無法經常摸索的話，那麼，抱歉的是，學了後面的， 前面的忘光光！學了等於沒學，這也是為什麼鳥哥當初要寫『鳥哥的私房菜』這個網站的主要原因， 因為，我的忘性似乎比一般人還要好∼∼呵呵！所以，除了要實作之外，還得要常摸！才會熟悉Linux而且不會怕他呢！

好了，底下列出幾個學習網站來提供大家做為參考實作的依據：

- Study-Area http://www.study-area.org

- 鳥哥的私房菜館 http://linux.vbird.org

- 臥龍大師的網路技術文件 http://linux.tnc.edu.tw/techdoc/

- 臺灣 Linux 社群 http://www.linux.org.tw/

- 狼主的網路實驗室 http://netlab.kh.edu.tw/index.htm

- 大南國小（林克敏主任文件集）http://freebsd.lab.mlc.edu.tw/

- 吳仁智的文件集 http://www.cses.tcc.edu.tw/~chihwu/

Tips:

由於不同的網站當初撰寫的時候所用的Linux軟體或版本與目前的主流並不相同，因此參考他人的實作經驗時， 必須要特別留意對方的版本，否則反而可能造成你的困擾喔！

發生問題怎麼處理啊？建議流程是這樣..

我們是『人』不是『神』，所以在學習的過程中發生問題是很常見的啦！重點是，我們該如何處理在自身所發生的Linux問題呢？ 在這裡鳥哥的建議是這樣的流程：

1. 在自己的主機/網路資料庫上查詢How-To或FAQ

其實，在Linux主機及網路上面已經有相當多的FAQ整理出來了！所以，當你發生任何問題的時候，除了自己檢查， 或者到上述的實作網站上面查詢一下是否有設定錯誤的問題之外，最重要的當然就是到各大FAQ的網站上查詢囉！ 以下列出一些有用的FAQ與How-To網站給您參考一下：

- Linux自己的文件資料： /usr/share/doc (在你的Linux系統中)

- CLDP 中文文件計畫 http://www.linux.org.tw/CLDP/

- The Linux Documentation Project：http://www.tldp.org/

上面比較有趣的是那個TLDP(The Linux Documentation Project)， 他幾乎列出了所有Linux上面可以看到的文獻資料，各種How-To的作法等等，雖然是英文的，不過，很有參考價值！

除了這些基本的FAQ之外，其實，還有更重要的問題查詢方法，那就是利用酷狗(Google)幫您去搜尋答案呢！ 在鳥哥學習Linux的過程中，如果有什麼奇怪的問題發生時，第一個想到的， 就是去http://www.google.com.tw搜尋是否有相關的議題。 舉例來說，我想要找出Linux底下的NAT，只要在上述的網站內，輸入Linux跟NAT， 立刻就有一堆文獻跑出來了！真的相當的優秀好用喔！您也可以透過酷狗來找鳥哥網站上的資料呢！

- Google： http://www.google.com.tw

- 鳥哥網站： http://linux.vbird.org/Searching.php

1. 注意訊息輸出，自行解決疑難雜症：

一般而言，Linux在下達指令的過程當中，或者是log file裡頭就可以自己查得錯誤資訊了，舉個例子來說，當你下達：

[root@linux ~]# ls -l /vbird

由於系統並沒有 /vbird 這個目錄，所以會在螢幕前面顯示：

ls: /vbird: No such file or directory

這個錯誤訊息夠明確了吧！系統很完整的告訴您『查無該資料』！ 呵呵！所以囉，請注意，發生錯誤的時候，請先自行以螢幕前面的資訊來進行 debug(除錯)的動作，然後，如果是網路服務的問題時，請到/var/log/這個目錄裡頭去查閱一下 log file(登錄檔)，這樣可以幾乎解決大部分的問題了！

1. 搜尋過後，注意網路禮節，討論區大膽的發言吧：

一般來說，如果發生錯誤現象，一定會有一些訊息對吧！那麼當您要請教別人之前，就得要將這些訊息整理整理， 否則網路上人家也無法告訴您解決的方法啊！這一點很重要的喔！

萬一真的經過了自己的查詢，卻找不到相關的資訊，那麼就發問吧！不過，在發問之前建議您最好先看一下『 提問的智慧 http://phorum.vbird.org/viewtopic.php?t=96』 這一篇討論！然後，你可以到底下幾個討論區發問看看：

- 酷學園討論區 http://phorum.study-area.org

- 鳥哥的私房菜館討論區 http://phorum.vbird.org

- telnet://bbs.sayya.org

不過，基本上去每一個討論區回答問題的熟手，其實都差不多是那幾個， 所以，您的問題『不要重複發表在各個主要的討論區！』 舉例來說，鳥園與酷學園討論區上的朋友重複性很高，如果您兩邊都發問， 可能會得到反效果，因為大家都覺得，另外一邊已經回答您的問題了呢∼∼

1. Netman大大給的建議：

此外，Netman 兄提供的一些學習的基本方針，提供給大家參考：

- 在Windows裡面，程式有問題時，如果可能的話先將所有其它程式保存並結束，然後嘗試按救命三鍵 (Ctrl+Alt+Delete)，將有問題的程式(不要選錯了程式哦)『結束工作』，看看能不能恢復系統。不要動不動就直接關機或reset。

- 有系統地設計檔案目錄，不要隨便到處保存檔案以至以後不知道放哪裡了， 或找到檔案也不知道為何物。

- 養成一個做記錄的習慣。尤其是發現問題的時候， 把錯誤信息和引發狀況以及解決方法記錄清楚，同時最後歸類及定期整理。別以為您還年輕，等你再弄多幾年電腦了， 您將會非常慶幸您有此一習慣。

- 如果看在網路上看到任何好文章，可以為自己留一份copy，同時定好題目，歸類存檔。(鳥哥註：需要注意智慧財產權！)

- 作為一個使用者，人要遷就機器；做為一個開發者，要機器遷就人。

- 學寫 script 的確沒設定 server 那麼好玩，不過以我自己的感覺是：關鍵是會得『偷』， 偷了會得改，改了會得變，變則通矣。

- 在Windows裡面，設定不好設備，您可以罵它；在Linux裡面，如果設定好設備了，您得要感激它﹗

鳥哥的建議(重點在Solution的學習)：

除了上面的學習建議之外，還有其他的建議嗎？確實是有的！其實， 無論作什麼事情，對人類而言，兩個重要的因素是造成我們學習的原動力：

- 成就感

- 興趣

很多人問過我，鳥哥是怎麼學習Linux的？由上面鳥哥的悲慘Linux學習之路你會發現， 原來我本人對於電腦就蠻有興趣的，加上工作的需要，而鳥哥又從中得到了相當多的成就感， 所以囉，就一發不可收拾的愛上Linux囉！因此，鳥哥個人認為，學習Linux如果玩不出興趣， 他對你也不是什麼重要的生財工具，那麼就不要再玩下去了！ 因為很累人ㄋㄟ∼而如果你真的想要玩這麼一套優良的作業系統， 除了前面提到的一些建議之外，說真的，得要培養出興趣與成就感才行！ 那麼如何培養出興趣與成就感呢？可能有幾個方向可以提供給你參考：

- 建立興趣：

Linux上面可以玩的東西真的太多了，你可以選擇一個有趣的課題來深入的玩一玩！不論是Shell還是圖形介面等等， 只要能夠玩出興趣，那麼再怎麼苦你都會不覺得喔！

- 成就感：

成就感是怎麼來的？說實在話，就是『被認同』來的！怎麼被認同呢？寫心得分享啊！當你寫了心得分享，並且公告在 BBS 上面，自然有朋友會到你的網頁去瞧一瞧，當大家覺得你的網頁內容很棒的時候， 哈哈！你肯定會加油繼續的分享下去而無法自拔的！那就是我啦...... ^_^！

就鳥哥的經驗來說，你『學會一樣東西』與 『要教人家會一樣東西』思考的紋路是不太一樣的！ 學會一樣東西可能學一學會了就算了！但是要『教會』別人，那可就不是鬧著玩的！ 得要思考相當多的理論性與實務性方面的咚咚，這個時候，你所能學到的東西就更深入了！ 鳥哥常常說，我這個網站對我在Linux的瞭解上面真的的幫助很大！

- 協助回答問題：

另一個創造成就感與滿足感的方法就是『助人為快樂之本！』當你在 BBS 上面告訴一些新手，回答他們的問題，你可以獲得的可能只是一句『謝謝！感恩吶！』 但是那句話真的會讓人很有快樂的氣氛！很多的老手都是因為有這樣的滿足感， 才會不斷的協助新來的朋友的呢！此外，回答別人問題的時候，就如同上面的說明一般， 你會更深入的去瞭解每個項目，哈哈！又多學會了好多東西呢！

- 參與討論：

參與大家的技術討論一直是一件提昇自己能力的快速道路！因為有這些技術討論， 你提出了意見，不論討論的結果你的意見是對是錯，對你而言，都是一次次的知識成長！這很重要喔！ 目前台灣地區辦活動的能力是數一數二的Linux社群『酷學園(Study Area, SA)』，每個月不定期的在北/中/南舉辦自由軟體相關活動， 有興趣的朋友可以看看：

http://phorum.study-area.org/index.php/board,22.0.html

此外，除了這些鳥哥的經驗之外，還有在 BBS 上面有一封對於Linux新手相當有幫助的文件資料，大家可以多看一看：

- 李果正先生之 GNU/Linux 初學者之旅： http://info.sayya.org/~edt1023/linux_entry.html

鳥哥這裡有也一個備份 http://linux.vbird.org/linux_basic/0120howtolinux/0120howtolinux_3.php

- 資訊人的有效學習(洪朝貴教授網頁) http://people.ofset.org/~ckhung/a/c013.php

除了這些基本的初學者建議外，其實，對於未來的學習，這裡建議大家要『眼光看遠！』一般來說，公司行號會發生問題時， 他們絕不會只要求各位『單獨解決一部主機的問題』而已，他們需要的是整體環境的總體解決『Total Solution』。 而我們目前學習的Linux其實僅是在一部主機上面進行各項設定而已， 還沒有到達解決整體公司所有問題的狀態。當然啦，得要先學會Linux相關技巧後， 才有辦法將這些技巧用之於其他的solution上面！

所以，大家在學習Linux的時候，千萬不要有『門戶之見』，認為MS的東西就比較不好∼ 否則，未來在職場上，競爭力會比人家弱的！有辦法的話，多接觸，不排斥任何學習的機會！都會帶給自己很多的成長！ 而且要謹記：『不同的環境下，解決問題的方法有很多種，只要行的通，就是好方法！』

重點回顧

- Linux在企業應用方面，著重於『網路伺服器』、『關鍵任務的應用(金融資料庫、大型企業網管環境)』及『高效能運算』等任務；

- Linux在個人環境的使用上，著重於：桌上型電腦、手持系統(PDA、手機)、嵌入式設備(如家電用品等)；

- Linux distributions有針對桌面電腦所開發的，例如Ubuntu, OpenSuSE及Fedora等等，為學習X Window的好工具；

- 有心朝Linux學習者，應該多接觸文字介面(shell)的環境，包括正規表示法、管線命令與資料流重導向，最好都要學習！ 最好連shell script都要有能力自行撰寫；

- 『實作』是學習Linux的最佳方案，空讀書，遇到問題也不見得能夠自己處理的！

- 學習Linux時，建立興趣、建立成就感是很重要的，另外，協助回答問題、參與社群活動也是增加熱情的方式！

- Linux文件計畫的網站在：http://www.tldp.org

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

實作題部分：

- 我的 Linux 系統上面老是出現問題，他有一個錯誤訊息為『fatal: SASL per-connection security setup』請幫我找出可能的原因為何？

先跑到 http://www.google.com.tw 裡面去，輸入上列的錯誤訊息，就可以找到很多文件，根據文件去判斷吧！

- Windows的作業系統當中，老是自動出現一個名為internet optimizer的軟體，我想要知道他是什麼，可以怎麼找？

利用 http://www.google.com.tw 輸入 internet optimizer 後， 就可以找到相關的資訊。基本上，這是一個木馬程式啦！趕緊移除吧！

- 想一想再回答，為何您想要學習Linux？有沒有持續學習的動力？您想要Linux幫您達成什麼樣的工作目標？

問答題部分：

- 我的Linux發生問題，我老是找不到正確的答案，想要去http://phorum.study-area.org提問，應該要先做哪些動作才發問？

1. 先將您 Linux 上面的問題作一個清楚的描述，例如，做了什麼動作，結果發生了什麼訊息與結果。

2. 先到 http://phorum.study-area.org 內的『搜尋』查詢有無相關的問題

3. 再到 http://www.google.com.tw 查詢一下有無相關的資訊

4. 將您的問題描述寫下，並且寫下您的判斷，以及查詢過資料的結果。

5. 等待回覆∼

- 你覺得學習Linux最重要的一環是什麼？

其實是自己的學習心態∼最重要的地方在於能夠『刻苦耐勞∼』 ^_^

- 什麼是TLDP？全名為何？網站在哪裡？

TLDP是 The Linux Documentation Project 的縮寫，內容提到的是 Linux 作業系統的各個 How-To 以及相關的說明文件如 man page 等等。網站在 http://www.tldp.org 喔！

參考資料與延伸閱讀

- 註1：例如甲骨文(Oracle)資料庫系統公司就有支援Linux的版本出現。有興趣的朋友可以參考底下數則新聞：

http://www.openfoundry.org/index.php?option=com_content&Itemid=345&id=1501&lang=en&task=view

http://www.zdnet.com.tw/news/software/0,2000085678,20064784,00.htm

http://govforge.e-land.gov.tw/modules/news/article.php?storyid=84

http://www.openfoundry.org/index.php?option=com_content&Itemid=336&id=1283&lang=en&task=view

http://www.oc.com.tw/readvarticle.asp?id=9539

http://searchenterpriselinux.techtarget.com/news/article/0,289142,sid39_gci1309650,00.html

- 註2：維基百科對於 cluster 的解釋：http://en.wikipedia.org/wiki/Cluster_%28computing%29

2002/07/08：第一次完成或者是上次更新...忘記了∼ @_@

2003/01/28：重新修訂，加入 X-Window 的簡易說明

2005/06/03：將舊的資料移至 此處。同時更新網頁資料！

2005/06/08：加入一些練習題∼之前的寫的不好∼已經抽換掉了∼

2008/07/26：將原本舊的FC4的版本移動到此處。

2008/07/28：將本章與『新手建議』做個連結，加強Linux應用的說明！

2009/08/06：調整一些顯示的方式，調整一下課後練習的部分，將題目分開處理。

第三章、主機規劃與磁碟分割

切換解析度為 800x600

最近更新日期：2009/08/06

事實上，要安裝好一部Linux主機並不是那麼簡單的事情，你必須要針對distributions的特性、伺服器軟體的能力、 未來的升級需求、硬體擴充性需求等等來考量，還得要知道磁碟分割、檔案系統、Linux操作較頻繁的目錄等等， 都得要有一定程度的瞭解才行，所以，安裝Linux並不是那麼簡單的工作喔！ 不過，要學習Linux總得要有Linux系統存在吧？所以鳥哥在這裡還是得要提前說明如何安裝一部Linux練習機。 在這一章裡面，鳥哥會介紹一下，在開始安裝Linux之前，您應該要先思考哪些工作？ 好讓您後續的主機維護輕鬆愉快啊！此外，要瞭解這個章節的重要性，您至少需要瞭解到Linux檔案系統的基本概念， 所以，在您完成了後面的相關章節之後，記得要再回來這裡看看如何規劃主機喔！ ^_^

1. Linux與硬體的搭配

1.1 認識電腦的硬體配備

1.2 選擇與Linux搭配的主機配備： 硬體支援相關網站

1.3 各硬體裝置在Linux中的檔名

2. 磁碟分割

2.1 磁碟連接的方式與裝置檔名的關係

2.2 磁碟的組成複習

2.3 磁碟分割表(partition table)

2.4 開機流程與主要開機記錄區(MBR)

2.5 Linux安裝模式下，磁碟分割的選擇(極重要)

3. 安裝Linux前的規劃

3.1 選擇適當的distribution

3.2 主機的服務規劃與硬體的關係

3.3 主機硬碟的主要規劃(partition)

3.4 鳥哥說：關於練習機的安裝建議

3.5 鳥哥的兩個實際案例

3.6 大硬碟配合舊主機造成的無法開機問題

4. 重點回顧

5. 本章習題

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23874

Linux與硬體的搭配

雖然個人電腦各元件的主要介面是大同小異的，包括前面第零章計算機概論講到的種種介面等， 但是由於新的技術來得太快，Linux核心針對新硬體所納入的驅動程式模組比不上硬體更新的速度， 加上硬體廠商針對Linux所推出的驅動程式較慢，因此你在選購新的個人電腦(或伺服器)時， 應該要選擇已經過安裝Linux測試的硬體比較好。

此外，在安裝Linux之前，你最好瞭解一下你的Linux預計是想達成什麼任務，這樣在選購硬體時才會知道那個元件是最重要的。 舉例來說，桌面電腦(Desktop)的使用者，應該會用到X Window系統， 此時，顯示卡的優劣與記憶體的大小可就佔有很重大的影響。如果是想要做成檔案伺服器， 那麼硬碟或者是其他的儲存設備，應該就是您最想要增購的元件囉！所以說，功課還是需要作的啊！

鳥哥在這裡要不厭其煩的再次的強調，Linux對於電腦各元件/裝置的分辨， 與大家慣用的Windows系統完全不一樣！因為，各個元件或裝置在Linux底下都是『一個檔案！』 這個觀念我們在第一章Linux是什麼裡面已經提過， 這裡我們再次的強調。因此，你在認識各項裝置之後，學習Linux的裝置檔名之前， 務必要先將Windows對於裝置名稱的概念先拿掉∼否則會很難理解喔！

認識電腦的硬體配備

『什麼？學Linux還得要玩硬體？』呵呵！沒錯！ 這也是為什麼鳥哥要將計算機概論搬上檯面之故！ 我們這裡主要是介紹較為普遍的個人電腦架構來設定Linux伺服器，因為比較便宜啦！ 至於各相關的硬體元件說明已經在第零章計概內講過了，這裡不再重複說明。 僅將重要的主機板與元件的相關性圖示如下：

圖1.1.1、個人電腦各元件的相關性

(上述圖示主要取自tom's硬體指南，各元件圖片分屬個別公司所有)

那麼我們應該如何挑選電腦硬體呢？隨便買買就好，還是有特殊的考量？底下有些思考角度可以提供給大家參考看看：

- 遊戲機/工作機的考量

事實上，電腦主機的硬體配備與這部主機未來的功能是很有相關性的！舉例來說，家裡有小孩， 或者自己仍然算是小孩的朋友大概都知道：『要用來打Game的『遊戲機電腦』 所需要的配備一定比辦公室用的『工作機電腦』配備更高檔』，為什麼呢？ 因為現在一般的三維(3D)電腦遊戲所需要的3D光影運算太多了，所以顯示卡與CPU資源都會被耗用的非常多！ 當然就需要比較高級的配備囉，尤其是在顯示卡、CPU(例如Intel的Core 2 Duo及AMD的Athlon64 X2等)及主機板晶片組方面的功能。

至於辦公室的工作環境中，最常使用到的軟體大多是辦公軟體(Office)，最常使用的網路功能是瀏覽器， 這些軟體所需要的運算並不高，理論上目前的入門級電腦都能夠跑得非常順暢了！(例如Intel Celeron及AMD的Sempron)。 甚至很多企業都喜歡購買將顯示卡、主機板晶片組整合在一起的整合型晶片的電腦，因為便宜又好用！

- 效能/價格比的考量

並不是『貴就比較好』喔！在目前(2009)全球經濟蕭條的情況下，如何兼顧省錢與電腦硬體的效能問題，很重要！ 如果你喜歡購買最新最快的電腦零件，這些剛出爐的元件都非常的貴，而且作業系統還不見得能夠完整的支援。 所以，鳥哥都比較喜歡購買主流級的產品而非最高檔的。因為我們最好能夠考慮到效能/價格比。 如果高一級的產品讓你的花費多一倍，但是新增加的效能卻只有10%而已，那這個效能/價格的比值太低，不建議啦！

此外，由於電價越來越高，如何『省電』就很重要啦！因此目前硬體評論界有所謂的『每瓦效能』的單位， 每瓦電力所發揮的效能越高，當然代表越省電啊！這也是購買硬體時的考量之一啦！要知道，如果是做為伺服器用， 一年365天中時時刻刻都開機，則你的電腦多花費50瓦的電力時，每年就得要多花450度電左右，如果以企業來講， 每百部電腦每年多花450度電的話，每年得多花十萬塊以上的電費呢！所以這也需要考量啊！

- 支援度的考量

並非所有的產品都會支援特定的作業系統，這牽涉到硬體開發商是否有意願提供適當的驅動程式之故。 因此，當我們想要購買或者是升級某些電腦元件時，應該要特別注意該硬體是否有針對您的作業系統提供適當的驅動程式， 否則，買了無法使用，那才是叫人嘔死啊！因此，針對Linux來說，底下的硬體分析就重要啦！

選擇與Linux搭配的主機配備

由於硬體的加速發展與作業系統核心功能的增強，導致較早期的電腦已經沒有能力再負荷新的作業系統了。 舉例來說，Pentun-II以前的硬體配備可能已經不再適合現在的新的Linux distribution。 而且較早期的硬體配備也可能由於保存的問題或者是電子零件老化的問題， 導致這樣的電腦系統反而非常容易在運作過程中出現不明的當機情況，因此在利用舊零件拼湊Linux使用的電腦系統時， 真的得要特別留意呢！

不過由於Linux運作所需要的硬體配備實在不需要太高檔，因此，如果有近期汰換下來的， 比Pentun-III 500還要新的硬體配備， 不必急著丟棄。由於P-III的硬體不算太老舊，在效能方面其實也算的上非常OK了∼所以， 鳥哥建議您如果有P-III以後等級的電腦被淘汰，可以拿下來測試一下，說不定能夠作為你日常生活的Linux伺服器， 或者是備用伺服器，都是非常好用的功能哩！

但是由於不同的任務的主機所需要的硬體配備並不相同，舉例來說，如果你的Linux主機是要作為企業內部的Mail server或者是Proxy server時，或者是需要使用到圖形介面的運算(X Window內的Open GL等等功能)， 那麼你就必須要選擇高檔一點的電腦配備了，使用過去的電腦零件可能並不適合呢。

底下我們稍微談一下，如果你的Linux主要是作為小型伺服器使用，並不負責學術方面的大量運算， 而且也沒有使用X Window的圖形介面，那你的硬體需求只要像底下這樣就差不多了：

- CPU

CPU只要不是老舊到會讓你的硬體系統當機的都能夠支援！如同前面談到的，目前(2009)的環境中， Pentun-III的CPU不算太舊而且效能也不錯，也就是說P-III就非常好用了。

- RAM

主記憶體是越大越好！事實上在Linux伺服器中，主記憶體的重要性比CPU還要高的多！因為如果主記憶體不夠大， 就會使用到硬碟的記憶體置換空間(swap)。 而由計算機概論的內容我們知道硬碟比記憶體的速度要慢的多， 所以主記憶體太小可能會影響到整體系統的效能的！尤其如果你還想要玩X window的話，那主記憶體的容量就不能少。 對於一般的小型伺服器來說，建議至少也要512MB以上的主記憶體容量較佳。

- Hard Disk

由於資料量與資料存取頻率的不同，對於硬碟的要求也不相同。 舉例來說，如果是一般小型伺服器，通常重點在於容量，硬碟容量大於20GB就夠用到不行了！ 但如果你的伺服器是作為備份或者是小企業的檔案伺服器，那麼你可能就得要考量較高階的磁碟陣列(RAID)模式了。

Tips:

磁碟陣列(RAID)是利用硬體技術將數個硬碟整合成為一個大硬碟的方法，作業系統只會看到最後被整合起來的大硬碟。 由於磁碟陣列是由多個硬碟組成，所以可以達成速度效能、備份等任務。更多相關的磁碟陣列我們會在第十五章中介紹的。

- VGA

對於不需要X Window的伺服器來說，顯示卡算是最不重要的一個元件了！你只要有顯示卡能夠讓電腦啟動，那就夠了。 但如果需要X window系統時，你的顯示卡最好能夠擁有32MB以上的記憶體容量，否則跑X系統會很累喔！ 鳥哥曾使用一塊只有2MB記憶體的顯示卡跑X，光是按一個按鈕就花費數分鐘時間，真是折磨人家的耐心啊！

- Network Interface Card

網路卡是伺服器上面最重要的元件了！目前新式的主機板大多擁有10/100/1000Mbps的高速網路，不過，老實說， 只要好一點的10/100網路卡就非常夠用了！畢竟我們的頻寬並沒有大到Gigabit的速度！如果是小型伺服器， 一塊Realtek RTL8139晶片的網卡就非常好用了，不過，如果是讀取非常頻繁的網站， 好一點的Intel/3Com網卡應該是比較適合的喔。

- 光碟、軟碟、鍵盤與滑鼠

不要舊到你的電腦不支援就好了，因為這些配備都是非必備的喔！舉例來說，鳥哥安裝好Linux系統後， 可能就將該系統的光碟機、滑鼠、軟碟機等通通拔除，只有網路線連接在電腦後面而已，其他的都是透過網路連線來管控的哩！ 因為通常伺服器這東西最需要的就是穩定，而穩定的最理想狀態就是平時沒事不要去動他是最好的。

底下鳥哥針對一般你可能會接觸到的電腦主機的用途與相關硬體配備的基本要求來說明一下好了：

- 一般小型主機且不含X Window系統：

- 用途：家庭用NAT主機(IP分享器功能)或小型企業之非圖形介面小型主機。

- CPU：大於P-III 500以上等級即可。

- RAM：至少128MB，不過還是大於256MB以上比較妥當！

- 網路卡：一般的10/100 Mbps即可應付。

- 顯示卡：只要能夠被Linux捉到的顯示卡即可，例如NVidia或ATI的主流顯示卡均可。

- 硬碟：20GB以上即可！

- 桌上型(Desktop)Linux系統/含X Window：

- 用途：Linux的練習機或辦公室(Office)工作機。(一般我們會用到的環境)

- CPU：最好等級高一點，例如P-4以上等級。

- RAM：一定要大於512MB比較好！否則容易有圖形介面停頓的現象。

- 網路卡：普通的10/100 Mbps就好了！

- 顯示卡：使用32MB以上記憶體的顯示卡！

- 硬碟：越大越好，最好有60GB。

- 中型以上Linux伺服器：

- 用途：中小型企業/學校單位的FTP/mail/WWW等網路服務主機。

- CPU：最好等級高一點，可以考慮使用雙核心系統。

- RAM：最好能夠大於1GB以上，大於4GB更好！

- 網路卡：知名的3Com或Intel等廠牌，比較穩定效能較佳！也可選購10/100/1000 Mbps的速度。

- 顯示卡：如果有使用到圖形功能，則一張64MB記憶體的顯示卡是需要的！

- 硬碟：越大越好，如果可能的話，使用磁碟陣列，或者網路硬碟等等的系統架構， 能夠具有更穩定安全的傳輸環境，更佳！

- 建議企業用電腦不要自行組裝，可購買商用伺服器較佳， 因為商用伺服器已經通過製造商的散熱、穩定度等測試，對於企業來說，會是一個比較好的選擇。

總之，鳥哥在這裡僅是提出一個方向：如果你的Linux主機是小型環境使用的，即時當機也不太會影響到企業環境的運作時， 那麼使用升級後被淘汰下來的零件以組成電腦系統來運作，那是非常好的回收再利用的案例。 但如果你的主機系統是非常重要的，你想要更一部更穩定的Linux伺服器，那考慮系統的整體搭配與運作效能的考量， 購買已組裝測試過的商用伺服器會是一個比較好的選擇喔！

Tips:

一般來說，目前(2009)的入門電腦機種，CPU至少都是Intel Core的2GHz系列的等級以上， 主記憶體至少有1GB，顯示卡記憶體也有128MB以上，所以如果您是新購置的電腦， 那麼該電腦用來作為Linux的練習機，而且加裝X Window系統，肯定是可以跑的嚇嚇叫的啦！^_^

此外，Linux開發商在釋出Linux distribution之前，都會針對該版所預設可以支援的硬體做說明， 因此，你除了可以在Linux的Howto文件去查詢硬體的支援度之外，也可以到各個相關的Linux distributions網站去查詢呢！ 底下鳥哥列出幾個常用的硬體與Linux distributions搭配的網站，建議大家想要瞭解你的主機支不支援該版Linux時， 務必到相關的網站去搜尋一下喔！

- Red Hat的硬體支援：https://hardware.redhat.com/?pagename=hcl

- Open SuSE的硬體支援：http://en.opensuse.org/Hardware?LANG=en_UK

- Mandriva的硬體支援：http://hcl.mandriva.com/

- Linux對筆記型電腦的支援：http://www.linux-laptop.net/

- Linux對印表機的支援：http://www.openprinting.org/

- 顯示卡對XFree86/Xorg的支援：http://www.linuxhardware.org/

- Linux硬體支援的中文HowTo：http://www.linux.org.tw/CLDP/HOWTO/hardware.html#hardware

總之，如果是自己維護的一個小網站，考慮到經濟因素，你可以自行組裝一部主機來架設。 而如果是中、大型企業，那麼主機的錢不要省∼因為，省了這些錢，未來主機掛點時， 光是要找出哪個元件出問題，或者是系統過熱的問題，會氣死人ㄟ！ 而且，要注意的就是未來你的Linux主機規劃的『用途』來決定你的Linux主機硬體配備喔！相當的重要呢！

各硬體裝置在Linux中的檔名

選擇好你所需要的硬體配備後，接下來得要瞭解一下各硬體在Linux當中所扮演的角色囉。 這裡鳥哥再次的強調一下：『在Linux系統中，每個裝置都被當成一個檔案來對待』 舉例來說，IDE介面的硬碟的檔案名稱即為/dev/hd[a-d]，其中， 括號內的字母為a-d當中的任意一個，亦即有/dev/hda, /dev/hdb, /dev/hdc, 及 /dev/hdd這四個檔案的意思。

Tips:

這種中括號[]型式的表示法在後面的章節當中會使用得很頻繁，請特別留意

另外先提出來強調一下，在Linux這個系統當中，幾乎所有的硬體裝置檔案都在/dev這個目錄內， 所以你會看到/dev/hda, /dev/fd0等等的檔名喔。

那麼印表機與軟碟呢？分別是/dev/lp0, /dev/fd0囉！好了，其他的周邊設備呢？ 底下列出幾個常見的裝置與其在Linux當中的檔名囉：

裝置

裝置在Linux內的檔名

IDE硬碟機

/dev/hd[a-d]

SCSI/SATA/USB硬碟機

/dev/sd[a-p]

USB快閃碟

/dev/sd[a-p](與SATA相同)

軟碟機

/dev/fd[0-1]

印表機

25針: /dev/lp[0-2]

USB: /dev/usb/lp[0-15]

滑鼠

USB: /dev/usb/mouse[0-15]

PS2: /dev/psaux

當前CDROM/DVDROM

/dev/cdrom

當前的滑鼠

/dev/mouse

磁帶機

IDE: /dev/ht0

SCSI: /dev/st0

需要特別留意的是硬碟機(不論是IDE/SCSI/USB都一樣)，每個磁碟機的磁碟分割(partition)不同時， 其磁碟檔名還會改變呢！下一小節我們會介紹磁碟分割的相關概念啦！需要特別注意的是磁帶機的檔名， 在某些不同的distribution當中可能會發現不一樣的檔名，需要稍微留意。 總之，你得先背一下IDE與SATA硬碟的檔名就是了！其他的，用的到再來背吧！

Tips:

更多Linux核心支援的硬體裝置與檔名，可以參考如下網頁：

http://www.kernel.org/pub/linux/docs/device-list/devices.txt

磁碟分割

這一章在規劃的重點是為了要安裝Linux，那Linux系統是安裝在電腦元件的那個部分呢？就是磁碟啦！所以我們當然要來認識一下磁碟先。 我們知道一塊磁碟是可以被分割成多個分割槽的(partition)，以舊有的Windows觀點來看，你可能會有一顆磁碟並且將他分割成為C:, D:, E:槽對吧！那個C, D, E就是分割槽(partition)囉。但是Linux的裝置都是以檔案的型態存在，那分割槽的檔名又是什麼？ 如何進行磁碟分割，磁碟分割有哪些限制？是我們這個小節所要探討的內容囉。

磁碟連接的方式與裝置檔名的關係

由第零章提到的磁碟說明，我們知道個人電腦常見的磁碟介面有兩種， 分別是IDE與SATA介面，目前(2009)的主流已經是SATA介面了，但是老一點的主機其實大部分還是使用IDE介面。 我們稱呼可連接到IDE介面的裝置為IDE裝置，不管是磁碟還是光碟設備。

以IDE介面來說，由於一個IDE排線可以連接兩個IDE裝置，又通常主機都會提供兩個IDE介面，因此最多可以接到四個IDE裝置。 也就是說，如果你已經有一個光碟設備了，那麼最多就只能再接三顆IDE介面的磁碟囉。 這兩個IDE介面通常被稱為IDE1(primary)及IDE2(secondary)， 而每條排線上面的IDE裝置可以被區分為Master與Slave。這四個IDE裝置的檔名為：

IDE\Jumper

Master

Slave

IDE1(Primary)

/dev/hda

/dev/hdb

IDE2(Secondary)

/dev/hdc

/dev/hdd

例題：

假設你的主機僅有一顆IDE介面的磁碟，而這一顆磁碟接在IDE2的Master上面，請問他在Linux作業系統裡面的裝置檔名為何？

答：

比較上表的裝置檔名對照，IDE2的Master之裝置檔名為/dev/hdc

再以SATA介面來說，由於SATA/USB/SCSI等磁碟介面都是使用SCSI模組來驅動的， 因此這些介面的磁碟裝置檔名都是/dev/sd[a-p]的格式。 但是與IDE介面不同的是，SATA/USB介面的磁碟根本就沒有一定的順序，那如何決定他的裝置檔名呢？ 這個時候就得要根據Linux核心偵測到磁碟的順序了！這裡以底下的例子來讓你瞭解囉。

例題：

如果你的PC上面有兩個SATA磁碟以及一個USB磁碟，而主機板上面有六個SATA的插槽。這兩個SATA磁碟分別安插在主機板上的SATA1, SATA5插槽上， 請問這三個磁碟在Linux中的裝置檔名為何？

答：

由於是使用偵測到的順序來決定裝置檔名，並非與實際插槽代號有關，因此裝置的檔名如下：

2. SATA1插槽上的檔名：/dev/sda

3. SATA5插槽上的檔名：/dev/sdb

4. USB磁碟(開機完成後才被系統捉到)：/dev/sdc

通過上面的介紹後，你應該知道了在Linux系統下的各種不同介面的磁碟的裝置檔名了。 OK！好像沒問題了呦！才不是呢∼問題很大呦！ 因為如果你的磁碟被分割成兩個分割槽，那麼每個分割槽的裝置檔名又是什麼？在瞭解這個問題之前，我們先來複習一下磁碟的組成， 因為現今磁碟的分割與他物理的組成很有關係！

磁碟的組成複習

我們在計算機概論談過磁碟的組成主要有磁碟盤、機械手臂、磁碟讀取頭與主軸馬達所組成， 而資料的寫入其實是在磁碟盤上面。磁碟盤上面又可細分出磁區(Sector)與磁柱(Cylinder)兩種單位， 其中磁區每個為512bytes那麼大。假設磁碟只有一個磁碟盤，那麼磁碟盤有點像底下這樣：

圖2.2.1、磁碟盤組成示意圖

那麼是否每個磁區都一樣重要呢？其實整顆磁碟的第一個磁區特別的重要，因為他記錄了整顆磁碟的重要資訊！ 磁碟的第一個磁區主要記錄了兩個重要的資訊，分別是：

- 主要開機記錄區(Master Boot Record, MBR)：可以安裝開機管理程式的地方，有446 bytes

- 分割表(partition table)：記錄整顆硬碟分割的狀態，有64 bytes

MBR是很重要的，因為當系統在開機的時候會主動去讀取這個區塊的內容，這樣系統才會知道你的程式放在哪裡且該如何進行開機。 如果你要安裝多重開機的系統，MBR這個區塊的管理就非常非常的重要了！ ^_^

那麼分割表又是啥？其實妳剛剛拿到的整顆硬碟就像一根原木，你必須要在這根原木上面切割出你想要的區段， 這個區段才能夠再製作成為你想要的家具！如果沒有進行切割，那麼原木就不能被有效的使用。 同樣的道理，你必須要針對你的硬碟進行分割，這樣硬碟才可以被你使用的！

Tips:

更多的磁碟分割與檔案系統管理，我們將在第二篇的時候深入介紹喔！

磁碟分割表(partition table)

但是硬碟總不能真的拿鋸子來切切割割吧？那硬碟還真的是會壞掉去！那怎辦？在前一小節的圖示中， 我們有看到『開始與結束磁柱』吧？那是檔案系統的最小單位，也就是分割槽的最小單位啦！沒有錯， 我們就是利用參考對照磁柱號碼的方式來處理啦！ 在分割表所在的64 bytes容量中，總共分為四組記錄區，每組記錄區記錄了該區段的啟始與結束的磁柱號碼。 若將硬碟以長條形來看，然後將磁柱以直條圖來看，那麼那64 bytes的記錄區段有點像底下的圖示：

圖2.3.1、磁碟分割表的作用示意圖

假設上面的硬碟裝置檔名為/dev/hda時，那麼這四個分割槽在Linux系統中的裝置檔名如下所示， 重點在於檔名後面會再接一個數字，這個數字與該分割槽所在的位置有關喔！

- P1:/dev/hda1

- P2:/dev/hda2

- P3:/dev/hda3

- P4:/dev/hda4

上圖中我們假設硬碟只有400個磁柱，共分割成為四個分割槽，第四個分割槽所在為第301到400號磁柱的範圍。 當你的作業系統為Windows時，那麼第一到第四個分割槽的代號應該就是C, D, E, F。當你有資料要寫入F槽時， 你的資料會被寫入這顆磁碟的301~400號磁柱之間的意思。

由於分割表就只有64 bytes而已，最多只能容納四筆分割的記錄， 這四個分割的記錄被稱為主要(Primary)或延伸(Extended)分割槽。 根據上面的圖示與說明，我們可以得到幾個重點資訊：

- 其實所謂的『分割』只是針對那個64 bytes的分割表進行設定而已！

- 硬碟預設的分割表僅能寫入四組分割資訊

- 這四組分割資訊我們稱為主要(Primary)或延伸(Extended)分割槽

- 分割槽的最小單位為磁柱(cylinder)

- 當系統要寫入磁碟時，一定會參考磁碟分割表，才能針對某個分割槽進行資料的處理

咦！你會不會突然想到，為啥要分割啊？基本上你可以這樣思考分割的角度：

1. 資料的安全性：

因為每個分割槽的資料是分開的！所以，當你需要將某個分割槽的資料重整時，例如你要將電腦中Windows的C槽重新安裝一次系統時， 可以將其他重要資料移動到其他分割槽，例如將郵件、桌面資料移動到D槽去，那麼C槽重灌系統並不會影響到D槽！ 所以善用分割槽，可以讓妳的資料更安全。

2. 系統的效能考量：

由於分割槽將資料集中在某個磁柱的區段，例如上圖當中第一個分割槽位於磁柱號碼1~100號，如此一來當有資料要讀取自該分割槽時， 磁碟只會搜尋前面1~100的磁柱範圍，由於資料集中了，將有助於資料讀取的速度與效能！所以說，分割是很重要的！

既然分割表只有記錄四組資料的空間，那麼是否代表我一顆硬碟最多只能分割出四個分割槽？當然不是啦！有經驗的朋友都知道， 你可以將一顆硬碟分割成十個以上的分割槽的！那又是如何達到的呢？在Windows/Linux系統中， 我們是透過剛剛談到的延伸分割(Extended)的方式來處理的啦！延伸分割的想法是： 既然第一個磁區所在的分割表只能記錄四筆資料， 那我可否利用額外的磁區來記錄更多的分割資訊？實際上圖示有點像底下這樣：

圖2.3.2、磁碟分割表的作用示意圖

在上圖當中，我們知道硬碟的四個分割記錄區僅使用到兩個，P1為主要分割，而P2則為延伸分割。請注意， 延伸分割的目的是使用額外的磁區來記錄分割資訊，延伸分割本身並不能被拿來格式化。 然後我們可以透過延伸分割所指向的那個區塊繼續作分割的記錄。

如上圖右下方那個區塊有繼續分割出五個分割槽， 這五個由延伸分割繼續切出來的分割槽，就被稱為邏輯分割槽(logical partition)。 同時注意一下，由於邏輯分割槽是由延伸分割繼續分割出來的，所以他可以使用的磁柱範圍就是延伸分割所設定的範圍喔！ 也就是圖中的101~400啦！

同樣的，上述的分割槽在Linux系統中的裝置檔名分別如下：

- P1:/dev/hda1

- P2:/dev/hda2

- L1:/dev/hda5

- L2:/dev/hda6

- L3:/dev/hda7

- L4:/dev/hda8

- L5:/dev/hda9

仔細看看，怎麼裝置檔名沒有/dev/hda3與/dev/hda4呢？因為前面四個號碼都是保留給Primary或Extended用的嘛！ 所以邏輯分割槽的裝置名稱號碼就由5號開始了！這是個很重要的特性，不能忘記喔！

主要分割、延伸分割與邏輯分割的特性我們作個簡單的定義囉：

- 主要分割與延伸分割最多可以有四筆(硬碟的限制)

- 延伸分割最多只能有一個(作業系統的限制)

- 邏輯分割是由延伸分割持續切割出來的分割槽；

- 能夠被格式化後，作為資料存取的分割槽為主要分割與邏輯分割。延伸分割無法格式化；

- 邏輯分割的數量依作業系統而不同，在Linux系統中，IDE硬碟最多有59個邏輯分割(5號到63號)， SATA硬碟則有11個邏輯分割(5號到15號)。

事實上，分割是個很麻煩的東西，因為他是以磁柱為單位的『連續』磁碟空間， 且延伸分割又是個類似獨立的磁碟空間，所以在分割的時候得要特別注意。我們舉底下的例子來解釋一下好了：

例題：

在Windows作業系統當中，如果你想要將D與E槽整合成為一個新的分割槽，而如果有兩種分割的情況如下圖所示， 圖中的特殊顏色區塊為D與E槽的示意，請問這兩種方式是否均可將D與E整合成為一個新的分割槽？

圖2.3.3、磁碟空間整合示意圖

答：

- 上圖可以整合：因為上圖的D與E同屬於延伸分割內的邏輯分割，因此只要將兩個分割槽刪除，然後再重新建立一個新的分割槽， 就能夠在不影響其他分割槽的情況下，將兩個分割槽的容量整合成為一個。

- 下圖不可整合：因為D與E分屬主分割與邏輯分割，兩者不能夠整合在一起。除非將延伸分割破壞掉後再重新分割。 但如此一來會影響到所有的邏輯分割槽，要注意的是：如果延伸分割被破壞，所有邏輯分割將會被刪除。 因為邏輯分割的資訊都記錄在延伸分割裡面嘛！

由於第一個磁區所記錄的分割表與MBR是這麼的重要，幾乎只要讀取硬碟都會先由這個磁區先讀起。 因此，如果整顆硬碟的第一個磁區(就是MBR與partition table所在的磁區)物理實體壞掉了，那這個硬碟大概就沒有用了！ 因為系統如果找不到分割表，怎麼知道如何讀取磁柱區間呢？您說是吧！底下還有一些例題您可以思考看看：

例題：

如果我想將一顆大硬碟『暫時』分割成為四個partitions，同時還有其他的剩餘容量可以讓我在未來的時候進行規劃， 我能不能分割出四個Primary？若不行，那麼你建議該如何分割？

答：

- 由於Primary+Extended最多只能有四個，其中Extended最多只能有一個，這個例題想要分割出四個分割槽且還要預留剩餘容量， 因此P+P+P+P的分割方式是不適合的。因為如果使用到四個P，則即使硬碟還有剩餘容量， 因為無法再繼續分割，所以剩餘容量就被浪費掉了。

- 假設你想要將所有的四筆記錄都花光，那麼P+P+P+E是比較適合的。所以可以用的四個partitions有3個主要及一個邏輯分割， 剩餘的容量在延伸分割中。

- 如果你要分割超過4槽以上時，一定要有Extended分割槽，而且必須將所有剩下的空間都分配給Extended， 然後再以logical的分割來規劃Extended的空間。 另外，考慮到磁碟的連續性，一般建議將Extended的磁柱號碼分配在最後面的磁柱內。

例題：

我能不能僅分割出一個Primary與一個Extended即可？

答：

當然可以，這也是早期Windows作業系統慣用的手法！此外，邏輯分割槽的號碼在IDE可達63號，SATA則可達15號， 因此僅一個主要與一個延伸分割即可，因為延伸分割可繼續被分割出邏輯分割槽嘛！

例題：

假如我的PC有兩顆SATA硬碟，我想在第二顆硬碟分割出6個可用的分割槽(可以被格式化來存取資料之用)， 那每個分割槽在Linux系統下的裝置檔名為何？且分割類型各為何？至少寫出兩種不同的分割方式。

答：

由於P(primary)+E(extended)最多只能有四個，其中E最多只能有一個。現在題目要求6個可用的分割槽，因此不可能分出四個P。 底下我們假設兩種環境，一種是將前四號全部用完，一種是僅花費一個P及一個E的情況：

- P+P+P+E的環境：

圖2.3.4、分割示意圖

實際可用的是/dev/sdb1, /dev/sdb2, /dev/sdb3, /dev/sdb5, /dev/sdb6, /dev/sdb7這六個，至於/dev/sdb4這個延伸分割本身僅是提供來給邏輯分割槽建立之用。

- P+E的環境：

圖2.3.5、分割示意圖

注意到了嗎？因為1~4號是保留給主要/延伸分割槽的，因此第一個邏輯分割槽一定是由5號開始的！再次強調啊！ 所以/dev/sdb3, /dev/sdb4就會被保留下來沒有用到了！

開機流程與主要開機記錄區(MBR)

我們在計算機概論裡面談到了，沒有執行軟體的硬體是沒有用的，除了會電人之外...， 而為了電腦硬體系統的資源合理分配，因此有了作業系統這個系統軟體的產生。由於作業系統會控制所有的硬體並且提供核心功能， 因此我們的電腦就能夠認識硬碟內的檔案系統，並且進一步的讀取硬碟內的軟體檔案與執行該軟體來達成各項軟體的執行目的。

問題是，你有沒有發現，既然作業系統也是軟體，那麼我的電腦又是如何認識這個作業系統軟體並且執行他的？ 明明開機時我的電腦還沒有任何軟體系統，那他要如何讀取硬碟內的作業系統檔案啊？嘿嘿！這就得要牽涉到電腦的開機程序了！ 底下就讓我們來談一談這個開機程序吧！

在計算機概論裡面我們有談到那個可愛的BIOS與CMOS兩個東西， CMOS是記錄各項硬體參數且嵌入在主機板上面的儲存器，BIOS則是一個寫入到主機板上的一個韌體(再次說明， 韌體就是寫入到硬體上的一個軟體程式)。這個BIOS就是在開機的時候，電腦系統會主動執行的第一個程式了！

接下來BIOS會去分析電腦裡面有哪些儲存設備，我們以硬碟為例，BIOS會依據使用者的設定去取得能夠開機的硬碟， 並且到該硬碟裡面去讀取第一個磁區的MBR位置。 MBR這個僅有446 bytes的硬碟容量裡面會放置最基本的開機管理程式， 此時BIOS就功成圓滿，而接下來就是MBR內的開機管理程式的工作了。

這個開機管理程式的目的是在載入(load)核心檔案， 由於開機管理程式是作業系統在安裝的時候所提供的，所以他會認識硬碟內的檔案系統格式，因此就能夠讀取核心檔案， 然後接下來就是核心檔案的工作，開機管理程式也功成圓滿，之後就是大家所知道的作業系統的任務啦！

簡單的說，整個開機流程到作業系統之前的動作應該是這樣的：

1. BIOS：開機主動執行的韌體，會認識第一個可開機的裝置；

2. MBR：第一個可開機裝置的第一個磁區內的主要開機記錄區塊，內含開機管理程式；

3. 開機管理程式(boot loader)：一支可讀取核心檔案來執行的軟體；

4. 核心檔案：開始作業系統的功能...

由上面的說明我們會知道，BIOS與MBR都是硬體本身會支援的功能，至於Boot loader則是作業系統安裝在MBR上面的一套軟體了。由於MBR僅有446 bytes而已，因此這個開機管理程式是非常小而美的。 這個boot loader的主要任務有底下這些項目：

- 提供選單：使用者可以選擇不同的開機項目，這也是多重開機的重要功能！

- 載入核心檔案：直接指向可開機的程式區段來開始作業系統；

- 轉交其他loader：將開機管理功能轉交給其他loader負責。

上面前兩點還容易理解，但是第三點很有趣喔！那表示你的電腦系統裡面可能具有兩個以上的開機管理程式呢！ 有可能嗎？我們的硬碟不是只有一個MBR而已？是沒錯啦！但是開機管理程式除了可以安裝在MBR之外， 還可以安裝在每個分割槽的開機磁區(boot sector)喔！瞎密？分割槽還有各別的開機磁區喔？ 沒錯啊！這個特色才能造就『多重開機』的功能啊！

我們舉一個例子來說，假設你的個人電腦只有一個硬碟，裡面切成四個分割槽，其中第一、二分割槽分別安裝了Windows及Linux， 你要如何在開機的時候選擇用Windows還是Linux開機呢？假設MBR內安裝的是可同時認識Windows/Linux作業系統的開機管理程式， 那麼整個流程可以圖示如下：

圖2.4.1、開機管理程式的工作執行示意圖

在上圖中我們可以發現，MBR的開機管理程式提供兩個選單，選單一(M1)可以直接載入Windows的核心檔案來開機； 選單二(M2)則是將開機管理工作交給第二個分割槽的開機磁區(boot sector)。當使用者在開機的時候選擇選單二時， 那麼整個開機管理工作就會交給第二分割槽的開機管理程式了。 當第二個開機管理程式啟動後，該開機管理程式內(上圖中)僅有一個開機選單，因此就能夠使用Linux的核心檔案來開機囉。 這就是多重開機的工作情況啦！我們將上圖作個總結：

- 每個分割槽都擁有自己的開機磁區(boot sector)

- 圖中的系統槽為第一及第二分割槽，

- 實際可開機的核心檔案是放置到各分割槽內的！

- loader只會認識自己的系統槽內的可開機核心檔案，以及其他loader而已；

- loader可直接指向或者是間接將管理權轉交給另一個管理程式。

那現在請你想一想，為什麼人家常常說：『如果要安裝多重開機， 最好先安裝Windows再安裝Linux』呢？這是因為：

- Linux在安裝的時候，你可以選擇將開機管理程式安裝在MBR或各別分割槽的開機磁區， 而且Linux的loader可以手動設定選單(就是上圖的M1, M2...)，所以你可以在Linux的boot loader裡面加入Windows開機的選項；

- Windows在安裝的時候，他的安裝程式會主動的覆蓋掉MBR以及自己所在分割槽的開機磁區，你沒有選擇的機會， 而且他沒有讓我們自己選擇選單的功能。

因此，如果先安裝Linux再安裝Windows的話，那MBR的開機管理程式就只會有Windows的項目，而不會有Linux的項目 (因為原本在MBR內的Linux的開機管理程式就會被覆蓋掉)。 那需要重新安裝Linux一次嗎？當然不需要，你只要用盡各種方法來處理MBR的內容即可。 例如利用全中文的spfdisk(http://spfdisk.sourceforge.net/)軟體來安裝認識Windows/Linux的管理程式， 也能夠利用Linux的救援模式來挽救MBR即可。

Tips:

開機管理程式與Boot sector的觀念是非常重要的，我們會在第二十章分別介紹，您在這裡只要先對於(1)開機需要開機管理程式， 而(2)開機管理程式可以安裝在MBR及Boot Sector兩處這兩個觀念有基本的認識即可， 一開始就背太多東西會很混亂啦！

Linux安裝模式下， 磁碟分割的選擇(極重要)

- 目錄樹結構(directory tree)

我們前面有談過Linux內的所有資料都是以檔案的形態來呈現的，所以囉，整個Linux系統最重要的地方就是在於目錄樹架構。 所謂的目錄樹架構(directory tree)就是以根目錄為主，然後向下呈現分支狀的目錄結構的一種檔案架構。 所以，整個目錄樹架構最重要的就是那個根目錄(root directory)，這個根目錄的表示方法為一條斜線『/』， 所有的檔案都與目錄樹有關。目錄樹的呈現方式如下圖所示：

圖2.5.1、目錄樹相關性示意圖

如上圖所示，所有的檔案都是由根目錄(/)衍生來的，而次目錄之下還能夠有其他的資料存在。上圖中長方形為目錄， 波浪形則為檔案。那當我們想要取得mydata那個檔案時，系統就得由根目錄開始找，然後找到home接下來找到dmtsai， 最終的檔名為：/home/dmtsai/mydata的意思。

我們現在知道整個Linux系統使用的是目錄樹架構，但是我們的檔案資料其實是放置在磁碟分割槽當中的， 現在的問題是『如何結合目錄樹的架構與磁碟內的資料』呢？ 這個時候就牽扯到『掛載(mount)』的問題啦！

- 檔案系統與目錄樹的關係(掛載)

所謂的『掛載』就是利用一個目錄當成進入點，將磁碟分割槽的資料放置在該目錄下； 也就是說，進入該目錄就可以讀取該分割槽的意思。這個動作我們稱為『掛載』，那個進入點的目錄我們稱為『掛載點』。 由於整個Linux系統最重要的是根目錄，因此根目錄一定需要掛載到某個分割槽的。 至於其他的目錄則可依使用者自己的需求來給予掛載到不同的分割槽。我們以下圖來作為一個說明：

圖2.5.2、目錄樹與分割槽之間的相關性

上圖中假設我的硬碟分為兩槽，partition 1是掛載到根目錄，至於partition 2則是掛載到/home這個目錄。 這也就是說，當我的資料放置在/home內的各次目錄時，資料是放置到partition 2的，如果不是放在/home底下的目錄， 那麼資料就會被放置到partition 1了！

其實判斷某個檔案在那個partition底下是很簡單的，透過反向追蹤即可。以上圖來說， 當我想要知道/home/vbird/test這個檔案在哪個partition時，由test --> vbird --> home --> /，看那個『進入點』先被查到那就是使用的進入點了。 所以test使用的是/home這個進入點而不是/喔！

例題：

現在讓我們來想一想，我的電腦系統如何讀取光碟內的資料呢？在Windows裡面使用的是『光碟機』的代號方式處理(假設為E槽時)， 但在Linux底下我們依舊使用目錄樹喔！在預設的情況下，Linux是將光碟機的資料放置到/media/cdrom裡頭去的。 如果光碟片裡面有個檔案檔名為『我的檔案』時，那麼這個檔案是在哪裡？

答：

這個檔案最終會在如下的完整檔名中：

- Windows： 桌面\我的電腦\E:\我的檔案

- Linux： /media/cdrom/我的檔案

如果光碟機並非被掛載到/media/cdrom，而是掛載到/mnt這個目錄時，剛剛讀取的這個檔案的檔名會變成：

- /mnt/我的檔案

如果你瞭解這個檔名，這表示你已經知道掛載的意義了！初次接觸Linux時，這裡最容易搞混，因為他與Windows的分割槽代號完全不一樣！

- distributions安裝時，掛載點與磁碟分割的規劃：

既然我們在Linux系統下使用的是目錄樹系統，所以安裝的時候自然就得要規劃磁碟分割與目錄樹的掛載了。 實際上，在Linux安裝的時候已經提供了相當多的預設模式讓你選擇分割的方式了， 不過，無論如何，分割的結果可能都不是很能符合自己主機的樣子！因為畢竟每個人的『想法』都不太一樣！ 因此，強烈建議使用『自訂安裝, Custom 』這個安裝模式！在某些Linux distribution中，會將這個模式寫的很厲害，叫做是『Expert, 專家模式』，這個就厲害了， 請相信您自己，瞭解上面的說明後，就請自稱為專家了吧！沒有問題！

- 自訂安裝『Custom』：

- A：初次接觸Linux：只要分割『 / 』及『swap』即可：

通常初次安裝Linux系統的朋友們，我們都會建議他直接以一個最大的分割槽『 / 』來安裝系統。 這樣作有個好處，就是不怕分割錯誤造成無法安裝的困境！例如/usr是Linux的可執行程式及相關的文件擺放的目錄， 所以他的容量需求蠻大的，萬一你分割了一塊分割槽給/usr，但是卻給的不夠大，那麼就傷腦筋了！ 因為會造成無法將資料完全寫入的問題，就有可能會無法安裝啦！因此如果你是初次安裝的話， 那麼可以僅分割成兩個分割槽『 / 與 Swap 』即可。

- B：建議分割的方法：預留一個備用的剩餘磁碟容量！

在想要學習Linux的朋友中，最麻煩的可能就是得要常常處理分割的問題，因為分割是系統管理員很重要的一個任務。 但如果你將整個硬碟的容量都用光了，那麼你要如何練習分割呢？^_^。所以鳥哥在後續的練習中也會這樣做， 就是請你特別預留一塊不分割的磁碟容量，作為後續練習時可以用來分割之用！

此外，預留的分割槽也可以拿來做為備份之用。因為我們在實際操作Linux系統的過程中， 可能會發現某些script或者是重要的檔案很值得備份時，就可以使用這個剩餘的容量分割出新的分割槽， 並使用來備份重要的設定檔或者是script。這有個最大的好處， 就是當我的Linux重新安裝的時候，我的一些軟體或工具程式馬上就可以直接在硬碟當中找到！呵呵！重新安裝比較便利啦。 為什麼要重新安裝？因為沒有安裝過Linux十次以上，不要說你學會了Linux了啦！慢慢體會這句話吧！ ^_^

- 選擇Linux安裝程式提供的預設硬碟分割方式：

對於首次接觸Linux的朋友們，鳥哥通常不建議使用各個distribution所提供預設的Server安裝方式， 因為會讓你無法得知Linux在搞什麼鬼，而且也不見得可以符合你的需求！而且要注意的是， 選擇Server的時候，請『確定』你的硬碟資料是不再需要！因為Linux會自動的把你的硬碟裡面舊有的資料全部殺掉！ 此外，硬碟至少需要2 GB以上才可以選擇這一個模式！

現在你知道Linux為什麼不好學了吧？因為很多基礎知識都得要先瞭解！否則連安裝都不知道怎麼安裝∼ 現在你知道Linux的可愛了吧！因為如果你學會了，嘿嘿！很多電腦系統/作業系統的概念都很清晰， 轉換到不同的資訊跑道是比較容易的喔！^_^

安裝Linux前的規劃

從前面的說明我們知道作業系統與硬體的相關性是很高的，而目前最熱門的電腦硬體系統為x86個人電腦系統。 我們也討論了一下各硬體元件在Linux當中的裝置檔名，同時也瞭解到磁碟分割與每個分割槽在Linux目錄樹的關係， 也簡單談論了開機管理程式的用途。接下來我們得要開始安裝Linux囉。

安裝最重要的第一件事，就是要取得Linux distributions的光碟資料，該如何去下載？ 目前有這麼多的distributions，你應該要選擇哪一個版本比較好？為什麼會比較好？ 在台灣，你可以在哪裡下載你所需要的Linux distribution呢？這都是這一小節所要討論的喔！

選擇適當的distribution

就如同第一章、Linux是什麼裡面的distributions談到的， 事實上每個Linux distributions使用的都是來自於http://www.kernel.org官方網站所提供的Linux核心，各家distribution使用的軟體其實也都是大同小異， 最大的差別或許就是在於軟體的安裝模式而已。所以，您只要選擇其中一套，並且玩得出神入化， 那麼Linux肯定可以學的成的。

不過，由於近年來網路環境實在不很安全，因此你在選擇distribution時，特別要瞭解到該distribution適合的環境， 並且最好選擇最新的distribution較佳喔！ 以鳥哥來說，如果是將Linux定位在伺服器上面的話，那麼Red Hat Enterprise Linux及SuSE Enterprise Linux應該是很不錯的選擇，因為他的版本更動幅度較小，並且更新支援的期限較長的原因。

在我們這次的練習中，不想給大家太沈重的$$負擔啦，所以鳥哥選擇CentOS這一個號稱與RHEL完全相容的版本來練習， 目前(2009/08)最新的版本是CentOS 5.3版，你可以選擇i386或x86_64的版本來安裝，請依據您的硬體來選擇。 如果你不知道你的硬體規格時，那麼建議就直接安裝i386的版本即可。因為i386的CentOS 5.x是可以安裝在x86_64的硬體中的。

你可以選擇到CentOS的官方網站去下載最新的版本，不過我們在台灣嘛！台灣有映設站台(mirror site)， 所以由映設站台來下載比較快啊！底下列出CentOS的下載點：

- 國家高速網路中心：http://ftp.twaren.net/Linux/CentOS/5/isos/

- 義守大學：http://ftp.isu.edu.tw/pub/Linux/CentOS/5.3/isos/

- CentOS官方網站：http://mirror.centos.org/centos/5/isos/

你要知道的是，因為Linux distributions裡面的軟體越包越多，所以使用到的光碟(CD)片越來越多了， 因此目前各distribution都有提供DVD的版本。以上面的連結來說，每個連結裡面的i386版本中， 你會發現到有DVD版本例如：CentOS-5.3-i386-bin-DVD.iso，也有CD版本例如： CentOS-5.3-i386-bin-[1-6]of6.iso。鳥哥建議您可以下載DVD版本，因為只有一片，比較環保啦！

Tips:

你所下載的檔案副檔名是.iso，這就是所謂的image檔案(映像檔)。這種image檔案是由光碟直接燒錄成檔案的， 檔案非常的大，建議你不要使用瀏覽器(IE/Firefox..)來下載，可以使用FTP用戶端程式來下載，例如Filezilla (http://filezilla-project.org/download.php)等。這樣比較不需要擔心斷線的問題，因為可以續傳啊！

此外，這種映像檔可不能以資料格式燒錄成為光碟/DVD的！你必須要使用燒錄程式的功能， 將他以『映像檔格式』燒錄成為光碟或DVD才行！切記不要使用燒錄資料檔格式來燒錄喔！重要重要！

主機的服務規劃與硬體的關係

我們前面已經提過，由於主機的服務目的不同，所需要的硬體等級與配備自然也就不一樣！ 底下鳥哥稍微提一提每種服務可能會需要的硬體配備規劃，當然，還是得提醒， 每個朋友的需求都不一樣，所以設計您的主機之前，請先針對自己的需求進行考量。而， 如果您不知道自己的考量為何，那麼就先拿一部普通的電腦來玩一玩吧！不過要記得！ 不要將重要資料放在練習用的Linux主機上面。

- 打造Windows與Linux共存的環境：

在某些情況之下，你可能會想要在『一部主機上面安裝兩套以上的作業系統』， 例如底下這些狀況：

- 我的環境裡面僅能允許我擁有一部主機，不論是經濟問題還是空間問題∼

- 因為目前各主要硬體還是針對Windows進行驅動程式的開發，我想要同時保有Windows作業系統與Linux作業系統， 以確定在Linux底下的硬體應該使用那個I/O port或者是IRQ的分配等等；

- 我的工作需要同時使用到Windows與Linux作業系統。

果真如此的話，那麼剛剛我們在上一個小節談到的開機流程與多重開機的資料就很重要了。 因為需要如此你才能夠在一部主機上面操弄兩種不同的作業系統嘛！

Tips:

一般來說，你還可以在Windows作業系統上面安裝Virtualbox (http://www.virtualbox.org/) 之類的軟體，讓你可以在Windows系統上面『同時』使用Linux系統， 就是兩個作業系統同時啟動！不過，那樣的環境比較複雜，尤其Virtualbox環境中很多硬體都是模擬的， 會讓新手很難理解系統控制原理。基本上，鳥哥很不建議您使用這樣的方式來學習Linux喔！

如果你的Linux主機已經是想要拿來作為某些服務之用時，那麼務必不要選擇太久的硬體喔！ 前面談到過，太老舊的硬體可能會有電子零件老化的問題∼另外，如果你的Linux主機必須要全年無休的開機著， 那麼擺放這部主機的位置也需要選擇啊！好了，底下再來談一談，在一般小型企業或學校單位中， 常見的某些服務與你的硬體關係有哪些？

- NAT(達成IP分享器的功能)：

通常小型企業或者是學校單位大多僅會有一條對外的連線，然後全公司/學校內的電腦全部透過這條連線連到網際網路上。 此時我們就得要使用IP分享器來讓這一條對外連線分享給所有的公司內部員工使用。 那麼Linux能不能達到此一IP分享的功能呢？當然可以，就是透過NAT服務即可達成這項任務了！

在這種環境中，由於Linux作為一個內/外分離的實體，因此網路流量會比較大一點。 此時Linux主機的網路卡就需要比較好些的配備。其他的CPU、RAM、硬碟等等的影響就小很多。 事實上，單利用Linux作為NAT主機來分享IP是很不智的∼因為PC的耗電能力比IP分享器要大的多∼

那麼為什麼你還要使用Linux作為NAT呢？因為Linux NAT還可以額外的加裝很多分析軟體， 可以用來分析用戶端的連線，或者是用來控制頻寬與流量，達到更公平的頻寬使用呢！ 更多的功能則有待後續更多的學習囉！你也可以參考我們在伺服器架設篇當中的資料囉！

- SAMBA(加入Windows網路上的芳鄰)：

在你的Windows系統之間如何傳輸資料呢？當然就是透過網路上的芳鄰來傳輸啦！那還用問。 這也是學校老師在上課過程中要分享資料給同學常用的機制了。問題是，Windows XP的網芳一般只能同時分享十部用戶端連線，超過的話就得要等待了∼真不人性化。

我們可以使用Linux上面的SAMBA這個軟體來達成加入Windows網芳的功能喔！SAMBA的效能不錯， 也沒有用戶端連線數的限制，相當適合於一般學校環境的檔案伺服器(file server)的角色呢！

這種伺服器由於分享的資料量較大，對於系統的網路卡與硬碟的大小及速度就比較重要， 如果你還針對不同的使用者提供檔案伺服器功能，那麼/home這個目錄可以考慮獨立出來，並且加大容量。

- Mail(郵件伺服器)：

郵件伺服器是非常重要的，尤其對於現代人來說，電子郵件幾乎已經取代了傳統的人工郵件遞送了。 拜硬碟價格大跌及Google/Yahoo/MicroSoft公平競爭之賜，一般免費的email信箱幾乎都提供了很不錯的郵件服務， 包過Web介面的傳輸、大於2GB以上的容量空間及全年無休的服務等等。例如非常多人使用的gmail就是一例： http://gmail.com。

雖然免費的信箱已經非常夠用了，老實說，鳥哥也不建議您架設mail server了。問題是， 如果你是一間私人單位的公司，你的公司內傳送的email是具有商業機密或隱私性的，那你還想要交給免費信箱去管理嗎？ 此時才有需要架設mail server囉。CentOS一安裝完畢就提供了Sendmail及Postfix兩種mail server軟體了！

在mail server上面，重要的也是硬碟容量與網路卡速度，在此情境中，也可以將/var目錄獨立出來，並加大容量。

- Web(WWW伺服器)：

WWW伺服器幾乎是所有的網路主機都會安裝的一個功能，因為他除了可以提供Internet的WWW連線之外， 很多在網路主機上面的軟體功能(例如某些分析軟體所提供的最終分析結果的畫面)也都使用WWW作為顯示的介面， 所以這傢伙真是重要到不行的。

CentOS使用的是Apache這套軟體來達成WWW網站的功能，在WWW伺服器上面，如果你還有提供資料庫系統的話， 那麼CPU的等級就不能太低，而最重要的則是RAM了！要增加WWW伺服器的效能，通常提升RAM是一個不錯的考量。

- DHCP(提供用戶端自動取得IP的功能)：

如果你是個區域網路管理員，你的區網內共有20部以上的電腦給一般員工使用，這些員工假設並沒有電腦網路的維護技能。 那你想要讓這些電腦在連上Internet時需要手動去設定IP還是他可以自動的取得IP呢？當然是自動取得比較方便啦！ 這就是DHCP服務的功能了！用戶端電腦只要選擇『自動取得IP』，其他的，就是你系統管理員在DHCP伺服器上面設定一下即可。 這個咚咚的硬體要求可以不必很高囉。

- Proxy(代理伺服器)：

這也是常常會安裝的一個伺服器軟體，尤其像中小學校的頻寬較不足的環境下， Proxy將可有效的解決頻寬不足的問題！當然，你也可以在家裡內部安裝一個Proxy喔！但是， 這個伺服器的硬體要求可以說是相對而言最高的，他不但需要較強有力的CPU來運作，對於硬碟的速度與容量要求也很高！ 自然，既然提供了網路服務，網路卡則是重要的一環！

- FTP：

常常看到很多朋友喜歡架設FTP去進行網路資料的傳輸，甚至很多人會架設地下FTP網站去傳輸些違法的資料。 老實說，『FTP傳輸再怎麼地下化也是很容易被捉到的』啦！所以，鳥哥相當不建議您架設FTP的喔！ 不過，對於大專院校來說，因為常常需要分享給全校師生一些免費的資源， 此時匿名使用者的FTP軟體功能就很需要存在了。對於FTP的硬體需求來說，硬碟容量與網路卡好壞相關性較高。

大致上我們會安裝的伺服器軟體就是這一些囉！ 當然啦，還是那句老話，在目前你剛接觸Linux的這個階段中，還是以Linux基礎為主， 鳥哥也希望你先瞭解Linux的相關主機操作技巧，其他的架站，未來再談吧！ 而上面列出的各項服務，僅是提供給你，如果想要架設某種網路服務的主機時，你應該如何規劃主機比較好！

主機硬碟的主要規劃

系統對於硬碟的需求跟剛剛提到的主機開放的服務有關，那麼除了這點之外，還有沒有其他的注意事項呢？ 當然有，那就是資料的分類與資料安全性的考量。所謂的『資料安全』並不是指資料被網路cracker所破壞， 而是指『當主機系統的硬體出現問題時，你的檔案資料能否安全的保存』之意。

常常會發現網路上有些朋友在問『我的Linux主機因為跳電的關係，造成不正常的關機，結果導致無法開機，這該如何是好？』 呵呵，幸運一點的可以使用fsck來解決硬碟的問題，麻煩一點的可能還需要重新安裝Linux呢！傷腦筋吧！另外， 由於Linux是多人多工的環境，因此很可能上面已經有很多人的資料在其中了， 如果需要重新安裝的話，光是搬移與備份資料就會瘋掉了！所以硬碟的分割考量是相當重要的！

雖然我們在本章的第二小節部分有談論過磁碟分割了，但是，硬碟的規劃對於Linux新鮮人而言，那將是造成你『頭疼』的主要兇手之一！ 因為硬碟的分割技巧需要對於Linux檔案結構有相當程度的認知之後才能夠做比較完善的規劃的！ 所以，在這裡你只要有個基礎的認識即可。老實說，沒有安裝過十次以上的Linux系統，是學不會Linux與磁碟分割的啦！

無論如何，底下還是說明一下基本硬碟分割的模式吧！

- 最簡單的分割方法：

這個在上面第二節已經談過了，就是僅分割出根目錄與記憶體置換空間( / & swap )即可。 然後再預留一些剩餘的磁碟以供後續的練習之用。不過，這當然是不保險的分割方法(所以鳥哥常常說這是『懶人分割法』)！ 因為如果任何一個小細節壞掉(例如壞軌的產生)，你的根目錄將可能整個的損毀∼挽救方面較困難！

- 稍微麻煩一點的方式：

較麻煩一點的分割方式就是先分析這部主機的未來用途，然後根據用途去分析需要較大容量的目錄， 以及讀寫較為頻繁的目錄，將這些重要的目錄分別獨立出來而不與根目錄放在一起， 那當這些讀寫較頻繁的磁碟分割槽有問題時，至少不會影響到根目錄的系統資料，那挽救方面就比較容易啊！ 在預設的CentOS環境中，底下的目錄是比較符合容量大且(或)讀寫頻繁的目錄囉：

- /

- /usr

- /home

- /var

- Swap

以鳥哥為例，通常我會希望我的郵件主機大一些，因此我的/var通常會給個數GB的大小， 如此一來就可以不擔心會有郵件空間不足的情況了！另外，由於我開放SAMBA服務， 因此提供每個研究室內人員的資料備份空間，所以囉，/home所開放的空間也很大！至於/usr/的容量， 大概只要給2-5GB即可！凡此種種均與您當初預計的主機服務有關！ 因此，請特別注意您的服務項目！然後才來進行硬碟的規劃。

鳥哥說：關於練習機的安裝建議

- 關於硬體方面

老實說，安裝Linux是非常困難的一件事，所以在補教界的教材方面，安裝(Installation)通常是在系統管理教完後才教的。 那因為我們不是在補教業的教室中，所以沒有現成的Linux系統可以用，當然就得要自行安裝一個啦！ 因此這裡才會先跟大家介紹如何安裝Linux的。雖然很多朋友都喜歡使用Virtualbox安裝Linux去學習， 但是Virtualbox或其他相關的虛擬化軟體都是用模擬的方式去啟動Linux的，新手學習方面常常會誤解∼

有鑑於此，因此，鳥哥『強烈的建議您，務必擁有一台獨立的主機， 而且內含一顆僅有Linux作業系統的硬碟』，以鳥哥自己為例，我的主機上面有一個抽取式硬碟盒，而我有兩顆分離的硬碟， 分別安裝Windows與Linux系統，要使用不同的作業系統時就抽換硬碟，如此一來，主機很單純， 而抽換也很快速，不需要對機殼拆拆裝裝的，很方便！提供給您做為參考。

- 關於硬碟分割方面

此外，在硬碟的分割方面，鳥哥也建議新手們，先暫時以/及swap兩個分割即可，而且，還要預留一個未分割的空間喔！ 因為我們是練習機，暫時不會提供網路服務，所以只要有/及Swap提供給我們進行安裝Linux的空間即可。不過， 我們未來會針對系統的磁碟部分進行分割的練習以及磁碟配額(quota)的練習，因此，預留一個磁碟空間是必須要的！

舉例來說，如果你有一個20GB的硬碟，那麼建議你分15 GB給/來安裝Linux，512 MB給Swap，另外的4 GB左右不要分割，先保留下來，未來我們可以繼續來練習喔！^_^

- 關於軟體方面

另一個容易發現問題的地方，在於使用者常常會找不到某些指令，導致無法按照書上的說明去執行某些指令。 因為無法執行指令，所以就會一直給他放在那邊，不會繼續往下學習啊！真是可惜！ 為什麼會找不到指令呢？很簡單啊！就是因為沒有安裝該軟體啊！所以，『強烈的建議新手，務必將所有的套件都給他安裝上去！』也就是選擇『安裝所有套件』就是了。

當然啦，上面提到的都是針對『練習機』而言喔！如果是您自己預計要上線的Linux主機， 那就不建議按照上面的說明安裝了！切記切記！

鳥哥的兩個實際案例

這裡說一下鳥哥的兩個實際的案例，這兩個案例是目前還在運作的主機喔！ 要先聲明的是，鳥哥的範例不見得是最好的，因為每個人的考量並不一樣。我只是提供相對可以使用的方案而已喔！

- 案例一：家用的小型Linux伺服器，IP分享與檔案分享中心：

- 提供服務：

提供家裡的多部電腦的網路連線分享，所以需要NAT功能。提供家庭成員的資料存放容量，由於家裡使用Windows系統的成員不少， 所以建置SAMBA伺服器，提供網芳的網路磁碟功能。

- 主機硬體配備：

- CPU使用P-III 800 MHz；

- 記憶體大小為512 MB的RAM；

- 兩張網路卡，控制晶片為常見的螃蟹卡(Realtek)；

- 共有兩顆磁碟，一顆系統碟一顆資料碟。資料碟高達160 GB；

- 顯示卡為以前很流行的GeForce 2 MX含32 MB的記憶體；

- 安裝完畢後將螢幕,鍵盤,滑鼠,DVD-ROM等配備均移除，僅剩下網路線與電源線。

- 硬碟分割：

- 分成/boot, /, /usr, /var, /tmp等目錄均獨立；

- /home獨立出來，放置到那顆160GB的磁碟，提供給家庭成員存放個人資料；

- 1 GB的Swap；

- 案例二：提供Linux的PC叢集(Cluster)電腦群：

- 提供服務：

提供研究室成員對於模式模擬的軟、硬體平台，主要提供的服務並非網際網路服務， 而是研究室內部的研究工作分析。

- 主機硬體配備：

- 利用兩部雙CPU(均為雙核)的x86_64系統(泰安主機板提供的特殊功能)；

- 使用Geforce 7300顯示卡，內含64MB的記憶體；

- 使用一顆硬碟作為主系統，六顆磁碟組成磁碟陣列，以儲存模式模擬的結果；

- 使用PCI-Express介面的網路卡，速度為Gbps；

- 共有4 GB的主記憶體容量；

- 硬碟分割：

- 全部的磁碟陣列容量均給/cluster/raid目錄，佔有2TB的容量；

- 2 GB的swap容量；

- 分割出/, /usr, /var, /tmp等目錄，避免程式錯誤造成系統的困擾；

- /home也獨立出來，讓每個研究室成員可以擁有自己的資料存放容量；

在上面的案例中，案例一是屬於小規模的主機系統，因此只要使用預計被淘汰的配備即可進行主機的架設！ 唯一可能需要購買的大概是網路卡吧！呵呵！而在案例二中，由於我需要大量的數值運算， 且運算結果的資料非常的龐大，因此就需要比較大的磁碟容量與較佳的網路系統了。 以上的資料請先記得，因為下一章節在實際安裝Linux之前，你得先進行主機的規劃呀！

大硬碟配合舊主機造成的無法開機問題

隨著時代的演變，在2009年中的目前，個人電腦上面的硬碟容量竟然都已經高達750 GB以上了！ 這麼大的硬碟用起來當然是很爽快的啦∼不過，也有一些問題的∼那就是∼開機的問題∼

某些比較舊的主機板中，他們的BIOS可能找不到比較大容量的磁碟的。所以，你在舊主機板上面安裝新的大容量磁碟時， 很可能你的磁碟容量會被誤判！不過，即使是這樣，Linux還是能夠安裝喔！而且能夠順利的捉到完整的硬碟容量呢！ 為什麼呢？因為當Linux核心順利開機啟動後，他會重新再去偵測一次整個硬體而不理會BIOS所提供的資訊， 所以就能夠順利的捉到正確的硬碟，並且讓你安裝Linux。

但是，安裝完畢後，可能會無法開機喔！為什麼啊？前一小節裡面我們不是談到過開機流程與MBR的內容嗎？ 安裝的時候是以光碟開機並且由光碟載入Linux核心，所以核心可以被順利載入來安裝。但是若以這樣的配備來開機時， 因為BIOS捉到的硬碟是不對的，所以使用硬碟開機可能就會出現無法開機的錯誤了。那怎辦？

由於BIOS捉到的磁碟容量不對，但是至少在整顆磁碟前面的磁區他還讀的到啊！ 因此，你只要將這個磁碟最前面的容量分割出一個小分割槽，並將這個分割槽與系統開機檔案的放置目錄擺在一起， 那就是 /boot 這個目錄！就能夠解決了！很簡單吧！ 其實，重點是：『將開機磁區所在分割槽規範在小於1024個磁柱以內∼』 即可！那怎麼做到呢？很簡單，在進行安裝的時候，規劃出三個磁區，分別是：

- /boot

- /

- swap

那個/boot只要給100M Bytes左右即可！而且/boot要放在整塊硬碟的最前面！這部份你先有印象與概念即可，未來我們談到第二十章的開機流程時，會再加強說明的！ ^_^

重點回顧

- 新添購電腦硬體配備時，需要考量的角度有『遊戲機/工作機的考量』、『效能/價格比的考量』、『支援度的考量』等；

- 舊的硬體配備可能由於保存的問題或者是電子零件老化的問題， 導致電腦系統非常容易在運作過程中出現不明的當機情況

- Red Hat的硬體支援：https://hardware.redhat.com/?pagename=hcl

- 在Linux系統中，每個裝置都被當成一個檔案來對待，每個裝置都會有裝置檔名。

- 磁碟的裝置檔名主要分為 (1)IDE介面的/dev/hd[a-d]及 (2)SATA/SCSI/USB介面的/dev/sd[a-p]兩種；

- 磁碟的第一個磁區主要記錄了兩個重要的資訊，分別是： (1)主要開機記錄區(Master Boot Record, MBR)：可以安裝開機管理程式的地方，有446 bytes (1)分割表(partition table)：記錄整顆硬碟分割的狀態，有64 bytes；

- 磁碟的主要與延伸分割最多可以有四個，邏輯分割的裝置檔名號碼，一定由5號開始；

- 開機的流程由：BIOS-->MBR-->-->boot loader-->核心檔案；

- boot loader的功能主要有：提供選單、載入核心、轉交控制權給其他loader

- boot loader可以安裝的地點有兩個，分別是 MBR 與 boot sector

- Linux作業系統的檔案使用目錄樹系統，與磁碟的對應需要有『掛載』的動作才行；

- 新手的簡單分割，建議只要有/及swap兩個分割槽即可

本章習題

(要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

實作題部分：

- 請分析你的家用電腦，以你的硬體配備來計算可能產生的耗電量，最終再以計算出來的總瓦數乘上你可能開機的時間， 以推估出一年你可能會花費多少錢在你的這部主機上面？

硬體裡面包括 CPU/硬碟/主機板/記憶體/顯示卡/螢幕等等都會消耗電力，同時電源供應器也會消耗一部份的電力。 若有實際測量工具時，請使用測量結果來計算。若無測量工具，請上網找出每個元件的最大理論消耗功率來計算。

問答題部分：

- 一部電腦主機是否只要 CPU 夠快，整體速度就會提高？

不見得！一部電腦系統的速度與整體電腦系統的運作有關，每個元件皆會影響電腦的速度！ 這包括了記憶體、CPU、AGP與顯示卡速度，硬碟的速度以及其他相關的輸入輸出介面等等！ 所以，如果您的系統是升級的，那麼還得必須要注意各個舊元件是否可以保留， 或者舊的可以用的元件必須要捨棄！

- Linux 對於硬體的要求需要的考慮為何？是否一定要很高的配備才能安裝 Linux ？

Linux 對於硬體的要求是因『服務種類、服務範圍及主機的角色』而定的。例如一部專門用來運算數值解析的 Linux 運算工作站，需要比較強大的 CPU 與足夠的 RAM 來進行工作，至於一般家庭用的僅用來做為 ADSL 寬頻分享器的 Linux 主機，則只要 P-III 等級的電腦，甚至 P-II 系列的等級，就可以很順利的運行 Linux 了。

- 一部好的主機在安裝之前，最好先進行規劃，哪些是必定需要注意的 Linux 主機規劃事項？

依據上一題的答案內容，我們知道 Linux 對於硬體的要求是『因地制宜』地！所以，要進行 Linux 的安裝之前，一定需要規劃 Linux 主機的定位與角色！因此， Linux 的主機是否開放網路服務？這部主機的未來規劃中，是否需要進行大量的運算？這 部主機是否需要提供很大的硬碟容量來服務客戶端的使用？這部主機預計開放的網路服務內容？ 等等，都是需要經過考量的，尤其未來的『套件選擇安裝』上面，更需要依據這些規劃來設定。

- 請寫下下列配備中，在 Linux 的裝置檔名：

IDE 硬碟：

CDROM：

印表機：

軟碟機：

網路卡：

- IDE 硬碟：/dev/hd[a-d]

- CDROM：/dev/cdrom

- 印表機：/dev/lp[0-2]

- 軟碟機：/dev/fd[0-1]

- 網路卡：/dev/eth[0-n]

- 如果您的系統常常當機，又找不到方法解決，您可以朝硬體的那個方向去搜尋？

如果軟體沒有問題的話，那麼當然發生當機的，可能就是硬體的問題了。 1.可以先檢測系統有沒有超頻？ 2.再來則是查閱當系統運作時，系統的機殼內溫度會不會過高？ 因為過高的溫度常常會造成當機。 3.再者，檢查一下 CPU 的溫度，這也很重要。 4.再來，則是檢查是否插了多條的記憶體，因為不同廠牌的記憶體混插很容易造成系統不穩定。 5.電源供應器是否合乎標準？這些都可以進行檢測喔！

- 目前在個人電腦上面常見的硬碟與主機板的連接介面有哪兩個？

有早期的 IDE 介面與最近的 SATA 介面，購買時要分的很清楚！

參考資料與延伸閱讀

- SPFdisk http://spfdisk.sourceforge.net/

2002/04/08：第一次完成吧？

2003/02/02：重新編排與加入 FAQ

2005/06/04：將舊的文章移動到 這裡

2005/06/12：風格修訂之外，新增了 Linux 練習機硬體選擇與軟體安裝的建議

2005/06/15：感謝上奇編輯 Tim 兄來信告知一些可能有爭議的部分！包括 AthlonXP 已被 Sempron 取代，已經修訂！

2008/07/29：將舊的FC4文章移動到此處。

2008/08/21：將整份文件作個重新整理，移除計概有談到的硬體部分，增加partition的資料量。

2009/08/06：重新修訂習題與解答，尤其一些計概方面的問題將他挪開！

2002/02/03以來統計人數

第四章、安裝 CentOS 5.x 與多重開機小技巧

切換解析度為 800x600

最近更新日期：2009/08/11

Linux distributions越作越成熟，所以在安裝方面也越來越簡單！雖然安裝非常的簡單， 但是剛剛前一章所談到的基礎認知還是需要瞭解的，包括MBR, partition, boot loader, mount, software的選擇等等的資料。 這一章鳥哥的安裝定義為『一部練習機』，所以安裝的方式都是以最簡單的方式來處理的。 另外，鳥哥選擇的是CentOS 5.x的版本來安裝的啦！在內文中，只要標題內含有(Option) 的，代表是鳥哥額外的說明，你應該看看就好，不需要實作喔！^_^

1. 本練習機的規劃--尤其是分割參數

2. 開始安裝CentOS 5

2.1 調整開機媒體(BIOS)

2.2 選擇安裝模式與開機, 測試記憶體穩定度

2.3 選擇語系資料

2.4 磁碟分割, 進階軟體陣列建置

2.5 開機管理程式、網路、時區設定與root密碼

2.6 軟體選擇

2.7 其他功能：RAM testing, 安裝筆記型電腦的核心參數(Option)

3. 安裝後的首次設定

4. 多重開機安裝流程與技巧

4.1 新主機僅有一顆硬碟

4.2 舊主機有兩顆以上硬碟

4.3 舊主機只有一顆硬碟

5. 關於大硬碟導致無法開機的問題

6. 重點回顧

7. 本章習題

8. 參考資料與延伸閱讀

9. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?p=135157

本練習機的規劃--尤其是分割參數

讀完第三章、主機規劃與磁碟分割之後，相信你對於安裝 Linux 之前要作的事情已經有基本的概念了。唔！並沒有讀第三章...千萬不要這樣跳著讀，趕緊回去念一念第三章， 瞭解一下安裝前的各種考量對你Linux的學習會比較好啦！

如果你已經讀完第三章了，那麼底下就實際針對第三章的介紹來一一規劃我們所要安裝的練習機了吧！ 請大家注意唷，我們後續的章節與本章的安裝都有相關性，所以，請務必要瞭解到我們這一章的作法喔！

- Linux主機的角色定位：

本主機架設的主要目的在於練習Linux的相關技術，所以幾乎所有的資料都想要安裝進來。 因此連較耗系統資源的X Window System也必須要包含進來才行。所以使用的是前一章講到的Desktop類型的使用囉；

- 選擇的distribution：

由於我們對於Linux的定位為『伺服器』的角色，因此選擇號稱完全相容於商業版RHEL的社群版本， 就是CentOS 5.x版囉。請回到前一章去獲得下載的資訊吧！ ^_^。另外，由於鳥哥後續使用的硬體配備並非64位元， 因此使用的版本為i386的版本喔！

- 電腦系統硬體配備：

由於鳥哥身邊的電腦都有用途了，只剩下一部較舊的主機。硬體配備如下所示。雖然這樣的硬體配備已經過時了， 不過，對於練習Linux或者是架設一部實際上線的Linux server來說，還是很夠力的：

- 主機板與CPU：

使用Celoron 1.2GHz的CPU，內建256KBytes的第二層快取記憶體。 搭配華碩小型主機板(準系統用)；

- 記憶體：

總共具有三條256MB的PC133記憶體，總記憶體為768MB；

- 硬碟：

使用一顆40GB的IBM硬碟，規格為IDE介面，並且接到IDE2的master，所以裝置檔名為/dev/hdc喔！

- 網路卡：

由於主機板內建的網路卡需要額外的驅動程式，所以安插了一張螃蟹卡(Realtek 8139)， 並且於BIOS中關閉了內建的網路卡功能；

- 顯示卡(VGA)：

由於這部主機是準系統，因此是主機板內建的顯示晶片。顯示卡記憶體為與主記憶體分享的， 鳥哥分享出64MB給顯示卡使用。因此本系統主記憶體僅剩(768-64=704MB)喔；

- 其他輸入/輸出裝置：

具有一部DVD光碟機、1.44MB軟碟機、USB光學滑鼠、300W電源供應器。並使用17吋的液晶螢幕。

- 磁碟分割的配置

第三章談到關於舊主機板加上大容量硬碟可能會導致能安裝但無法開機的問題， 為了避免這個問題在各位朋友的實際案例中發生，因此鳥哥將我的40GB硬碟進行如下的分割：

所需目錄/裝置

磁碟容量

分割類型

/boot

100MB

primary

/

10GB

primary

/home

5GB

primary

swap

1GB

logical

- 你也可以僅分割出/及swap。如果想要安裝多重作業系統的，那甚至可以只存在/即可呢！連swap都不需要了！ 如果能安裝卻無法開機，可能就是由於沒有/boot存在的關係，請參考本章最後一節的說明了。

- 開機管理程式(boot loader)：

練習機的開機管理程式使用CentOS 5.x預設的grub軟體，並且安裝到MBR上面。 也必須要安裝到MBR上面才行！因為我們的硬碟是全部用在Linux上面的啊！ ^_^

- 選擇軟體：

如前所述，將所有的軟體通通安裝上去！等到未來再次重新安裝時，你再使用最小安裝來安裝你的系統， 藉以提昇自己的功力囉！注意，第一次安裝Linux的朋友，真的建議要完全安裝整個系統喔！切記切記！

- 檢查表單：

最後，你可以使用底下的表格來檢查一下，你要安裝的資料與實際的硬體是否吻合喔：

是與否，或詳細資訊

細部項目

是, DVD版

01. 是否已下載且燒錄所需的Linux distribution？(DVD或CD)

CentOS 5.3, i386

02. Linux distribution的版本為何？(如CentOS 5.3 i386版本)

i386

03. 硬體等級為何(如i386, x86_64, SPARC等等，以及DVD/CD-ROM)

是, 均為i386

04. 前三項安裝媒體/作業系統/硬體需求，是否吻合？

是

05. 硬碟資料是否可以全部被刪除？

已確認分割方式

06. Partition是否做好確認(包括/與swap等容量)

硬碟數量: 1顆40GB硬碟

/: 10GB

swap: 1GB

其他：/boot: 100MB, /home: 5GB

無

07. 是否具有特殊的硬體裝置(如SCSI磁碟陣列卡等)

無此需要

08. 若有上述特殊硬體，是否已下載驅動程式？

grub, MBR

09. 開機管理程式與安裝的位置為何？

未取得IP參數

10. 網路資訊(IP參數等等)是否已取得？

未取得IP的情況下，可以套用如下的IP參數：

是否使用DHCP：無

IP:192.168.1.100

子遮罩網路：255.255.255.0

主機名稱：www.vbird.tsai

預設安裝

11. 所需要的軟體有哪些？(預設/最小/全部/自訂安裝)

- 上面的表單中第11點頗有趣，如果你是第一次安裝Linux，那麼建議你使用全部安裝；如果是已經有安裝過的話， 那可以使用預設安裝；如果要挑戰自己的功力，那就使用最小安裝。如果想要自行挑選軟體的話，那就使用自訂安裝吧。 如果上面表單確認過都沒有問題的話，那麼我們就可以開始來安裝咱們的CentOS 5.x i386版本囉！ ^_^

開始安裝CentOS 5

由於本章的內容主要是針對安裝一部Linux練習機來設定的，所以安裝的分割等過程較為簡單。 如果你已經不是第一次接觸Linux，並且想要架設一部要上線的Linux主機，請務必前往第三章看一下整體規劃的想法喔！ 在本章中，你只要依照前一小節的檢查表單檢查你所需要的安裝媒體/硬體/軟體資訊等等， 然後就能夠安裝啦！

安裝的步驟在各主要Linux distributions都差不多，主要的內容大概是：

1. 調整開機媒體(BIOS)：務必要使用CD或DVD光碟開機，通常需要調整BIOS；

2. 選擇安裝模式與開機：包括圖形介面/文字介面等，也可加入特殊參數來開機進入安裝畫面；

3. 選擇語系資料：由於不同地區的鍵盤按鍵不同，此時需要調整語系/鍵盤/滑鼠等配備；

4. 磁碟分割：最重要的項目之一了！記得將剛剛的規劃單拿出來設定；

5. 開機管理程式、網路、時區設定與root密碼：一些需要的系統基礎設定！

6. 軟體選擇：需要什麼樣的軟體？全部安裝還是預設安裝即可？

7. 安裝後的首次設定：安裝完畢後還有一些事項要處理，包括使用者、SELinux與防火牆等！

大概就是這樣子吧！好了，底下我們就真的要來安裝囉！

1. 調整開機媒體(BIOS)

你不能在Windows的環境下安裝Linux的，你必須要使用Linux的安裝光碟開機後才能夠進行Linux的安裝流程。 目前幾乎所有的Linux distributions以及主機板都有支援光碟開機，所以以往使用軟碟開機的安裝方式我們就不再介紹了。

那如何讓你的主機可以用光碟開機呢？由前一章的開機流程我們知道開機的裝置是由BIOS調整的， 所以要讓光碟可以開機，當然就得要進入BIOS調整開機裝置的順序了。不過，各家主機板使用的BIOS程式不一樣， 而且進入BIOS的按鍵也不相同，因此這部份得要參考你的主機板說明書才好。鳥哥這裡使用的是我的測試機來解釋喔。

1. 開機進入BIOS的按鍵

將你的PC重新開機，在開機的畫面中按下[del]按鍵，以進入BIOS畫面，如下圖的箭頭所示：

圖2.1.1、按[Del]進入BIOS畫面示意圖

1. 進入BIOS操作介面

然後會出現如下的圖示，顯示出目前你的BIOS主要架構：

圖2.1.2、BIOS畫面示意圖

上圖畫面中最上方為主選單部分，計有『Main, Advanced, Power, Boot, Exit』等項目。我們有興趣的地方在『Boot』中。 上圖最下方則是一些BIOS操作說明，包括使用上、下、左、右等按鍵以及[Enter]按鍵等。 此時，請按照BIOS的操作說明，利用向右的方向鍵將選單移動到『Boot』項目

1. 開機裝置的順序調整

進入到Boot的畫面後，你就可以使用[+][-]按鍵來調整開機順序。以鳥哥的環境來說，我就調整開機裝置為光碟啦！ 如下圖所示：

圖2.1.3、BIOS內的開機順序選單

1. 儲存後離開

接下來，只要輸入[F10]然後按下[Enter]就能夠儲存剛剛的設定，系統會自動重新開機，就能夠使用光碟機裡面的光碟來開機了。 就是這麼簡單啊！

Tips:

另外一款常見的BIOS畫面中，會有一個『BIOS Features Setup』之類字眼的選項，進入該選項後找到『Boot Sequence』 或者是『First Boot Device』之類的字樣，並選擇CD-ROM開機為第一優先即可。 通常鳥哥都是用CD-ROM為第一項，然後是硬碟(HD-0)。

在調整完BIOS內的開機裝置的順序後，理論上你的主機已經可使用可開機光碟來開機了！ 如果發生一些錯誤訊息導致無法以CentOS 5.x DVD來開機，很可能是由於：1)電腦硬體不支援； 2)光碟機會挑片； 3)光碟片有問題； 如果是這樣，那麼建議你再仔細的確認一下你的硬體是否有超頻？或者其他不正常的現象。 另外，你的光碟來源也需要再次的確認！

在進行完上面的步驟之後，請放入我們的CentOS 5.x i386的DVD進入光碟機中，重新開機準備進入安裝畫面吧！

2. 選擇安裝模式與開機

由於為了畫面擷取的解析度，鳥哥使用Virtualbox(註1)這套軟體來捉圖給大家看。 所以如果有看到與上面練習機的規劃的資訊不同時，請大家多多包涵啊！好了， 如果一切都沒問題，那麼使用DVD開機後，你應該會看到螢幕出現如下的畫面了：

圖2.2.1、安裝程式的安裝模式選擇畫面，預設的[F1]畫面

上面的畫面中說明了：

1. 你可以直接按下<Enter>來進入圖形介面的安裝方式；

2. 也可以直接在boot:(上圖箭頭4所指處)後面輸入『linux text』來進入文字介面的安裝；

3. 還有其他功能選單，可按下鍵盤最上方那一列的[F1]...[F5]按鍵來查閱各功能。

要特別注意的是，如果你在 10 秒鐘內沒有按下任何按鍵的話，那麼安裝程式預設會使用圖形介面來開始安裝流程喔！ 由於目前安裝程式都作的非常棒！因此，建議你可以使用圖形介面來安裝即可。鳥哥底下就是使用圖形介面來安裝的。 如果想要知道安裝程式還提供什麼功能，我們可以按下功能鍵。例如底下就是[F2]的功能說明：

圖2.2.2、安裝程式的安裝模式選擇畫面，[F2]的畫面

上圖中箭頭指的地方需要留意一點點，那個是還算常用的功能！意義是這樣的：

- linux noprobe (1號箭頭)：

不進行硬體的偵測，如果你有特殊硬體時，或許可以使用這一項來停止硬體偵測；

- linux askmethod (2號箭頭)：

進入互動模式，安裝程式會進行一些詢問。如果你的硬碟內含有安裝媒體時， 或者是你的環境內有安裝伺服器(Installation server)，那就可以選這一項來填入正確的網路主機來安裝；

- memtest86 (3號箭頭)：

這個有趣了！這個項目會一直進行記憶體的讀寫，如果你懷疑你的記憶體穩定度不足的話， 可以使用這個項目來測試你的記憶體喔！測試完成後需要重新開機！

那如果按下的是[F5]時，就會進入到救援模式的說明畫面，如下圖所示：

圖2.2.3、安裝程式的安裝模式選擇畫面，[F5]的救援模式說明畫面

上圖的意思是說，如果你的Linux系統因為設定錯誤導致無法開機時，可以使用『linux rescue』來進入救援模式。這個救援模式很有幫助喔！ 在我們後面各章節的練習中有很多練習是需要更動到系統設定檔的，萬一你設定錯誤將可能會導致無法開機。 此時請拿出此片DVD來進行救援模式，能夠救回你的Linux而不需要重新安裝呢！

因為我們是首次安裝Linux嘛！所以就請直接按下<Enter>按鍵，此時安裝程式會開始去偵測硬體， 偵測的結果會回報到你的螢幕上，如下所示：

圖2.2.4、安裝程式的核心進行硬體偵測流程示意圖

如果偵測過程中沒有問題，那麼就會出現要你選擇是否要進行儲存媒體的檢驗畫面，如下所示：

圖2.2.5、是否進行安裝媒體的檢測示意圖

如果你確定你所下載的DVD或光碟沒有問題的話，那麼這裡可以選擇『Skip(忽略)』， 不過，你也可以按下『OK』來進行DVD的分析，因為通過DVD的分析後，後續的安裝比較不會出現奇怪的問題。 不過如果你按下『OK』後，程式會開始分析光碟內的所有檔案的資訊，會花非常多的時間喔！如下所示：

圖2.2.6、是否真的要測試光碟或 DVD 碟？

若沒有問題，請按下『 Test 』按鈕，此時會出現分析過程如下圖所示：

圖2.2.7、開始分析 DVD 的內容！

最終的分析結果如下所示，按下『 OK 』即可！如果妳發現了分析錯誤的情況，很可能是你下載的 DVD 來源檔案不完整， 或者是光碟/DVD被妳的光碟機挑片，或者是燒錄的速度倍數太高而導致燒錄不完整等等，總之，可能就是要妳再重新捉一片新的 DVD 啦！這就是測試 DVD 的優點，雖然會花去一些時間就是了。

圖2.2.8、檢驗結果是正確的情況

如果還有其他光碟想要被測試時，在下圖中按下『 Test 』繼續！不過我們僅有一片 DVD 而已， 因此這邊選擇『 Continue 』來進入安裝的程序喔！

圖2.2.9、檢驗結束，開始安裝的流程

3. 選擇語系資料

接下來就是整個安裝的程序了。安裝的畫面如下所示：

圖2.3.1、歡迎畫面螢幕

如果你想要瞭解這一版的CentOS 5.3有什麼公告的注意事項，請按下上圖的『Release Notes』按鈕(1號箭頭處)， 就能夠看到釋出公告的項目。如果沒有問題的話，請按下『Next』開始安裝程序啦！如下所示會出現語系的選擇了。

圖2.3.2、安裝過程的語系選擇

我們慣用的中文為繁體中文，請先選擇繁體中文的項目(Chinese, Traditional)，然後繼續給他『Next』即可出現如下畫面：

圖2.3.3、鍵盤字元對應表的選擇

因為繁體中文預設也是使用美式英文的鍵盤對照表，因此你會看到畫面直接就是美式英文，你只要按下『下一步』即可！ 此時你也會發現，整個畫面通通變成中文介面啦！真是好具有親和力喔！

如果沒有問題的話，理論上應該會進入下個步驟，亦即是磁碟分割的畫面才對。不過，如果你的硬碟是全新的， 而且並沒有經過任何的磁碟分割時，就會出現如下的警告訊息：

圖2.3.4、安裝程式找不到磁碟分割表的警告圖示

因為鳥哥使用的是Virtualbox虛擬機器的環境，所以預設的那顆硬碟是全新的，所以才會出現上述的訊息。 請在上圖中按下『是』吧！你的主機內的硬碟如果不是全新的，上述的警告畫面不會出現！而如果你曾經安裝過 Linux 的話，那麼可能會出現如下圖的樣子：

圖2.3.5、曾經安裝過 CentOS 出現的全新安裝或升級

如果沒有其他特別的需求，那就選擇全新安裝吧！接下來讓我們開始磁碟分割去！

4. 磁碟分割

如同前面談到的，磁碟分割是整個安裝過程裡面最重要的部分了。CentOS預設給了我們四種分割模式，分別為：

- 移除所選磁碟上的所有分割區，並建立預設分割模式： 如果選擇這種模式，你硬碟會整個被Linux拿去使用，並且硬碟裡面的分割全部被刪除後， 以安裝程式的預設方式重新建立分割槽，使用上要特別注意！

- 移除所選磁碟上的 Linux 分割區，並建立預設的分割模式： 在這個硬碟內，只有Linux的分割槽會被刪除，然後再以安裝程式的預設方式重新建立分割槽。

- 使用所選取磁碟上的未使用空間，建立預設的分割模式： 如果你的這顆硬碟內還有未被分割的磁柱空間(注意，是未被分割，而不是該分割槽內沒有資料的意思！)， 那麼使用這個項目後，他不會更動原有的分割槽，只會就剩餘的未分割區塊進行預設分割的建置。

- 建立自訂的分割模式： 就是我們要使用的啦！不要使用安裝程式的預設分割方式，使用我們需要的分割方式來處理。

如果你想要玩一玩不同的分割模式，那如下圖箭頭所指的地方，點一下該按鈕就會出現上面說明的四種模式了。自己玩玩先！ 但是因為我們已經規劃好要建立四個分割槽，分別是/, /boot, /home與swap四個，所以不想要使用安裝程式預設的分割方式。 因此如下所示，我們所使用的是自訂分割的模式。不要搞錯喔！

圖2.4.1、磁碟分割方式的挑選

按下『下一步』後就會出現如下的分割視窗。這個畫面主要分為三大區塊，最上方為硬碟的分割示意圖， 目前因為鳥哥的硬碟並未分割，所以呈現的就是一整塊而且為Free的字樣。中間則是指令區，下方則是每個分割槽的裝置檔名、 掛載點目錄、檔案系統類型、是否需要格式化、分割槽容量大小、開始與結束的磁柱號碼等。

圖2.4.2、磁碟分割操作主畫面

至於指令區，總共有六大區塊，其中RAID與LVM是硬碟特殊的應用，這部份我們會在後續的第十五章的進階檔案系統當中再來說明。至於其他指令的作用如下：

- 『新增』是增加新分割，亦即進行分割動作，以建立新的磁碟分割槽；

- 『編輯』則是編輯已經存在的磁碟分割槽， 你可以在實際狀態顯示區點選想要修改的分割槽，然後再點選『編輯』即可進行該分割槽的編輯動作。

- 『刪除』則是刪除一個磁碟分割槽，同樣的， 你得要在實際狀態顯示區點選想要刪除的分割槽喔！

- 『重設』則是恢復最原始的磁碟分割狀態！

需要注意的是，你的系統與鳥哥的系統當然不可能完全一樣，所以你螢幕上的硬碟資訊應該不會與鳥哥的相同的喔！ 所以看到不同，不要太緊張啊，那是正常的！

- 建立根目錄的分割槽

好，接下來我們就嘗試來建立根目錄(/)的分割槽看看。按下『新增』後，就會出現如下的畫面。 由於我們需要的根目錄是使用Linux的檔案系統，因此預設就是ext3這個檔案系統啦！ 至於在掛載點的地方，你可以手動輸入也可以用滑鼠來挑選。 最後在大小(MB)的地方輸入你所需要的磁碟容量即可。不過由於鳥哥這個系統當中只有一顆磁碟， 所以在『可用的磁碟機』裡面就不能夠自由挑選囉！

圖2.4.3、新增磁碟分割槽的畫面

如果你想要知道Linux還支援什麼檔案系統類型，點一下上圖中的ext3那個按鈕，就會出現如下的畫面啦！

圖2.4.4、分割過程的檔案系統類型挑選

這幾種檔案系統類型分別是：

- ext2/ext3：是Linux適用的檔案系統類型。由於ext3檔案系統多了日誌的記錄， 對於系統的復原比較快速，因此建議你務必要選擇新的ext3不要用ext2了。 (日誌式檔案系統我們會在後續的第八章介紹他的意義。)

- physical volume (LVM)：這是用來彈性調整檔案系統容量的一種機制， 可以讓你的檔案系統容量變大或變小而不改變原有的檔案資料內容！這部份我們會在第十五章、進階檔案系統管理中談到！

- software RAID：利用Linux作業系統的特性，用軟體模擬出磁碟陣列的功能！ 這東西很棒！不過目前我們還用不到！在後續的第十五章再跟大家報告了！

- swap：就是記憶體置換空間！由於swap並不會使用到目錄樹的掛載， 所以用swap就不需要指定掛載點喔！

- vfat：同時被Linux與Windows所支援的檔案系統類型。 如果你的主機硬碟內同時存在Windows與Linux作業系統，為了資料的交換，確實可以建置一個vfat的檔案系統喔！

這幾樣東西都很有趣！不過，畢竟我們才剛剛碰這個Linux嘛！先安裝起來其他的以後再說。 所以，你只要使用ext3以及swap這兩者即可啦！

一切資料都填入妥當後，就會出現如下的畫面。因為我們的根目錄就是需要10GB的容量， 因此在大小(MB)的地方就得要填入10000的大小。 因為1G=1000M比較好記憶嘛！而且我們的根目錄容量是固定的，所以在下圖的大小選項就選擇『固定大小』了。 此外，如果你硬要自己調整主要/延伸/邏輯分割的類型時，最後那個『強制成為主要分割』可以自己玩一玩先！最後按下確定吧！

圖2.4.5、新增根目錄分割槽的最終圖示

按下確定後就會回到原本的分割操作畫面(如下圖所示)。此時你會看到分割示意圖多了一個hda1，且在實際分割區域顯示中， 也會看到/dev/hda1是對應到根目錄的。在『格式化』的項目中出現一個打勾的符號， 那代表後續的安裝會將/dev/hda1重新格式化的意思。接下來，我們繼續按下『新增』來建立/boot這個分割槽吧！

圖2.4.6、磁碟分割主畫面的改變示意圖

- 建立/boot目錄的分割槽

同樣的，在按下『新增』後，如下依序填入正確的資訊，包括掛載點、檔案系統、檔案大小等。 由於第三章的大硬碟配合舊主機當中我們談到如果有/boot獨立分割槽時， 務必讓該分割槽在整顆硬碟的最前面部分。因此，我們針對/boot就選擇『強制成為主要分割』囉！如下圖所示：

圖2.4.7、新增/boot分割槽的最終結果

最終建立/boot分割槽的結果如下所示，仔細看輸出的結果喔！安裝程式還挺聰明的， 他會主動的將/boot這個特殊目錄移到磁碟最前面，所以你會看到/boot所在的磁碟分割槽為/dev/hda1，而起始磁柱則為1號呢！ 很有趣吧！情況如下圖所示：

圖2.4.8、/boot分割槽自動調整磁柱號碼示意圖

- 建立記憶體置換空間swap的分割槽

在上圖中繼續按下『新增』來處理記憶體置換空間(swap)。如同上面談到的， 因為swap是記憶體置換空間，因此不需要有掛載點。所以，請如同下圖所示，在『檔案系統類型』處挑選為『swap』吧！

圖2.4.9、swap檔案系統的挑選示意圖

挑選了swap之後，你就會發現到『掛載點』部分自動變成『不適用』了！因為不需要掛載啦！那麼swap應該要選多大呢？ 雖然我們已經自訂為1GB這麼大的置換空間，不過，在傳統的Linux說明文件當中特別有指定到 『swap最好為實體記憶體的1.5到2倍之間』。swap置換空間是很重要的， 因為他可以避免因為實體記憶體不足而造成的系統效能低落的問題。但是如果你的實體記憶體有4GB以上時， 老實說，swap也可以不必額外設定啦！

Tips:

swap記憶體置換空間的功能是：當有資料被存放在實體記憶體裡面，但是這些資料又不是常被CPU所取用時， 那麼這些不常被使用的程序將會被丟到硬碟的swap置換空間當中， 而將速度較快的實體記憶體空間釋放出來給真正需要的程序使用！ 所以，如果你的系統不很忙，而記憶體又很大，自然不需要swap囉。

圖2.4.10、新增swap分割的最終結果

某些安裝程式在你沒有指定swap為記憶體的1.5~2倍時會有警告訊息的告知，此時只要將警告訊息忽略，按下一步即可。 好了，如果一切都順利完成的話，那麼你就會看到如下的分割結果囉！

圖2.4.11、詳細的分割參數結果

- 建立/home目錄的分割槽

讓我們繼續完成最後一個分割槽的分割吧！繼續按下上圖的『新增』然後完成如下資料的填寫並按下確定：

圖2.4.12、新增/home分割槽的最終結果

分割的最終結果終於出爐！如下圖所示。你會發現到系統自動的將/dev/hda4變成延伸分割喔！然後將所有容量都給/dev/hda4， 並且將swap分配到/dev/hda5去了！這就是分割的用途！這也是為什麼我們要在第三章花這麼多時間來解釋分割的原因啦！

圖2.4.13、詳細的分割參數結果

到此為止，我們這個練習機的分割就已經完成了！底下我們額外介紹如果你還想要刪除與建立軟體磁碟陣列， 該如何在安裝時就製作呢？

- 刪除已存在分割的方法：(Option, 看看就好別實作)

如果你想要將某個分割槽刪除，或者是你剛剛錯誤指定了一個分割槽的相關參數，想要重新處理時，要怎辦啊？ 舉例來說，我想要將上圖的/dev/hda5那個swap分割槽刪除掉。好，先將滑鼠指定到swap上面點一下，如下圖所示， 該分割槽會反白，然後再按下『刪除』此時會如下圖所示跳出一個視窗，在該視窗內按下『刪除』這個分割槽就被刪除啦！

圖2.4.14、刪除已存在分割的方法

- 建立軟體磁碟陣列的方法：(Option, 看看就好別實作)

如果你知道什麼是磁碟陣列的話，那麼底下的步驟可以讓你建置一個軟體模擬的磁碟陣列喔！ 由於磁碟陣列在後面第十五章、進階檔案系統管理才會講到，這裡只是先告訴您， 其實磁碟陣列可以在安裝時就建置了呢！首先，同樣的，在分割操作按鍵區按下『新增』，然後出現下圖，選擇『Software RAID』項目，並填入1000MB的大小，按下確定！

圖2.4.15、軟體磁碟陣列分割槽的建立示意圖

上述的動作『請要連續作兩次』之後，就會出現如下圖示。注意喔，由於我們尚未講到RAID的等級(level)， 所以你應該還不瞭解為什麼要作兩次。沒關係，先有個底，讀完整份資料後再回來查閱時，你就會知道如何處理了。 兩個軟體RAID的分割資訊如下圖所示：

圖2.4.16、在已具有軟體磁碟陣列分割槽的狀態下建置RAID

由於我們已經具有軟體RAID的分割槽，此時才能按下『RAID』來建立軟體磁碟陣列的裝置。 如上圖所示，看到了兩個軟體磁碟陣列，然後按下右上方的RAID按鈕，就會出現如下圖示：

圖2.4.17、建立軟體磁碟陣列/dev/md0

與一般裝置檔名不同的，第一個軟體磁碟陣列的裝置名稱為/dev/md0。 如上圖所示，你會發現到系統多出了一個怪怪的裝置名稱，這個檔名就是未來給我們格式化用的裝置啦！ 而這個軟體磁碟陣列的裝置其實是利用實體的分割槽來建立的哩。按下上圖的『確定』後就會出現如下的圖示：

圖2.4.18、軟體磁碟陣列的掛載點、等級與檔案系統格式

由於我們僅建立兩個軟體磁碟陣列分割槽，因此在這邊只能選擇RAID0或RAID1。我們以RAID0來作為示範， 你會發現中間白色框框的地方會有兩個可以選擇的分割槽，那就是剛剛我們建立起來的software RAID分割槽。 我們將這個/dev/md0掛載到/myshare目錄去！然後再按下確定吧！

圖2.4.19、最終細部分割參數示意圖

最終的結果就像上圖所示，在實際分割區就會顯示/dev/md0，而由於這個裝置是Linux系統模擬來的， 所以在磁柱號碼(開始/結束)的地方就會留白！這樣可以瞭解嗎？

5. 開機管理程式、網路、 時區設定與root密碼

- 開機管理程式的處理

分割完成後就會進入開機管理程式的安裝了，目前較新的Linux distributions大多使用grub管理程式， 而且我們也必須要將他安裝到MBR裡面才行！因此如下圖所示，在1號箭頭的地方就得要選擇整部磁碟的檔名 (/dev/hda)， 其實那就代表該顆硬碟的MBR之意。

下圖中2號箭頭所指的就是開機時若出現選單，那麼選單內就會有一個名為『CentOS』的可選擇標籤。 這個標籤代表他根目錄所在的位置為/dev/hda2這樣的意思。而如果開機內5秒鐘不按下任何按鍵，就預設會以此一標籤來開機。

如果你還想要加入/編輯各個標籤，那可以按下3號箭頭所指的那三個按鍵喔！

圖2.5.1、開機管理程式的處理

如果你覺得『CentOS』這個選單不好看，想要自訂自己的選單名稱，那麼在上圖中先點一下『CentOS』那個標籤， 然後按下3號箭頭所指的『編輯』按鈕，就會出現如下畫面。在如下畫面中可以填寫你自己想要的選單名稱喔！ 鳥哥是很討厭麻煩的，所以就使用預設的選單名稱而已。

圖2.5.2、編輯開機選單的標籤名稱

如果你的電腦系統當中還有其他的『已安裝作業系統』時，而且你想要讓Linux在開機的時候就能夠讓你選擇不同的作業系統開機， 那麼就如同下圖所示，你可以先按下『新增』，然後在2號箭頭的地方選擇其他作業系統所在的分割槽， 並在3號箭頭處填入適當的名稱(例如WindowsXP等等)，按下確定就能夠在開機時新增一個選單囉！

圖2.5.3、新增開機選單標籤的示意圖

如果你是個很龜毛的人，你希望你的系統除非你自己在電腦前面開機並輸入密碼後才能開始開機流程的話， 那麼可以如同下圖所示加入密碼管理機制。不過grub開機管理程式加入密碼雖然有好處， 但是如此一來我們就無法在遠端重新開機了，因此鳥哥暫時不建議你設定開機管理程式的密碼喔！ 底下只是一個示意圖，讓你知道如何加入密碼管理而已！

圖2.5.4、設定開機管理程式的密碼

- 將開機管理程式安裝到boot sector(Option, 看看就好，不要實作)

如果你因為特殊需求，所以Linux的開機管理程式無法安裝到MBR時，那就得要安裝到每塊partition的開機磁區(boot sector)了。果真如此的話，那麼如同下圖所示，先勾選『設定進階開機管理程式選項』的地方：

圖2.5.5、進階開機管理程式選項

然後就會出現如下的圖示，預設Linux會將開機管理程式安裝到MBR，如果你想要安裝到不同的地方去， 請如同下圖的箭頭處，選擇『開機分割區的第一個磁區』就是該分割槽的boot sector囉！

圖2.5.6、將開機管理程式安裝到boot sector的方法

- 網路參數的給予

如果你的網路卡可以被安裝程式捉到的話，那麼你就可以設定網路參數了！例如下圖所示的模樣。 目前各大版本幾乎都會預設網路卡IP的取得方式為『自動取得IP』，也就是所謂的『DHCP』網路協定啦！ 不過，由於這個協定需要有DHCP伺服器的輔助才行，如果你的環境沒有種伺服器存在的話， 那開機的過程中可能會等待一段時間。所以通常鳥哥都改成手動設定。不過，無論如何，都要與你的網路環境相同才是。

圖2.5.7、設定網路參數的過程

在上圖中我們可以看到所有的網路參數都是經過dhcp取得的，所以通通不需要設定任何項目。 至於網路裝置內的白色框框中僅有一張網卡的顯示。由於我們要將IP改為手動給予， 但我們尚未談到伺服器與網路基礎，所以這裡你不懂也沒有關係，請先按照先前我們所規劃的IP參數去填寫即可。 請按下上圖的『編輯』按鈕，就會出現如下的畫面了：

圖2.5.8、手動編輯網路IP參數

在上圖中的最上方我們可以看到這張網路卡的製造商(AMD)與網卡卡號(Hardware address:)， 並且我們的Linux也支援IPv4與IPv6(第四版與第六版的IP參數)。因為目前(2009)支援IPv6的環境還是很少， 所以我們先將IPv6的支援取消(3號箭頭處)。

至於IPv4的IP參數給予，如上圖所示，你得先在1號箭頭處點選手動設定(Manual configuration)， 然後在2號箭頭處輸入正確的IP與子遮罩網路(Netmask)，最後再按下確定即可。處理完畢後就會顯示如下的圖示了：

圖2.5.9、設定網路參數的過程

完成IP參數的設定後，接下來是這部練習機的主機名稱，請輸入你喜歡的主機名稱。 因為目前我們的主機尚未能與網際網路接軌，所以你可以隨便填寫任何你喜歡的主機名稱。 主機名稱通常的格式都是『主機名.網域名』，其實就有點像是『名字.姓氏』的樣子。 為了不與網際網路的其他主機衝突，因此這裡鳥哥使用我自己的名字作為主機名！ 填寫完畢後請按下『下一步』吧！

圖2.5.10、未設定閘道器的警告訊息

咦！怎麼會出現如同上圖所示的錯訊息呢？別擔心，因為我們的主機還不能夠連上Internet， 所以出現這個錯誤訊息是正常的。請按下『繼續』來往後處理吧！

- 時區的選擇

時區是很重要的！因為不同的時區會有不一樣的日期/時間顯示嘛！可能造成檔案時間的不一致呢， 所以，得要告知系統我們的時區在哪裡才行啊！ 如下圖所示，你可以直接在1號箭頭處選擇亞洲台北， 或直接用滑鼠在地圖上面點選也可以！要特別注意的是那個『UTC』，由於廣泛使用的 GMT 時間與現實的時間有點脫節了， 因此我們可以透過 UTC 這個原子鐘時間的計算方式，取得較為正確的時間喔！ 不過，要不要選擇隨你開心啦！預設是需要支援的喔！

圖2.5.11、時區的選擇

- 設定root的密碼

再來則是最重要的『系統管理員的密碼』設定啦！ 在Linux底下系統管理員的預設帳號名稱為root，請注意，這個密碼很重要！雖然我們是練習用的主機， 不過，還是請你養成良好的習慣，最好root的密碼可以設定的嚴格一點。可以設定至少8個字元以上， 而且含有特殊符號更好，例如：I&my_dog之類，有點怪，但是對你又挺好記的密碼！

圖2.5.12、設定root密碼

6. 軟體選擇

一切都差不多之後，就能夠開始挑選軟體的安裝啦！咦！我怎麼知道我要什麼套件？哈哈！ 您當然不可能會知道∼知道的話.....就不會來這兒查閱資料了 @_@ 沒有啦！開開玩笑....呼∼好冷∼∼

關於軟體的安裝有非常多的想法，如果你是初次接觸Linux的話，當然是全部安裝最好。 如果是已經安裝過多次Linux了，那麼使用預設安裝即可，以後有需要其他的軟體時，再透過網路安裝就好了！ 這樣你的系統也會比較乾淨。但是在這個練習機的安裝中，我們使用預設值加上CentOS提供的選項來安裝即可。 如下圖所示：

圖2.6.1、額外選擇多的軟體群組

如上圖所示，你可以增加1號箭頭所指的三個項目，然後在2號箭頭處保持預設值，再給他下一步即可。 這樣的安裝對於初學者來說已經是非常OK的啦！

- 額外的軟體自訂模式(Option, 進階使用者可以參考)

在Linux的軟體安裝中，由於每個各別軟體的功能非常龐大，很多軟體的開發工具其實一般用戶都用不到。 如果每個軟體都僅釋出一個檔案給我們安裝，那麼我們勢必會安裝到很多不需要的檔案。 所以，Linux開發商就將一項軟體分成多個檔案來給使用者選擇。如果你想要瞭解每項軟體背後的檔案資料， 就可以如同下圖所示，選擇『立即自訂』來設定專屬的軟體功能。

圖2.6.2、軟體自訂安裝的功能

自訂軟體的畫面如下所示，1號箭頭處為軟體群組，是開發商將某些相似功能的軟體綁在一起成為一個群組。 你可以在1號箭頭處選擇你有興趣的功能，然後在2號箭頭處挑選該項目內的細項。如下圖所示， 鳥哥挑選了『程式開發』的群組後，在2號箭頭處挑選了鳥哥有興趣的『開發工具』等， 而這些工具的意義在3號箭頭處所指的白色框框中就會有詳細的說明了。

圖2.6.3、自己選擇所需軟體的畫面

檢查完畢後安裝程式會去檢查你所挑選的軟體有沒有衝突(相依性檢查)，然後就會出現下列視窗， 告訴你你的安裝過程寫入到/root/install.log檔案中，並且你剛剛選擇的所有項目則寫入到/root/anaconda-ks.cfg檔案內。 這兩個檔案很有趣，安裝完畢後你可以自己先看看。

圖2.6.4、準備開始安裝

然後就是開始一連串的等待了！這個等待的過程與你的硬體以及選擇的軟體數量有關。 如下圖所示，2號箭頭處所指的則是安裝程式評估的剩餘時間這個時間不見得準啦！看看就好！

圖2.6.5、安裝過程的畫面示意圖

安裝完畢並按下『Reboot』重新開機後，螢幕會出現如下的訊息，這是正確的資訊，不要擔心出問題啊！ 此時請拿出你的DVD光碟，讓系統自動重新開機。其他的後續設定，請參考下一小節呢！

圖2.6.6、安裝完畢後，重新開機的示意圖

7. 其他功能：RAM testing, 安裝筆記型電腦的核心參數(Option)

- 記憶體壓力測試：memtest86

CentOS的DVD除了提供一般PC來安裝Linux之外，還提供了不少有趣的東西，其中一個就是進行『燒機』的任務！ 這個燒機不是台灣名產燒酒雞啊，而是當你組裝了一部新的個人電腦，想要測試這部主機是否穩定時， 就在這部主機上面運作一些比較耗系統資源的程式，讓系統在高負載的情況下去運作一陣子(可能是一天)， 去測試穩定度的一種情況，就稱為『燒機』啦！

那要如何進行呢？同樣的，放入CentOS的DVD到你的光碟中，然後用這片DVD重新開機，在進入到開機選單時， 輸入memtest86即可。如下圖所示：

圖2.7.1、RAM測試

之後系統就會進入這支記憶體測試的程式中，開始一直不斷的對記憶體寫入與讀出！ 如果燒機個一兩天，這支程式還是不斷的跑而沒有因為任何原因來當機，表示你的記憶體應該還算穩定啦！ 如下所示。如果不想跑這支程式了，就按下箭頭所指的『ESC』處，亦即按下[Esc]按鍵，就能夠重新開機囉！

圖2.7.2、RAM測試

對memtest86有興趣的朋友，可以參考如下的連結喔：

- http://www.memtest.org/

- 安裝筆記型電腦或其他類PC電腦的參數

由於筆記型電腦加入了非常多的省電機制或者是其他硬體的管理機制，包括顯示卡常常是整合型的， 因此在筆記型電腦上面的硬體常常與一般桌上型電腦不怎麼相同。所以當你使用適合於一般桌上型電腦的DVD來安裝Linux時， 可能常常會出現一些問題，導致無法順利的安裝Linux到你的筆記型電腦中啊！那怎辦？

其實很簡單，只要在安裝的時候，告訴安裝程式的linux核心不要載入一些特殊功能即可。 最常使用的方法就是，在使用DVD開機時，加入底下這些選項：

boot: linux nofb apm=off acpi=off pci=noacpi

apm(Advanced Power Management)是早期的電源管理模組，acpi(Advanced Configuration and Power Interface)則是近期的電源管理模組。這兩者都是硬體本身就有支援的，但是筆記型電腦可能不是使用這些機制， 因此，當安裝時啟動這些機制將會造成一些錯誤，導致無法順利安裝。

nofb則是取消顯示卡上面的緩衝記憶體偵測。因為筆記型電腦的顯示卡常常是整合型的， Linux安裝程式本身可能就不是很能夠偵測到該顯示卡模組。此時加入nofb將可能使得你的安裝過程順利一些。

對於這些在開機的時候所加入的參數，我們稱為『核心參數』，這些核心參數是有意義的！ 如果你對這些核心參數有興趣的話，可以參考文後的參考資料來查詢更多資訊(註2)。

安裝後的首次設定

安裝完畢並且重新開機後，系統就會開始以Linux開機囉！但事實上我們的安裝尚未完成喔！ 因為還沒有進行諸如防火牆、SELinux、慣用登入帳號的設定等等。在X Window裡面還有重要的音效裝置也還沒有設定哩！ 所以，底下我們就來處理首次進入X Window的設定吧！

重新開機後，一開始螢幕會出現如下的訊息，這個訊息是說，你如果沒有在數秒鐘之內按下任意按鍵， 那麼系統就會以CentOS (2.6.18-128.el5)那個開機選項進入開機的流程喔。

圖3.1、開機過程的讀秒畫面

那如果你真的按下了任意按鍵，螢幕就會出現如下的訊息，該訊息是由grub開機管理程式所控管的， 目前鳥哥的系統裡面也只有一個選項，那就是剛剛你在讀秒畫面中看到的那個項目。 如果你還有想要加入什麼特殊的參數在開機的過程當中，可以使用下圖中箭頭所指的地方，利用幾個簡單的項目來處理喔！ 這部份我們會在第二十章、開機管理程式中談到的！如果你有設定多重開機， 那麼在下圖的畫面中就會看到多個選單囉！

圖3.2、grub管理程式的選單畫面

一切都沒有問題就按下[Enter]吧！此時grub就會去讀取核心檔案來進行硬體偵測，並載入適當的硬體驅動程式後， 就開始進行CentOS各項服務的啟動了。下圖中箭頭有指到/vmlinuz-2.6.18-128.el5吧？那就是我們的Linux核心檔案啦！ 至於出現Welcome字樣後，就是開始執行各項服務的流程了。

圖3.3、開機過程的核心偵測與服務啟動

接下來系統會開始出現圖形介面，如下圖所示。如果你想要知道系統目前實際在進行什麼服務的啟動時， 可以按下箭頭所指的『詳細資料』。

圖3.4、開機進入圖形介面的示意圖

按下『詳細資料』就會出現下圖，因為安裝的時候我們選擇的是中文，此時啟動各項服務就會以中文來顯示囉！很不錯吧！ ^_^

圖3.5、查閱詳細開機資訊的示意圖

怕了吧？有這麼多不知名的咚咚已經在你的Linux裡面啟動了呢！裡面其實有很多是我們不需要的， 在未來你瞭解了Linux相關的知識之後，就可以將那些不需要的程式(或稱為服務)給他關掉了。目前還不需要緊張， 因為我們還沒有連上Internet吶！還不需要太緊張啦！ ^_^

好了，接下來讓我們開始來設定X Window的相關功能吧！設定很簡單，用滑鼠點一點就可以完成了！別擔心！

1. 防火牆與SELinux

首先，系統會進入歡迎畫面，如下圖所示。下圖的左手邊則是等一下需要設定的項目有哪些。如果沒有問題的話，按『下一頁』繼續設定。

圖3.6、首次設定的歡迎畫面

因為我們目前是Linux練習機而已，因此，建議你將防火牆的功能先取消，反正我們也還沒有連上Intenet嘛！ 所以請在下圖的箭頭處將他點選成為『停用』的狀態。

圖3.7、關閉防火牆的設定項目

因為我們停用防火牆，安裝程式很好心的會提示我們：『你沒有啟用防火牆喔！』 沒關係！繼續吧！ 因為我們在伺服器篇裡面會提到自己設定的防火牆功能啊！所以如下圖箭頭所指，點選『是』即可繼續。

圖3.8、關閉防火牆的警告訊息

接下來如下圖所示出現一個『SELinux』的東西，這個SELinux可就重要了！ 他是Security Enhanced Linux的縮寫，這個軟體是由美國國家安全局(National Security Agency, NSA,註3)所開發的，這東西並不是防火牆喔！SELinux是一個Linux系統存取控制(Access control)的細部設定， 重點在於控制程式對於系統檔案的存取權限限制。由於CentOS 5.x以後的Linux版本對於SELinux的設定已經非常的妥當了， 因此建議您務必要打開這個功能！這部份我們會在第十七章繼續說明的。

圖3.9、啟動SELinux的示意圖

1. Kdump與時區的校正

完成了防火牆與SELinux的選擇後，接下來會出現如下的Kdump視窗。什麼是Kdump呢？這個Kdump就是，當核心出現錯誤的時候， 是否要將當時的記憶體內的訊息寫到檔案中，而這個檔案就能夠給核心開發者研究為啥會當機之用。 我們並不是核心開發者，而且記憶體內的資料實在太大了，因此常常進行Kdump會造成硬碟空間的浪費。 所以，這裡建議不要啟動Kdump的功能喔！

圖3.10、關閉Kdump示意圖

再來就是時間的確認啦！先看一下系統的日期與你的手錶一致否？若不一致請自行調整他。

圖3.11、時區與時間的校正

常常手動調整時間很討厭吧！尤其是如果你的系統是老電腦，一關機BIOS電力不足就會造成系統時間的錯亂時！真討厭∼ 此時我們可以使用網路來進行時間的校正喔！如下圖所示，先按下1號箭頭所指處，然後勾選2號箭頭指的『啟用網路時間通訊協定』， 接下來按下3號箭頭處所指的『新增』來增加時間伺服器喔！

圖3.12、網路校時設定

按下『新增』後就會出現如下畫面，由於系統預設給予的三部網路上面可以提供人家進行時間校正的主機都不在台灣， 為了快速的校正時間，建議你可以將下圖中前三個主機都刪除，只保留後來我們自己加上的台灣的時間伺服器， 就是：tock.stdtime.gov.tw這一部即可。輸入完畢後請按下[Enter]吧！

圖3.13、加入網路時間伺服器的方式

由於我們的Linux練習機還沒有連上Internet，所以當你加上上圖所指向的那部主機時，就會出現如下圖的錯誤啦！ 沒關係，不要理他！那是正常的！請按下『是』來繼續吧！

圖3.14、未連上Interenet的警告訊息

1. 建立一般使用者

一般來說，我們在操作Linux系統時，除非必要，否則不要使用root的權限，這是因為管理員(root)的權限太大了！ 我們可能會隨時不小心搞錯了一個小咚咚，結果卻造成整個系統的掛點去.....所以，建立一個一般身份使用者來操作才是好習慣。 舉例來說，鳥哥都會建立一個一般身份使用者的帳號(例如底下的vbird)，用這個帳號來操作Linux， 而當我的主機需要額外的root權限來管理時，才使用身份轉換指令來切換身份成為root來管理維護呢！^_^

如下圖所示，鳥哥建立的登入帳號名稱為vbird，而全名僅是一個簡易的說明而已，那個地方隨便填沒關係(不填也無所謂！)。 但是兩個密碼欄均需填寫，螢幕並不會顯示出你輸入的字元，而是以黑點來取代。兩個欄位必須輸入相同的密碼喔！

圖3.15、一般帳號的建立

1. 音效卡與其他軟體的安裝

如果你的主機有音效卡，而且Linux也能夠正確的捉到該音效卡時，就會出現如下畫面。如果你想要知道到底這個音效卡能否順利運作， 如下圖箭頭所指處，按下測試就能夠聽聽有沒有聲音的輸出啦！

圖3.16、音效卡的測試

最後，如果你還有自己的第三方軟體需要安裝，才放入光碟繼續安裝。我們當然沒有額外的光碟，所以下圖不用理他！

圖3.17、額外的軟體光碟安裝

到此為止，我們的Linux就安裝與設定好了，接下來就能夠登入Linux啦！如果沒有特殊需求的話， 請開始閱讀下一章首次開關機與線上求助(man page)吧！

多重開機安裝流程與技巧

有鑑於自由軟體的蓬勃發展以及專利軟體越來越貴，所以政府單位也慢慢的希望各部門在選購電腦時， 能夠考量同時含有兩種以上作業系統的機器了。加上很多朋友其實也常常有需要兩種不同作業系統來處理日常生活與工作的事情。 那我是否需要兩部主機來操作不同的作業系統？不需要的，我們可以透過多重開機來選擇登入不同的作業系統喔！ 一部機器搞定不同作業系統哩。

不過，就如同鳥哥之前提過的，多重開機系統是有很多風險存在的，而且你也不能隨時變動這個多重作業系統的開機磁區， 這對於初學者想要『很猛烈的』玩Linux是有點妨礙∼所以，鳥哥不是很建議新手使用多重開機啦！ 所以，底下僅是提出一個大概，你可以看一看，未來我們談到後面的章節時，你自然就會有『豁然開朗』的笑容出現了！ ^_^

新主機僅有一顆硬碟

如果你的系統是新的，並且想要安裝多重作業系統時，那麼這個多重作業系統的安裝將顯的很簡單啊！ 假設以目前主流的160GB硬碟作為規劃好了，而你想要有WindowsXP, WindowsXP的資料碟, Linux, Swap及一個共用分割槽， 那我們首先來規劃一下硬碟分割吧！如果是這樣的需求，那你可以這樣規劃：

Linux裝置檔名

Windows裝置

實際內容

檔案系統

容量(GB)

/dev/sda1

C

Windows系統

NTFS

30

/dev/sda2

D

Windows資料碟

NTFS

60

/dev/sda3

不要掛載

Linux根目錄(/)

Ext3

50

/dev/sda5

不要掛載

記憶體置換空間swap

swap

1

/dev/sda6

E

Windows/Linux共用

vfat

其他所有

接下來就是系統的安裝了！安裝一定要先裝WindowsXP再裝Linux才好！順序搞錯了會很麻煩喔！ 基本上，你可以這樣安裝：

1. 先裝Windows XP

在這個階段依舊使用Windows XP光碟開機來安裝，安裝到了分割時，記得依照上述表格的規劃製作出兩個主要分割槽， 並且將檔案系統格式化為NTFS，然後再將Windows XP裝到C槽當中。理論上，此時僅有/dev/sda1, /dev/sda2而已喔！

2. 安裝CentOS 5.x

再來則是安裝Linux囉，安裝時要注意的地方也是在分割的地方，請回到前一小節的磁碟分割部分來進行分割設定。另外一個要注意的地方則是在開機管理程式的地方， 同樣回到前一小節看一下開機管理程式是如何指定開機選單的！ 尤其是『預設開機』項目，是預設要Windows還是Linux開機呢？這需要你的選擇喔！而且grub務必要安裝到MBR上頭。

3. 後續維護的注意事項

多重開機設定完畢後請特別注意， (1)Windows的環境中最好將Linux的根目錄與swap取消掛載，否則未來你打開檔案總管時， 該軟體會要求你『格式化！』如果一個不留神，你的Linux系統就毀了。 (2)你的Linux不可以隨便的刪除！ 因為grub會去讀取Linux根目錄下的/boot/目錄內容，如果你將Linux移除了，你的Windows也就無法開機了！ 因為整個開機選單都會不見喔！

舊主機有兩顆以上硬碟

如果你的主機上面已經有Windows了，為了擔心與Linux衝突，所以你想要加裝一顆新的硬碟來安裝Linux，這樣好嗎？ 也是不錯的想法啦！不過你得要注意的是，整部個人電腦僅會有一個MBR而已！雖然你有兩顆硬碟。

為什麼有兩顆硬碟卻只有一個MBR呢？因為你得在BIOS裡面調整開機的裝置，只有第一個可開機裝置內的MBR會被系統主動讀取。 所以囉，理論上，你不會將Windows的開機管理程式安裝到/dev/sda而將Linux安裝到/dev/sdb上頭， 而是得要將grub安裝到/dev/sda上，透過他來管理Windows/Linux才行，即使你的Linux是放到/dev/sdb這顆硬碟上面的。

比較聰明的朋友會想到『我可以調整BIOS內的開機裝置，使得要進入不同的作業系統時，就用不同的開機裝置來開機， 如此一來應該就能夠避免將grub安裝到/dev/sda了吧？』這個想法本身是OK的，只不過， 因為SATA的裝置檔名是利用偵測的順序來決定的，所以你如果這樣調整來調整去的話， 你的SATA裝置檔名可能會產生不同，這對於linux的運作會有問題，因此如果這樣隨時調整BIOS時， 可能還是會造成無法開機成功的問題！

所以鳥哥還是建議BIOS內的開機順序不要改變，然後以grub來控制全部的開機選單較佳！ 不過，如果你覺得grub不是這麼好用，那怎辦？沒關係，你可以使用spfdisk這個國人寫的開機管理程式來管理喔！ 如果你真的想要使用spfdisk來管理開機選單的話，那你在安裝Linux的時候，記得將grub安裝到開機磁區(boot sector)， 然後重新開機進入Windows後，以spfdisk來設定正確的開機選單即可。spfdisk的官網與鳥哥之前寫的教學文章可以參考：

- spfdisk官網：http://spfdisk.sourceforge.net/

- 鳥哥的spfdisk教學：http://linux.vbird.org/linux_basic/0140spfdisk.php

舊主機只有一顆硬碟

如果你想要在你的Windows主機上面多加一個Linux作業系統呢？那就得要注意啦！ 因為Windows/Linux不能共存在同一個partition上！而Linux的根目錄最好使用Ext3這種Linux支援的檔案系統。 所以，你就得要清出來一個空的分割槽給Linux使用才行喔。

舉例來說，如果你的系統只有C槽，那能不能安裝Linux呢？很抱歉！沒辦法！如果你的系統有C與D槽， 但是你又想要保留一個資料槽給Windows使用，那你就得要這樣做：

1. 先將D槽的資料搬移出來，不論是搬到隨身碟還是C槽中暫存；

2. 在Windows的邏輯分割管理員中，將D槽刪除並重建成兩個分割槽，一個是D一個是E；

3. 將D槽格式化為NTFS(或FAT32)，然後將剛剛的備份資料搬回D槽去；

4. E槽不要掛載，這是Linux預計要安裝的系統槽。

這種情況是比較麻煩啦，因為資料需要搬來搬去的，需要很注意移動的過程喔！ 否則，很容易將自己好幾年辛苦工作的資料一不小心的全部刪除！那就欲哭無淚了！

關於大硬碟導致無法開機的問題

有些朋友可能在第一次安裝完Linux後，卻發現無法開機的問題，也就是說，確實可以使用上面鳥哥介紹的方法來安裝CentOS5， 但就是無法順利開機，只要重新開機就會出現類似底下的畫面：

# 前面是一些奇怪的提示字元啊！

grub> _

然後等待你輸入一些資料∼如果不幸你發生了這樣的問題，那麼可能的主要原因就是......

- 你的主機板BIOS太舊，導致捉不到您的新硬碟；

- 你的硬碟容量太大了(例如超過120 GB以上)，但是主機板並不支援∼

如果真的是這樣，那就麻煩了∼你可能可以這樣做：

- 前往您主機板的官方網站，下載最新的BIOS檔案，並且更新BIOS吧！

- 將你硬碟的cylinders, heads, sectors抄下來，進入BIOS內，將硬碟的型號以使用者設定的方式手動設定好∼

當然還有一個最簡單的解決方法，那就是：重新安裝Linux，並且在磁碟分割的地方，建立一個100MB左右的分割槽， 將他掛載到/boot這個掛載點。並且要注意，/boot的那個掛載點，必須要在整個硬碟的最前面！ 例如，必須是/dev/hda1才行！

至於會產生這個問題的原因確實是與BIOS支援的硬碟容量有關，處理方法雖然比較麻煩，不過也只能這樣做了。 更多與硬碟及開機有關的問題，鳥哥會在第二十章開機與關機程序再進一步說明的啦！

重點回顧

- 不論你要安裝什麼樣的Linux作業系統角色，都應該要事先規劃例如分割、開機管理程式等；

- 建議練習機安裝時的磁碟分割能有/, /boot, /home, swap四個分割槽；

- 調整開機裝置的順序必須要重新開機並進入BIOS系統調整；

- 安裝CentOS 5.x的模式至少有兩種，分別是圖形介面與文字介面；

- 若安裝筆記型電腦時失敗，可嘗試在開機時加入『linux nofb apm=off acpi=off』來關閉省電功能；

- 安裝過程進入分割後，請以『自訂的分割模式』來處理自己規劃的分割方式；

- 在安裝的過程中，可以建立軟體磁碟陣列(software RAID)；

- 一般要求swap應該要是1.5~2倍的實體記憶體量；

- 即使沒有swap依舊能夠安裝與運作Linux作業系統；

- CentOS 5.x的開機管理程式為grub，安裝時最好選擇安裝置MBR中；

- 沒有連上Internet時，可嘗試關閉防火牆，但SELinux最好選擇『強制』狀態；

- 設定時不要選擇啟動kdump，因為那是給核心開發者查閱當機資料的；

- 可加入時間伺服器來同步化時間，台灣可選擇tock.stdtime.gov.tw這一部；

- 盡量使用一般用戶來操作Linux，有必要再轉身份成為root即可。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

問答題部分：

- Linux的目錄配置以『樹狀目錄』來配置，至於磁碟分割槽(partition)則需要與樹狀目錄相配合！ 請問，在預設的情況下，在安裝的時候系統會要求你一定要分割出來的兩個Partition為何？

就是根目錄『/』與記憶體置換空間『Swap』

- 若在分割的時候，在 IDE1 的 slave 硬碟中，分割『六個有用』的分割槽 (具有 filesystem 的) ，此外，已知有兩個 primary 的分割類型！請問六個分割槽的檔名？

/dev/hdb1(primary)

/dev/hdb2(primary)

/dev/hdb3(extended)

/dev/hdb5(logical 底下皆為 logical)

/dev/hdb6

/dev/hdb7

/dev/hdb8

請注意，5-8 這四個 logical 容量相加的總和為 /dev/hdb3！

- 一般而言，在RAM為64 MB或128 MB的系統中，swap要開多大？

Swap 可以簡單的想成是虛擬記憶體，通常他的建議大小為 RAM 的兩倍， 但是實際上還是得視您的主機規格配備與用途而定。約兩倍的 RAM ，亦即為 128 MB 或 256 MB ，可獲得較佳效能！

- 什麼是GMT時間？台北時間差幾個鐘頭？

GMT 時間指的是格林威治時間，稱為標準的時間，而台北時間較 GMT 快了 8 小時！

- 軟體磁碟陣列的裝置檔名為何？

RAID : /dev/md[0-15];

- 如果我的磁碟分割時，設定了四個 Primary 分割槽，但是磁碟還有空間，請問我還能不能使用這些空間？

不行！因為最多只有四個 Primary 的磁碟分割槽，沒有多的可以進行分割了！且由於沒有 Extended ，所以自然不能再使用 Logical 分割

- 硬碟的第零軌含有MBR及partition table，請問，partition 的最小單位為(磁柱、磁頭、磁軌)

為 Cylinder (磁柱)，所以 partition 的大小為磁柱大小的倍數。

參考資料與延伸閱讀

- 註1：Virtualbox為一個虛擬機器的軟體，可以在一部機器上面同時運作多個作業系統。 鳥哥是在Windows XP上面安裝Virtualbox本版來進行CentOS 5.x的捉圖。其官網如下：

http://www.virtualbox.org/

- 進階記憶體測試網站：http://www.memtest.org/

- 註2：更多的核心參數可以參考如下連結：

http://www.faqs.org/docs/Linux-HOWTO/BootPrompt-HOWTO.html

對於安裝過程所加入的參數有興趣的，則可以參考底下這篇連結，裡面有詳細說明硬體原因：

http://polishlinux.org/choose/laptop/

- 註3：SELinux是由美國國家安全局開發出來的，SELinux是被整合到Linux核心當中， SELinux並非防火牆，他是一個存取權限控制的模組。 最早之前SELinux的開發是有鑑於系統常常會被一般使用者誤用而造成系統資料的安全性問題， 因此加上這個模組來防止系統被終端用戶不小心濫用系統資源喔！詳細的說明可以參考底下的連結：

http://www.nsa.gov/selinux/

- SPFdisk的官網：http://spfdisk.sourceforge.net/

2008/08/21：舊的FC4安裝文章被移到到此處

2008/09/02：經過過去兩個星期的忙碌，終於完成這篇安裝說明！

2009/08/11：重新以 CentOS 5.3 的 DVD 來捉圖解釋！

2011/03/17：參考讀者 Xlfdll 的來信告知，UTC 的解釋應該不是日光節約時間，而是較為正確的時間鐘！

2008/09/02以來統計人數

第五章、首次登入與線上求助 man page

切換解析度為 800x600

最近更新日期：2009/08/17

終於可以開始使用Linux這個有趣的系統了！由於Linux系統使用了非同步的磁碟/記憶體資料傳輸模式，同時又是個多人多工的環境， 所以你不能隨便的不正常關機，關機有一定的程序喔！錯誤的關機方法可能會造成磁碟資料的損毀呢！ 此外，Linux有多種不同的操作方式，圖形介面與文字介面的操作有何不同？ 我們能否在文字介面取得大量的指令說明，而不需要硬背某些指令的選項與參數等等。這都是這一章要來介紹的呢！

1. 首次登入系統

1.1 首次登入CentOS 5.x圖形介面

1.2 GNOME的操作與登出

1.3 KDE的操作與登出

1.4 X Window與文字模式的切換

1.5 在終端介面登入linux

2. 文字模式下指令的下達

2.1 開始下達指令, 語系的支援

2.2 基礎指令的操作, date, cal, bc

2.3 重要的幾個熱鍵[Tab], [ctrl]-c, [ctrl]-d

2.4 錯誤訊息的查看

3. Linux系統的線上求助man page與info page

3.1 man page

3.2 info page

3.3 其他有用的文件(documents)

4. 超簡單文書編輯器： nano

5. 正確的關機方法: sync, shutdown, reboot, halt, poweroff, init

6. 開機過程的問題排解

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23877

首次登入系統

登入系統有這麼難嗎？並不難啊！雖然說是這樣說，然而很多人第一次登入Linux的感覺都是『接下來我要幹啥？』如果是以圖形介面登入的話，或許還有很多好玩的事物， 但要是以文字介面登入的話，面對著一片黑壓壓的螢幕，還真不曉得要幹嘛呢！為了讓大家更瞭解如何正確的使用Linux， 正確的登入與離開系統還是需要說明的！

首次登入CentOS 5.x圖形介面

開機就開機呀！怎麼還有所謂的登入與離開呀？不是開機就能夠用電腦了嗎？ 開什麼玩笑，在Linux系統中由於是多人多工的環境，所以系統隨時都有很多任務在進行，因此正確的開關機可是很重要的！ 不正常的關機可能會導致檔案系統錯亂，造成資料的毀損呢！這也是為什麼通常我們的Linux主機都會加掛一個不斷電系統囉！

如果在第四章一切都順利的將CentOS 5.x完成安裝並且重新開機後， 應該就會出現如下的等待登入的圖形畫面才對。畫面的左上方是CentOS 5的distribution說明， 而1號箭頭所指處的四個文字則是可以改變工作環境的地方，2號箭頭說明今天的日期/時間與主機名稱(www.vbird.tsai)， 3號箭頭就是我們可以使用帳號登入的輸入框框囉。

圖1.1.1、X等待登入的畫面

讓我們來瞭解一下上圖1號箭頭所指的那四個功能吧！先點選一下『語言』按鈕，你會發現螢幕出現很多可以選擇的語系資料！ 鳥哥擷取部分畫面如下所示。在下圖中你可以選擇不同的中文或者是其他語言，等一下你登入後， 螢幕就會顯示你所選擇的語系畫面了。不過要注意的是，如果你選擇的語系的軟體檔案並沒有被安裝， 那麼登入系統後就會出現很多亂碼啊！如下圖所示，鳥哥先選擇台灣的繁體中文，然後按下『改變語言』按鈕即可。

圖1.1.2、選擇語系的畫面

接下來讓我們按一下『作業階段』按鈕吧！按下作業階段後螢幕就會出現如下的畫面。 所謂的作業階段指的是你可以使用不同的圖形介面來操作整個Linux系統。 這個圖形介面並不是只有將桌面背景更改而已，而是整個顯示、控制、管理、圖形軟體都不相同了！ 非常的好玩！目前CentOS 5.x預設至少就提供GNOME/KDE這兩種圖形介面(我們稱為視窗管理員, Window Manager, 註1)。 如下圖所示。CentOS 5.x預設使用的是GNOME這個玩意兒，如果你沒有改變的話，那等一下就會登入GNOME的圖形介面囉。

圖1.1.3、更改作業階段的視窗示意圖

接下來準備要登入啦！我們在經過第四章的安裝過程後，理論上現在會有兩個可用的帳號，以鳥哥的安裝為例， 我有root及vbird兩個可用的帳號喔！那第四章我們也說過，最好不要使用root啦！因此， 鳥哥就在圖1.1.1的地方開始用vbird來登入了，如下所示，記得輸入完畢後要按『Enter』喔！

圖1.1.4、輸入使用者帳號的地方

接著系統會要你輸入密碼，此時請在密碼欄填入該帳號的密碼！在你輸入密碼時該欄位會顯示黑點來取代！ 這是為了保密啦！輸入完畢後請按下『Enter』開始登入囉！

圖1.1.5、輸入密碼的示意圖

由於鳥哥在圖1.1.2曾經修改過語系資料，因此系統就會詢問你， 是否要將剛剛的設定變更成為預設值？還是只有這次登入才使用呢？你可以按下『成為預設值』， 讓你這次的決定套用到未來的操作喔！OK！讓我們開始來玩一玩GNOME這個預設的視窗管理員吧！

圖1.1.6、詢問是否將設定值更改為預設值的視窗

GNOME的操作與登出

終於給他看到圖形介面啦！真是很開心吧！如下圖所示，整個GNOME的視窗大約分為三個部分：

- 上方工作列(control panel)

上半部有應用程式、位置與系統及快捷鍵的地方，可以看成是工作列，你可以使用滑鼠在1號箭頭處 (應用程式) 點擊一下， 就會有更多的程式集出現！然後移動滑鼠就能夠使用各個軟體了。至於3號箭頭所指的地方，就是系統時間與聲音調整。 另外，在3號箭頭的左邊不是有個打X的符號嗎？那個是CentOS 5.x的線上更新系統(update)。由於我們尚未連上Internet， 所以這邊就會顯示X喔。

- 桌面

整個畫面中央就是桌面啦！在桌面上預設有三個小按鈕，例如箭頭2所指的就是檔案總管。你可以使用滑鼠連擊兩下就能夠打開該功能。 其實電腦與個人資料夾都是檔案總管啦！如果有執行各種程式，程式的顯示也都是在桌面位置喔。

- 下方工作列

下方工作列的目的是將各工作顯示在這裡，可以方便使用者點選之用。其中4號箭頭所指處為將所有工作最小化隱藏， 至於5號箭頭處指的那四個玩意兒，就是四個虛擬桌面(Virtual Desktop)了！GNOME提供四個桌面給使用者操作， 你可以在那四個桌面隨便點一點，看看有啥不同！尤其是當你有執行不同的程式時，就會發現他的功能啦！ ^_^

圖1.2.1、GNOME的視窗畫面示意圖

Linux桌面的使用方法幾乎跟Windows一模一樣，你可以在桌面上按下右鍵就可以有額外的選單出現； 你也可以直接按下桌面上的『個人資料夾』，就會出現類似Windows的『檔案總管』的檔案/目錄管理視窗， 裡面則出現你自己的工作目錄；好了，讓我們點擊一下『應用程式』那個按鈕吧！看看下拉式選單中有什麼軟體可用！ 如下圖所示。你要注意的是，因為我們的Linux尚未連上Internet，所以線上更新系統會有警告訊息(2號箭頭處)， 請你將他關閉吧！

Tips:

關於『個人資料夾』的內容，記得我們之前說過Linux是多人多工的作業系統吧？ 每個人都會有自己的『工作目錄』，這個目錄是使用者可以完全掌控的， 所以就稱為『使用者個人家目錄』了。一般來說，家目錄都在/home底下， 以鳥哥這次的登入為例，我的帳號是vbird，那麼我的家目錄就應該在/home/vbird/囉！

圖1.2.2、應用程式的下拉式選單示意圖

Tips:

那個線上升級的按鈕不是不重要喔！而是因為我們尚未連上Internet所以這裡才先將他略過的。 你的系統穩不穩定、安不安全與這個玩意兒相關性可大了！千萬別小看他囉！ 有興趣的朋友可以到google先搜尋一下yum這個機制來看看先！ ^_^ 因為你的Linux尚未線上更新過，所以先不要連上Internet喔！

- 使用檔案總管

首先我們來瞭解一下常用的GNOME檔案總管要怎麼用？要說明的是，GNOME的檔案總管其實稱為『鸚鵡螺(Nautilus)』， 只是我們比較習慣稱呼檔案總管就是了。^_^。當你在桌面中點選『個人資料夾』就會出現如下圖示。 預設鸚鵡螺是用小圖示來顯示檔案，而且隱藏檔也沒有顯示出來呢！ 所以你只會看到一個檔案。注意1號箭頭所指的地方，你可以按下那個小按鈕來切換到不同的目錄去喔！

圖1.2.3、鸚鵡螺檔案總管的預設顯示畫面

鳥哥還是比較喜歡清單式的將所有資料都列出來，所以我們的設定需要修正一下。 請在上圖中按下『編輯』點選『偏好設定』後，會出現如下圖示，請將箭頭所在處的兩個地方修訂一下， 包括以清單顯示及顯示隱藏檔喔！填完就按下右下角的『關閉』即可。

圖1.2.4、鸚鵡螺檔案總管的偏好設定視窗

將原本的畫面關閉再重開一個檔案總管，請如下圖所示，按下『顯示』選擇『顯示隱藏檔』及『以清單方式顯示』後， 就可以發現到好多檔案囉！什麼是隱藏檔呢？其實檔名開頭為小數點『.』的， 那個檔案就是隱藏檔了。所以在如下圖的畫面中，你會看到多出來的檔案檔名都是小數點開頭的！

圖1.2.5、家目錄下的隱藏檔資料

除了自己的家目錄之外，你可以在上圖的左下角『vbird』處點一下，然後選擇根目錄(/)，就會出現如下圖示。 1號箭頭告訴我們，這個vbird帳號無法登入該目錄，所以有個紅色的禁止圖示；如果想要查閱某目錄的內容， 如2號箭頭所指處，你可以點一下三角形的圖示，就能夠將該目錄內的資料捉出來了；最後，如同3號箭頭所指的， 如果是出現紙張的圖示，代表那是個檔案而不是目錄囉！

圖1.2.6、鸚鵡螺檔案總管的目錄/檔案顯示情況

- 中文輸入法

在CentOS 5.x當中所使用的中文輸入法為SCIM軟體，你要啟動SCIM很簡單，只要叫出任何一個能夠輸入文字的軟體， 然後按下『Ctrl』+『Space(空白鍵)』就能夠呼叫出來了！以下圖為例，鳥哥執行『附屬應用程式』內的『文字編輯』軟體， 然後按下[ctrl]+[space]就出現下圖。然後點一下圖中的箭頭所指處，你就會看到很多輸入法了！ 比較有趣的是那個『新酷音』輸入法， 其實那就是大家常用的新注音啦！可以自動挑字的輸入法！不錯用喔！

圖1.2.7、SCIM中文輸入法呼叫示意圖

- 登出GNOME

如果你沒有想要繼續玩X Window了，那就登出吧！如何登出呢？如下圖所示，點選『系統』內的『登出』即可。 要記得的是，登出前最好將所有不需要的程式都關閉了再登出啊！

圖1.2.8、登出GNOME的按鈕

會有一個確認視窗跑出來給我們確認一下，就給他點選『登出』吧！

圖1.2.9、登出GNOME的確認視窗

請注意喔，登出並不是關機！只是讓你的帳號離開系統而已喔！

- 其他練習

底下的例題請大家自行參考並且實作一下喔！題目很簡單，所以鳥哥就不額外抓圖了！

- 如何在上方工作列中新增其他的圖示(icons)，讓操作更方便？請嘗試新增終端機圖示；

- 嘗試瀏覽一下/etc這個目錄內，有哪些檔案/目錄存在；

- 請將/etc/crontab這個檔案『複製』到你的家目錄中；

- 請修改四個Virtual Desktop的底色圖案，讓他們都不相同；

- 嘗試修改螢幕解析度；

KDE的操作與登出

玩過了GNOME之後，接下來讓我們來瞭解一下KDE這個也是很常見的視窗管理程式吧！ 請回到圖1.1.1中，在按下『作業階段』後請選擇KDE，然後輸入你的帳號密碼來登入KDE的環境。 登入後的預設畫面如下所示：

圖1.3.1、KDE登入後的預設畫面

上圖中的箭頭所指處的功能說明如下：

- 桌面：上圖中整個藍色畫面就是桌面。而一號箭頭指的地方，一開始僅有垃圾桶而已，你可以自行增加其他的快速按鈕在桌面！ 當有工作被執行時，該工作就是顯示在這個桌面的區域中；

- 工作列快捷鍵：2號箭頭指的地方就是KDE的K選單！你給他按一下該選單就會出現更多的選項功能。 感覺上就是開始功能表囉！至於K選單的右邊還有很多的快捷按鈕，你可以自行點選看看；

- 虛擬桌面：3號箭頭所指的就是虛擬桌面。與GNOME相似的，CentOS的KDE也提供四個虛擬桌面。 你可以在各個桌面分別放置不同的底圖哩！自己玩看看吧！

- 工作列：4號箭頭處，當你有執行任何工作時，該工作的圖示就會顯示到這個地方。

- 小時鐘：5號箭頭所指的地方就是目前的時間。預設是數位時鐘，你可以將他改為圓形的小時鐘喔！

- KDE內的檔案管理

同樣的，得先來瞭解一下檔案管理的軟體啊！在GNOME檔案總管稱為鸚鵡螺， 在KDE檔案總管稱為『Konqueror, 征服家』。你可以按下『K選單』然後選擇『家目錄』，如下所示：

圖1.3.2、開啟征服家的方式之一

啟動征服家預設會出現如下圖所示的畫面：

圖1.3.3、KDE的征服家顯示檔案資料圖示

如上圖所示為征服家的預設顯示情況。畫面的左邊有點類似目錄的列表，右邊則是檔案詳細的資訊。 而征服家可以讓妳僅選擇使用者可以隨意應用的家目錄 (2號箭頭處) 或者是整個系統的檔案資訊 (1號箭頭處)。 征服家預設顯示的是家目錄啦。3號箭頭處指出該目錄內有哪些資訊，4號箭頭則是詳細的檔案參數啦。 接下來請點選『Root資料夾』吧！讓我們瞧瞧整個檔案系統有些什麼東西？

圖1.3.4、根目錄資料的顯示

如上圖所示，當你點選Root資料夾，並且按下/etc那個資料夾後，畫面右邊就會出現/etc資料夾的檔案內容了。 一開始檔案是以小圖示來顯示，如果你按下清單圖示，就是上圖中3號箭頭處，那就會出現詳細的檔案資料了。 如下圖所示：

圖1.3.5、檔案資料的詳細清單顯示

如上圖所示，按下2號箭頭處讓加號 (+) 展開，妳就能夠看到更詳細的檔案資料。然後拉動4號箭頭處的移動鈕， 你就能夠看到3號箭頭處的更詳細的資訊，包括檔案大小、類型、更動時間、所屬使用者與群組等參數資料。 其他更詳細的資料就請自己玩玩吧！

- 登出KDE或關機

如果不想要玩KDE了，請按下『K選單』，然後選擇『登出』功能，就會出現如下圖示：

圖1.3.6、KDE的登出畫面示意圖

如上圖所示，畫面最上方的『vbird』指的是你的帳號，如果你使用不同的帳號登入，這裡就會有不同的帳號名稱。 至於畫面中的三個按鈕功能為：

- 『關閉目前的工作階段』：就是登出而已，會回到圖1.1.1等待登入的畫面；

- 『關閉電腦』：就是關機的功能；

- 『重新啟動電腦』：就是重新開機的功能！

至於更多的X window相關的使用技巧，以及相關的軟體應用，鳥哥這裡就不多說了， 因為鳥哥著重在Linux作業系統的基礎應用以及網路伺服器的應用啊！ ^_^ 如果你還真的有興趣， 建議你可以前往楊老師的網站上看看喔！http://apt.nc.hcc.edu.tw/docs/FC3_X/ 。

- 其他練習

- 由『K選單』-->『尋找檔案/資料夾』啟動搜尋，並找尋檔名為 crontab 的檔案在哪裡？

- 工作列的最右方原本是數字形態的時鐘，請將他改為圖形顯示的時鐘；

- 如何叫出控制台？控制台的『區域性』裡面的『鍵盤配置』有何用處？

- 重新啟動X Window的快速按鈕

一般來說，我們是可以手動來直接修改X Window的設定檔的，不過，修改完成之後的設定項目並不會立刻被載入， 必須要重新啟動X才行(特別注意，不是重新開機，而是重新啟動X！) 。那麼如何重新啟動X呢？ 最簡單的方法就是：

- 直接登出，然後再重新登入即可；

- 在X的畫面中直接按下[Alt] + [Ctrl] + [Backspace]

第二個方法比較有趣，[backspace]是倒退鍵，你按下三個按鈕後X Window立刻會被重新啟動。 如果你的X Window因為不明原因導致有點問題時，也可以利用這個方法來重新啟動X喔！^_^

X window與文字模式的切換

我們前面一直談到的是X Window的視窗管理員環境，那麼在這裡面有沒有純文字介面的環境啊？ 當然有啊！但是，要怎麼切換X Window與文字模式呢？注意喔，通常我們也稱文字模式為終端機介面, terminal 或 console喔！Linux預設的情況下會提供六個Terminal來讓使用者登入， 切換的方式為使用：[Ctrl] + [Alt] + [F1]~[F6]的組合按鈕。

那這六個終端介面如何命名呢，系統會將[F1] ~ [F6]命名為tty1 ~ tty6的操作介面環境。 也就是說，當你按下[crtl] + [Alt] + [F1]這三個組合按鈕時 (按著[ctrl]與[Alt]不放，再按下[F1]功能鍵)， 就會進入到tty1的terminal介面中了。同樣的[F2]就是tty2囉！那麼如何回到剛剛的X視窗介面呢？很簡單啊！按下[Ctrl] + [Alt] + [F7]就可以了！我們整理一下登入的環境如下：

- [Ctrl] + [Alt] + [F1] ~ [F6]  ：文字介面登入 tty1 ~ tty6 終端機；

- [Ctrl] + [Alt] + [F7]   ：圖形介面桌面。

在Linux預設的登入模式中，主要分為兩種，一種是僅有純文字介面(所謂的執行等級run level 3)的登入環境，在這種環境中你可以有tty1~tty6的終端介面，但是並沒有圖形視窗介面的環境喔。 另一種則是圖形介面的登入環境(所謂的執行等級run level 5)，這也是我們第四章安裝妥當後的預設環境！ 在這個環境中你就具有tty1~tty7了！其中的tty7就是開機完成後的預設等待登入的圖形環境！

如果你是以純文字環境啟動Linux的，預設的tty7是沒有東西的！萬一如此的話，那要怎麼啟動X視窗畫面呢？ 你可以在tty1~tty6的任意一個終端介面使用你的帳號登入後(登入的方法下一小節會介紹)， 然後下達如下的指令即可：

[vbird@www ~]$ startx

不過startx這個指令並非萬靈丹，你要讓startx生效至少需要底下這幾件事情的配合：

- 你的tty7並沒有其他的視窗軟體正在運作(tty7必須是空出來的)；

- 你必須要已經安裝了X Window system，並且X server是能夠順利啟動的；

- 你最好要有視窗管理員，例如GNOME/KDE或者是陽春的TWM等；

- 啟動X所必須要的服務，例如字型伺服器(X Font Server, xfs)必須要先啟動。

剛剛我們談到的Linux啟動時可以選擇純文字或者是視窗環境，也談到了執行等級(run level)這東西！ Linux預設提供了七個Run level給我們使用，其中最常用到的就是run level 3與run level 5這兩者了。 如果你想要讓Linux在下次開機時使用純文字環境(run level 3)來登入， 只要修訂一下/etc/inittab這個檔案的內容，就能夠在下次重新開機時生效了！ 因為我們尚未提到vi以及開機過程的詳細資訊， 所以啊，這部分得到系統管理員篇幅的時候再說明！別擔心，再仔細的看下去吧！

在終端介面登入linux

剛剛你如果有按下[Ctrl] + [Alt] + [F1]就可以來到tty1的登入畫面，而如果你是使用純文字介面(其實是run level 3)啟動Linux主機的話，那麼預設就是會來到tty1這個環境中。這個環境的等待登入的畫面有點像這樣：

CentOS release 5.3 (Final)

Kernel 2.6.18-128.el5 on an i686

www login: vbird

Password:

[vbird@www ~]$ _

上面顯示的內容是這樣的：

1. CentOS release 5.3 (Final)：

顯示Linux distribution的名稱(CentOS)與版本(5.3)；

2. Kernel 2.6.18-128.el5 on an i686：

顯示核心的版本為2.6.18-128.el5， 且目前這部主機的硬體等級為i686。如果是使用x86_64的Linux版本且安裝到64位元的PC，那你的硬體等級就會是『X86_64』喔！

3. www login:：

那個www是你的主機名稱。我們在第四章安裝時有填寫主機名稱為： www.vbird.tsai，主機名稱的顯示通常只取第一個小數點前的字母，所以就成為www啦！至於login:則是一支可以讓我們登入的程式。 你可以在login:後面輸入你的帳號。以鳥哥為例，我輸入的就是第四章建立的vbird那個帳號啦！ 當然囉，你也可以使用root這個帳號來登入的。不過『root』這個帳號代表在Linux系統下無窮的權力， 所以盡量不要使用root帳號來登入啦！

4. Password:：

這一行則在第三行的vbird輸入後才會出現，要你輸入密碼囉！ 請注意，在輸入密碼的時候，螢幕上面『不會顯示任何的字樣！』， 所以不要以為你的鍵盤壞掉去！很多初學者一開始到這裡都會拼命的問！啊我的鍵盤怎麼不能用...

5. [vbird@www ~]$ _：

這一行則是正確登入之後才顯示的訊息， 最左邊的vbird顯示的是『目前使用者的帳號』，而@之後接的www則是『主機名稱』，至於最右邊的~則指的是 『目前所在的目錄』，那個$則是我們常常講的『提示字元』啦！

Tips:

那個 ~ 符號代表的是『使用者的家目錄』的意思，他是個『變數！』 這相關的意義我們會在後續的章節依序介紹到。舉例來說，root的家目錄在/root， 所以 ~ 就代表/root的意思。而vbird的家目錄在/home/vbird， 所以如果你以vbird登入時，他看到的 ~ 就會等於/home/vbird喔！

至於提示字元方面，在Linux當中，預設root的提示字元為 # ，而一般身份使用者的提示字元為 $ 。

還有，上面的第一、第二行的內容其實是來自於/etc/issue這個檔案喔！

好了這樣就是登入主機了！很快樂吧！耶∼

另外，再次強調，在Linux系統下最好常使用一般帳號來登入即可，所以上例中鳥哥是以自己的帳號vbird來登入的。 因為系統管理員帳號(root)具有無窮大的權力，例如他可以刪除任何一個檔案或目錄。因此若你以root身份登入Linux系統， 一個不小心下錯指令，這個時候可不是『欲哭無淚』就能夠解決的了問題的∼

因此，一個稱職的網路/系統管理人員，通常都會具有兩個帳號，平時以自己的一般帳號來使用Linux主機的任何資源， 有需要動用到系統功能修訂時，才會轉換身份成為root呢！所以，鳥哥強烈建議你建立一個普通的帳號來供自己平時使用喔！ 更詳細的帳號訊息，我們會在後續的『第十四章帳號管理』再次提及！ 這裡先有概念即可！

那麼如何離開系統呢？其實應該說『登出Linux』才對！登出很簡單，直接這樣做：

[vbird@www ~]$ exit

就能夠登出Linux了。但是請注意：『離開系統並不是關機！』 基本上，Linux本身已經有相當多的工作在進行，你的登入也僅是其中的一個『工作』而已， 所以當你離開時，這次這個登入的工作就停止了，但此時Linux其他的工作是還是繼續在進行的！ 本章後面我們再來提如何正確的關機，這裡先建立起這個概念即可！

文字模式下指令的下達

其實我們都是透過『程式』在跟系統作溝通的，本章上面提到的視窗管理員或文字模式都是一組或一隻程式在負責我們所想要完成的指令。 文字模式登入後所取得的程式被稱為殼(Shell)，這是因為這支程式負責最外面跟使用者(我們)溝通，所以才被戲稱為殼程式！ 更多與作業系統及殼程式的相關性可以參考第零章、計算機概論內的說明。

我們Linux的殼程式就是厲害的bash這一支！關於更多的bash我們在第三篇再來介紹。現在讓我們來練一練打字吧！

開始下達指令

其實整個指令下達的方式很簡單，你只要記得幾個重要的概念就可以了。 舉例來說，你可以這樣下達指令的：

[vbird@www ~]$ command [-options] parameter1 parameter2 ...

指令     選項      參數(1)    參數(2)

說明：

0. 一行指令中第一個輸入的部分絕對是『指令(command)』或『可執行檔案』

1. command 為指令的名稱，例如變換路徑的指令為 cd 等等；

2. 中刮號[]並不存在於實際的指令中，而加入選項設定時，通常選項前會帶 - 號，

例如 -h；有時候會使用選項的完整全名，則選項前帶有 -- 符號，例如 --help；

3. parameter1 parameter2.. 為依附在選項後面的參數，或者是 command 的參數；

4. 指令, 選項, 參數等這幾個咚咚中間以空格來區分，不論空幾格 shell 都視為一格；

5. 按下[Enter]按鍵後，該指令就立即執行。[Enter]按鍵代表著一行指令的開始啟動。

6. 指令太長的時候，可以使用反斜線 (\) 來跳脫[Enter]符號，使指令連續到下一行。

注意！反斜線後就立刻接特殊字符，才能跳脫！

其他：

a. 在 Linux 系統中，英文大小寫字母是不一樣的。舉例來說， cd 與 CD 並不同。

b. 更多的介紹等到第十一章 bash 時，再來詳述。

注意到上面的說明當中，『第一個被輸入的資料絕對是指令或者是可執行的檔案』！ 這個是很重要的概念喔！還有，按下[Enter]鍵表示要開始執行此一命令的意思。我們來實際操作一下： 以ls這個『指令』列出『自己家目錄(~)』下的『所有隱藏檔與相關的檔案屬性』， 要達成上述的要求需要加入 -al 這樣的選項，所以：

[vbird@www ~]$ ls -al ~

[vbird@www ~]$ ls           -al   ~

[vbird@www ~]$ ls -a  -l ~

上面這三個指令的下達方式是一模一樣的執行結果喔！為什麼？請參考上面的說明吧！ 關於更詳細的文字模式使用方式，我們會在第十一章認識BASH再來強調喔！ 此外，請特別留意，在Linux的環境中， 『大小寫字母是不一樣的東西！』也就是說，在Linux底下， VBird與vbird這兩個檔案是『完全不一樣的』檔案呢！所以， 你在下達指令的時候千萬要注意到指令是大寫還是小寫。例如當輸入底下這個指令的時候，看看有什麼現象：

[vbird@www ~]$ date  <==結果顯示日期與時間

[vbird@www ~]$ Date  <==結果顯示找不到指令

[vbird@www ~]$ DATE  <==結果顯示找不到指令

很好玩吧！只是改變小寫成為大寫而已，該指令就變的不存在了！ 因此，請千萬記得這個狀態呦！

- 語系的支援

另外，很多時候你會發現，咦！怎麼我輸入指令之後顯示的結果的是亂碼？ 這跟鳥哥說的不一樣啊！呵呵！不要緊張∼我們前面提到過，Linux是可以支援多國語系的，若可能的話， 螢幕的訊息是會以該支援語系來輸出的。但是，我們的終端機介面(terminal)在預設的情況下， 無法支援以中文編碼輸出資料的。這個時候，我們就得將支援語系改為英文，才能夠以英文顯示出正確的訊息。 那怎麼做呢？你可以這樣做：

1. 顯示目前所支援的語系

[vbird@www ~]$ echo $LANG

zh_TW.UTF-8

# 上面的意思是說，目前的語系(LANG)為zh_TW.UTF-8，亦即台灣繁體中文的萬國碼

2. 修改語系成為英文語系

[vbird@www ~]$ LANG=en_US

# 注意到上面的指令中沒有空白字元，且英文語系為en_US才對喔！

[vbird@www ~]$ echo $LANG

en_US

# 再次確認一下，結果出現，確實是en_US這個英文語系！

注意一下，那個『LANG=en_US』是連續輸入的，等號兩邊並沒有空白字元喔！ 這樣一來，就能夠在『這次的登入』察看英文訊息囉！為什麼說是『這次的登入』呢？ 因為，如果你登出Linux後，剛剛下達的指令就沒有用啦！ ^_^，這個我們會在第十一章再好好聊一聊的！好囉，底下我們來練習一下一些簡單的指令， 好讓你可以瞭解指令下達方式的模式：

基礎指令的操作

底下我們立刻來操作幾個簡單的指令看看囉！

- 顯示日期與時間的指令： date

- 顯示日曆的指令： cal

- 簡單好用的計算機： bc

1. 顯示日期的指令： date

如果在文字介面中想要知道目前Linux系統的時間，那麼就直接在指令列模式輸入date即可顯示：

[vbird@www ~]$ date

Mon Aug 17 17:02:52 CST 2009

上面顯示的是：星期一, 八月十七日, 17:02 分, 52秒，在 2009 年的 CST 時區！台灣在CST時區中啦！ 請趕快動手做做看呦！好了，那麼如果我想要讓這個程式顯示出『2009/08/17』這樣的日期顯示方式呢？ 那麼就使用date的格式化輸出功能吧！

[vbird@www ~]$ date +%Y/%m/%d

2009/08/17

[vbird@www ~]$ date +%H:%M

17:04

那個『+%Y%m%d』就是date指令的一些參數功能啦！很好玩吧！那你問我， 鳥哥怎麼知道這些參數的啊？要背起來嗎？當然不必啦！底下再告訴你怎麼查這些參數囉！

從上面的例子當中我們也可以知道，指令之後的選項除了前面帶有減號『-』之外，某些特殊情況下， 選項或參數前面也會帶有正號『+』的情況！這部份可不要輕易的忘記了呢！

2. 顯示日曆的指令： cal

那如果我想要列出目前這個月份的月曆呢？呵呵！直接給他下達cal即可！

[vbird@www ~]$ cal

August 2009

Su Mo Tu We Th Fr Sa

1

2  3  4  5  6  7  8

9 10 11 12 13 14 15

16 17 18 19 20 21 22

23 24 25 26 27 28 29

30 31

除了本月的日曆之外，連同今日所在處都會有反白的顯示呢！真有趣！cal (calendar)這個指令可以做的事情還很多，例如你可以顯示整年的月曆情況：

[vbird@www ~]$ cal 2009

2009

January               February                 March

Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa

1  2  3    1  2  3  4  5  6  7    1  2  3  4  5  6  7

4  5  6  7  8  9 10    8  9 10 11 12 13 14    8  9 10 11 12 13 14

11 12 13 14 15 16 17   15 16 17 18 19 20 21   15 16 17 18 19 20 21

18 19 20 21 22 23 24   22 23 24 25 26 27 28   22 23 24 25 26 27 28

25 26 27 28 29 30 31                          29 30 31

April                   May                   June

Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa   Su Mo Tu We Th Fr Sa

1  2  3  4                   1  2       1  2  3  4  5  6

5  6  7  8  9 10 11    3  4  5  6  7  8  9    7  8  9 10 11 12 13

12 13 14 15 16 17 18   10 11 12 13 14 15 16   14 15 16 17 18 19 20

19 20 21 22 23 24 25   17 18 19 20 21 22 23   21 22 23 24 25 26 27

26 27 28 29 30         24 25 26 27 28 29 30   28 29 30

31

....(以下省略)....

基本上cal這個指令可以接的語法為：

[vbird@www ~]$ cal [month] [year]

所以，如果我想要知道2009年10月的月曆，可以直接下達：

[vbird@www ~]$ cal 10 2009

October 2009

Su Mo Tu We Th Fr Sa

1  2  3

4  5  6  7  8  9 10

11 12 13 14 15 16 17

18 19 20 21 22 23 24

25 26 27 28 29 30 31

那請問今年有沒有13月啊？來測試一下這個指令的正確性吧！下達下列指令看看：

[vbird@www ~]$ cal 13 2009

cal: illegal month value: use 1-12

cal竟然會告訴我們『錯誤的月份，請使用1-12』這樣的資訊呢！所以， 未來你可以很輕易的就以cal來取得日曆上面的日期囉！簡直就是萬年曆啦！ ^_^。 另外，由這個cal指令的練習我們也可以知道，某些指令有特殊的參數存在， 若輸入錯誤的參數，則該指令會有錯誤訊息的提示，透過這個提示我們可以藉以瞭解指令下達錯誤之處。 這個練習的結果請牢記在心中喔！

3. 簡單好用的計算機： bc

如果在文字模式當中，突然想要作一些簡單的加減乘除，偏偏手邊又沒有計算機！這個時候要筆算嗎？ 不需要啦！我們的Linux有提供一支計算程式，那就是bc喔。你在指令列輸入bc後，螢幕會顯示出版本資訊， 之後就進入到等待指示的階段。如下所示：

[vbird@www ~]$ bc

bc 1.06

Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.

This is free software with ABSOLUTELY NO WARRANTY.

For details type `warranty'.

_ <==這個時候，游標會停留在這裡等待你的輸入

事實上，我們是『進入到bc這個軟體的工作環境當中』了！ 就好像我們在Windows裡面使用『小算盤』一樣！所以，我們底下嘗試輸入的資料， 都是在bc程式當中在進行運算的動作。所以囉，你輸入的資料當然就得要符合bc的要求才行！ 在基本的bc計算機操作之前，先告知幾個使用的運算子好了：

- + 加法

- - 減法

- * 乘法

- / 除法

- ^ 指數

- % 餘數

好！讓我們來使用bc計算一些咚咚吧！

[vbird@www ~]$ bc

bc 1.06

Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.

This is free software with ABSOLUTELY NO WARRANTY.

For details type `warranty'.

1+2+3+4  <==只有加法時

10

7-8+3

2

10*52

520

10%3     <==計算『餘數』

1

10^2

100

10/100   <==這個最奇怪！不是應該是 0.1 嗎？

0

quit     <==離開 bc 這個計算器

在上表當中，粗體字表示輸入的資料，而在每個粗體字的底下就是輸出的結果。 咦！每個計算都還算正確，怎麼10/100會變成0呢？這是因為bc預設僅輸出整數，如果要輸出小數點下位數，那麼就必須要執行 scale=number ，那個number就是小數點位數，例如：

[vbird@www ~]$ bc

bc 1.06

Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.

This is free software with ABSOLUTELY NO WARRANTY.

For details type `warranty'.

scale=3     <==沒錯！就是這裡！！

1/3

.333

340/2349

.144

quit

注意啊！要離開bc回到命令提示字元時，務必要輸入『quit』來離開bc的軟體環境喔！ 好了！就是這樣子啦！簡單的很吧！以後你可以輕輕鬆鬆的進行加減乘除啦！

從上面的練習我們大概可以知道在指令列模式裡面下達指令時，會有兩種主要的情況：

- 一種是該指令會直接顯示結果然後回到命令提示字元等待下一個指令的輸入；

- 一種是進入到該指令的環境，直到結束該指令才回到命令提示字元的環境。

我們以一個簡單的圖示來說明：

圖2.2.1、指令下達的環境，上圖為直接顯示結果，下圖為進入軟體功能

如圖2.2.1所示，上方指令下達後立即顯示訊息且立刻回到命令提示字元的環境。 如果有進入軟體功能的環境(例如上面的bc軟體)，那麼就得要使用該軟體的結束指令 (例如在bc環境中輸入quit)才能夠回到命令提示字元中！那你怎麼知道你是否在命令提示字元的環境呢？ 很簡單！你只要看到游標是在『[vbird@www ~]$』這種提示字元後面， 那就是等待輸入指令的環境了。很容易判斷吧！不過初學者還是很容易忘記啦！

重要的幾個熱鍵[Tab], [ctrl]-c, [ctrl]-d

在繼續後面章節的學習之前，這裡很需要跟大家再來報告一件事，那就是我們的文字模式裡頭具有很多的功能組合鍵， 這些按鍵可以輔助我們進行指令的編寫與程式的中斷呢！這幾個按鍵請大家務必要記住的！很重要喔！

- [Tab]按鍵

[Tab]按鍵就是在鍵盤的大寫燈切換按鍵([Caps Lock])上面的那個按鍵！在各種Unix-Like的Shell當中， 這個[Tab]按鍵算是Linux的Bash shell最棒的功能之一了！他具有『命令補全』與『檔案補齊』的功能喔！ 重點是，可以避免我們打錯指令或檔案名稱呢！很棒吧！但是[Tab]按鍵在不同的地方輸入，會有不一樣的結果喔！ 我們舉下面的例子來說明。上一小節我們不是提到 cal 這個指令嗎？如果我在指令列輸入 ca 再按兩次 [tab] 按鍵， 會出現什麼訊息？

[vbird@www ~]$ ca[tab][tab]    <==[tab]按鍵是緊接在 a 字母後面！

cadaver             callgrind_control   capifax             card

cal                 cameratopam         capifaxrcvd         case

caller              cancel              capiinfo            cat

callgrind_annotate  cancel.cups         captoinfo           catchsegv

# 上面的 [tab] 指的是『按下那個tab鍵』，不是要你輸入中括號內的tab啦！

發現什麼事？所有以ca為開頭的指令都被顯示出來啦！很不錯吧！那如果你輸入『ls -al ~/.bash』再加兩個[tab]會出現什麼？

[vbird@www ~]$ ls -al ~/.bash[tab][tab]

.bash_history  .bash_logout   .bash_profile  .bashrc

咦！在該目錄下面所有以 .bash 為開頭的檔案名稱都會被顯示出來了呢！注意看上面兩個例子喔， 我們按[tab]按鍵的地方如果是在command(第一個輸入的資料)後面時，他就代表著 『命令補全』，如果是接在第二個字以後的，就會變成『檔案補齊』的功能了！總結一下：

- [Tab] 接在一串指令的第一個字的後面，則為命令補全；

- [Tab] 接在一串指令的第二個字以後時，則為『檔案補齊』！

善用 [tab] 按鍵真的是個很好的習慣！可以讓你避免掉很多輸入錯誤的機會！

- [Ctrl]-c 按鍵

如果你在Linux底下輸入了錯誤的指令或參數，有的時候這個指令或程式會在系統底下『跑不停』這個時候怎麼辦？別擔心， 如果你想讓當前的程式『停掉』的話，可以輸入：[Ctrl]與c按鍵(先按著[Ctrl]不放，且再按下c按鍵，是組合按鍵)， 那就是中斷目前程式的按鍵啦！舉例來說，如果你輸入了『find /』這個指令時，系統會開始跑一些東西(先不要理會這個指令串的意義)，此時你給他按下 [Ctrl]-c 組合按鍵，嘿嘿！是否立刻發現這個指令串被終止了！就是這樣的意思啦！

[vbird@www ~]$ find /

....(一堆東西都省略)....

# 此時螢幕會很花，你看不到命令提示字元的！直接按下[ctrl]-c即可！

[vbird@www ~]$ <==此時提示字元就會回來了！find程式就被中斷！

不過你應該要注意的是，這個組合鍵是可以將正在運作中的指令中斷的， 如果你正在運作比較重要的指令，可別急著使用這個組合按鍵喔！ ^_^

- [Ctrl]-d 按鍵

那麼[Ctrl]-d是什麼呢？就是[Ctrl]與d按鍵的組合啊！這個組合按鍵通常代表著： 『鍵盤輸入結束(End Of File, EOF 或 End Of Input)』的意思！ 另外，他也可以用來取代exit的輸入呢！例如你想要直接離開文字介面，可以直接按下[Ctrl]-d就能夠直接離開了(相當於輸入exit啊！)。

總之，在Linux底下，文字介面的功能是很強悍的！要多多的學習他，而要學習他的基礎要訣就是...多使用、多熟悉啦！

錯誤訊息的察看

萬一我下達了錯誤的指令怎麼辦？不要緊呀！你可以藉由螢幕上面顯示的錯誤訊息來瞭解你的問題點， 那就很容易知道如何改善這個錯誤訊息囉！舉個例子來說，假如想執行date卻因為大小寫打錯成為DATE時， 這個錯誤的訊息是這樣顯示的：

[vbird@www ~]$ DATE

-bash: DATE: command not found

上面那個bash:表示的是我們的Shell的名稱， 本小節一開始就談到過Linux的預設殼程式就是bash囉！ 那麼上面的例子說明了bash有錯誤，什麼錯誤呢？bash告訴你：

DATE: command not found

字面上的意思是說『指令找不到』，那個指令呢？就是DATE這個指令啦！ 所以說，系統上面可能並沒有DATE這個指令囉！就是這麼簡單！通常出現『command not found』的可能原因為：

- 這個指令不存在，因為該軟體沒有安裝之故。解決方法就是安裝該軟體；

- 這個指令所在的目錄目前的用戶並沒有將他加入指令搜尋路徑中，請參考bash的PATH說明；

- 很簡單！因為你打錯字！

另外常見的錯誤就是我們曾經看過的例子，如下所示：

[vbird@www ~]$ cal 13 2009

cal: illegal month value: use 1-12

螢幕會告訴我們錯誤的訊息啦！照著螢幕的訊息去處理即可解決你的錯誤啦！是否很簡單啊！ 因此，以後如果出現了問題，螢幕上的訊息真的是很重要的呢！不要忽略了他呦！

介紹這幾個指令讓你玩一玩先，更詳細的指令操作方法我們會在第三篇的時候再進行介紹！ 現在讓我們來想一想，萬一我在操作date這個指令的時候，手邊又沒有這本書，我要怎麼知道要如何加那些奇怪的參數， 好讓輸出的結果符合我想要的輸出格式呢？嘿嘿！到下一節鳥哥來告訴你怎麼辦吧！

Linux系統的線上求助man page與info page

先來瞭解一下Linux有多少指令呢？在文字模式下，你可以直接按下兩個[Tab]按鍵，看看總共有多少指令可以讓你用？

[vbird@www ~]$ <==在這裡不要輸入任何字元，直接輸入兩次[tab]按鍵

Display all 2450 possibilities? (y or n) <==如果不想要看，按 n 離開

如上所示，鳥哥安裝的這個系統中，少說也有2000多個以上的指令可以讓vbird這個帳號使用。 那在Linux裡面到底要不要背『指令』啊？可以啊！你背啊！這種事，鳥哥這個『忘性』特佳的老人家實在是背不起來 @_@ ∼當然啦，有的時候為了要考試(例如一些認證考試等等的)還是需要背一些重要的指令與選項的！ 不過，鳥哥主要還是以理解『在什麼情況下，應該要使用哪方面的指令』為準的！

既然鳥哥說不需要背指令，那麼我們如何知道每個指令的詳細用法？還有，某些設定檔的內容到底是什麼？ 這個可就不需要擔心了！因為在Linux上開發的軟體大多數都是自由軟體，而這些軟體的開發者為了讓大家能夠瞭解指令的用法， 都會自行製作很多的文件，而這些文件也可以直接在線上就能夠輕易的被使用者查詢出來喔！很不賴吧！ 這根本就是『線上說明文件』嘛！哈哈！沒錯！確實如此。我們底下就來談一談，Linux到底有多少的線上文件資料呢？

man page

嗄？不知道怎麼使用date這個指令？嘿嘿！不要擔心，我們Linux上面的線上求助系統已經都幫你想好要怎麼辦了， 所以你只要使用簡單的方法去尋找一下說明的內容，馬上就清清楚楚的知道該指令的用法了！怎麼看呢？就是找男人(man) 呀！喔！不是啦！這個man是manual(操作說明)的簡寫啦！只要下達：『man date』 馬上就會有清楚的說明出現在你面前喔！如下所示：

[vbird@www ~]$ LANG="en"

# 還記得這個咚咚的用意吧？前面提過了，是為了『語系』的需要啊！下達過一次即可！

[vbird@www ~]$ man date

DATE(1)                          User Commands                         DATE(1)

# 請注意上面這個括號內的數字

NAME  <==這個指令的完整全名，如下所示為date且說明簡單用途為設定與顯示日期/時間

date - print or set the system date and time

SYNOPSIS  <==這個指令的基本語法如下所示

date [OPTION]... [+FORMAT]

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

DESCRIPTION  <==詳細說明剛剛語法談到的選項與參數的用法

Display  the  current  time  in  the given FORMAT, or set the system

date.

-d, --date=STRING  <==左邊-d為短選項名稱，右邊--date為完整選項名稱

display time described by STRING, not 'now'

-f, --file=DATEFILE

like --date once for each line of DATEFILE

-r, --reference=FILE

display the last modification time of FILE

....(中間省略)....

# 找到了！底下就是格式化輸出的詳細資料！

FORMAT controls the output.  The only valid option  for  the  second

form  specifies  Coordinated  Universal Time.  Interpreted sequences

are:

%%     a literal %

%a     locale's abbreviated weekday name (e.g., Sun)

%A     locale's full weekday name (e.g., Sunday)

....(中間省略)....

ENVIRONMENT  <==與這個指令相關的環境參數有如下的說明

TZ     Specifies the timezone, unless  overridden  by  command  line

parameters.   If  neither  is  specified,  the  setting  from

/etc/localtime is used.

AUTHOR  <==這個指令的作者啦！

Written by David MacKenzie.

REPORTING BUGS  <==有問題請留言給底下的email的意思！

Report bugs to <bug-coreutils@gnu.org>.

COPYRIGHT  <==受到著作權法的保護！用的就是 GPL 了！

Copyright ? 2006 Free Software Foundation, Inc.

This is free software.  You may redistribute copies of it under  the

terms      of      the      GNU      General      Public     License

<http://www.gnu.org/licenses/gpl.html>.  There is  NO  WARRANTY,  to

the extent permitted by law.

SEE ALSO  <==這個重要，你還可以從哪裡查到與date相關的說明文件之意

The  full  documentation for date is maintained as a Texinfo manual.

If the info and date programs are properly installed at  your  site,

the command

info date

should give you access to the complete manual.

date 5.97                          May 2006                            DATE(1)

Tips:

進入man指令的功能後，你可以按下『空白鍵』往下翻頁，可以按下『 q 』按鍵來離開man的環境。 更多在man指令下的功能，本小節後面會談到的！

看(鳥哥沒罵人！)馬上就知道一大堆的用法了！如此一來，不就可以知道date的相關選項與參數了嗎？真方便！ 而出現的這個螢幕畫面，我們稱呼他為man page， 你可以在裡頭查詢他的用法與相關的參數說明。如果仔細一點來看這個man page的話，你會發現幾個有趣的東西。

首先，在上個表格的第一行，你可以看到的是：『DATE(1)』，DATE我們知道是指令的名稱， 那麼(1)代表什麼呢？他代表的是『一般使用者可使用的指令』的意思！咦！還有這個用意啊！呵呵！ 沒錯∼在查詢資料的後面的數字是有意義的喔！他可以幫助我們瞭解或者是直接查詢相關的資料。 常見的幾個數字的意義是這樣的：

代號

代表內容

1

使用者在shell環境中可以操作的指令或可執行檔

2

系統核心可呼叫的函數與工具等

3

一些常用的函數(function)與函式庫(library)，大部分為C的函式庫(libc)

4

裝置檔案的說明，通常在/dev下的檔案

5

設定檔或者是某些檔案的格式

6

遊戲(games)

7

慣例與協定等，例如Linux檔案系統、網路協定、ASCII code等等的說明

8

系統管理員可用的管理指令

9

跟kernel有關的文件

上述的表格內容可以使用『man 7 man』來更詳細的取得說明。透過這張表格的說明， 未來你如果使用man page在察看某些資料時，就會知道該指令/檔案所代表的基本意義是什麼了。 舉例來說，如果你下達了『man null』時，會出現的第一行是：『NULL(4)』，對照一下上面的數字意義， 嘿嘿！原來null這個玩意兒竟然是一個『裝置檔案』呢！很容易瞭解了吧！

Tips:

上表中的1, 5, 8這三個號碼特別重要，也請讀者要將這三個數字所代表的意義背下來喔！

再來，man page的內容也分成好幾個部分來加以介紹該指令呢！就是上頭man date那個表格內， 以NAME作為開始介紹，最後還有個SEE ALSO來作為結束。基本上，man page大致分成底下這幾個部分：

代號

內容說明

NAME

簡短的指令、資料名稱說明

SYNOPSIS

簡短的指令下達語法(syntax)簡介

DESCRIPTION

較為完整的說明，這部分最好仔細看看！

OPTIONS

針對 SYNOPSIS 部分中，有列舉的所有可用的選項說明

COMMANDS

當這個程式(軟體)在執行的時候，可以在此程式(軟體)中下達的指令

FILES

這個程式或資料所使用或參考或連結到的某些檔案

SEE ALSO

可以參考的，跟這個指令或資料有相關的其他說明！

EXAMPLE

一些可以參考的範例

BUGS

是否有相關的臭蟲！

有時候除了這些外，還可能會看到Authors與Copyright等，不過也有很多時候僅有NAME與DESCRIPTION等部分。 通常鳥哥在查詢某個資料時是這樣來查閱的：

1. 先察看NAME的項目，約略看一下這個資料的意思；

2. 再詳看一下DESCRIPTION，這個部分會提到很多相關的資料與使用時機，從這個地方可以學到很多小細節呢；

3. 而如果這個指令其實很熟悉了(例如上面的date)，那麼鳥哥主要就是查詢關於OPTIONS的部分了！ 可以知道每個選項的意義，這樣就可以下達比較細部的指令內容呢！

4. 最後，鳥哥會再看一下，跟這個資料有關的還有哪些東西可以使用的？舉例來說，上面的SEE ALSO就告知我們還可以利用『info coreutils date』來進一步查閱資料；

5. 某些說明內容還會列舉有關的檔案(FILES 部分)來提供我們參考！這些都是很有幫助的！

大致上瞭解了man page的內容後，那麼在man page當中我還可以利用哪些按鍵來幫忙查閱呢？首先， 如果要向下翻頁的話，可以按下鍵盤的空白鍵，也可以使用[Page Up]與[Page Down]來翻頁呢！同時，如果你知道某些關鍵字的話， 那麼可以在任何時候輸入『/word』，來主動搜尋關鍵字！例如在上面的搜尋當中，我輸入了『/date』會變成怎樣？

DATE(1)                          User Commands                         DATE(1)

NAME

date - print or set the system date and time

SYNOPSIS

date [OPTION]... [+FORMAT]

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

DESCRIPTION

Display  the  current  time  in  the given FORMAT, or set the system date.

....(中間省略)....

/date <==只要按下/，游標就會跑到這個地方來，你就可以開始輸入搜尋字串咯

看到了嗎，當你按下『/』之後，游標就會移動到螢幕的最下面一行， 並等待你輸入搜尋的字串了。此時，輸入date後，man page就會開始搜尋跟date有關的字串， 並且移動到該區域呢！很方便吧！最後，如果要離開man page時，直接按下『 q 』就能夠離開了。 我們將一些在man page常用的按鍵給他整理整理：

按鍵

進行工作

空白鍵

向下翻一頁

[Page Down]

向下翻一頁

[Page Up]

向上翻一頁

[Home]

去到第一頁

[End]

去到最後一頁

/string

向『下』搜尋 string 這個字串，如果要搜尋 vbird 的話，就輸入 /vbird

?string

向『上』搜尋 string 這個字串

n, N

利用 / 或 ? 來搜尋字串時，可以用 n 來繼續下一個搜尋 (不論是 / 或 ?) ，可以利用 N 來進行『反向』搜尋。舉例來說，我以 /vbird 搜尋 vbird 字串， 那麼可以 n 繼續往下查詢，用 N 往上查詢。若以 ?vbird 向上查詢 vbird 字串， 那我可以用 n 繼續『向上』查詢，用 N 反向查詢。

q

結束這次的 man page

要注意喔！上面的按鍵是在man page的畫面當中才能使用的！ 比較有趣的是那個搜尋啦！我們可以往下或者是往上搜尋某個字串，例如要在man page內搜尋vbird這個字串， 可以輸入 /vbird 或者是 ?vbird ，只不過一個是往下而一個是往上來搜尋的。而要 重複搜尋 某個字串時，可以使用 n 或者是 N 來動作即可呢！ 很方便吧！^_^

既然有man page，自然就是因為有一些文件資料，所以才能夠以man page讀出來囉！那麼這些man page的資料 放在哪裡呢？不同的distribution通常可能有點差異性，不過，通常是放在/usr/share/man這個目錄裡頭，然而，我們可以透過修改他的man page搜尋路徑來改善這個目錄的問題！修改/etc/man.config (有的版本為man.conf或manpath.conf)即可囉！至於更多的關於man的訊息你可以使用『 man man 』來查詢呦！關於更詳細的設定，我們會在第十一章 bash 當中繼續的說明喔！

- 搜尋特定指令/檔案的man page說明文件

在某些情況下，你可能知道要使用某些特定的指令或者是修改某些特定的設定檔，但是偏偏忘記了該指令的完整名稱。 有些時候則是你只記得該指令的部分關鍵字。這個時候你要如何查出來你所想要知道的man page呢？ 我們以底下的幾個例子來說明man這個指令有用的地方喔！

例題：

你可否查出來，系統中還有哪些跟『man』這個指令有關的說明文件呢？

答：

你可以使用底下的指令來查詢一下：

[vbird@www ~]$ man -f man

man                  (1)  - format and display the on-line manual pages

man                  (7)  - macros to format man pages

man.config [man]     (5)  - configuration data for man

使用 -f 這個選項就可以取得更多與man相關的資訊，而上面這個結果當中也有提示了 (數字) 的內容， 舉例來說，第二行的『 man (7) 』表示有個man (7)的說明文件存在喔！但是卻有個man (1)存在啊！ 那當我們下達『 man man 』的時候，到底是找到哪一個說明檔呢？ 其實，你可以指定不同的文件的，舉例來說，上表當中的兩個 man 你可以這樣將他的文件叫出來：

[vbird@www ~]$ man 1 man  <==這裡是用 man(1) 的文件資料

[vbird@www ~]$ man 7 man  <==這裡是用 man(7) 的文件資料

你可以自行將上面兩個指令輸入一次看看，就知道，兩個指令輸出的結果是不同的。 那個1, 7就是分別取出在man page裡面關於1與7相關資料的文件檔案囉！ 好了，那麼萬一我真的忘記了下達數字，只有輸入『 man man 』時，那麼取出的資料到底是1還是7啊？ 這個就跟搜尋的順序有關了。搜尋的順序是記錄在/etc/man.conf這個設定檔當中， 先搜尋到的那個說明檔，就會先被顯示出來！ 一般來說，通常會先找到數字較小的那個啦！因為排序的關係啊！所以， man man 會跟 man 1 man 結果相同！

除此之外，我們還可以利用『關鍵字』找到更多的說明文件資料喔！什麼是關鍵字呢？ 從上面的『man -f man』輸出的結果中，我們知道其實輸出的資料是：

- 左邊部分：指令(或檔案)以及該指令所代表的意義(就是那個數字)；

- 右邊部分：這個指令的簡易說明，例如上述的『-macros to format man pages』

當使用『man -f 指令』時，man只會找資料中的左邊那個指令(或檔案)的完整名稱，有一點不同都不行！ 但如果我想要找的是『關鍵字』呢？也就是說，我想要同時找上面說的兩個地方的內容，只要該內容有關鍵字存在， 不需要完全相同的指令(或檔案)就能夠找到時，該怎麼辦？請看下個範例囉！

例題：

找出系統的說明檔中，只要有man這個關鍵字就將該說明列出來。

答：

[vbird@www ~]$ man -k man

. [builtins]         (1)  - bash built-in commands, see bash(1)

.TP 15 php [php]     (1)  - PHP Command Line Interface 'CLI'

....(中間省略)....

zshall               (1)  - the Z shell meta-man page

zshbuiltins          (1)  - zsh built-in commands

zshzle               (1)  - zsh command line editor

看到了吧！很多對吧！因為這個是利用關鍵字將說明文件裡面只要含有man那個字眼的(不見得是完整字串) 就將他取出來！很方便吧！ ^_^(上面的結果有特殊字體的顯示是為了方便讀者查看， 實際的輸出結果並不會有特別的顏色顯示喔！)

事實上，還有兩個指令與man page有關呢！而這兩個指令是man的簡略寫法說∼就是這兩個：

[vbird@www ~]$ whatis  [指令或者是資料]   <==相當於 man -f [指令或者是資料]

[vbird@www ~]$ apropos [指令或者是資料]   <==相當於 man -k [指令或者是資料]

而要注意的是，這兩個特殊指令要能使用，必須要有建立 whatis 資料庫才行！這個資料庫的建立需要以 root 的身份下達如下的指令：

[root@www ~]# makewhatis

Tips:

一般來說，鳥哥是真的不會去背指令的，只會去記住幾個常見的指令而已。那麼鳥哥是怎麼找到所需要的指令呢？ 舉例來說，列印的相關指令，鳥哥其實僅記得 lp (line print)而已。那我就由 man lp 開始，去找相關的說明， 然後，再以 lp[tab][tab] 找到任何以 lp 為開頭的指令，找到我認為可能有點相關的指令後， 再以 man 去查詢指令的用法！呵呵！所以，如果是實際在管理 Linux ， 那麼真的只要記得幾個很重要的指令即可，其他需要的，嘿嘿！努力的找男人(man)吧！

info page

在所有的Unix Like系統當中，都可以利用 man 來查詢指令或者是相關檔案的用法； 但是，在Linux裡面則又額外提供了一種線上求助的方法，那就是利用info這個好用的傢伙啦！

基本上，info與man的用途其實差不多，都是用來查詢指令的用法或者是檔案的格式。但是與man page一口氣輸出一堆資訊不同的是，info page則是將文件資料拆成一個一個的段落，每個段落用自己的頁面來撰寫， 並且在各個頁面中還有類似網頁的『超連結』來跳到各不同的頁面中，每個獨立的頁面也被稱為一個節點(node)。 所以，你可以將info page想成是文字模式的網頁顯示資料啦！

不過你要查詢的目標資料的說明文件必須要以info的格式來寫成才能夠使用info的特殊功能(例如超連結)。 而這個支援info指令的文件預設是放置在/usr/share/info/這個目錄當中的。 舉例來說，info這個指令的說明文件有寫成info格式，所以，你使用『 info info 』可以得到如下的畫面：

[vbird@www ~]$ info info

File: info.info,  Node: Top,  Next: Getting Started,  Up: (dir)

Info: An Introduction

*********************

The GNU Project distributes most of its on-line manuals in the "Info

format", which you read using an "Info reader".  You are probably using

an Info reader to read this now.

....(中間省略)....

To read about expert-level Info commands, type `n' twice.  This

brings you to `Info for Experts', skipping over the `Getting Started'

chapter.

* Menu:

* Getting Started::             Getting started using an Info reader.

* Expert Info::                 Info commands for experts.

* Creating an Info File::       How to make your own Info file.

* Index::                       An index of topics, commands, and variables.

--zz-Info: (info.info.gz)Top, 29 lines --Top------------------------------

Welcome to Info version 4.8. Type ? for help, m for menu item.

仔細的看到上面這個顯示的結果，裡面的第一行顯示了很多的資訊喔！第一行裡面的資料意義為：

- File：代表這個info page的資料是來自info.info檔案所提供的；

- Node：代表目前的這個頁面是屬於Top節點。 意思是info.info內含有很多資訊，而Top僅是info.info檔案內的一個節點內容而已；

- Next：下一個節點的名稱為Getting Started，你也可以按『N』到下個節點去；

- Up：回到上一層的節點總攬畫面，你也可以按下『U』回到上一層；

- Prev：前一個節點。但由於Top是info.info的第一個節點，所以上面沒有前一個節點的資訊。

從第一行你可以知道這個節點的內容、來源與相關連結的資訊。更有用的資訊是，你可以透過直接按下N, P, U來去到下一個、上一個與上一層的節點(node)！非常的方便！ 第一行之後就是針對這個節點的說明。在上表的範例中，第二行以後的說明就是針對info.info內的Top這個節點所做的。

再來，你也會看到有『Menu』那個咚咚吧！底下共分為四小節，分別是Getting Started等等的，我們可以使用上下左右按鍵來將游標移動到該文字或者『 * 』上面，按下Enter， 就可以前往該小節了！另外，也可以按下[Tab]按鍵，就可以快速的將游標在上表的畫面中的node間移動， 真的是非常的方便好用。如果將info.info內的各個節點串在一起並繪製成圖表的話，情況有點像底下這樣：

圖3.2.1、info page各說明文件相關性的示意圖

如同上圖所示，info的說明文件將內容分成多個node，並且每個node都有定位與連結。 在各連結之間還可以具有類似『超連結』的快速按鈕，可以透過[tab]鍵在各個超連結間移動。 也可以使用U,P,N來在各個階層與相關連結中顯示！非常的不錯用啦！ 至於在info page當中可以使用的按鍵，可以整理成這樣：

按鍵

進行工作

空白鍵

向下翻一頁

[Page Down]

向下翻一頁

[Page Up]

向上翻一頁

[tab]

在 node 之間移動，有 node 的地方，通常會以 * 顯示。

[Enter]

當游標在 node 上面時，按下 Enter 可以進入該 node 。

b

移動游標到該 info 畫面當中的第一個 node 處

e

移動游標到該 info 畫面當中的最後一個 node 處

n

前往下一個 node 處

p

前往上一個 node 處

u

向上移動一層

s(/)

在 info page 當中進行搜尋

h

顯示求助選單

?

指令一覽表

q

結束這次的 info page

info page是只有Linux上面才有的產物，而且易讀性增強很多∼不過查詢的指令說明要具有info page功能的話，得用info page的格式來寫成線上求助文件才行！我們CentOS 5將info page的文件放置到/usr/share/info/目錄中！至於非以info page格式寫成的說明文件(就是man page)，雖然也能夠使用info來顯示，不過其結果就會跟man相同。 舉例來說，你可以下達『info man』就知道結果了！ ^_^

其他有用的文件(documents)

剛剛前面說，一般而言，指令或者軟體製作者，都會將自己的指令或者是軟體的說明製作成『線上說明文件』！ 但是，畢竟不是每個咚咚都需要做成線上說明文件的，還有相當多的說明需要額外的文件！此時，這個所謂的 How-To(如何做的意思)就很重要啦！還有，某些軟體不只告訴你『如何做』， 還會有一些相關的原理會說明呢。

那麼這些說明文件要擺在哪裡呢？哈哈！就是擺在/usr/share/doc這個目錄啦！所以說，你只要到這個目錄底下， 就會發現好多好多的說明文件檔啦！還不需要到網路上面找資料呢！厲害吧！^_^ 舉例來說，你想要知道這一版的CentOS相關的各項資訊，可以直接到底下的目錄去瞧瞧：

- /usr/share/doc/centos-release-notes-5.3/

那如果想要知道本章講過多次的bash是什麼，則可以到/usr/share/doc/bash-3.2/ 這個目錄中去瀏覽一番！很多東西呦！而且/usr/share/doc這個目錄下的資料主要是以套件(packages)為主的， 例如GCC這個套件的相關資訊在/usr/share/doc/gcc-xxx(那個xxx表示版本的意思！)。 未來可得多多查閱這個目錄喔！ ^_^

總結上面的三個咚咚(man, info, /usr/share/doc/)，請記住喔：

- 在文字介面下，有任何你不知道的指令或檔案格式這種玩意兒，但是你想要瞭解他，請趕快使用man或者是info來查詢！

- 而如果你想要架設一些其他的服務，或想要利用一整組軟體來達成某項功能時，請趕快到/usr/share/doc 底下查一查有沒有該服務的說明檔喔！

- 另外，再次的強調，因為Linux畢竟是外國人發明的，所以中文文件確實是比較少的！ 但是不要害怕，拿本英文字典在身邊吧！隨時查閱！不要害怕英文喔！

超簡單文書編輯器： nano

在Linux系統當中有非常多的文書編輯器存在，其中最重要的就是後續章節我們會談到的vi這傢伙！ 不過其實還有很多不錯用的文書編輯器存在的！在這裡我們就介紹一下簡單的nano這一支文書編輯器來玩玩先！

nano的使用其實很簡單，你可以直接加上檔名就能夠開啟一個舊檔或新檔！底下我們就來開啟一個名為text.txt的檔名來看看：

[vbird@www ~]$ nano text.txt

# 不管text.txt存不存在都沒有關係！存在就開啟舊檔，不存在就開啟新檔

GNU nano 1.3.12          File: text.txt

<==這個是游標所在處

[ New File ]

^G Get Help^O WriteOut^R Read Fil^Y Prev Pag^K Cut Text^C Cur Pos

^X Exit    ^J Justify ^W Where Is^V Next Pag^U UnCut Te^T To Spell

# 上面兩行是指令說明列，其中^代表的是[ctrl]的意思

如上圖所示，你可以看到第一行反白的部分，那僅是在宣告nano的版本與檔名(File: text.txt)而已。 之後你會看到最底下的三行，分別是檔案的狀態(New File)與兩行指令說明列。指令說明列反白的部分就是組合鍵， 接的則是該組合鍵的功能。那個指數符號(^)代表的是鍵盤的[Ctrl]按鍵啦！底下先來說說比較重要的幾個組合按鍵：

- [ctrl]-G：取得線上說明(help)，很有用的！

- [ctrl]-X：離開naon軟體，若有修改過檔案會提示是否需要儲存喔！

- [ctrl]-O：儲存檔案，若你有權限的話就能夠儲存檔案了；

- [ctrl]-R：從其他檔案讀入資料，可以將某個檔案的內容貼在本檔案中；

- [ctrl]-W：搜尋字串，這個也是很有幫助的指令喔！

- [ctrl]-C：說明目前游標所在處的行數與列數等資訊；

- [ctrl]-_：可以直接輸入行號，讓游標快速移動到該行；

- [alt]-Y：校正語法功能開啟或關閉(按一下開、再按一下關)

- [alt]-M：可以支援滑鼠來移動游標的功能

比較常見的功能是這些，如果你想要取得更完整的說明，可以在nano的畫面中按下[ctrl]-G或者是[F1]按鍵， 就能夠顯示出完整的naon內指令說明了。好了，請你在上述的畫面中隨便輸入許多字， 輸入完畢之後就儲存後離開，如下所示：

GNU nano 1.3.12          File: text.txt

Type some words in this nano editor program.

You can use [ctrl] plus some keywords to go to some functions.

Hello every one.

Bye bye.

<==這個是由標所在處

[ New File ]

^G Get Help^O WriteOut^R Read Fil^Y Prev Pag^K Cut Text^C Cur Pos

^X Exit    ^J Justify ^W Where Is^V Next Pag^U UnCut Te^T To Spell

此時按下[crtl]-X會出現類似下面的畫面：

GNU nano 1.3.12          File: text.txt

Type some words in this nano editor program.

You can use [ctrl] plus some keywords to go to some functions.

Hello every one.

Bye bye.

Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES) ? ▋

Y Yes

N No           ^C Cancel

如果不要儲存資料只想要離開，可以按下N即可離開。如果確實是需要儲存的，那麼按下Y後，最後三行會出現如下畫面：

File Name to Write: text.txt▋  <==可在這裡修改檔名或直接按[enter]

^G Get Help     ^T To Files     M-M Mac Format  M-P Prepend

^C Cancel       M-D DOS Format  M-A Append      M-B Backup File

如果是單純的想要儲存而已，直接按下[enter]即可儲存後離開nano程式。不過上圖中最底下還有兩行，我們知道指數符號代表[crtl]， 那個M是代表什麼呢？其實就是[alt]囉！其實nano也不需要記太多指令啦！只要知道怎麼進入nano、怎麼離開，怎麼搜尋字串即可。 未來我們還會學習更有趣的vi呢！

正確的關機方法

OK！大概知道開機的方法，也知道基本的指令操作，而且還已經知道線上查詢了，好累呦！ 想去休息呢！那麼如何關機呢？我想，很多朋友在DOS的年代已經有在玩電腦了！ 在當時我們關掉DOS的系統時，常常是直接關掉電源開關，而 Windows 在你不爽的時候，按著電源開關四秒也可以關機！但是在Linux則相當的不建議這麼做！

Why？在 Windows (非 NT 主機系統) 系統中，由於是單人假多工的情況，所以即使你的電腦關機， 對於別人應該不會有影響才對！不過呢，在 Linux 底下，由於每個程序 (或者說是服務) 都是在在背景下執行的，因此，在你看不到的螢幕背後其實可能有相當多人同時在你的主機上面工作， 例如瀏覽網頁啦、傳送信件啦以 FTP 傳送檔案啦等等的，如果你直接按下電源開關來關機時， 則其他人的資料可能就此中斷！那可就傷腦筋了！

此外，最大的問題是，若不正常關機，則可能造成檔案系統的毀損 （因為來不及將資料回寫到檔案中，所以有些服務的檔案會有問題！）。所以正常情況下，要關機時需要注意底下幾件事：

- 觀察系統的使用狀態：

如果要看目前有誰在線上，可以下達『who』這個指令，而如果要看網路的連線狀態，可以下達 『 netstat -a 』這個指令，而要看背景執行的程序可以執行『 ps -aux 』這個指令。使用這些指令可以讓你稍微瞭解主機目前的使用狀態！當然囉，就可以讓你判斷是否可以關機了 （這些指令在後面Linux常用指令中會提及喔！）

- 通知線上使用者關機的時刻：

要關機前總得給線上的使用者一些時間來結束他們的工作，所以，這個時候你可以使用 shutdown 的特別指令來達到此一功能。

- 正確的關機指令使用：

例如 shutdown 與 reboot 兩個指令！

所以底下我們就來談一談幾個與關機/重新開機相關的指令囉！

- 將資料同步寫入硬碟中的指令： sync

- 慣用的關機指令： shutdown

- 重新開機，關機： reboot, halt, poweroff

Tips:

由於Linux系統的關機/重新開機是很重大的系統運作，因此只有root才能夠進行例如shutdown, reboot等指令。 不過在某些distributions當中，例如我們這裡談到的CentOS系統，他允許你在本機前的tty7使用圖形介面登入時， 可以用一般帳號來關機或重新開機！但某些distributions則在你要關機時，他會要你輸入root的密碼呢！^_^

資料同步寫入磁碟： sync

在第零章、計算機概論裡面我們談到過資料在電腦中運作的模式， 所有的資料都得要被讀入記憶體後才能夠被CPU所處理，但是資料又常常需要由記憶體寫回硬碟當中(例如儲存的動作)。 由於硬碟的速度太慢(相對於記憶體來說)，如果常常讓資料在記憶體與硬碟中來回寫入/讀出，系統的效能就不會太好。

因此在Linux系統中，為了加快資料的讀取速度，所以在預設的情況中， 某些已經載入記憶體中的資料將不會直接被寫回硬碟，而是先暫存在記憶體當中，如此一來， 如果一個資料被你重複的改寫，那麼由於他尚未被寫入硬碟中，因此可以直接由記憶體當中讀取出來， 在速度上一定是快上相當多的！

不過，如此一來也造成些許的困擾，那就是萬一你的系統因為某些特殊情況造成不正常關機 (例如停電或者是不小心踢到power)時，由於資料尚未被寫入硬碟當中，哇！所以就會造成資料的更新不正常啦！ 那要怎麼辦呢？這個時候就需要sync這個指令來進行資料的寫入動作啦！ 直接在文字介面下輸入sync，那麼在記憶體中尚未被更新的資料，就會被寫入硬碟中！所以，這個指令在系統關機或重新開機之前， 很重要喔！最好多執行幾次！

雖然目前的 shutdown/reboot/halt 等等指令均已經在關機前進行了 sync 這個工具的呼叫， 不過，多做幾次總是比較放心點∼呵呵∼

[root@www ~]# sync

Tips:

事實上sync也可以被一般帳號使用喔！只不過一般帳號使用者所更新的硬碟資料就僅有自己的資料， 不像root可以更新整個系統中的資料了。

慣用的關機指令： shutdown

由於Linux的關機是那麼重要的工作，因此除了你是在主機前面以tty7圖形介面來登入系統時， 不論用什麼身份都能夠關機之外，若你是使用遠端管理工具(如透過pietty使用ssh服務來從其他電腦登入主機)， 那關機就只有root有權力而已喔！

嗯！那麼就來關機試試看吧！我們較常使用的是shutdown這個指令，而這個指令會通知系統內的各個程序 (processes)，並且將通知系統中的run-level內的一些服務來關閉。shutdown可以達成如下的工作：

- 可以自由選擇關機模式：是要關機、重新開機或進入單人操作模式均可；

- 可以設定關機時間: 可以設定成現在立刻關機, 也可以設定某一個特定的時間才關機。

- 可以自訂關機訊息：在關機之前，可以將自己設定的訊息傳送給線上 user 。

- 可以僅發出警告訊息：有時有可能你要進行一些測試，而不想讓其他的使用者干擾， 或者是明白的告訴使用者某段時間要注意一下！這個時候可以使用 shutdown 來嚇一嚇使用者，但卻不是真的要關機啦！

- 可以選擇是否要 fsck 檢查檔案系統 。

那麼shutdown的語法是如何呢？聰明的讀者大概已經開始找『男人』了！沒錯，隨時隨地的 man 一下，是很不錯的舉動！好了，簡單的語法規則為：

[root@www ~]# /sbin/shutdown [-t 秒] [-arkhncfF] 時間 [警告訊息]

選項與參數：

-t sec ： -t 後面加秒數，亦即『過幾秒後關機』的意思

-k     ： 不要真的關機，只是發送警告訊息出去！

-r     ： 在將系統的服務停掉之後就重新開機(常用)

-h     ： 將系統的服務停掉後，立即關機。 (常用)

-n     ： 不經過 init 程序，直接以 shutdown 的功能來關機

-f     ： 關機並開機之後，強制略過 fsck 的磁碟檢查

-F     ： 系統重新開機之後，強制進行 fsck 的磁碟檢查

-c     ： 取消已經在進行的 shutdown 指令內容。

時間   ： 這是一定要加入的參數！指定系統關機的時間！時間的範例底下會說明。

範例：

[root@www ~]# /sbin/shutdown -h 10 'I will shutdown after 10 mins'

# 告訴大家，這部機器會在十分鐘後關機！並且會顯示在目前登入者的螢幕前方！

# 至於參數有哪些呢？以下介紹幾個吧！

此外，需要注意的是，時間參數請務必加入指令中，否則shutdown會自動跳到 run-level 1 (就是單人維護的登入情況)，這樣就傷腦筋了！底下提供幾個時間參數的例子吧：

[root@www ~]# shutdown -h now

立刻關機，其中 now 相當於時間為 0 的狀態

[root@www ~]# shutdown -h 20:25

系統在今天的 20:25 分會關機，若在21:25才下達此指令，則隔天才關機

[root@www ~]# shutdown -h +10

系統再過十分鐘後自動關機

[root@www ~]# shutdown -r now

系統立刻重新開機

[root@www ~]# shutdown -r +30 'The system will reboot'

再過三十分鐘系統會重新開機，並顯示後面的訊息給所有在線上的使用者

[root@www ~]# shutdown -k now 'This system will reboot'

僅發出警告信件的參數！系統並不會關機啦！嚇唬人！

重新開機，關機： reboot, halt, poweroff

還有三個指令可以進行重新開機與關機的任務，那就是reboot, halt, poweroff。 其實這三個指令呼叫的函式庫都差不多，所以當你使用『man reboot』時，會同時出現三個指令的用法給你看呢。 其實鳥哥通常都只有記shutdown與reboot這兩個指令啦！不過使用poweroff這個指令卻比較簡單就是了！^_^ 通常鳥哥在重新開機時，都會下達如下的指令喔：

[root@www ~]# sync; sync; sync; reboot

既然這些指令都能夠關機或重新開機，那他有沒有什麼差異啊？基本上，在預設的情況下， 這幾個指令都會完成一樣的工作！(因為halt會先呼叫shutdown，而shutdown最後會呼叫halt！)。 不過，shutdown可以依據目前已啟動的服務來逐次關閉各服務後才關機；至於halt卻能夠在不理會目前系統狀況下， 進行硬體關機的特殊功能！你可以在你的主機上面使用root進行底下兩個指令來關機，比較看看差異在哪裡喔！

[root@www ~]# shutdown -h now

[root@www ~]# poweroff -f

更多halt與poweroff的選項功能，請務必使用man去查詢一下喔！

切換執行等級： init

本章上頭有談到過關於run level的問題。之前談到的是系統運作的模式，分為純文字(run level 3)及圖形介面模式(run level 5)。除了這兩種模式外，有沒有其他模式呢？其實Linux共有七種執行等級， 七種等級的意義我們在後面會再談到。本章你只要知道底下四種執行等級就好了：

- run level 0：關機

- run level 3：純文字模式

- run level 5：含有圖形介面模式

- run level 6：重新開機

那如何切換各模式呢？可以使用init這個指令來處理喔！也就是說，如果你想要關機的話， 除了上述的shutdown -h now以及poweroff之外，你也可以使用如下的指令來關機：

[root@www ~]# init 0

開機過程的問題排解

事實上，Linux主機是很穩定的，除非是硬體問題與系統管理員不小心的動作，否則， 很難會造成一些無法挽回的錯誤的。但是，畢竟我們目前使用的可能是練習機，會常常開開關關的， 所以確實可能會有一些小問題發生。好了，我們先來簡單的談一談，如果無法順利開機時， 你應該如何解決。要注意的是，底下說到的內容很多都還沒有開始介紹， 因此，看不懂也不要太緊張∼在本書全部都讀完且看第二遍時，你自然就會有感覺了！ ^_^

檔案系統錯誤的問題

在開機的過程中最容易遇到的問題就是硬碟可能有壞軌或檔案系統發生錯誤(資料損毀)的情況， 這種情況雖然不容易發生在穩定的Linux系統下，不過由於不當的開關機行為， 還是可能會造成的，常見的發生原因可能有：

- 最可能發生的原因是因為斷電或不正常關機所導致的檔案系統發生錯誤， 鳥哥的主機就曾經發生過多次因為跳電，家裡的主機又沒有安裝不斷電系統， 結果就導致硬碟內的檔案系統錯誤！檔案系統錯誤並非硬體錯誤，而是軟體資料的問題喔！

- 硬碟使用率過高或主機所在環境不良也是一個可能的原因， 例如你開放了一個FTP服務，裡面有些資料很有用， 所以一堆人搶著下載，如果你又不是使用較穩定的SCSI介面硬碟，僅使用一般PC使用的硬碟， 雖然機率真的不高，但還是有可能造成硬碟壞軌的。此外，如果主機所在環境沒有散熱的設備， 或者是相對濕度比較高的環境，也很容易造成硬碟的損壞喔！

解決的方法其實很簡單，不過因為出錯磁區所掛載的目錄不同，處理的流程困難度就有差異了。 舉例來說，如果你的根目錄『/』並沒有損毀，那就很容易解決，如果根目錄已經損毀了，那就比較麻煩！

- 如果根目錄沒有損毀：

假設你發生錯誤的partition是在/dev/sda7這一塊，那麼在開機的時候，螢幕應該會告訴你：press root password or ctrl+D : 這時候請輸入root的密碼登入系統，然後進行如下動作：

- 在游標處輸入root密碼登入系統，進行單人單機的維護工作；

- 輸入『 fsck /dev/sda7 』(fsck 為檔案系統檢查的指令，/dev/sda7為錯誤的partition，請依你的情況下達參數)， 這時螢幕會顯示開始修理硬碟的訊息，如果有發現任何的錯誤時，螢幕會顯示： clear [Y/N]？ 的詢問訊息，就直接輸入 Y 吧！

- 修理完成之後，以 reboot 重新開機囉！

- 如果根目錄損毀了

一般初學者喜歡將自己的硬碟只劃分為一個大partition，亦即只有根目錄， 那檔案系統錯誤一定是根目錄的問題囉！這時你可以將硬碟拔掉，接到另一台Linux系統的電腦上， 並且不要掛載(mount)該硬碟，然後以root的身份執行『 fsck /dev/sdb1 』(/dev/sdb1 指的是你的硬碟裝置檔名，你要依你的實際狀況來設定)，這樣就 OK 囉！

另外，也可以使用近年來很熱門的Live CD，也就是利用光碟開機就能夠進入Linux作業系統的特性， 你可以前往：『http://knoppix.tnc.edu.tw/』 這個網站來下載，並且燒錄成為CD，這個時候先用Live CD光碟開機，然後使用fsck去修復原本的根目錄， 例如： fsck /dev/sda1 ，就能夠救回來了！

- 如果硬碟整個壞掉：

如果硬碟實在壞的離譜時，那就先將舊硬碟內的資料，能救出來的救出來，然後換一顆硬碟來重新安裝Linux吧！ 不要不願意換硬碟啊！啥時後硬碟會壞掉誰也說不準的！

那麼硬碟該如何預防發生檔案系統錯誤的問題呢？可以參考底下說明：

- 妥善保養硬碟：

例如：主機通電之後不要搬動，避免移動或震動硬碟；盡量降低硬碟的溫度，可以加裝風扇來冷卻硬碟； 或者可以換裝 SCSI 硬碟。

- 劃分不同的partition：

為什麼磁碟分割這麼重要！因為Linux每個目錄被讀寫的頻率不同，妥善的分割將會讓我們的Linux更安全！ 通常我們會建議劃分下列的磁碟區塊：

- /

- /boot

- /usr

- /home

- /var

這樣劃分有些好處，例如/var是系統預設的一些資料暫存或者是cache資料的儲存目錄， 像 e-mail 就含在這裡面。如果還有使用proxy時，因為常常存取，所以有可能會造成磁碟損壞， 而當這部份的磁碟損壞時，由於其他的地方是沒問題的，因此資料得以保存，而且在處理時也比較容易！

忘記 root 密碼：

常常有些朋友在設定好了Linux之後，結果root密碼給他忘記去！要重新安裝嗎？不需要的， 你只要以單人維護模式登入即可更改你的root密碼喔！由於lilo這個開機管理程式已經很少見了， 這裡鳥哥使用grub開機管理程式作為範例來介紹囉！

先將系統重新開機，在讀秒的時候按下任意鍵就會出現如同第四章圖3.2的選單畫面，仔細看選單底下的說明， 按下『e』就能夠進入grub的編輯模式了。此時你看到的畫面有點像底下這樣：

root (hd0,0)

kernel /vmlinuz-2.6.18-128.el5 ro root=LABEL=/ rhgb quiet

initrd /initrd-2.6.18-128.el5.img

此時，請將游標移動到kernel那一行，再按一次『 e 』進入kernel該行的編輯畫面中， 然後在出現的畫面當中，最後方輸入 single ：

kernel /vmlinuz-2.6.18-128.el5 ro root=LABEL=/ rhgb quiet single

再按下『 Enter 』確定之後，按下 b 就可以開機進入單人維護模式了！ 在這個模式底下，你會在tty1的地方不需要輸入密碼即可取得終端機的控制權(而且是使用root的身份喔！)。 之後就能夠修改root的密碼了！請使用底下的指令來修改root的密碼喔！

[root@www ~]# passwd

# 接下來系統會要求你輸入兩次新的密碼，然後再來reboot即可順利修訂root密碼了！

這裡僅是介紹一個簡單的處理方法而已，更多的原理與說明將會在後續的各相關章節介紹的喔！

重點回顧

- 為了避免瞬間斷電造成的Linux系統危害，建議做為伺服器的Linux主機應該加上不斷電系統來持續提供穩定的電力；

- 預設的圖形模式登入中，可以選擇語系以及作業階段。作業階段為多種視窗管理員軟體所提供，如GNOME及KDE等；

- CentOS 5.x預設的中文輸入法為使用SCIM這個軟體所提供的輸入；

- 不論是KDE還是GNOME預設都提供四個Virtual Desktop給使用者使用；

- 在X的環境下想要重新啟動X的組合按鍵為：『[alt]+[ctrl]+[backspace]』；

- 預設情況下，Linux提供tty1~tty6的文字介面登入，以及tty7的圖形介面登入環境；

- 除了run level 5預設取得圖形介面之外，run level 3亦可使用 startx 進入圖形環境；

- 在終端機環境中，可依據提示字元為$或#判斷為一般帳號或root帳號；

- 取得終端機支援的語系資料可下達『echo $LANG』或『locale』指令；

- date可顯示日期、cal可顯示日曆、bc可以做為計算機軟體；

- 組合按鍵中，[tab]按鍵可做為命令補齊或檔名補齊，[crtl]-[c]可以中斷目前正在運作中的程式；

- 線上說明系統有man及info兩個常見的指令；

- man page說明後面的數字中，1代表一般帳號可用指令，8代表系統管理員常用指令，5代表系統設定檔格式；

- info page可將一份說明文件拆成多個節點(node)顯示，並具有類似超連結的功能，增加易讀性；

- 系統需正確的關機比較不容易損壞，可使用shutdown, poweroff等指令關機。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

情境模擬題一：我們在tty1裡面看到的歡迎畫面，就是在那個login:之前的畫面(CentOS release 5.3 (Final)...)是怎麼來的？

- 目標：瞭解到終端機介面的歡迎訊息是怎麼來的？

- 前提：歡迎訊息的內容，是記錄到/etc/issue當中的

- 需求：利用man找到該檔案當中的變數內容

情境模擬題一的解決步驟：

1. 歡迎畫面是在/etc/issue檔案中，你可以使用『nano /etc/issue』看看該檔案的內容(注意，不要修改這個檔案內容，看完就離開)，這個檔案的內容有點像底下這樣：

CentOS release 5.3 (Final)

Kernel \r on an \m

1. 與tty2比較之下，發現到核心版本使用的是 \r 而硬體等級則是 \m 來取代，這兩者代表的意義為何？ 由於這個檔案的檔名是issue，所以我們使用『man issue』來查閱這個檔案的格式；

2. 透過上一步的查詢我們會知道反斜線(\)後面接的字元是與mingetty(8)有關，故進行『man mingetty』這個指令的查詢。

3. 由於反斜線(\)的英文為『escape』因此在上個步驟的man環境中，你可以使用『/escape』來搜尋各反斜線後面所接字元所代表的意義為何。

4. 請自行找出：如果我想要在/etc/issue檔案內表示『時間(localtime)』與『tty號碼(如tty1, tty2的號碼)』的話， 應該要找到那個字元來表示(透過反斜線的功能)？(答案為：\t 與 \l)

簡答題部分：

- 請問如果我以文字模式登入Linux主機時，我有幾個終端機介面可以使用？如何切換各個不同的終端機介面？

共有六個， tty1 ~ tty6 ，切換的方式為 Crtl + Alt + [F1]~[F6]，其中， [F7] 為圖形介面的使用。

- 在Linux系統中，/VBird與/vbird是否為相同的檔案？

兩者為不同的檔案，因為 Linux 系統中，大小寫字母代表意義不一樣！

- 我想要知道 date 如何使用，應該如何查詢？

最簡單的方式就是使用 man date 或 info date 來查看，如果該套件有完整說明的話，那麼應該也可以在 /usr/share/doc 裡面找到說明檔！

- 我想要在今天的 1:30 讓系統自己關機，要怎麼做？

shutdown -h 1:30

- 如果我 Linux 的 X Window 突然發生問題而掛掉，但 Linux 本身還是好好的，那麼我可以按下哪三個按鍵來讓 X window 重新啟動？

[crtl]+[alt]+[backspace]

- 我想要知道 2010 年 5 月 2 日是星期幾？該怎麼做？

最簡單的方式直接使用 cal 5 2010 即可找出 2010 年 5 月份的月曆。

- 使用 man date 然後找出顯示目前的日期與時間的參數，成為類似：2009/10/16-20:03

date +%Y/%m/%d-%H:%M

- 若以 X-Window 為預設的登入方式，那請問如何進入 Virtual console 呢？

可以按下 [Ctrl] + [Alt] + [F1] ~ [F6] 進入 Virtual console ( 共六個 )； 而按下 [Ctrl] + [Alt] + [F8] 或 [F7] 可回到 X-Window 的 desktop 中！

- 簡單說明在 bash shell 的環境下， [tab] 按鍵的用途？

[Tab] 按鍵可做為命令補齊或檔案補齊的功能，與所接的指令位置有關。 接在一串指令的第一個單字後面，則為命令補齊，否則則為檔案補齊！

- 如何強制中斷一個程式的進行？(利用按鍵，非利用 kill 指令)

可以利用 [Ctrl] + c 來中斷！

- Linux 提供相當多的線上查詢，稱為 man page，請問，我如何知道系統上有多少關於 passwd 的說明？又，可以使用其他的程式來取代 man 的這個功能嗎？

可以利用 man -f passwd 來查詢，另外，如果有提供 info 的文件資料時 (在 /usr/share/info/ 目錄中) ，則能夠利用 info passwd 來查詢之！

- man -k passwd 與 man -K passwd 有什麼差異(大小寫的 K )？

小寫的 -k 為查詢關鍵字，至於 -K 則是整個系統的 man page 查詢∼ 每個被檢查到有關鍵字的 man page file 都會被詢問是否要顯示， 你可以輸入『ynq』，來表示：y:要顯示到螢幕上；n:不顯示；q:結束 man 的查詢。

- 在 man 的時候， man page 顯示的內容中，指令(或檔案)後面會接一組數字，這個數字若為 1, 5, 8 ，表示該查詢的指令(或檔案)意義為何？

代表意義為 1) 一般使用者可以使用的指令或可執行檔案 5)一些設定檔的檔案內容格式 8)系統管理員能夠使用的管理指令。

- man page 顯示的內容的檔案是放置在哪些目錄中？

放置在 /usr/share/man/ 與 /usr/local/man 等預設目錄中。

- 請問這一串指令『 foo1 -foo2 foo3 foo4 』中，各代表什麼意義？

foo1 一定是指令， -foo2 則是 foo1 這個指令的選擇項目參數， foo3 與 foo4 則不一定， 可能是 foo1 的參數設定值，也可能是額外加入的 parameters。

- 當我輸入 man date 時，在我的終端機卻出現一些亂碼，請問可能的原因為何？如何修正？

如果沒有其他錯誤的發生，那麼發生亂碼可能是因為語系的問題所致。 可以利用 LANG=en 或者是 LANG=en_US 等設定來修訂這個問題。

- 我輸入這個指令『ls -al /vbird』，系統回覆我這個結果：『ls: /vbird: No such file or directory』 請問發生了什麼事？』

不要緊張，很簡單的英文，因為系統根本沒有 /vbird 這個檔案的存在啊！ ^_^

- 你目前的 Linux 底下，預設共有多少可以被你執行的指令？

最簡單的做法，直接輸入兩次 [tab] 按鍵即可知道有多少指令可以被執行。

- 我想知道目前系統有多少指令是以 bz 為開頭的，可以怎麼作？

直接輸入 bz[tab][tab] 就可以知道了！

- 承上題，在出現的許多指令中，請問 bzip2 是幹嘛用的？

在使用 man bzip2 之後，可以發現到，其實 bzip2 是用來作為壓縮與解壓縮檔案用的！

- Linux 提供一些線上文獻資料，這些資料通常放在那個目錄當中

通常放在 /usr/share/doc 當中！

- 在終端機裡面登入後，看到的提示字元 $ 與 # 有何不同？平時操作應該使用哪一個？

# 代表以 root 的身份登入系統，而 $ 則代表一般身份使用者。依據提示字元的不同， 我們可以約略判斷登入者身份。一般來說，建議日常操作使用一般身份使用者登入，亦即是 $ ！

- 我使用dmtsai這個帳號登入系統了，請問我能不能使用reboot來重新開機？ 若不能，請說明原因，若可以，請說明指令如何下達？

理論上reboot僅能讓root執行。不過，如果dmtsai是在主機前面以圖形介面登入時，則dmtsai還是可以透過圖形介面功能來關機。

參考資料與延伸閱讀

- 註1：為了讓Linux的視窗顯示效果更佳，很多團體開始發展桌面應用的環境，GNOME/KDE都是。 他們的目標就是發展出類似Windows桌面的一整套可以工作的桌面環境，他可以進行視窗的定位、放大、縮小、 同時還提供很多的桌面應用軟體。底下是KDE與GNOME的相關連結：

http://www.kde.org/

http://www.gnome.org/

- 楊錦昌老師的X Window操作圖解，以Fedora Core 3為例：http://apt.nc.hcc.edu.tw/docs/FC3_X/

- man 7 man ：取得更詳細的數字說明內容

2002/07/16：第一次完成吧？

2003/02/06：重新編排與加入 FAQ

2004/05/01：在shutdown的指令部分，修改 shutdown -k "messages" 成為 shutdown -k now "messages"，很抱歉，寫錯了！

2005/06/17：將原本的文章移動到 這裡

2005/06/27：終於寫完了！寫的真久∼沒辦法，將 man page 擴大解釋，增加的幅度還挺多的！

2005/08/23：剛剛才發現，那個man page的內部指令說明中， n 與 N 的說明錯誤了！已訂正！

2007/12/08：透過網友sheaushyong的發現，之前將Live CD中，說明要掛載 / 才 fsck 是不對的！請查閱此處。

2008/09/03：將原本的Fedora Core IV的文章移動到此處。

2008/09/08：加入了一些圖示說明，尤其是info的部分多了一個示意圖！

2008/09/09：加入了nano這個簡單的文書編輯器說明，以及情境模擬題的解釋！

2009/09/17：修訂了顯示的資訊，將圖片重新抓圖彙整。

2002/01/01以來統計人數

第六章、Linux 的檔案權限與目錄配置

切換解析度為 800x600

最近更新日期：2009/08/18

Linux最優秀的地方之一，就在於他的多人多工環境。而為了讓各個使用者具有較保密的檔案資料，因此檔案的權限管理就變的很重要了。 Linux一般將檔案可存取的身份分為三個類別，分別是 owner/group/others，且三種身份各有 read/write/execute 等權限。若管理不當，你的Linux主機將會變的很『不蘇服！@_@』。另外，你如果首次接觸Linux的話，那麼， 在Linux底下這麼多的目錄/檔案，到底每個目錄/檔案代表什麼意義呢？底下我們就來一一介紹呢！

1. 使用者與群組

2. Linux檔案權限概念

2.1 Linux檔案屬性

2.2 如何改變檔案屬性與權限： chgrp, chown, chmod

2.3 目錄與檔案之權限意義

2.4 Linux檔案種類與副檔名

3. Linux目錄配置

3.1 Linux目錄配置的依據--FHS：/, /usr, /var

3.2 目錄樹(directory tree)

3.3 絕對路徑與相對路徑

3.4 CentOS 的觀察： lsb_release

4. 重點回顧

5. 本章練習

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23878

使用者與群組

經過第五章的洗禮之後，你應該可以在Linux的指令列模式底下輸入指令了吧？ 接下來，當然是要讓你好好的瀏覽一下Linux系統裡面有哪些重要的檔案囉。 不過，每個檔案都有相當多的屬性與權限，其中最重要的可能就是檔案的擁有者的概念了。 所以，在開始檔案相關資訊的介紹前，鳥哥先就簡單的(1)使用者及(2)群組與(3)非本群組外的其他人等概念作個說明吧∼ 好讓你快點進入狀況的哩！ ^_^

1. 檔案擁有者

初次接觸Linux的朋友大概會覺得很怪異，怎麼『Linux有這麼多使用者， 還分什麼群組，有什麼用？』。這個『使用者與群組』的功能可是相當健全而好用的一個安全防護呢！怎麼說呢？ 由於Linux是個多人多工的系統，因此可能常常會有多人同時使用這部主機來進行工作的情況發生， 為了考慮每個人的隱私權以及每個人喜好的工作環境，因此，這個『檔案擁有者』的角色就顯的相當的重要了！

例如當你將你的e-mail情書轉存成檔案之後，放在你自己的家目錄，你總不希望被其他人看見自己的情書吧？ 這個時候，你就把該檔案設定成『只有檔案擁有者，就是我，才能看與修改這個檔案的內容』， 那麼即使其他人知道你有這個相當『有趣』的檔案，不過由於你有設定適當的權限， 所以其他人自然也就無法知道該檔案的內容囉！

2. 群組概念

那麼群組呢？為何要設定檔案還有所屬的群組？其實，群組最有用的功能之一，就是當你在團隊開發資源的時候啦！ 舉例來說，假設有兩組專題生在我的主機裡面，第一個專題組別為projecta，裡面的成員有 class1, class2, class3三個；第二個專題組別為projectb，裡面的成員有class4, class5, class6。 這兩個專題之間是有競爭性質的，但卻要繳交同一份報告。每組的組員之間必須要能夠互相修改對方的資料， 但是其他組的組員則不能看到本組自己的檔案內容，此時該如何是好？

在Linux底下這樣的限制是很簡單啦！我可以經由簡易的檔案權限設定，就能限制非自己團隊(亦即是群組囉) 的其他人不能夠閱覽內容囉！而且亦可以讓自己的團隊成員可以修改我所建立的檔案！ 同時，如果我自己還有私人隱密的文件，仍然可以設定成讓自己的團隊成員也看不到我的檔案資料。 很方便吧！

另外，如果teacher這個帳號是projecta與projectb這兩個專題的老師， 他想要同時觀察兩者的進度，因此需要能夠進入這兩個群組的權限時，你可以設定teacher這個帳號， 『同時支援projecta與projectb這兩個群組！』，也就是說：每個帳號都可以有多個群組的支援呢！

這樣說或許你還不容易理解這個使用者與群組的關係吧？沒關係，我們可以使用目前『家庭』的觀念來進行解說喔！ 假設有一家人，家裡只有三兄弟，分別是王大毛、王二毛與王三毛三個人， 而這個家庭是登記在王大毛的名下的！所以，『王大毛家有三個人，分別是王大毛、王二毛與王三毛』， 而且這三個人都有自己的房間，並且共同擁有一個客廳喔！

- 使用者的意義：由於王家三人各自擁有自己的房間，所以， 王二毛雖然可以進入王三毛的房間，但是二毛不能翻三毛的抽屜喔！那樣會被三毛K的！ 因為抽屜裡面可能有三毛自己私人的東西，例如情書啦，日記啦等等的，這是『私人的空間』，所以當然不能讓二毛拿囉！

- 群組的概念：由於共同擁有客廳，所以王家三兄弟可以在客廳打開電視機啦、 翻閱報紙啦、坐在沙發上面發呆啦等等的！ 反正，只要是在客廳的玩意兒，三兄弟都可以使用喔！ 因為大家都是一家人嘛！

這樣說來應該有點曉得了喔！那個『王大毛家』就是所謂的『群組』囉， 至於三兄弟就是分別為三個『使用者』，而這三個使用者是在同一個群組裡面的喔！ 而三個使用者雖然在同一群組內，但是我們可以設定『權限』， 好讓某些使用者個人的資訊不被群組的擁有者查詢，以保有個人『私人的空間』啦！ 而設定群組共享，則可讓大家共同分享喔！

1. 其他人的概念

好了，那麼今天又有個人，叫做張小豬，他是張小豬家的人，與王家沒有關係啦！ 這個時候，除非王家認識張小豬，然後開門讓張小豬進來王家，否則張小豬永遠沒有辦法進入王家， 更不要說進到王三毛的房間啦！不過，如果張小豬透過關係認識了三毛，並且跟王三毛成為好朋友， 那麼張小豬就可以透過三毛進入王家啦！呵呵！沒錯！那個張小豬就是所謂的『其他人，Others』囉！

因此，我們就可以知道啦，在Linux裡面，任何一個檔案都具有『User, Group及Others』三種身份的個別權限， 我們可以將上面的說明以底下的圖示來解釋：

圖1.1、每個檔案的擁有者、群組與其他人的示意圖

我們以王三毛為例，王三毛這個『檔案』的擁有者為王三毛，他屬於王大毛這個群組， 而張小豬相對於王三毛，則只是一個『其他人(others)』而已。

不過，這裡有個特殊的人物要來介紹的，那就是『萬能的天神』！這個天神具有無限的神力， 所以他可以到達任何他想要去的地方，呵呵！那個人在Linux系統中的身份代號是『 root 』啦！所以要小心喔！那個root可是『萬能的天神』喔！

無論如何，『使用者身份』，與該使用者所支援的『群組』概念，在Linux的世界裡面是相當的重要的， 他可以幫助你讓你的多工Linux環境變的更容易管理！更詳細的 『身份與群組』 設定，我們將在第十四章、帳號管理再進行解說。 底下我們將針對檔案系統與檔案權限來進行說明。

- Linux 使用者身份與群組記錄的檔案

在我們Linux系統當中，預設的情況下，所有的系統上的帳號與一般身份使用者，還有那個root的相關資訊， 都是記錄在/etc/passwd這個檔案內的。至於個人的密碼則是記錄在/etc/shadow這個檔案下。 此外，Linux所有的群組名稱都紀錄在/etc/group內！這三個檔案可以說是Linux系統裡面帳號、密碼、群組資訊的集中地囉！ 不要隨便刪除這三個檔案啊！ ^_^

至於更多的與帳號群組有關的設定，還有這三個檔案的格式，不要急，我們在第十四章的帳號管理時，會再跟大家詳細的介紹的！這裡先有概念即可。

Linux 檔案權限概念

大致瞭解了Linux的使用者與群組之後，接著下來，我們要來談一談， 這個檔案的權限要如何針對這些所謂的『使用者』與『群組』來設定呢？ 這個部分是相當重要的，尤其對於初學者來說，因為檔案的權限與屬性是學習Linux的一個相當重要的關卡， 如果沒有這部份的概念，那麼你將老是聽不懂別人在講什麼呢！尤其是當你在你的螢幕前面出現了『Permission deny』的時候，不要擔心，『肯定是權限設定錯誤』啦！呵呵！好了，閒話不多聊，趕快來瞧一瞧先。

Linux檔案屬性

嗯！既然要讓你瞭解Linux的檔案屬性，那麼有個重要的也是常用的指令就必須要先跟你說囉！那一個？就是『 ls 』這一個察看檔案的指令囉！在你以root的身份登入Linux之後，下達『 ls -al 』看看，會看到底下的幾個咚咚：

[root@www ~]# ls -al

total 156

drwxr-x---   4    root   root     4096   Sep  8 14:06 .

drwxr-xr-x  23    root   root     4096   Sep  8 14:21 ..

-rw-------   1    root   root     1474   Sep  4 18:27 anaconda-ks.cfg

-rw-------   1    root   root      199   Sep  8 17:14 .bash_history

-rw-r--r--   1    root   root       24   Jan  6  2007 .bash_logout

-rw-r--r--   1    root   root      191   Jan  6  2007 .bash_profile

-rw-r--r--   1    root   root      176   Jan  6  2007 .bashrc

-rw-r--r--   1    root   root      100   Jan  6  2007 .cshrc

drwx------   3    root   root     4096   Sep  5 10:37 .gconf      <=範例說明處

drwx------   2    root   root     4096   Sep  5 14:09 .gconfd

-rw-r--r--   1    root   root    42304   Sep  4 18:26 install.log <=範例說明處

-rw-r--r--   1    root   root     5661   Sep  4 18:25 install.log.syslog

[    1   ][  2 ][   3  ][  4 ][    5   ][     6     ][       7          ]

[  權限  ][連結][擁有者][群組][檔案容量][  修改日期 ][      檔名        ]

Tips:

由於本章後續的chgrp, chown等指令可能都需要使用root的身份才能夠處理，所以這裡建議您以root的身份登入Linux來學習本章。

ls是『list』的意思，重點在顯示檔案的檔名與相關屬性。而選項『-al』則表示列出所有的檔案詳細的權限與屬性 (包含隱藏檔，就是檔名第一個字元為『 . 』的檔案)。如上所示，在你第一次以root身份登入Linux時， 如果你輸入上述指令後，應該有上列的幾個東西，先解釋一下上面七個欄位個別的意思：

圖2.1.1、檔案屬性的示意圖

- 第一欄代表這個檔案的類型與權限(permission)：

這個地方最需要注意了！仔細看的話，你應該可以發現這一欄其實共有十個字元：(圖2.1.1及圖2.1.2內的權限並無關係)

圖2.1.2、檔案的類型與權限之內容

- 第一個字元代表這個檔案是『目錄、檔案或連結檔等等』：

- 當為[ d ]則是目錄，例如上表檔名為『.gconf』的那一行；

- 當為[ - ]則是檔案，例如上表檔名為『install.log』那一行；

- 若是[ l ]則表示為連結檔(link file)；

- 若是[ b ]則表示為裝置檔裡面的可供儲存的周邊設備(可隨機存取裝置)；

- 若是[ c ]則表示為裝置檔裡面的序列埠設備，例如鍵盤、滑鼠(一次性讀取裝置)。

- 接下來的字元中，以三個為一組，且均為『rwx』 的三個參數的組合。其中，[ r ]代表可讀(read)、[ w ]代表可寫(write)、[ x ]代表可執行(execute)。 要注意的是，這三個權限的位置不會改變，如果沒有權限，就會出現減號[ - ]而已。

- 第一組為『檔案擁有者的權限』，以『install.log』那個檔案為例， 該檔案的擁有者可以讀寫，但不可執行；

- 第二組為『同群組的權限』；

- 第三組為『其他非本群組的權限』。

例題：

若有一個檔案的類型與權限資料為『-rwxr-xr--』，請說明其意義為何？

答：

先將整個類型與權限資料分開查閱，並將十個字元整理成為如下所示：

[-][rwx][r-x][r--]

1  234  567  890

1 為：代表這個檔名為目錄或檔案，本例中為檔案(-)；

234為：擁有者的權限，本例中為可讀、可寫、可執行(rwx)；

567為：同群組使用者權限，本例中為可讀可執行(rx)；

890為：其他使用者權限，本例中為可讀(r)

同時注意到，rwx所在的位置是不會改變的，有該權限就會顯示字元，沒有該權限就變成減號(-)就是了。

另外，目錄與檔案的權限意義並不相同，這是因為目錄與檔案所記錄的資料內容不相同所致。 由於目錄與檔案的權限意義非常的重要，所以鳥哥將他獨立到2.3節目錄與檔案之權限意義中再來談。

- 第二欄表示有多少檔名連結到此節點(i-node)：

每個檔案都會將他的權限與屬性記錄到檔案系統的i-node中，不過，我們使用的目錄樹卻是使用檔名來記錄， 因此每個檔名就會連結到一個i-node囉！這個屬性記錄的，就是有多少不同的檔名連結到相同的一個i-node號碼去就是了。 關於i-node的相關資料我們會在第八章談到檔案系統時再加強介紹的。

- 第三欄表示這個檔案(或目錄)的『擁有者帳號』

- 第四欄表示這個檔案的所屬群組

在Linux系統下，你的帳號會附屬於一個或多個的群組中。舉剛剛我們提到的例子，class1, class2, class3均屬於projecta這個群組，假設某個檔案所屬的群組為projecta，且該檔案的權限如圖2.1.2所示(-rwxrwx---)， 則class1, class2, class3三人對於該檔案都具有可讀、可寫、可執行的權限(看群組權限)。 但如果是不屬於projecta的其他帳號，對於此檔案就不具有任何權限了。

- 第五欄為這個檔案的容量大小，預設單位為bytes；

- 第六欄為這個檔案的建檔日期或者是最近的修改日期：

這一欄的內容分別為日期(月/日)及時間。如果這個檔案被修改的時間距離現在太久了，那麼時間部分會僅顯示年份而已。 如下所示：

[root@www ~]# ls -l /etc/termcap /root/install.log

-rw-r--r-- 1 root root 807103 Jan  7  2007 /etc/termcap

-rw-r--r-- 1 root root  42304 Sep  4 18:26 /root/install.log

# 如上所示，/etc/termcap 為 2007 年所修改過的檔案，離現在太遠之故；

# 至於 install.log 是今年 (2009) 所建立的，所以就顯示完整的時間了。

如果想要顯示完整的時間格式，可以利用ls的選項，亦即：『ls -l --full-time』就能夠顯示出完整的時間格式了！包括年、月、日、時間喔。 另外，如果你當初是以繁體中文安裝你的Linux系統，那麼日期欄位將會以中文來顯示。 可惜的是，中文並沒有辦法在純文字的終端機模式中正確的顯示，所以此欄會變成亂碼。 那你就得要使用『LANG=en_US』來修改語系喔！

如果想要讓系統預設的語系變成英文的話，那麼你可以修改系統設定檔『/etc/sysconfig/i18n』，利用第五章談到的nano來修改該檔案的內容，使LANG這個變數成為上述的內容即可。

- 第七欄為這個檔案的檔名

這個欄位就是檔名了。比較特殊的是：如果檔名之前多一個『 . 』，則代表這個檔案為『隱藏檔』，例如上表中的.gconf那一行，該檔案就是隱藏檔。 你可以使用『ls』及『ls -a』這兩個指令去感受一下什麼是隱藏檔囉！

Tips:

對於更詳細的 ls 用法，還記得怎麼查詢嗎？對啦！使用 man ls 或 info ls 去看看他的基礎用法去！自我進修是很重要的， 因為『師傅帶進門，修行看個人！』，自古只有天才學生，沒有天才老師呦！加油吧！^_^

這七個欄位的意義是很重要的！務必清楚的知道各個欄位代表的意義！尤其是第一個欄位的九個權限， 那是整個Linux檔案權限的重點之一。底下我們來做幾個簡單的練習，你就會比較清楚囉！

例題：

假設test1, test2, test3同屬於testgroup這個群組，如果有下面的兩個檔案，請說明兩個檔案的擁有者與其相關的權限為何？

-rw-r--r--  1 root     root          238 Jun 18 17:22 test.txt

-rwxr-xr--  1 test1    testgroup    5238 Jun 19 10:25 ping_tsai

答：

- 檔案test.txt的擁有者為root，所屬群組為root。至於權限方面則只有root這個帳號可以存取此檔案，其他人則僅能讀此檔案；

- 另一個檔案ping_tsai的擁有者為test1，而所屬群組為testgroup。其中：

- test1 可以針對此檔案具有可讀可寫可執行的權力；

- 而同群組的test2, test3兩個人與test1同樣是testgroup的群組帳號，則僅可讀可執行但不能寫(亦即不能修改)；

- 至於非testgoup這一個群組的人則僅可以讀，不能寫也不能執行！

例題：

如果我的目錄為底下的樣式，請問testgroup這個群組的成員與其他人(others)是否可以進入本目錄？

drwxr-xr--   1 test1    testgroup    5238 Jun 19 10:25 groups/

答：

- 檔案擁有者test1[rwx]可以在本目錄中進行任何工作；

- 而testgroup這個群組[r-x]的帳號，例如test2, test3亦可以進入本目錄進行工作，但是不能在本目錄下進行寫入的動作；

- 至於other的權限中[r--]雖然有r ，但是由於沒有x的權限，因此others的使用者，並不能進入此目錄！

- Linux檔案權限的重要性：

與Windows系統不一樣的是，在Linux系統當中，每一個檔案都多加了很多的屬性進來，尤其是群組的概念，這樣有什麼用途呢？ 其實，最大的用途是在『資料安全性』上面的。

- 系統保護的功能：

舉個簡單的例子，在你的系統中，關於系統服務的檔案通常只有root才能讀寫或者是執行，例如/etc/shadow這一個帳號管理的檔案，由於該檔案記錄了你系統中所有帳號的資料， 因此是很重要的一個設定檔，當然不能讓任何人讀取(否則密碼會被竊取啊)，只有root才能夠來讀取囉！所以該檔案的權限就會成為[ -rw------- ]囉！

- 團隊開發軟體或資料共用的功能：

此外，如果你有一個軟體開發團隊，在你的團隊中，你希望每個人都可以使用某一些目錄下的檔案， 而非你的團隊的其他人則不予以開放呢？以上面的例子來說，testgroup的團隊共有三個人，分別是test1, test2, test3，那麼我就可以將團隊所需的檔案權限訂為[ -rwxrwx--- ]來提供給testgroup的工作團隊使用囉！

- 未將權限設定妥當的危害：

再舉個例子來說，如果你的目錄權限沒有作好的話，可能造成其他人都可以在你的系統上面亂搞囉！ 例如本來只有root才能做的開關機、ADSL的撥接程式、新增或刪除使用者等等的指令，若被你改成任何人都可以執行的話， 那麼如果使用者不小心給你重新開機啦！重新撥接啦！等等的！那麼你的系統不就會常常莫名其妙的掛掉囉！ 而且萬一你的使用者的密碼被其他不明人士取得的話，只要他登入你的系統就可以輕而易舉的執行一些root的工作！

可怕吧！因此，在你修改你的linux檔案與目錄的屬性之前，一定要先搞清楚， 什麼資料是可變的，什麼是不可變的！千萬注意囉！接下來我們來處理一下檔案屬性與權限的變更吧！

如何改變檔案屬性與權限

我們現在知道檔案權限對於一個系統的安全重要性了，也知道檔案的權限對於使用者與群組的相關性， 那麼如何修改一個檔案的屬性與權限呢？又！有多少檔案的權限我們可以修改呢？ 其實一個檔案的屬性與權限有很多！我們先介紹幾個常用於群組、擁有者、各種身份的權限之修改的指令，如下所示：

- chgrp ：改變檔案所屬群組

- chown ：改變檔案擁有者

- chmod ：改變檔案的權限, SUID, SGID, SBIT等等的特性

- 改變所屬群組, chgrp

改變一個檔案的群組真是很簡單的，直接以chgrp來改變即可，咦！這個指令就是change group的縮寫嘛！這樣就很好記了吧！ ^_^。不過，請記得，要被改變的群組名稱必須要在/etc/group檔案內存在才行，否則就會顯示錯誤！

假設你是以root的身份登入Linux系統的，那麼在你的家目錄內有一個install.log的檔案， 如何將該檔案的群組改變一下呢？假設你已經知道在/etc/group裡面已經存在一個名為users的群組， 但是testing這個群組名字就不存在/etc/group當中了，此時改變群組成為users與testing分別會有什麼現象發生呢？

[root@www ~]# chgrp [-R] dirname/filename ...

選項與參數：

-R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案、目錄

都更新成為這個群組之意。常常用在變更某一目錄內所有的檔案之情況。

範例：

[root@www ~]# chgrp users install.log

[root@www ~]# ls -l

-rw-r--r--  1 root users 68495 Jun 25 08:53 install.log

[root@www ~]# chgrp testing install.log

chgrp: invalid group name `testing' <== 發生錯誤訊息囉∼找不到這個群組名∼

發現了嗎？檔案的群組被改成users了，但是要改成testing的時候， 就會發生錯誤∼注意喔！發生錯誤訊息還是要努力的查一查錯誤訊息的內容才好！ 將他英文翻譯成為中文，就知道問題出在哪裡了。

- 改變檔案擁有者, chown

如何改變一個檔案的擁有者呢？很簡單呀！既然改變群組是change group，那麼改變擁有者就是change owner囉！BINGO！那就是chown這個指令的用途，要注意的是， 使用者必須是已經存在系統中的帳號，也就是在/etc/passwd 這個檔案中有紀錄的使用者名稱才能改變。

chown的用途還滿多的，他還可以順便直接修改群組的名稱呢！此外，如果要連目錄下的所有次目錄或檔案同時更改檔案擁有者的話，直接加上 -R 的選項即可！我們來看看語法與範例：

[root@www ~]# chown [-R] 帳號名稱 檔案或目錄

[root@www ~]# chown [-R] 帳號名稱:群組名稱 檔案或目錄

選項與參數：

-R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案都變更

範例：將install.log的擁有者改為bin這個帳號：

[root@www ~]# chown bin install.log

[root@www ~]# ls -l

-rw-r--r--  1 bin  users 68495 Jun 25 08:53 install.log

範例：將install.log的擁有者與群組改回為root：

[root@www ~]# chown root:root install.log

[root@www ~]# ls -l

-rw-r--r--  1 root root 68495 Jun 25 08:53 install.log

Tips:

事實上，chown也可以使用『chown user.group file』，亦即在擁有者與群組間加上小數點『.』也行！ 不過很多朋友設定帳號時，喜歡在帳號當中加入小數點(例如vbird.tsai這樣的帳號格式)，這就會造成系統的誤判了！ 所以我們比較建議使用冒號『:』來隔開擁有者與群組啦！此外，chown也能單純的修改所屬群組呢！ 例如『chown .sshd install.log』就是修改群組∼看到了嗎？就是那個小數點的用途！

知道如何改變檔案的群組與擁有者了，那麼什麼時候要使用chown或chgrp呢？或許你會覺得奇怪吧？ 是的，確實有時候需要變更檔案的擁有者的，最常見的例子就是在複製檔案給你之外的其他人時， 我們使用最簡單的cp指令來說明好了：

[root@www ~]# cp 來源檔案 目的檔案

假設你今天要將.bashrc這個檔案拷貝成為.bashrc_test檔名，且是要給bin這個人，你可以這樣做：

[root@www ~]# cp .bashrc .bashrc_test

[root@www ~]# ls -al .bashrc*

-rw-r--r--  1 root root 395 Jul  4 11:45 .bashrc

-rw-r--r--  1 root root 395 Jul 13 11:31 .bashrc_test  <==新檔案的屬性沒變

由於複製行為(cp)會複製執行者的屬性與權限，所以！怎麼辦？.bashrc_test還是屬於root所擁有， 如此一來，即使你將檔案拿給bin這個使用者了，那他仍然無法修改的(看屬性/權限就知道了吧)， 所以你就必須要將這個檔案的擁有者與群組修改一下囉！知道如何修改了吧？

- 改變權限, chmod

檔案權限的改變使用的是chmod這個指令，但是，權限的設定方法有兩種， 分別可以使用數字或者是符號來進行權限的變更。我們就來談一談：

- 數字類型改變檔案權限

Linux檔案的基本權限就有九個，分別是owner/group/others三種身份各有自己的read/write/execute權限， 先複習一下剛剛上面提到的資料：檔案的權限字元為：『-rwxrwxrwx』， 這九個權限是三個三個一組的！其中，我們可以使用數字來代表各個權限，各權限的分數對照表如下：

r:4

w:2

x:1

每種身份(owner/group/others)各自的三個權限(r/w/x)分數是需要累加的，例如當權限為： [-rwxrwx---] 分數則是：

owner = rwx = 4+2+1 = 7

group = rwx = 4+2+1 = 7

others= --- = 0+0+0 = 0

所以等一下我們設定權限的變更時，該檔案的權限數字就是770啦！變更權限的指令chmod的語法是這樣的：

[root@www ~]# chmod [-R] xyz 檔案或目錄

選項與參數：

xyz : 就是剛剛提到的數字類型的權限屬性，為 rwx 屬性數值的相加。

-R : 進行遞迴(recursive)的持續變更，亦即連同次目錄下的所有檔案都會變更

舉例來說，如果要將.bashrc這個檔案所有的權限都設定啟用，那麼就下達：

[root@www ~]# ls -al .bashrc

-rw-r--r--  1 root root 395 Jul  4 11:45 .bashrc

[root@www ~]# chmod 777 .bashrc

[root@www ~]# ls -al .bashrc

-rwxrwxrwx  1 root root 395 Jul  4 11:45 .bashrc

那如果要將權限變成『 -rwxr-xr-- 』呢？那麼權限的分數就成為 [4+2+1][4+0+1][4+0+0]=754 囉！所以你需要下達『 chmod 754 filename』。 另外，在實際的系統運作中最常發生的一個問題就是，常常我們以vim編輯一個shell的文字批次檔後，他的權限通常是 -rw-rw-r-- 也就是664， 如果要將該檔案變成可執行檔，並且不要讓其他人修改此一檔案的話， 那麼就需要-rwxr-xr-x這樣的權限，此時就得要下達：『 chmod 755 test.sh 』的指令囉！

另外，如果有些檔案你不希望被其他人看到，那麼應該將檔案的權限設定為例如：『-rwxr-----』，那就下達『 chmod 740 filename 』吧！

例題：

將剛剛你的.bashrc這個檔案的權限修改回-rw-r--r--的情況吧！

答：

-rw-r--r--的分數是644，所以指令為：

chmod 644 .bashrc

- 符號類型改變檔案權限

還有一個改變權限的方法呦！從之前的介紹中我們可以發現，基本上就九個權限分別是(1)user (2)group (3)others三種身份啦！那麼我們就可以藉由u, g, o來代表三種身份的權限！此外， a 則代表 all 亦即全部的身份！那麼讀寫的權限就可以寫成r, w, x囉！也就是可以使用底下的方式來看：

chmod

u

g

o

a

+(加入)

-(除去)

=(設定)

r

w

x

檔案或目錄

- 來實作一下吧！假如我們要『設定』一個檔案的權限成為『-rwxr-xr-x』時，基本上就是：

- user (u)：具有可讀、可寫、可執行的權限；

- group 與 others (g/o)：具有可讀與執行的權限。

所以就是：

[root@www ~]# chmod  u=rwx,go=rx  .bashrc

# 注意喔！那個 u=rwx,go=rx 是連在一起的，中間並沒有任何空白字元！

[root@www ~]# ls -al .bashrc

-rwxr-xr-x  1 root root 395 Jul  4 11:45 .bashrc

那麼假如是『 -rwxr-xr-- 』這樣的權限呢？可以使用『 chmod u=rwx,g=rx,o=r filename 』來設定。此外，如果我不知道原先的檔案屬性，而我只想要增加.bashrc這個檔案的每個人均可寫入的權限， 那麼我就可以使用：

[root@www ~]# ls -al .bashrc

-rwxr-xr-x  1 root root 395 Jul  4 11:45 .bashrc

[root@www ~]# chmod  a+w  .bashrc

[root@www ~]# ls -al .bashrc

-rwxrwxrwx  1 root root 395 Jul  4 11:45 .bashrc

而如果是要將權限去掉而不更動其他已存在的權限呢？例如要拿掉全部人的可執行權限，則：

[root@www ~]# chmod  a-x  .bashrc

[root@www ~]# ls -al .bashrc

-rw-rw-rw-  1 root root 395 Jul  4 11:45 .bashrc

知道 +, -, = 的不同點了嗎？對啦！ + 與 – 的狀態下，只要是沒有指定到的項目，則該權限『不會被變動』， 例如上面的例子中，由於僅以 – 拿掉 x 則其他兩個保持當時的值不變！多多實作一下，你就會知道如何改變權限囉！ 這在某些情況底下很好用的∼舉例來說，你想要教一個朋友如何讓一個程式可以擁有執行的權限， 但你又不知道該檔案原本的權限為何，此時，利用『chmod a+x filename』 ，就可以讓該程式擁有執行的權限了。是否很方便？

目錄與檔案之權限意義：

現在我們知道了Linux系統內檔案的三種身份(擁有者、群組與其他人)，知道每種身份都有三種權限(rwx)， 已知道能夠使用chown, chgrp, chmod去修改這些權限與屬性，當然，利用ls -l去觀察檔案也沒問題。 前兩小節也談到了這些檔案權限對於資料安全的重要性。那麼，這些檔案權限對於一般檔案與目錄檔案有何不同呢？ 有大大的不同啊！底下就讓鳥哥來說清楚，講明白！

- 權限對檔案的重要性

檔案是實際含有資料的地方，包括一般文字檔、資料庫內容檔、二進位可執行檔(binary program)等等。 因此，權限對於檔案來說，他的意義是這樣的：

- r (read)：可讀取此一檔案的實際內容，如讀取文字檔的文字內容等；

- w (write)：可以編輯、新增或者是修改該檔案的內容(但不含刪除該檔案)；

- x (eXecute)：該檔案具有可以被系統執行的權限。

那個可讀(r)代表讀取檔案內容是還好瞭解，那麼可執行(x)呢？這裡你就必須要小心啦！ 因為在Windows底下一個檔案是否具有執行的能力是藉由『 副檔名 』來判斷的， 例如：.exe, .bat, .com 等等，但是在Linux底下，我們的檔案是否能被執行，則是藉由是否具有『x』這個權限來決定的！跟檔名是沒有絕對的關係的！

至於最後一個w這個權限呢？當你對一個檔案具有w權限時，你可以具有寫入/編輯/新增/修改檔案的內容的權限， 但並不具備有刪除該檔案本身的權限！對於檔案的rwx來說， 主要都是針對『檔案的內容』而言，與檔案檔名的存在與否沒有關係喔！因為檔案記錄的是實際的資料嘛！

- 權限對目錄的重要性

檔案是存放實際資料的所在，那麼目錄主要是儲存啥玩意啊？目錄主要的內容在記錄檔名清單，檔名與目錄有強烈的關連啦！ 所以如果是針對目錄時，那個 r, w, x 對目錄是什麼意義呢？

- r (read contents in directory)：

表示具有讀取目錄結構清單的權限，所以當你具有讀取(r)一個目錄的權限時，表示你可以查詢該目錄下的檔名資料。 所以你就可以利用 ls 這個指令將該目錄的內容列表顯示出來！

- w (modify contents of directory)：

這個可寫入的權限對目錄來說，是很了不起的！ 因為他表示你具有異動該目錄結構清單的權限，也就是底下這些權限：

- 建立新的檔案與目錄；

- 刪除已經存在的檔案與目錄(不論該檔案的權限為何！)

- 將已存在的檔案或目錄進行更名；

- 搬移該目錄內的檔案、目錄位置。

總之，目錄的w權限就與該目錄底下的檔名異動有關就對了啦！

- x (access directory)：

咦！目錄的執行權限有啥用途啊？目錄只是記錄檔名而已，總不能拿來執行吧？沒錯！目錄不可以被執行，目錄的x代表的是使用者能否進入該目錄成為工作目錄的用途！ 所謂的工作目錄(work directory)就是你目前所在的目錄啦！舉例來說，當你登入Linux時， 你所在的家目錄就是你當下的工作目錄。而變換目錄的指令是『cd』(change directory)囉！

大致的目錄權限概念是這樣，底下我們來看幾個範例，讓你瞭解一下啥是目錄的權限囉！

例題：

有個目錄的權限如下所示：

drwxr--r--  3  root  root  4096   Jun 25 08:35   .ssh

系統有個帳號名稱為vbird，這個帳號並沒有支援root群組，請問vbird對這個目錄有何權限？是否可切換到此目錄中？

答：

vbird對此目錄僅具有r的權限，因此vbird可以查詢此目錄下的檔名列表。因為vbird不具有x的權限， 因此vbird並不能切換到此目錄內！(相當重要的概念！)

上面這個例題中因為vbird具有r的權限，因為是r乍看之下好像就具有可以進入此目錄的權限，其實那是錯的。 能不能進入某一個目錄，只與該目錄的x權限有關啦！此外， 工作目錄對於指令的執行是非常重要的，如果你在某目錄下不具有x的權限， 那麼你就無法切換到該目錄下，也就無法執行該目錄下的任何指令，即使你具有該目錄的r的權限。

很多朋友在架設網站的時候都會卡在一些權限的設定上，他們開放目錄資料給網際網路的任何人來瀏覽， 卻只開放r的權限，如上面的範例所示那樣，那樣的結果就是導致網站伺服器軟體無法到該目錄下讀取檔案(最多只能看到檔名)， 最終用戶總是無法正確的查閱到檔案的內容(顯示權限不足啊！)。要注意：要開放目錄給任何人瀏覽時，應該至少也要給予r及x的權限，但w權限不可隨便給！ 為什麼w不能隨便給，我們來看下一個例子：

例題：

假設有個帳號名稱為dmtsai，他的家目錄在/home/dmtsai/，dmtsai對此目錄具有[rwx]的權限。 若在此目錄下有個名為the_root.data的檔案，該檔案的權限如下：

-rwx------ 1 root  root  4365 Sep 19 23:20  the_root.data

請問dmtsai對此檔案的權限為何？可否刪除此檔案？

答：

如上所示，由於dmtsai對此檔案來說是『others』的身份，因此這個檔案他無法讀、無法編輯也無法執行， 也就是說，他無法變動這個檔案的內容就是了。

但是由於這個檔案在他的家目錄下， 他在此目錄下具有rwx的完整權限，因此對於the_root.data這個『檔名』來說，他是能夠『刪除』的！ 結論就是，dmtsai這個用戶能夠刪除the_root.data這個檔案！

還是看不太懂？有聽沒有懂喔！沒關係∼我們底下就來設計一個練習， 讓你實際玩玩看，應該就能夠比較近入狀況啦！不過，由於很多指令我們還沒有教， 所以底下的指令有的先瞭解即可，詳細的指令用法我們會在後面繼續介紹的。

- 先用root的身份建立所需要的檔案與目錄環境

我們用root的身份在所有人都可以工作的/tmp目錄中建立一個名為testing的目錄， 該目錄的權限為744且目錄擁有者為root。另外，在testing目錄下在建立一個空的檔案， 檔名亦為testing。建立目錄可用mkdir(make directory)，建立空檔案可用touch(下一章會說明)來處理。 所以過程如下所示：

[root@www ~]# cd /tmp                     <==切換工作目錄到/tmp

[root@www tmp]# mkdir testing             <==建立新目錄

[root@www tmp]# chmod 744 testing         <==變更權限

[root@www tmp]# touch testing/testing     <==建立空的檔案

[root@www tmp]# chmod 600 testing/testing <==變更權限

[root@www tmp]# ls -ald testing testing/testing

drwxr--r-- 2 root root 4096 Sep 19 16:01 testing

-rw------- 1 root root    0 Sep 19 16:01 testing/testing

# 仔細看一下，目錄的權限是 744 ，且所屬群組與使用者均是 root 喔！

# 那麼在這樣的情況底下，一般身份使用者對這個目錄/檔案的權限為何？

- 一般用戶的讀寫權限為何？觀察中

在上面的例子中，雖然目錄是744的權限設定，一般用戶應該能有 r 的權限， 但這樣的權限使用者能做啥事呢？假設鳥哥的系統中含有一個帳號名為 vbird 的， 我們可以透過『 su - vbird 』這個指令來變換身份喔！看看底下的操作先！

[root@www tmp]# su - vbird <==切換身份成為 vbird 囉！

[vbird@www ~]$ cd /tmp     <==看一下，身份變了喔！提示字元也變成 $ 了！

[vbird@www tmp]$ ls -l testing/

?--------- ? ? ? ?             ? testing

# 因為具有 r 的權限可以查詢檔名。不過權限不足(沒有x)，所以會有一堆問號。

[vbird@www tmp]$ cd testing/

-bash: cd: testing/: Permission denied

# 因為不具有 x ，所以當然沒有進入的權限啦！有沒有呼應前面的權限說明啊！

- 如果該目錄屬於用戶本身，會有什麼狀況？

上面的練習我們知道了只有r確實可以讓使用者讀取目錄的檔名列表，不過詳細的資訊卻還是讀不到的， 同時也不能將該目錄變成工作目錄(用 cd 進入該目錄之意)。那如果我們讓該目錄變成使用者的， 那麼使用者在這個目錄底下是否能夠刪除檔案呢？底下的練習做看看：

[vbird@www tmp]$ exit               <==讓 vbird 變回原本的 root 身份喔！

[root@www tmp]# chown vbird testing <==修改權限，讓vbird擁有此目錄

[root@www tmp]# su - vbird          <==再次變成vbird來操作

[vbird@www ~]$ cd /tmp/testing      <==可以進入目錄了呢！

[vbird@www testing]$ ls -l

-rw------- 1 root root 0 Sep 19 16:01 testing  <==檔案不是vbird的！

[vbird@www testing]$ rm testing     <==嘗試殺掉這個檔案看看！

rm: remove write-protected regular empty file `testing'? y

# 竟然可以刪除！這樣理解了嗎？！

透過上面這個簡單的步驟，你就可以清楚的知道， x 在目錄當中是與『能否進入該目錄』有關， 至於那個 w 則具有相當重要的權限，因為他可以讓使用者刪除、更新、新建檔案或目錄， 是個很重要的參數啊！這樣可以理解了嗎？！ ^_^

Linux檔案種類與副檔名

我們在基礎篇一直強調一個概念，那就是：任何裝置在Linux底下都是檔案， 不僅如此，連資料溝通的介面也有專屬的檔案在負責∼所以，你會瞭解到，Linux的檔案種類真的很多∼ 除了前面提到的一般檔案(-)與目錄檔案(d)之外，還有哪些種類的檔案呢？

- 檔案種類：

我們在剛剛提到使用『ls -l』觀察到第一欄那十個字元中，第一個字元為檔案的類型。 除了常見的一般檔案(-)與目錄檔案(d)之外，還有哪些種類的檔案類型呢？

- 正規檔案(regular file )：

就是一般我們在進行存取的類型的檔案，在由 ls -al 所顯示出來的屬性方面，第一個字元為 [ - ]，例如 [-rwxrwxrwx ]。另外，依照檔案的內容，又大略可以分為：

- 純文字檔(ASCII)：這是Linux系統中最多的一種檔案類型囉， 稱為純文字檔是因為內容為我們人類可以直接讀到的資料，例如數字、字母等等。 幾乎只要我們可以用來做為設定的檔案都屬於這一種檔案類型。 舉例來說，你可以下達『 cat ~/.bashrc 』就可以看到該檔案的內容。 (cat 是將一個檔案內容讀出來的指令)

- 二進位檔(binary)：還記得我們在『 第零章、計算機概論 』裡面的軟體程式的運作中提過， 我們的系統其實僅認識且可以執行二進位檔案(binary file)吧？沒錯∼ 你的Linux當中的可執行檔(scripts, 文字型批次檔不算)就是這種格式的啦∼ 舉例來說，剛剛下達的指令cat就是一個binary file。

- 資料格式檔(data)： 有些程式在運作的過程當中會讀取某些特定格式的檔案，那些特定格式的檔案可以被稱為資料檔 (data file)。舉例來說，我們的Linux在使用者登入時，都會將登錄的資料記錄在 /var/log/wtmp那個檔案內，該檔案是一個data file，他能夠透過last這個指令讀出來！ 但是使用cat時，會讀出亂碼∼因為他是屬於一種特殊格式的檔案。瞭乎？

- 目錄(directory)：

就是目錄囉∼第一個屬性為 [ d ]，例如 [drwxrwxrwx]。

- 連結檔(link)：

就是類似Windows系統底下的捷徑啦！ 第一個屬性為 [ l ](英文L的小寫)，例如 [lrwxrwxrwx] ；

- 設備與裝置檔(device)：

與系統周邊及儲存等相關的一些檔案， 通常都集中在/dev這個目錄之下！通常又分為兩種：

- 區塊(block)設備檔 ：就是一些儲存資料， 以提供系統隨機存取的周邊設備，舉例來說，硬碟與軟碟等就是啦！ 你可以隨機的在硬碟的不同區塊讀寫，這種裝置就是區塊裝置囉！你可以自行查一下/dev/sda看看， 會發現第一個屬性為[ b ]喔！

- 字元(character)設備檔：亦即是一些序列埠的周邊設備， 例如鍵盤、滑鼠等等！這些設備的特色就是『一次性讀取』的，不能夠截斷輸出。 舉例來說，你不可能讓滑鼠『跳到』另一個畫面，而是『滑動』到另一個地方啊！第一個屬性為 [ c ]。

- 資料接口檔(sockets)：

既然被稱為資料接口檔， 想當然爾，這種類型的檔案通常被用在網路上的資料承接了。我們可以啟動一個程式來監聽用戶端的要求， 而用戶端就可以透過這個socket來進行資料的溝通了。第一個屬性為 [ s ]， 最常在/var/run這個目錄中看到這種檔案類型了。

- 資料輸送檔(FIFO, pipe)：

FIFO也是一種特殊的檔案類型，他主要的目的在解決多個程序同時存取一個檔案所造成的錯誤問題。 FIFO是first-in-first-out的縮寫。第一個屬性為[p] 。

除了設備檔是我們系統中很重要的檔案，最好不要隨意修改之外(通常他也不會讓你修改的啦！)， 另一個比較有趣的檔案就是連結檔。如果你常常將應用程式捉到桌面來的話，你就應該知道在 Windows底下有所謂的『捷徑』。同樣的，你可以將 linux下的連結檔簡單的視為一個檔案或目錄的捷徑。 至於socket與FIFO檔案比較難理解，因為這兩個咚咚與程序(process)比較有關係， 這個等到未來你瞭解process之後，再回來查閱吧！此外， 你也可以透過man fifo及man socket來查閱系統上的說明！

- Linux檔案副檔名：

基本上，Linux的檔案是沒有所謂的『副檔名』的，我們剛剛就談過，一個Linux檔案能不能被執行，與他的第一欄的十個屬性有關， 與檔名根本一點關係也沒有。這個觀念跟Windows的情況不相同喔！在Windows底下， 能被執行的檔案副檔名通常是 .com .exe .bat等等，而在Linux底下，只要你的權限當中具有x的話，例如[ -rwxr-xr-x ] 即代表這個檔案可以被執行喔！

不過，可以被執行跟可以執行成功是不一樣的∼舉例來說，在root家目錄下的install.log 是一個純文字檔，如果經由修改權限成為 -rwxrwxrwx 後，這個檔案能夠真的執行成功嗎？ 當然不行∼因為他的內容根本就沒有可以執行的資料。所以說，這個x代表這個檔案具有可執行的能力， 但是能不能執行成功，當然就得要看該檔案的內容囉∼

雖然如此，不過我們仍然希望可以藉由副檔名來瞭解該檔案是什麼東西，所以， 通常我們還是會以適當的副檔名來表示該檔案是什麼種類的。底下有數種常用的副檔名：

- *.sh ： 腳本或批次檔 (scripts)，因為批次檔為使用shell寫成的，所以副檔名就編成 .sh 囉；

- *Z, *.tar, *.tar.gz, *.zip, *.tgz： 經過打包的壓縮檔。這是因為壓縮軟體分別為 gunzip, tar 等等的，由於不同的壓縮軟體，而取其相關的副檔名囉！

- *.html, *.php：網頁相關檔案，分別代表 HTML 語法與 PHP 語法的網頁檔案囉！ .html 的檔案可使用網頁瀏覽器來直接開啟，至於 .php 的檔案， 則可以透過 client 端的瀏覽器來 server 端瀏覽，以得到運算後的網頁結果呢！

基本上，Linux系統上的檔名真的只是讓你瞭解該檔案可能的用途而已， 真正的執行與否仍然需要權限的規範才行！例如雖然有一個檔案為可執行檔， 如常見的/bin/ls這個顯示檔案屬性的指令，不過，如果這個檔案的權限被修改成無法執行時， 那麼ls就變成不能執行囉！

上述的這種問題最常發生在檔案傳送的過程中。例如你在網路上下載一個可執行檔，但是偏偏在你的 Linux系統中就是無法執行！呵呵！那麼就是可能檔案的屬性被改變了！不要懷疑，從網路上傳送到你的 Linux系統中，檔案的屬性與權限確實是會被改變的喔！

- Linux檔案長度限制：

在Linux底下，使用預設的Ext2/Ext3檔案系統時，針對檔案的檔名長度限制為：

- 單一檔案或目錄的最大容許檔名為 255 個字元；

- 包含完整路徑名稱及目錄 (/) 之完整檔名為 4096 個字元。

是相當長的檔名喔！我們希望Linux的檔案名稱可以一看就知道該檔案在幹嘛的， 所以檔名通常是很長很長！而用慣了Windows的人可能會受不了，因為檔案名稱通常真的都很長， 對於用慣Windows而導致打字速度不快的朋友來說，嗯！真的是很困擾.....不過，只得勸你好好的加強打字的訓練囉！

而由第五章談到的熱鍵你也會知道， 其實可以透過[tab]按鍵來確認檔案的檔名的！這很好用啊！ 當然啦，如果你已經讀完了本書第三篇關於BASH的用法，那麼你將會發現 『哇！變數真是一個相當好用的東西吶！』 嗯！看不懂，沒關係，到第三篇談到bash再說！

- Linux檔案名稱的限制：

由於Linux在文字介面下的一些指令操作關係，一般來說，你在設定Linux底下的檔案名稱時， 最好可以避免一些特殊字元比較好！例如底下這些：

* ? > < ; & ! [ ] | \ ' " ` ( ) { }

因為這些符號在文字介面下，是有特殊意義的！另外，檔案名稱的開頭為小數點『.』時， 代表這個檔案為『隱藏檔』喔！同時，由於指令下達當中，常常會使用到 -option 之類的選項， 所以你最好也避免將檔案檔名的開頭以 - 或 + 來命名啊！

Linux目錄配置

在瞭解了每個檔案的相關種類與屬性，以及瞭解了如何更改檔案屬性/權限的相關資訊後，再來要瞭解的就是， 為什麼每套Linux distributions他們的設定檔啊、執行檔啊、每個目錄內放置的咚咚啊，其實都差不多？ 原來是有一套標準依據的哩！我們底下就來瞧一瞧。

Linux目錄配置的依據--FHS

因為利用Linux來開發產品或distributions的社群/公司與個人實在太多了， 如果每個人都用自己的想法來配置檔案放置的目錄，那麼將可能造成很多管理上的困擾。 你能想像，你進入一個企業之後，所接觸到的Linux目錄配置方法竟然跟你以前學的完全不同嗎？ 很難想像吧∼所以，後來就有所謂的Filesystem Hierarchy Standard (FHS)標準的出爐了！

根據FHS(http://www.pathname.com/fhs/)的官方文件指出， 他們的主要目的是希望讓使用者可以瞭解到已安裝軟體通常放置於那個目錄下， 所以他們希望獨立的軟體開發商、作業系統製作者、以及想要維護系統的使用者，都能夠遵循FHS的標準。 也就是說，FHS的重點在於規範每個特定的目錄下應該要放置什麼樣子的資料而已。 這樣做好處非常多，因為Linux作業系統就能夠在既有的面貌下(目錄架構不變)發展出開發者想要的獨特風格。

事實上，FHS是根據過去的經驗一直再持續的改版的，FHS依據檔案系統使用的頻繁與否與是否允許使用者隨意更動， 而將目錄定義成為四種交互作用的形態，用表格來說有點像底下這樣：

可分享的(shareable)

不可分享的(unshareable)

不變的(static)

/usr (軟體放置處)

/etc (設定檔)

/opt (第三方協力軟體)

/boot (開機與核心檔)

可變動的(variable)

/var/mail (使用者郵件信箱)

/var/run (程序相關)

/var/spool/news (新聞群組)

/var/lock (程序相關)

上表中的目錄就是一些代表性的目錄，該目錄底下所放置的資料在底下會談到，這裡先略過不談。 我們要瞭解的是，什麼是那四個類型？

- 可分享的：可以分享給其他系統掛載使用的目錄，所以包括執行檔與使用者的郵件等資料， 是能夠分享給網路上其他主機掛載用的目錄；

- 不可分享的：自己機器上面運作的裝置檔案或者是與程序有關的socket檔案等， 由於僅與自身機器有關，所以當然就不適合分享給其他主機了。

- 不變的：有些資料是不會經常變動的，跟隨著distribution而不變動。 例如函式庫、文件說明檔、系統管理員所管理的主機服務設定檔等等；

- 可變動的：經常改變的資料，例如登錄檔、一般用戶可自行收受的新聞群組等。

事實上，FHS針對目錄樹架構僅定義出三層目錄底下應該放置什麼資料而已，分別是底下這三個目錄的定義：

- / (root, 根目錄)：與開機系統有關；

- /usr (unix software resource)：與軟體安裝/執行有關；

- /var (variable)：與系統運作過程有關。

為什麼要定義出這三層目錄呢？其實是有意義的喔！每層目錄底下所應該要放置的目錄也都又特定的規定喔！ 由於我們尚未介紹完整的Linux系統，所以底下的介紹你可能會看不懂！沒關係，先有個概念即可， 等到妳將基礎篇全部看完後，就重頭將基礎篇再看一遍！到時候你就會豁然開朗啦！^_^

Tips:

這個 root 在 Linux 裡面的意義真的很多很多∼多到讓人搞不懂那是啥玩意兒。 如果以『帳號』的角度來看，所謂的 root 指的是『系統管理員！』的身份， 如果以『目錄』的角度來看，所謂的 root 意即指的是根目錄，就是 / 啦∼ 要特別留意喔！

- 根目錄 (/) 的意義與內容：

根目錄是整個系統最重要的一個目錄，因為不但所有的目錄都是由根目錄衍生出來的， 同時根目錄也與開機/還原/系統修復等動作有關。 由於系統開機時需要特定的開機軟體、核心檔案、開機所需程式、 函式庫等等檔案資料，若系統出現錯誤時，根目錄也必須要包含有能夠修復檔案系統的程式才行。 因為根目錄是這麼的重要，所以在FHS的要求方面，他希望根目錄不要放在非常大的分割槽內， 因為越大的分割槽妳會放入越多的資料，如此一來根目錄所在分割槽就可能會有較多發生錯誤的機會。

因此FHS標準建議：根目錄(/)所在分割槽應該越小越好， 且應用程式所安裝的軟體最好不要與根目錄放在同一個分割槽內，保持根目錄越小越好。 如此不但效能較佳，根目錄所在的檔案系統也較不容易發生問題。

有鑑於上述的說明，因此FHS定義出根目錄(/)底下應該要有底下這些次目錄的存在才好：

目錄

應放置檔案內容

/bin

系統有很多放置執行檔的目錄，但/bin比較特殊。因為/bin放置的是在單人維護模式下還能夠被操作的指令。 在/bin底下的指令可以被root與一般帳號所使用，主要有：cat, chmod, chown, date, mv, mkdir, cp, bash等等常用的指令。

/boot

這個目錄主要在放置開機會使用到的檔案，包括Linux核心檔案以及開機選單與開機所需設定檔等等。 Linux kernel常用的檔名為：vmlinuz，如果使用的是grub這個開機管理程式， 則還會存在/boot/grub/這個目錄喔！

/dev

在Linux系統上，任何裝置與周邊設備都是以檔案的型態存在於這個目錄當中的。 你只要透過存取這個目錄底下的某個檔案，就等於存取某個裝置囉∼ 比要重要的檔案有/dev/null, /dev/zero, /dev/tty, /dev/lp*, /dev/hd*, /dev/sd*等等

/etc

系統主要的設定檔幾乎都放置在這個目錄內，例如人員的帳號密碼檔、 各種服務的啟始檔等等。一般來說，這個目錄下的各檔案屬性是可以讓一般使用者查閱的， 但是只有root有權力修改。FHS建議不要放置可執行檔(binary)在這個目錄中喔。比較重要的檔案有： /etc/inittab, /etc/init.d/, /etc/modprobe.conf, /etc/X11/, /etc/fstab, /etc/sysconfig/ 等等。另外，其下重要的目錄有：

- /etc/init.d/：所有服務的預設啟動 script 都是放在這裡的，例如要啟動或者關閉 iptables 的話：『 /etc/init.d/iptables start』、『/etc/init.d/iptables stop』

- /etc/xinetd.d/：這就是所謂的super daemon管理的各項服務的設定檔目錄。

- /etc/X11/：與 X Window 有關的各種設定檔都在這裡，尤其是 xorg.conf 這個 X Server 的設定檔。

/home

這是系統預設的使用者家目錄(home directory)。在你新增一個一般使用者帳號時， 預設的使用者家目錄都會規範到這裡來。比較重要的是，家目錄有兩種代號喔：

~：代表目前這個使用者的家目錄，而

~dmtsai ：則代表 dmtsai 的家目錄！

/lib

系統的函式庫非常的多，而/lib放置的則是在開機時會用到的函式庫， 以及在/bin或/sbin底下的指令會呼叫的函式庫而已。 什麼是函式庫呢？妳可以將他想成是『外掛』，某些指令必須要有這些『外掛』才能夠順利完成程式的執行之意。 尤其重要的是/lib/modules/這個目錄， 因為該目錄會放置核心相關的模組(驅動程式)喔！

/media

media是『媒體』的英文，顧名思義，這個/media底下放置的就是可移除的裝置啦！ 包括軟碟、光碟、DVD等等裝置都暫時掛載於此。常見的檔名有：/media/floppy, /media/cdrom等等。

/mnt

如果妳想要暫時掛載某些額外的裝置，一般建議妳可以放置到這個目錄中。 在古早時候，這個目錄的用途與/media相同啦！只是有了/media之後，這個目錄就用來暫時掛載用了。

/opt

這個是給第三方協力軟體放置的目錄。什麼是第三方協力軟體啊？ 舉例來說，KDE這個桌面管理系統是一個獨立的計畫，不過他可以安裝到Linux系統中，因此KDE的軟體就建議放置到此目錄下了。 另外，如果妳想要自行安裝額外的軟體(非原本的distribution提供的)，那麼也能夠將你的軟體安裝到這裡來。 不過，以前的Linux系統中，我們還是習慣放置在/usr/local目錄下呢！

/root

系統管理員(root)的家目錄。之所以放在這裡，是因為如果進入單人維護模式而僅掛載根目錄時， 該目錄就能夠擁有root的家目錄，所以我們會希望root的家目錄與根目錄放置在同一個分割槽中。

/sbin

Linux有非常多指令是用來設定系統環境的，這些指令只有root才能夠利用來『設定』系統，其他使用者最多只能用來『查詢』而已。 放在/sbin底下的為開機過程中所需要的，裡面包括了開機、修復、還原系統所需要的指令。 至於某些伺服器軟體程式，一般則放置到/usr/sbin/當中。至於本機自行安裝的軟體所產生的系統執行檔(system binary)， 則放置到/usr/local/sbin/當中了。常見的指令包括：fdisk, fsck, ifconfig, init, mkfs等等。

/srv

srv可以視為『service』的縮寫，是一些網路服務啟動之後，這些服務所需要取用的資料目錄。 常見的服務例如WWW, FTP等等。舉例來說，WWW伺服器需要的網頁資料就可以放置在/srv/www/裡面。

/tmp

這是讓一般使用者或者是正在執行的程序暫時放置檔案的地方。 這個目錄是任何人都能夠存取的，所以你需要定期的清理一下。當然，重要資料不可放置在此目錄啊！ 因為FHS甚至建議在開機時，應該要將/tmp下的資料都刪除唷！

事實上FHS針對根目錄所定義的標準就僅有上面的咚咚，不過我們的Linux底下還有許多目錄你也需要瞭解一下的。 底下是幾個在Linux當中也是非常重要的目錄喔：

目錄

應放置檔案內容

/lost+found

這個目錄是使用標準的ext2/ext3檔案系統格式才會產生的一個目錄，目的在於當檔案系統發生錯誤時， 將一些遺失的片段放置到這個目錄下。這個目錄通常會在分割槽的最頂層存在， 例如你加裝一顆硬碟於/disk中，那在這個系統下就會自動產生一個這樣的目錄『/disk/lost+found』

/proc

這個目錄本身是一個『虛擬檔案系統(virtual filesystem)』喔！他放置的資料都是在記憶體當中， 例如系統核心、行程資訊(process)、周邊裝置的狀態及網路狀態等等。因為這個目錄下的資料都是在記憶體當中， 所以本身不佔任何硬碟空間啊！比較重要的檔案例如：/proc/cpuinfo, /proc/dma, /proc/interrupts, /proc/ioports, /proc/net/* 等等。

/sys

這個目錄其實跟/proc非常類似，也是一個虛擬的檔案系統，主要也是記錄與核心相關的資訊。 包括目前已載入的核心模組與核心偵測到的硬體裝置資訊等等。這個目錄同樣不佔硬碟容量喔！

除了這些目錄的內容之外，另外要注意的是，因為根目錄與開機有關，開機過程中僅有根目錄會被掛載， 其他分割槽則是在開機完成之後才會持續的進行掛載的行為。就是因為如此，因此根目錄下與開機過程有關的目錄， 就不能夠與根目錄放到不同的分割槽去！那哪些目錄不可與根目錄分開呢？有底下這些：

- /etc：設定檔

- /bin：重要執行檔

- /dev：所需要的裝置檔案

- /lib：執行檔所需的函式庫與核心所需的模組

- /sbin：重要的系統執行檔

這五個目錄千萬不可與根目錄分開在不同的分割槽！請背下來啊！ 好了，談完了根目錄，接下來我們就來談談/usr以及/var囉！先看/usr裡面有些什麼東西：

- /usr 的意義與內容：

依據FHS的基本定義，/usr裡面放置的資料屬於可分享的與不可變動的(shareable, static)， 如果你知道如何透過網路進行分割槽的掛載(例如在伺服器篇會談到的NFS伺服器)，那麼/usr確實可以分享給區域網路內的其他主機來使用喔！

很多讀者都會誤會/usr為user的縮寫，其實usr是Unix Software Resource的縮寫， 也就是『Unix作業系統軟體資源』所放置的目錄，而不是使用者的資料啦！這點要注意。 FHS建議所有軟體開發者，應該將他們的資料合理的分別放置到這個目錄下的次目錄，而不要自行建立該軟體自己獨立的目錄。

因為是所有系統預設的軟體(distribution發佈者提供的軟體)都會放置到/usr底下，因此這個目錄有點類似Windows 系統的『C:\Windows\ (當中的一部份) + C:\Program files\』這兩個目錄的綜合體，系統剛安裝完畢時，這個目錄會佔用最多的硬碟容量。一般來說，/usr的次目錄建議有底下這些：

目錄

應放置檔案內容

/usr/X11R6/

為X Window System重要資料所放置的目錄，之所以取名為X11R6是因為最後的X版本為第11版，且該版的第6次釋出之意。

/usr/bin/

絕大部分的使用者可使用指令都放在這裡！請注意到他與/bin的不同之處。(是否與開機過程有關)

/usr/include/

c/c++等程式語言的檔頭(header)與包含檔(include)放置處，當我們以tarball方式 (*.tar.gz 的方式安裝軟體)安裝某些資料時，會使用到裡頭的許多包含檔喔！

/usr/lib/

包含各應用軟體的函式庫、目標檔案(object file)，以及不被一般使用者慣用的執行檔或腳本(script)。 某些軟體會提供一些特殊的指令來進行伺服器的設定，這些指令也不會經常被系統管理員操作， 那就會被擺放到這個目錄下啦。要注意的是，如果你使用的是X86_64的Linux系統， 那可能會有/usr/lib64/目錄產生喔！

/usr/local/

系統管理員在本機自行安裝自己下載的軟體(非distribution預設提供者)，建議安裝到此目錄， 這樣會比較便於管理。舉例來說，你的distribution提供的軟體較舊，你想安裝較新的軟體但又不想移除舊版， 此時你可以將新版軟體安裝於/usr/local/目錄下，可與原先的舊版軟體有分別啦！ 你可以自行到/usr/local去看看，該目錄下也是具有bin, etc, include, lib...的次目錄喔！

/usr/sbin/

非系統正常運作所需要的系統指令。最常見的就是某些網路伺服器軟體的服務指令(daemon)囉！

/usr/share/

放置共享文件的地方，在這個目錄下放置的資料幾乎是不分硬體架構均可讀取的資料， 因為幾乎都是文字檔案嘛！在此目錄下常見的還有這些次目錄：

- /usr/share/man：線上說明文件

- /usr/share/doc：軟體雜項的文件說明

- /usr/share/zoneinfo：與時區有關的時區檔案

/usr/src/

一般原始碼建議放置到這裡，src有source的意思。至於核心原始碼則建議放置到/usr/src/linux/目錄下。

- /var 的意義與內容：

如果/usr是安裝時會佔用較大硬碟容量的目錄，那麼/var就是在系統運作後才會漸漸佔用硬碟容量的目錄。 因為/var目錄主要針對常態性變動的檔案，包括快取(cache)、登錄檔(log file)以及某些軟體運作所產生的檔案， 包括程序檔案(lock file, run file)，或者例如MySQL資料庫的檔案等等。常見的次目錄有：

目錄

應放置檔案內容

/var/cache/

應用程式本身運作過程中會產生的一些暫存檔；

/var/lib/

程式本身執行的過程中，需要使用到的資料檔案放置的目錄。在此目錄下各自的軟體應該要有各自的目錄。 舉例來說，MySQL的資料庫放置到/var/lib/mysql/而rpm的資料庫則放到/var/lib/rpm去！

/var/lock/

某些裝置或者是檔案資源一次只能被一個應用程式所使用，如果同時有兩個程式使用該裝置時， 就可能產生一些錯誤的狀況，因此就得要將該裝置上鎖(lock)，以確保該裝置只會給單一軟體所使用。 舉例來說，燒錄機正在燒錄一塊光碟，你想一下，會不會有兩個人同時在使用一個燒錄機燒片？ 如果兩個人同時燒錄，那片子寫入的是誰的資料？所以當第一個人在燒錄時該燒錄機就會被上鎖， 第二個人就得要該裝置被解除鎖定(就是前一個人用完了)才能夠繼續使用囉。

/var/log/

重要到不行！這是登錄檔放置的目錄！裡面比較重要的檔案如/var/log/messages, /var/log/wtmp(記錄登入者的資訊)等。

/var/mail/

放置個人電子郵件信箱的目錄，不過這個目錄也被放置到/var/spool/mail/目錄中！ 通常這兩個目錄是互為連結檔啦！

/var/run/

某些程式或者是服務啟動後，會將他們的PID放置在這個目錄下喔！ 至於PID的意義我們會在後續章節提到的。

/var/spool/

這個目錄通常放置一些佇列資料，所謂的『佇列』就是排隊等待其他程式使用的資料啦！ 這些資料被使用後通常都會被刪除。舉例來說，系統收到新信會放置到/var/spool/mail/中， 但使用者收下該信件後該封信原則上就會被刪除。信件如果暫時寄不出去會被放到/var/spool/mqueue/中， 等到被送出後就被刪除。如果是工作排程資料(crontab)，就會被放置到/var/spool/cron/目錄中！

建議在你讀完整個基礎篇之後，可以挑戰FHS官方英文文件(參考本章參考資料)，相信會讓你對於Linux作業系統的目錄有更深入的瞭解喔！

- 針對FHS，各家distributions的異同

由於FHS僅是定義出最上層(/)及次層(/usr, /var)的目錄內容應該要放置的檔案或目錄資料， 因此，在其他次目錄層級內，就可以隨開發者自行來配置了。舉例來說，CentOS的網路設定資料放在 /etc/sysconfig/network-scripts/ 目錄下，但是SuSE則是將網路放置在 /etc/sysconfig/network/ 目錄下，目錄名稱可是不同的呢！不過只要記住大致的FHS標準，差異性其實有限啦！

目錄樹(directory tree)

另外，在Linux底下，所有的檔案與目錄都是由根目錄開始的！那是所有目錄與檔案的源頭∼ 然後再一個一個的分支下來，有點像是樹枝狀啊∼因此，我們也稱這種目錄配置方式為：『目錄樹(directory tree)』 這個目錄樹有什麼特性呢？他主要的特性有：

- 目錄樹的啟始點為根目錄 (/, root)；

- 每一個目錄不止能使用本地端的 partition 的檔案系統，也可以使用網路上的 filesystem 。舉例來說， 可以利用 Network File System (NFS) 伺服器掛載某特定目錄等。

- 每一個檔案在此目錄樹中的檔名(包含完整路徑)都是獨一無二的。

好，談完了FHS的標準之後，實際來看看CentOS在根目錄底下會有什麼樣子的資料吧！我們可以下達以下的指令來查詢：

[root@www ~]# ls -l /

drwxr-xr-x   2 root root  4096 Sep  5 12:34 bin

drwxr-xr-x   4 root root  1024 Sep  4 18:06 boot

drwxr-xr-x  12 root root  4320 Sep 22 12:10 dev

drwxr-xr-x 105 root root 12288 Sep 22 12:10 etc

drwxr-xr-x   4 root root  4096 Sep  5 14:08 home

drwxr-xr-x  14 root root  4096 Sep  5 12:12 lib

drwx------   2 root root 16384 Sep  5 01:49 lost+found

drwxr-xr-x   2 root root  4096 Mar 30  2007 media

drwxr-xr-x   2 root root     0 Sep 22 12:09 misc

drwxr-xr-x   2 root root  4096 Mar 30  2007 mnt

drwxr-xr-x   2 root root     0 Sep 22 12:09 net

drwxr-xr-x   2 root root  4096 Mar 30  2007 opt

dr-xr-xr-x  95 root root     0 Sep 22  2008 proc

drwxr-x---   4 root root  4096 Sep  8 14:06 root

drwxr-xr-x   2 root root 12288 Sep  5 12:33 sbin

drwxr-xr-x   4 root root     0 Sep 22  2008 selinux

drwxr-xr-x   2 root root  4096 Mar 30  2007 srv

drwxr-xr-x  11 root root     0 Sep 22  2008 sys

drwxrwxrwt   6 root root  4096 Sep 22 12:10 tmp

drwxr-xr-x  14 root root  4096 Sep  4 18:00 usr

drwxr-xr-x  26 root root  4096 Sep  4 18:19 var

上面表格中比較特殊的應該是/selinux這個目錄了，這個目錄的內容資料也是在記憶體中的資訊， 同樣的不會佔用任何的硬碟容量。這個/selinux是Secure Enhance Linux(SELinux)的執行目錄， 而SELinux是Linux核心的重要外掛功能之一，他可以用來作為細部權限的控管，主要針對程序(尤其是網路程序)的存取權限來限制。 關於SELinux我們會在後續的章節繼續做介紹的喔！

如果我們將整個目錄樹以圖示的方法來顯示，並且將較為重要的檔案資料列出來的話，那麼目錄樹架構有點像這樣：

圖3.2.1、目錄樹架構示意圖

鳥哥只有就各目錄進行簡單的解釋，看看就好，詳細的解釋請回到剛剛說明的表格中去查閱喔！ 看完了FHS標準之後，現在回到第三章裡面去看看安裝前Linux規劃的分割情況， 對於當初為何需要分割為這樣的情況，有點想法了嗎？^_^。根據FHS的定義，妳最好能夠將/var獨立出來， 這樣對於系統的資料還有一些安全性的保護呢！因為至少/var死掉時，你的根目錄還會活著嘛！ 還能夠進入救援模式啊！

絕對路徑與相對路徑

除了需要特別注意的FHS目錄配置外，在檔名部分我們也要特別注意喔！因為根據檔名寫法的不同，也可將所謂的路徑(path)定義為絕對路徑(absolute)與相對路徑(relative)。 這兩種檔名/路徑的寫法依據是這樣的：

- 絕對路徑：由根目錄(/)開始寫起的檔名或目錄名稱， 例如 /home/dmtsai/.bashrc；

- 相對路徑：相對於目前路徑的檔名寫法。 例如 ./home/dmtsai 或 ../../home/dmtsai/ 等等。反正開頭不是 / 就屬於相對路徑的寫法

而你必須要瞭解，相對路徑是以『你當前所在路徑的相對位置』來表示的。舉例來說，你目前在 /home 這個目錄下， 如果想要進入 /var/log 這個目錄時，可以怎麼寫呢？

1. cd /var/log   (absolute)

2. cd ../var/log (relative)

因為你在 /home 底下，所以要回到上一層 (../) 之後，才能繼續往 /var 來移動的！ 特別注意這兩個特殊的目錄：

- .  ：代表當前的目錄，也可以使用 ./ 來表示；

- .. ：代表上一層目錄，也可以 ../ 來代表。

這個 . 與 .. 目錄概念是很重要的，你常常會看到 cd .. 或 ./command 之類的指令下達方式， 就是代表上一層與目前所在目錄的工作狀態喔！很重要的吶！

例題：

如何先進入/var/spool/mail/目錄，再進入到/var/spool/cron/目錄內？

答：

由於/var/spool/mail與/var/spool/cron是同樣在/var/spool/目錄中，因此最簡單的指令下達方法為：

1. cd /var/spool/mail

2. cd ../cron

如此就不需要在由根目錄開始寫起了。這個相對路徑是非常有幫助的！尤其對於某些軟體開發商來說。 一般來說，軟體開發商會將資料放置到/usr/local/裡面的各相對目錄，妳可以參考圖3.2.1的相對位置。 但如果使用者想要安裝到不同目錄呢？就得要使用相對路徑囉！^_^

例題：

網路文件常常提到類似『./run.sh』之類的資料，這個指令的意義為何？

答：

由於指令的執行需要變數(bash章節才會提到)的支援，若你的執行檔放置在本目錄，並且本目錄並非正規的執行檔目錄(/bin, /usr/bin等為正規)，此時要執行指令就得要嚴格指定該執行檔。『./』代表『本目錄』的意思，所以『./run.sh』代表『執行本目錄下， 名為run.sh的檔案』囉！

CentOS 的觀察

某些時刻你可能想要知道你的 distribution 使用的是那個 Linux 標準 (Linux Standard Base)， 而且我們也知道 distribution 使用的都是 Linux 的核心！那你如何觀察這些基本的資訊呢？ 可以使用如下的指令來觀察看看啦：

[root@www ~]# uname -r

2.6.18-128.el5 <==可以察看實際的核心版本

[root@www ~]# lsb_release -a

LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:

graphics-3.1-ia32:graphics-3.1-noarch      <==LSB 的版本

Distributor ID: CentOS

Description:    CentOS release 5.3 (Final) <==distribution 的版本

Release:        5.3

Codename:       Final

重點回顧

- Linux的每個檔案中，依據權限分為使用者、群組與其他人三種身份；

- 群組最有用的功能之一，就是當你在團隊開發資源的時候，且每個帳號都可以有多個群組的支援；

- 利用ls -l顯示的檔案屬性中，第一個欄位是檔案的權限，共有十個位元，第一個位元是檔案類型， 接下來三個為一組共三組，為使用者、群組、其他人的權限，權限有r,w,x三種；

- 如果檔名之前多一個『 . 』，則代表這個檔案為『隱藏檔』；

- 更改檔案的群組支援可用chgrp，修改檔案的擁有者可用chown，修改檔案的權限可用chmod

- chmod修改權限的方法有兩種，分別是符號法與數字法，數字法中r,w,x分數為4,2,1；

- 對檔案來講，權限的效能為：

- r：可讀取此一檔案的實際內容，如讀取文字檔的文字內容等；

- w：可以編輯、新增或者是修改該檔案的內容(但不含刪除該檔案)；

- x：該檔案具有可以被系統執行的權限。

- 對目錄來說，權限的效能為：

- r (read contents in directory)

- w (modify contents of directory)

- x (access directory)

- 要開放目錄給任何人瀏覽時，應該至少也要給予r及x的權限，但w權限不可隨便給；

- Linux檔名的限制為：單一檔案或目錄的最大容許檔名為 255 個字元；包含完整路徑名稱及目錄 (/) 之完整檔名為 4096 個字元

- 根據FHS的官方文件指出， 他們的主要目的是希望讓使用者可以瞭解到已安裝軟體通常放置於那個目錄下

- FHS訂定出來的四種目錄特色為：shareable, unshareable, static, variable等四類；

- FHS所定義的三層主目錄為：/, /var, /usr三層而已；

- 有五個目錄不可與根目錄放在不同的partition，分別為/etc, /bin, /lib, /dev, /sbin五個。

本章練習

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 請說明/bin與/usr/bin目錄所放置的執行檔有何不同之處？

/bin主要放置在開機時，以及進入單人維護模式後還能夠被使用的指令，至於/usr/bin則是大部分軟體提供的指令放置處。

- 請說明/bin與/sbin目錄所放置的執行檔有何不同之處？

/bin放置的是一般使用者慣用的指令，至於/sbin則是系統管理員才會使用到的指令。不過/bin與/sbin都與開機、單人維護模式有關。 更多的執行檔會被放置到/usr/bin及/usr/sbin底下。

- 哪幾個目錄不能夠與根目錄(/)放置到不同的partition中？並請說明該目錄所放置的資料為何？

/etc(設定檔), /bin(一般身份可用執行檔), /dev(裝置檔案), /lib(執行檔的函式庫或核心模組等), /sbin(系統管理員可用指令)

- 試說明為何根目錄要小一點比較好？另外在分割時，為什麼/home, /usr, /var, /tmp最好與根目錄放到不同的分割槽？ 試說明可能的原因為何(由目錄放置資料的內容談起)？

根據FHS的說明，越小的/可以放置的較為集中且讀取頻率較不頻繁，可避免較多的錯誤。 至於/home(使用者家目錄), /usr(軟體資源), /var(變動幅度較大的資料), /tmp(系統暫存，資料莫名)中， 因為資料量較大或者是讀取頻率較高，或者是不明的使用情況較多，因此建議不要與根目錄放在一起， 也會有助於系統安全。

- 早期的 Unix 系統檔名最多允許 14 個字元，而新的 Unix 與 Linux 系統中，檔名最多可以容許幾個字元？

由於使用Ext2/Ext3檔案系統，單一檔名可達 255 字元，完整檔名 (包含路徑) 可達 4096 個字元

- 當一個一般檔案權限為 -rwxrwxrwx 則表示這個檔案的意義為？

任何人皆可讀取、修改或編輯、可以執行，但不一定能刪除。

- 我需要將一個檔案的權限改為 -rwxr-xr-- 請問該如何下達指令？

chmod 754 filename 或 chmod u=rwx,g=rx,o=r filename

- 若我需要更改一個檔案的擁有者與群組，該用什麼指令？

chown, chgrp

- Linux 傳統的檔案系統為何？此外，常用的 Journaling 檔案格式有哪些？

傳統檔案格式為：ext2,

Journaling 有 ext3 及 Reiserfs 等

- 請問底下的目錄與主要放置什麼資料：

/etc/, /etc/init.d, /boot, /usr/bin, /bin, /usr/sbin, /sbin, /dev, /var/log

- /etc/：幾乎系統的所有設定檔案均在此，尤其 passwd,shadow

- /etc/init.d：系統開機的時候載入服務的 scripts 的擺放地點

- /boot：開機設定檔，也是預設擺放核心 vmlinuz 的地方

- /usr/bin, /bin：一般執行檔擺放的地方

- /usr/sbin, /sbin：系統管理員常用指令集

- /dev：擺放所有系統裝置檔案的目錄

- /var/log：擺放系統登錄檔案的地方

- 若一個檔案的檔名開頭為『 . 』，例如 .bashrc 這個檔案，代表什麼？另外，如何顯示出這個檔名與他的相關屬性？

有『 . 』為開頭的為隱藏檔，需要使用 ls -a 這個 -a 的選項才能顯示出隱藏檔案的內容，而使用 ls -al 才能顯示出屬性。

參考資料與延伸閱讀

- FHS的標準官方文件：http://proton.pathname.com/fhs/，非常值得參考的文獻！

- 關於 Journaling 日誌式文章的相關說明 http://www.linuxplanet.com/linuxplanet/reports/3726/1/

2002/07/18：第一次完成

2003/02/06：重新編排與加入FAQ

2005/06/28：將舊的資料移動到 這裡

2005/07/15：呼呼∼終於改完成了∼這次的修訂當中，加入了 FHS 的說明，希望大家能夠比較清楚 Linux 的目錄配置！

2005/08/05：修訂了最大檔名字元，應該是 255 才對！另外，加入了『檔名限制』的部分！

2005/09/03：修訂了目錄權限相關的說明，將原本僅具有 r 卻寫成無法使用 ls 瀏覽的說明資料移除！

2008/09/08：舊的針對FC4所寫的文章移動到此處

2008/09/20：針對FHS加強說明了一下，分為/, /usr, /var三層來個別說明！並非抄襲官網的資料而已喔！

2008/09/23：經過一場大感冒，停工了四、五天，終於還是給他完工了！^_^

2008/10/21：原本的第四小節 Linux 的檔案系統，因為與第八章重複性太高，將他移除了！

2009/08/01：加入了 lsb_release 的相關說明！

2009/08/18：調整一下顯示的情況，使得更易讀∼

2002/02/18以來統計人數

第七章、Linux 檔案與目錄管理

切換解析度為 800x600

最近更新日期：2009/08/26

在第六章我們認識了Linux系統下的檔案權限概念以及目錄的配置說明。 在這個章節當中，我們就直接來進一步的操作與管理檔案與目錄吧！包括在不同的目錄間變換、 建立與刪除目錄、建立與刪除檔案，還有尋找檔案、查閱檔案內容等等， 都會在這個章節作個簡單的介紹啊！

1. 目錄與路徑

1.1 相對路徑與絕對路徑

1.2 目錄的相關操作： cd, pwd, mkdir, rmdir

1.3 關於執行檔路徑的變數： $PATH

2. 檔案與目錄管理

2.1 檔案與目錄的檢視： ls

2.2 複製、刪除與移動： cp, rm, mv

2.3 取得路徑的檔案名稱與目錄名稱

3. 檔案內容查閱：

3.1 直接檢視檔案內容： cat, tac, nl

3.2 可翻頁檢視： more, less

3.3 資料擷取： head, tail

3.4 非純文字檔： od

3.5 修改檔案時間與建置新檔： touch

4. 檔案與目錄的預設權限與隱藏權限

4.1 檔案預設權限：umask

4.2 檔案隱藏屬性： chattr, lsattr

4.4 檔案特殊權限：SUID, SGID, SBIT, 權限設定

4.3 觀察檔案類型：file

5. 指令與檔案的搜尋：

5.1 指令檔名的搜尋：which

5.2 檔案檔名的搜尋：whereis, locate, find

6. 極重要！權限與指令間的關係：

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23879

目錄與路徑：

由第六章Linux的檔案權限與目錄配置中透過FHS瞭解了Linux的『樹狀目錄』概念之後， 接下來就得要實際的來搞定一些基本的路徑問題了！這些目錄的問題當中，最重要的莫過於第六章也談過的『絕對路徑』與『相對路徑』的意義啦！ 絕對/相對路徑的寫法並不相同，要特別注意。此外，當妳下達指令時，該指令是透過什麼功能來取得的？ 這與PATH這個變數有關呢！底下就讓我們來談談囉！

相對路徑與絕對路徑：

在開始目錄的切換之前，你必須要先瞭解一下所謂的『路徑(PATH)』， 有趣的是：什麼是『相對路徑』與『絕對路徑』？ 雖然前一章已經稍微針對這個議題提過一次，不過，這裡不厭其煩的再次的強調一下！

- 絕對路徑：路徑的寫法『一定由根目錄 / 寫起』，例如： /usr/share/doc 這個目錄。

- 相對路徑：路徑的寫法『不是由 / 寫起』，例如由 /usr/share/doc 要到 /usr/share/man 底下時，可以寫成： 『cd ../man』這就是相對路徑的寫法啦！相對路徑意指『相對於目前工作目錄的路徑！』

- 相對路徑的用途

那麼相對路徑與絕對路徑有什麼了不起呀？喝！那可真的是了不起了！假設你寫了一個軟體， 這個軟體共需要三個目錄，分別是 etc, bin, man 這三個目錄，然而由於不同的人喜歡安裝在不同的目錄之下， 假設甲安裝的目錄是 /usr/local/packages/etc, /usr/local/packages/bin 及 /usr/local/packages/man ，不過乙卻喜歡安裝在 /home/packages/etc, /home/packages/bin, /home/packages/man 這三個目錄中，請問如果需要用到絕對路徑的話，那麼是否很麻煩呢？是的！ 如此一來每個目錄下的東西就很難對應的起來！這個時候相對路徑的寫法就顯的特別的重要了！

此外，如果你跟鳥哥一樣，喜歡將路徑的名字寫的很長，好讓自己知道那個目錄是在幹什麼的，例如： /cluster/raid/output/taiwan2006/smoke 這個目錄，而另一個目錄在 /cluster/raid/output/taiwan2006/cctm ，那麼我從第一個要到第二個目錄去的話，怎麼寫比較方便？ 當然是『 cd ../cctm 』比較方便囉！對吧！

- 絕對路徑的用途

但是對於檔名的正確性來說，『絕對路徑的正確度要比較好∼』。 一般來說，鳥哥會建議你，如果是在寫程式 (shell scripts) 來管理系統的條件下，務必使用絕對路徑的寫法。 怎麼說呢？因為絕對路徑的寫法雖然比較麻煩，但是可以肯定這個寫法絕對不會有問題。 如果使用相對路徑在程式當中，則可能由於你執行的工作環境不同，導致一些問題的發生。 這個問題在工作排程(at, cron, 第十六章)當中尤其重要！這個現象我們在十三章、shell script時，會再次的提醒你喔！ ^_^

目錄的相關操作：

我們之前稍微提到變換目錄的指令是cd，還有哪些可以進行目錄操作的指令呢？ 例如建立目錄啊、刪除目錄之類的∼還有，得要先知道的，就是有哪些比較特殊的目錄呢？ 舉例來說，底下這些就是比較特殊的目錄，得要用力的記下來才行：

.         代表此層目錄

..        代表上一層目錄

-         代表前一個工作目錄

~         代表『目前使用者身份』所在的家目錄

~account  代表 account 這個使用者的家目錄(account是個帳號名稱)

需要特別注意的是：在所有目錄底下都會存在的兩個目錄，分別是『.』與『..』 分別代表此層與上層目錄的意思。那麼來思考一下底下這個例題：

例題：

請問在Linux底下，根目錄下有沒有上層目錄(..)存在？

答：

若使用『 ls -al / 』去查詢，可以看到根目錄下確實存在 . 與 .. 兩個目錄，再仔細的查閱， 可發現這兩個目錄的屬性與權限完全一致，這代表根目錄的上一層(..)與根目錄自己(.)是同一個目錄。

底下我們就來談一談幾個常見的處理目錄的指令吧：

- cd：變換目錄

- pwd：顯示目前的目錄

- mkdir：建立一個新的目錄

- rmdir：刪除一個空的目錄

- cd (變換目錄)

我們知道vbird這個使用者的家目錄是/home/vbird/，而root家目錄則是/root/，假設我以root身份在 Linux系統中，那麼簡單的說明一下這幾個特殊的目錄的意義是：

[root@www ~]# cd [相對路徑或絕對路徑]

# 最重要的就是目錄的絕對路徑與相對路徑，還有一些特殊目錄的符號囉！

[root@www ~]# cd ~vbird

# 代表去到 vbird 這個使用者的家目錄，亦即 /home/vbird

[root@www vbird]# cd ~

# 表示回到自己的家目錄，亦即是 /root 這個目錄

[root@www ~]# cd

# 沒有加上任何路徑，也還是代表回到自己家目錄的意思喔！

[root@www ~]# cd ..

# 表示去到目前的上層目錄，亦即是 /root 的上層目錄的意思；

[root@www /]# cd -

# 表示回到剛剛的那個目錄，也就是 /root 囉∼

[root@www ~]# cd /var/spool/mail

# 這個就是絕對路徑的寫法！直接指定要去的完整路徑名稱！

[root@www mail]# cd ../mqueue

# 這個是相對路徑的寫法，我們由/var/spool/mail 去到/var/spool/mqueue 就這樣寫！

cd是Change Directory的縮寫，這是用來變換工作目錄的指令。注意，目錄名稱與cd指令之間存在一個空格。 一登入Linux系統後，root會在root的家目錄！那回到上一層目錄可以用『 cd .. 』。 利用相對路徑的寫法必須要確認你目前的路徑才能正確的去到想要去的目錄。例如上表當中最後一個例子， 你必須要確認你是在/var/spool/mail當中，並且知道在/var/spool當中有個mqueue的目錄才行啊∼ 這樣才能使用cd ../mqueue去到正確的目錄說，否則就要直接輸入cd /var/spool/mqueue囉∼

其實，我們的提示字元，亦即那個 [root@www ~]# 當中，就已經有指出目前的目錄了， 剛登入時會到自己的家目錄，而家目錄還有一個代碼，那就是『 ~ 』符號！ 例如上面的例子可以發現，使用『 cd ~ 』可以回到個人的家目錄裡頭去呢！ 另外，針對 cd 的使用方法，如果僅輸入 cd 時，代表的就是『 cd ~ 』的意思喔∼ 亦即是會回到自己的家目錄啦！而那個『 cd - 』比較難以理解，請自行多做幾次練習， 就會比較明白了。

Tips:

還是要一再地提醒，我們的 Linux 的預設指令列模式 (bash shell) 具有檔案補齊功能， 你要常常利用 [tab] 按鍵來達成你的目錄完整性啊！這可是個好習慣啊∼ 可以避免你按錯鍵盤輸入錯字說∼ ^_^

- pwd (顯示目前所在的目錄)

[root@www ~]# pwd [-P]

選項與參數：

-P  ：顯示出確實的路徑，而非使用連結 (link) 路徑。

範例：單純顯示出目前的工作目錄：

[root@www ~]# pwd

/root   <== 顯示出目錄啦∼

範例：顯示出實際的工作目錄，而非連結檔本身的目錄名而已

[root@www ~]# cd /var/mail   <==注意，/var/mail是一個連結檔

[root@www mail]# pwd

/var/mail         <==列出目前的工作目錄

[root@www mail]# pwd -P

/var/spool/mail   <==怎麼回事？有沒有加 -P 差很多∼

[root@www mail]# ls -ld /var/mail

lrwxrwxrwx 1 root root 10 Sep  4 17:54 /var/mail -> spool/mail

# 看到這裡應該知道為啥了吧？因為 /var/mail 是連結檔，連結到 /var/spool/mail

# 所以，加上 pwd -P 的選項後，會不以連結檔的資料顯示，而是顯示正確的完整路徑啊！

pwd是Print Working Directory的縮寫，也就是顯示目前所在目錄的指令， 例如在上個表格最後的目錄是/var/mail這個目錄，但是提示字元僅顯示mail， 如果你想要知道目前所在的目錄，可以輸入pwd即可。此外，由於很多的套件所使用的目錄名稱都相同，例如 /usr/local/etc還有/etc，但是通常Linux僅列出最後面那一個目錄而已，這個時候你就可以使用pwd 來知道你的所在目錄囉！免得搞錯目錄，結果...

其實有趣的是那個 -P 的選項啦！他可以讓我們取得正確的目錄名稱，而不是以連結檔的路徑來顯示的。 如果你使用的是CentOS 5.x的話，剛剛好/var/mail是/var/spool/mail的連結檔， 所以，透過到/var/mail下達pwd -P就能夠知道這個選項的意義囉∼ ^_^

- mkdir (建立新目錄)

[root@www ~]# mkdir [-mp] 目錄名稱

選項與參數：

-m ：設定檔案的權限喔！直接設定，不需要看預設權限 (umask) 的臉色∼

-p ：幫助你直接將所需要的目錄(包含上層目錄)遞迴建立起來！

範例：請到/tmp底下嘗試建立數個新目錄看看：

[root@www ~]# cd /tmp

[root@www tmp]# mkdir test    <==建立一名為 test 的新目錄

[root@www tmp]# mkdir test1/test2/test3/test4

mkdir: cannot create directory `test1/test2/test3/test4':

No such file or directory       <== 沒辦法直接建立此目錄啊！

[root@www tmp]# mkdir -p test1/test2/test3/test4

# 加了這個 -p 的選項，可以自行幫你建立多層目錄！

範例：建立權限為rwx--x--x的目錄

[root@www tmp]# mkdir -m 711 test2

[root@www tmp]# ls -l

drwxr-xr-x  3 root  root 4096 Jul 18 12:50 test

drwxr-xr-x  3 root  root 4096 Jul 18 12:53 test1

drwx--x--x  2 root  root 4096 Jul 18 12:54 test2

# 仔細看上面的權限部分，如果沒有加上 -m 來強制設定屬性，系統會使用預設屬性。

# 那麼你的預設屬性為何？這要透過底下介紹的 umask 才能瞭解喔！ ^_^

如果想要建立新的目錄的話，那麼就使用mkdir (make directory)吧！ 不過，在預設的情況下， 你所需要的目錄得一層一層的建立才行！例如：假如你要建立一個目錄為 /home/bird/testing/test1，那麼首先必須要有 /home 然後 /home/bird ，再來 /home/bird/testing 都必須要存在，才可以建立 /home/bird/testing/test1 這個目錄！假如沒有 /home/bird/testing 時，就沒有辦法建立 test1 的目錄囉！

不過，現在有個更簡單有效的方法啦！那就是加上 -p 這個選項喔！你可以直接下達：『 mkdir -p /home/bird/testing/test1 』 則系統會自動的幫你將 /home, /home/bird, /home/bird/testing 依序的建立起目錄！並且， 如果該目錄本來就已經存在時，系統也不會顯示錯誤訊息喔！挺快樂的吧！ ^_^。 不過鳥哥不建議常用-p這個選項，因為擔心如果妳打錯字，那麼目錄名稱就會變的亂七八糟的！

另外，有個地方你必須要先有概念，那就是『預設權限』的地方。我們可以利用 -m 來強制給予一個新的目錄相關的權限， 例如上表當中，我們給予 -m 711 來給予新的目錄 drwx--x--x 的權限。不過，如果沒有給予 -m 選項時， 那麼預設的新建目錄權限又是什麼呢？這個跟 umask 有關，我們在本章後頭會加以介紹的。

- rmdir (刪除『空』的目錄)

[root@www ~]# rmdir [-p] 目錄名稱

選項與參數：

-p ：連同上層『空的』目錄也一起刪除

範例：將於mkdir範例中建立的目錄(/tmp底下)刪除掉！

[root@www tmp]# ls -l   <==看看有多少目錄存在？

drwxr-xr-x  3 root  root 4096 Jul 18 12:50 test

drwxr-xr-x  3 root  root 4096 Jul 18 12:53 test1

drwx--x--x  2 root  root 4096 Jul 18 12:54 test2

[root@www tmp]# rmdir test   <==可直接刪除掉，沒問題

[root@www tmp]# rmdir test1  <==因為尚有內容，所以無法刪除！

rmdir: `test1': Directory not empty

[root@www tmp]# rmdir -p test1/test2/test3/test4

[root@www tmp]# ls -l        <==您看看，底下的輸出中test與test1不見了！

drwx--x--x  2 root  root 4096 Jul 18 12:54 test2

# 瞧！利用 -p 這個選項，立刻就可以將 test1/test2/test3/test4 一次刪除∼

# 不過要注意的是，這個 rmdir 僅能『刪除空的目錄』喔！

如果想要刪除舊有的目錄時，就使用rmdir吧！例如將剛剛建立的test殺掉，使用『 rmdir test 』即可！請注意呦！目錄需要一層一層的刪除才行！而且被刪除的目錄裡面必定不能存在其他的目錄或檔案！ 這也是所謂的空的目錄(empty directory)的意思啊！那如果要將所有目錄下的東西都殺掉呢？！ 這個時候就必須使用『 rm -r test 』囉！不過，還是使用 rmdir 比較不危險！你也可以嘗試以 -p 的選項加入，來刪除上層的目錄喔！

關於執行檔路徑的變數： $PATH

經過第六章FHS的說明後，我們知道查閱檔案屬性的指令ls完整檔名為：/bin/ls(這是絕對路徑)， 那你會不會覺得很奇怪：『為什麼我可以在任何地方執行/bin/ls這個指令呢？ 』 為什麼我在任何目錄下輸入 ls 就一定可以顯示出一些訊息而不會說找不到該 /bin/ls 指令呢？ 這是因為環境變數 PATH 的幫助所致呀！

當我們在執行一個指令的時候，舉例來說『ls』好了，系統會依照PATH的設定去每個PATH定義的目錄下搜尋檔名為ls的可執行檔， 如果在PATH定義的目錄中含有多個檔名為ls的可執行檔，那麼先搜尋到的同名指令先被執行！

現在，請下達『echo $PATH』來看看到底有哪些目錄被定義出來了？ echo有『顯示、印出』的意思，而 PATH 前面加的 $ 表示後面接的是變數，所以會顯示出目前的 PATH ！

範例：先用root的身份列出搜尋的路徑為何？

[root@www ~]# echo $PATH

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin

:/bin:/usr/sbin:/usr/bin:/root/bin  <==這是同一行！

範例：用vbird的身份列出搜尋的路徑為何？

[root@www ~]# su - vbird

[vbird@www ~]# echo $PATH

/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/vbird/bin

# 仔細看，一般用戶vbird的PATH中，並不包含任何『sbin』的目錄存在喔！

PATH(一定是大寫)這個變數的內容是由一堆目錄所組成的，每個目錄中間用冒號(:)來隔開， 每個目錄是有『順序』之分的。仔細看一下上面的輸出，妳可以發現到無論是root還是vbird都有/bin 這個目錄在PATH變數內，所以當然就能夠在任何地方執行ls來找到/bin/ls執行檔囉！

我們用幾個範例來讓你瞭解一下，為什麼PATH是那麼重要的項目！

例題：

請問你能不能使用一般身份使用者下達ifconfig eth0這個指令呢？

答：

如上面的範例所示，當你使用vbird這個帳號執行ifconfig時，會出現『-bash: ifconfig: command not found』的字樣， 因為ifconfig的是放置到/sbin底下，而由上表的結果中我們可以發現vbird的PATH並沒有設置/sbin， 所以預設無法執行。

但是你可以使用『/sbin/ifconfig eth0』來執行這個指令喔！因為一般用戶還是可以使用ifconfig來查詢系統IP的參數， 既然PATH沒有規範到/sbin，那麼我們使用『絕對路徑』也可以執行到該指令的！

例題：

假設你是root，如果你將ls由/bin/ls移動成為/root/ls(可用『mv /bin/ls /root』指令達成)，然後你自己本身也在/root目錄下， 請問(1)你能不能直接輸入ls來執行？(2)若不能，你該如何執行ls這個指令？(3)若要直接輸入ls即可執行，又該如何進行？

答：

由於這個例題的重點是將某個執行檔移動到非正規目錄去，所以我們先要進行底下的動作才行：(務必使用root的身份)

[root@www ~]# mv /bin/ls /root

# mv 為移動，可將檔案在不同的目錄間進行移動作業

(1)接下來不論你在那個目錄底下輸入任何與ls相關的指令，都沒有辦法順利的執行ls了！ 也就是說，你不能直接輸入ls來執行，因為/root這個目錄並不在PATH指定的目錄中， 所以，即使你在/root目錄下，也不能夠搜尋到ls這個指令！

(2)因為這個ls確實存在於/root底下，並不是被刪除了！所以我們可以透過使用絕對路徑或者是相對路徑直接指定這個執行檔檔名， 底下的兩個方法都能夠執行ls這個指令：

[root@www ~]# /root/ls  <==直接用絕對路徑指定該檔名

[root@www ~]# ./ls      <==因為在 /root 目錄下，就用./ls來指定

(3)如果想要讓root在任何目錄均可執行/root底下的ls，那麼就將/root加入PATH當中即可。 加入的方法很簡單，就像底下這樣：

[root@www ~]# PATH="$PATH":/root

上面這個作法就能夠將/root加入到執行檔搜尋路徑PATH中了！不相信的話請您自行使用『echo $PATH』去查看吧！ 如果確定這個例題進行沒有問題了，請將ls搬回/bin底下，不然系統會掛點的！

[root@www ~]# mv /root/ls /bin

例題：

如果我有兩個ls指令在不同的目錄中，例如/usr/local/bin/ls與/bin/ls那麼當我下達 ls 的時候，哪個ls會被執行？

答：

那還用說，就找出 PATH 裡面哪個目錄先被查詢，則那個目錄下的指令就會被先執行了！

例題：

為什麼PATH搜尋的目錄不加入本目錄(.)？加入本目錄的搜尋不是也不錯？

答：

如果在PATH中加入本目錄(.)後，確實我們就能夠在指令所在目錄進行指令的執行了。 但是由於你的工作目錄並非固定(常常會使用cd來切換到不同的目錄)， 因此能夠執行的指令會有變動(因為每個目錄底下的可執行檔都不相同嘛！)，這對使用者來說並非好事。

另外，如果有個壞心使用者在/tmp底下做了一個指令，因為/tmp是大家都能夠寫入的環境，所以他當然可以這樣做。 假設該指令可能會竊取使用者的一些資料，如果你使用root的身份來執行這個指令，那不是很糟糕？ 如果這個指令的名稱又是經常會被用到的ls時，那『中標』的機率就更高了！

所以，為了安全起見，不建議將『.』加入PATH的搜尋目錄中。

而由上面的幾個例題我們也可以知道幾件事情：

- 不同身份使用者預設的PATH不同，預設能夠隨意執行的指令也不同(如root與vbird)；

- PATH是可以修改的，所以一般使用者還是可以透過修改PATH來執行某些位於/sbin或/usr/sbin下的指令來查詢；

- 使用絕對路徑或相對路徑直接指定某個指令的檔名來執行，會比搜尋PATH來的正確；

- 指令應該要放置到正確的目錄下，執行才會比較方便；

- 本目錄(.)最好不要放到PATH當中。

對於PATH更詳細的『變數』說明，我們會在第三篇的bash shell中詳細說明的！

檔案與目錄管理：

談了談目錄與路徑之後，再來討論一下關於檔案的一些基本管理吧！檔案與目錄的管理上，不外乎『顯示屬性』、 『拷貝』、『刪除檔案』及『移動檔案或目錄』等等，由於檔案與目錄的管理在 Linux 當中是很重要的， 尤其是每個人自己家目錄的資料也都需要注意管理！所以我們來談一談有關檔案與目錄的一些基礎管理部分吧！

檔案與目錄的檢視： ls

[root@www ~]# ls [-aAdfFhilnrRSt] 目錄名稱

[root@www ~]# ls [--color={never,auto,always}] 目錄名稱

[root@www ~]# ls [--full-time] 目錄名稱

選項與參數：

-a  ：全部的檔案，連同隱藏檔( 開頭為 . 的檔案) 一起列出來(常用)

-A  ：全部的檔案，連同隱藏檔，但不包括 . 與 .. 這兩個目錄

-d  ：僅列出目錄本身，而不是列出目錄內的檔案資料(常用)

-f  ：直接列出結果，而不進行排序 (ls 預設會以檔名排序！)

-F  ：根據檔案、目錄等資訊，給予附加資料結構，例如：

*:代表可執行檔； /:代表目錄； =:代表 socket 檔案； |:代表 FIFO 檔案；

-h  ：將檔案容量以人類較易讀的方式(例如 GB, KB 等等)列出來；

-i  ：列出 inode 號碼，inode 的意義下一章將會介紹；

-l  ：長資料串列出，包含檔案的屬性與權限等等資料；(常用)

-n  ：列出 UID 與 GID 而非使用者與群組的名稱 (UID與GID會在帳號管理提到！)

-r  ：將排序結果反向輸出，例如：原本檔名由小到大，反向則為由大到小；

-R  ：連同子目錄內容一起列出來，等於該目錄下的所有檔案都會顯示出來；

-S  ：以檔案容量大小排序，而不是用檔名排序；

-t  ：依時間排序，而不是用檔名。

--color=never  ：不要依據檔案特性給予顏色顯示；

--color=always ：顯示顏色

--color=auto   ：讓系統自行依據設定來判斷是否給予顏色

--full-time    ：以完整時間模式 (包含年、月、日、時、分) 輸出

--time={atime,ctime} ：輸出 access 時間或改變權限屬性時間 (ctime)

而非內容變更時間 (modification time)

在Linux系統當中，這個 ls 指令可能是最常被執行的吧！因為我們隨時都要知道檔案或者是目錄的相關資訊啊∼ 不過，我們Linux的檔案所記錄的資訊實在是太多了，ls 沒有需要全部都列出來呢∼ 所以，當你只有下達 ls 時，預設顯示的只有：非隱藏檔的檔名、 以檔名進行排序及檔名代表的顏色顯示如此而已。舉例來說， 你下達『 ls /etc 』之後，只有經過排序的檔名以及以藍色顯示目錄及白色顯示一般檔案，如此而已。

那如果我還想要加入其他的顯示資訊時，可以加入上頭提到的那些有用的選項呢∼ 舉例來說，我們之前一直用到的 -l 這個長串顯示資料內容，以及將隱藏檔也一起列示出來的 -a 選項等等。 底下則是一些常用的範例，實際試做看看：

範例一：將家目錄下的所有檔案列出來(含屬性與隱藏檔)

[root@www ~]# ls -al ~

total 156

drwxr-x---  4 root root  4096 Sep 24 00:07 .

drwxr-xr-x 23 root root  4096 Sep 22 12:09 ..

-rw-------  1 root root  1474 Sep  4 18:27 anaconda-ks.cfg

-rw-------  1 root root   955 Sep 24 00:08 .bash_history

-rw-r--r--  1 root root    24 Jan  6  2007 .bash_logout

-rw-r--r--  1 root root   191 Jan  6  2007 .bash_profile

-rw-r--r--  1 root root   176 Jan  6  2007 .bashrc

drwx------  3 root root  4096 Sep  5 10:37 .gconf

-rw-r--r--  1 root root 42304 Sep  4 18:26 install.log

-rw-r--r--  1 root root  5661 Sep  4 18:25 install.log.syslog

# 這個時候你會看到以 . 為開頭的幾個檔案，以及目錄檔 (.) (..) .gconf 等等，

# 不過，目錄檔檔名都是以深藍色顯示，有點不容易看清楚就是了。

範例二：承上題，不顯示顏色，但在檔名末顯示出該檔名代表的類型(type)

[root@www ~]# ls -alF --color=never  ~

total 156

drwxr-x---  4 root root  4096 Sep 24 00:07 ./

drwxr-xr-x 23 root root  4096 Sep 22 12:09 ../

-rw-------  1 root root  1474 Sep  4 18:27 anaconda-ks.cfg

-rw-------  1 root root   955 Sep 24 00:08 .bash_history

-rw-r--r--  1 root root    24 Jan  6  2007 .bash_logout

-rw-r--r--  1 root root   191 Jan  6  2007 .bash_profile

-rw-r--r--  1 root root   176 Jan  6  2007 .bashrc

drwx------  3 root root  4096 Sep  5 10:37 .gconf/

-rw-r--r--  1 root root 42304 Sep  4 18:26 install.log

-rw-r--r--  1 root root  5661 Sep  4 18:25 install.log.syslog

# 注意看到顯示結果的第一行，嘿嘿∼知道為何我們會下達類似 ./command

# 之類的指令了吧？因為 ./ 代表的是『目前目錄下』的意思啊！至於什麼是 FIFO/Socket ？

# 請參考前一章節的介紹啊！另外，那個.bashrc 時間僅寫2007，能否知道詳細時間？

範例三：完整的呈現檔案的修改時間 *(modification time)

[root@www ~]# ls -al --full-time  ~

total 156

drwxr-x---  4 root root  4096 2008-09-24 00:07:00.000000 +0800 .

drwxr-xr-x 23 root root  4096 2008-09-22 12:09:32.000000 +0800 ..

-rw-------  1 root root  1474 2008-09-04 18:27:10.000000 +0800 anaconda-ks.cfg

-rw-------  1 root root   955 2008-09-24 00:08:14.000000 +0800 .bash_history

-rw-r--r--  1 root root    24 2007-01-06 17:05:04.000000 +0800 .bash_logout

-rw-r--r--  1 root root   191 2007-01-06 17:05:04.000000 +0800 .bash_profile

-rw-r--r--  1 root root   176 2007-01-06 17:05:04.000000 +0800 .bashrc

drwx------  3 root root  4096 2008-09-05 10:37:49.000000 +0800 .gconf

-rw-r--r--  1 root root 42304 2008-09-04 18:26:57.000000 +0800 install.log

-rw-r--r--  1 root root  5661 2008-09-04 18:25:55.000000 +0800 install.log.syslog

# 請仔細看，上面的『時間』欄位變了喔！變成較為完整的格式。

# 一般來說， ls -al 僅列出目前短格式的時間，有時不會列出年份，

# 藉由 --full-time 可以查閱到比較正確的完整時間格式啊！

其實 ls 的用法還有很多，包括查閱檔案所在 i-node 號碼的 ls -i 選項，以及用來進行檔案排序的 -S 選項，還有用來查閱不同時間的動作的 --time=atime 等選項(更多時間說明請參考本章後面touch的說明)。而這些選項的存在都是因為 Linux 檔案系統記錄了很多有用的資訊的緣故。那麼 Linux 的檔案系統中，這些與權限、屬性有關的資料放在哪裡呢？ 放在 i-node 裡面。關於這部分，我們會在下一章繼續為你作比較深入的介紹啊！

無論如何， ls 最常被使用到的功能還是那個 -l 的選項，為此，很多 distribution 在預設的情況中， 已經將 ll (L 的小寫) 設定成為 ls -l 的意思了！其實，那個功能是 Bash shell 的 alias 功能呢∼也就是說，我們直接輸入 ll 就等於是輸入 ls -l 是一樣的∼關於這部分，我們會在後續 bash shell 時再次的強調滴∼

複製、刪除與移動： cp, rm, mv

要複製檔案，請使用 cp (copy) 這個指令即可∼不過， cp 這個指令的用途可多了∼ 除了單純的複製之外，還可以建立連結檔 (就是捷徑囉)，比對兩檔案的新舊而予以更新， 以及複製整個目錄等等的功能呢！至於移動目錄與檔案，則使用 mv (move)， 這個指令也可以直接拿來作更名 (rename) 的動作喔！至於移除嗎？那就是 rm (remove) 這個指令囉∼底下我們就來瞧一瞧先∼

- cp (複製檔案或目錄)

[root@www ~]# cp [-adfilprsu] 來源檔(source) 目標檔(destination)

[root@www ~]# cp [options] source1 source2 source3 .... directory

選項與參數：

-a  ：相當於 -pdr 的意思，至於 pdr 請參考下列說明；(常用)

-d  ：若來源檔為連結檔的屬性(link file)，則複製連結檔屬性而非檔案本身；

-f  ：為強制(force)的意思，若目標檔案已經存在且無法開啟，則移除後再嘗試一次；

-i  ：若目標檔(destination)已經存在時，在覆蓋時會先詢問動作的進行(常用)

-l  ：進行硬式連結(hard link)的連結檔建立，而非複製檔案本身；

-p  ：連同檔案的屬性一起複製過去，而非使用預設屬性(備份常用)；

-r  ：遞迴持續複製，用於目錄的複製行為；(常用)

-s  ：複製成為符號連結檔 (symbolic link)，亦即『捷徑』檔案；

-u  ：若 destination 比 source 舊才更新 destination ！

最後需要注意的，如果來源檔有兩個以上，則最後一個目的檔一定要是『目錄』才行！

複製(cp)這個指令是非常重要的，不同身份者執行這個指令會有不同的結果產生，尤其是那個-a, -p的選項， 對於不同身份來說，差異則非常的大！底下的練習中，有的身份為root有的身份為一般帳號(在我這裡用vbird這個帳號)， 練習時請特別注意身份的差別喔！好！開始來做複製的練習與觀察：

範例一：用root身份，將家目錄下的 .bashrc 複製到 /tmp 下，並更名為 bashrc

[root@www ~]# cp ~/.bashrc /tmp/bashrc

[root@www ~]# cp -i ~/.bashrc /tmp/bashrc

cp: overwrite `/tmp/bashrc'? n  <==n不覆蓋，y為覆蓋

# 重複作兩次動作，由於 /tmp 底下已經存在 bashrc 了，加上 -i 選項後，

# 則在覆蓋前會詢問使用者是否確定！可以按下 n 或者 y 來二次確認呢！

範例二：變換目錄到/tmp，並將/var/log/wtmp複製到/tmp且觀察屬性：

[root@www ~]# cd /tmp

[root@www tmp]# cp /var/log/wtmp . <==想要複製到目前的目錄，最後的 . 不要忘

[root@www tmp]# ls -l /var/log/wtmp wtmp

-rw-rw-r-- 1 root utmp 96384 Sep 24 11:54 /var/log/wtmp

-rw-r--r-- 1 root root 96384 Sep 24 14:06 wtmp

# 注意上面的特殊字體，在不加任何選項的情況下，檔案的某些屬性/權限會改變；

# 這是個很重要的特性！要注意喔！還有，連檔案建立的時間也不一樣了！

# 那如果你想要將檔案的所有特性都一起複製過來該怎辦？可以加上 -a 喔！如下所示：

[root@www tmp]# cp -a /var/log/wtmp wtmp_2

[root@www tmp]# ls -l /var/log/wtmp wtmp_2

-rw-rw-r-- 1 root utmp 96384 Sep 24 11:54 /var/log/wtmp

-rw-rw-r-- 1 root utmp 96384 Sep 24 11:54 wtmp_2

# 瞭了吧！整個資料特性完全一模一樣ㄟ！真是不賴∼這就是 -a 的特性！

這個 cp 的功能很多，由於我們常常會進行一些資料的複製，所以也會常常用到這個指令的。 一般來說，我們如果去複製別人的資料 (當然，該檔案你必須要有 read 的權限才行啊！ ^_^) 時， 總是希望複製到的資料最後是我們自己的，所以，在預設的條件中， cp 的來源檔與目的檔的權限是不同的，目的檔的擁有者通常會是指令操作者本身。舉例來說， 上面的範例二中，由於我是 root 的身份，因此複製過來的檔案擁有者與群組就改變成為 root 所有了！ 這樣說，可以明白嗎？^_^

由於具有這個特性，因此當我們在進行備份的時候，某些需要特別注意的特殊權限檔案， 例如密碼檔 (/etc/shadow) 以及一些設定檔，就不能直接以 cp 來複製，而必須要加上 -a 或者是 -p 等等可以完整複製檔案權限的選項才行！另外，如果你想要複製檔案給其他的使用者， 也必須要注意到檔案的權限(包含讀、寫、執行以及檔案擁有者等等)， 否則，其他人還是無法針對你給予的檔案進行修訂的動作喔！注意注意！

範例三：複製 /etc/ 這個目錄下的所有內容到 /tmp 底下

[root@www tmp]# cp /etc/ /tmp

cp: omitting directory `/etc'   <== 如果是目錄則不能直接複製，要加上 -r 的選項

[root@www tmp]# cp -r /etc/ /tmp

# 還是要再次的強調喔！ -r 是可以複製目錄，但是，檔案與目錄的權限可能會被改變

# 所以，也可以利用『 cp -a /etc /tmp 』來下達指令喔！尤其是在備份的情況下！

範例四：將範例一複製的 bashrc 建立一個連結檔 (symbolic link)

[root@www tmp]# ls -l bashrc

-rw-r--r-- 1 root root 176 Sep 24 14:02 bashrc  <==先觀察一下檔案情況

[root@www tmp]# cp -s bashrc bashrc_slink

[root@www tmp]# cp -l bashrc bashrc_hlink

[root@www tmp]# ls -l bashrc*

-rw-r--r-- 2 root root 176 Sep 24 14:02 bashrc  <==與原始檔案不太一樣了！

-rw-r--r-- 2 root root 176 Sep 24 14:02 bashrc_hlink

lrwxrwxrwx 1 root root   6 Sep 24 14:20 bashrc_slink -> bashrc

範例四可有趣了！使用 -l 及 -s 都會建立所謂的連結檔(link file)，但是這兩種連結檔卻有不一樣的情況。這是怎麼一回事啊？ 那個 -l 就是所謂的實體連結(hard link)，至於 -s 則是符號連結(symbolic link)， 簡單來說，bashrc_slink 是一個『捷徑』，這個捷徑會連結到bashrc去！所以你會看到檔名右側會有個指向(->)的符號！

至於bashrc_hlink檔案與bashrc的屬性與權限完全一模一樣，與尚未進行連結前的差異則是第二欄的link數由1變成2了！ 鳥哥這裡先不介紹實體連結，因為實體連結涉及 i-node 的相關知識，我們下一章談到檔案系統(filesystem)時再來討論這個問題。

範例五：若 ~/.bashrc 比 /tmp/bashrc 新才複製過來

[root@www tmp]# cp -u ~/.bashrc /tmp/bashrc

# 這個 -u 的特性，是在目標檔案與來源檔案有差異時，才會複製的。

# 所以，比較常被用於『備份』的工作當中喔！ ^_^

範例六：將範例四造成的 bashrc_slink 複製成為 bashrc_slink_1 與bashrc_slink_2

[root@www tmp]# cp bashrc_slink bashrc_slink_1

[root@www tmp]# cp -d bashrc_slink bashrc_slink_2

[root@www tmp]# ls -l bashrc bashrc_slink*

-rw-r--r-- 2 root root 176 Sep 24 14:02 bashrc

lrwxrwxrwx 1 root root   6 Sep 24 14:20 bashrc_slink -> bashrc

-rw-r--r-- 1 root root 176 Sep 24 14:32 bashrc_slink_1       <==與原始檔案相同

lrwxrwxrwx 1 root root   6 Sep 24 14:33 bashrc_slink_2 -> bashrc <==是連結檔！

# 這個例子也是很有趣喔！原本複製的是連結檔，但是卻將連結檔的實際檔案複製過來了

# 也就是說，如果沒有加上任何選項時，cp複製的是原始檔案，而非連結檔的屬性！

# 若要複製連結檔的屬性，就得要使用 -d 的選項了！如 bashrc_slink_2 所示。

範例七：將家目錄的 .bashrc 及 .bash_history 複製到 /tmp 底下

[root@www tmp]# cp ~/.bashrc ~/.bash_history /tmp

# 可以將多個資料一次複製到同一個目錄去！最後面一定是目錄！

例題：

你能否使用vbird的身份，完整的複製/var/log/wtmp檔案到/tmp底下，並更名為vbird_wtmp呢？

答：

實際做看看的結果如下：

[vbird@www ~]$ cp -a /var/log/wtmp /tmp/vbird_wtmp

[vbird@www ~]$ ls -l /var/log/wtmp /tmp/vbird_wtmp

-rw-rw-r-- 1 vbird vbird 96384  9月 24 11:54 /tmp/vbird_wtmp

-rw-rw-r-- 1 root  utmp  96384  9月 24 11:54 /var/log/wtmp

由於vbird的身份並不能隨意修改檔案的擁有者與群組，因此雖然能夠複製wtmp的相關權限與時間等屬性， 但是與擁有者、群組相關的，原本vbird身份無法進行的動作，即使加上 -a 選項，也是無法達成完整複製權限的！

總之，由於 cp 有種種的檔案屬性與權限的特性，所以，在複製時，你必須要清楚的瞭解到：

- 是否需要完整的保留來源檔案的資訊？

- 來源檔案是否為連結檔 (symbolic link file)？

- 來源檔是否為特殊的檔案，例如 FIFO, socket 等？

- 來源檔是否為目錄？

- rm (移除檔案或目錄)

[root@www ~]# rm [-fir] 檔案或目錄

選項與參數：

-f  ：就是 force 的意思，忽略不存在的檔案，不會出現警告訊息；

-i  ：互動模式，在刪除前會詢問使用者是否動作

-r  ：遞迴刪除啊！最常用在目錄的刪除了！這是非常危險的選項！！！

範例一：將剛剛在 cp 的範例中建立的 bashrc 刪除掉！

[root@www ~]# cd /tmp

[root@www tmp]# rm -i bashrc

rm: remove regular file `bashrc'? y

# 如果加上 -i 的選項就會主動詢問喔，避免你刪除到錯誤的檔名！

範例二：透過萬用字元*的幫忙，將/tmp底下開頭為bashrc的檔名通通刪除：

[root@www tmp]# rm -i bashrc*

# 注意那個星號，代表的是 0 到無窮多個任意字元喔！很好用的東西！

範例三：將 cp 範例中所建立的 /tmp/etc/ 這個目錄刪除掉！

[root@www tmp]# rmdir /tmp/etc

rmdir: etc: Directory not empty  <== 刪不掉啊！因為這不是空的目錄！

[root@www tmp]# rm -r /tmp/etc

rm: descend into directory `/tmp/etc'? y

....(中間省略)....

# 因為身份是 root ，預設已經加入了 -i 的選項，所以你要一直按 y 才會刪除！

# 如果不想要繼續按 y ，可以按下『 [ctrl]-c 』來結束 rm 的工作。

# 這是一種保護的動作，如果確定要刪除掉此目錄而不要詢問，可以這樣做：

[root@www tmp]# \rm -r /tmp/etc

# 在指令前加上反斜線，可以忽略掉 alias 的指定選項喔！至於 alias 我們在bash再談！

範例四：刪除一個帶有 - 開頭的檔案

[root@www tmp]# touch ./-aaa-  <==touch這個指令可以建立空檔案！

[root@www tmp]# ls -l

-rw-r--r-- 1 root  root      0 Sep 24 15:03 -aaa-  <==檔案大小為0，所以是空檔案

[root@www tmp]# rm -aaa-

Try `rm --help' for more information.  <== 因為 "-" 是選項嘛！所以系統誤判了！

[root@www tmp]# rm ./-aaa-

這是移除的指令(remove)，要注意的是，通常在Linux系統下，為了怕檔案被誤殺，所以很多 distributions 都已經預設加入 -i 這個選項了！而如果要連目錄下的東西都一起殺掉的話， 例如子目錄裡面還有子目錄時，那就要使用 -r 這個選項了！不過，使用『 rm -r 』這個指令之前，請千萬注意了，因為該目錄或檔案『肯定』會被 root 殺掉！因為系統不會再次詢問你是否要砍掉呦！所以那是個超級嚴重的指令下達呦！ 得特別注意！不過，如果你確定該目錄不要了，那麼使用 rm -r 來循環殺掉是不錯的方式！

另外，範例四也是很有趣的例子，我們在之前就談過，檔名最好不要使用 "-" 號開頭， 因為 "-" 後面接的是選項，因此，單純的使用『 rm -aaa- 』系統的指令就會誤判啦！ 那如果使用後面會談到的正規表示法時，還是會出問題的！所以，只能用避過首位字元是 "-" 的方法啦！ 就是加上本目錄『 ./ 』即可！如果 man rm 的話，其實還有一種方法，那就是『 rm -- -aaa- 』也可以啊！

- mv (移動檔案與目錄，或更名)

[root@www ~]# mv [-fiu] source destination

[root@www ~]# mv [options] source1 source2 source3 .... directory

選項與參數：

-f  ：force 強制的意思，如果目標檔案已經存在，不會詢問而直接覆蓋；

-i  ：若目標檔案 (destination) 已經存在時，就會詢問是否覆蓋！

-u  ：若目標檔案已經存在，且 source 比較新，才會更新 (update)

範例一：複製一檔案，建立一目錄，將檔案移動到目錄中

[root@www ~]# cd /tmp

[root@www tmp]# cp ~/.bashrc bashrc

[root@www tmp]# mkdir mvtest

[root@www tmp]# mv bashrc mvtest

# 將某個檔案移動到某個目錄去，就是這樣做！

範例二：將剛剛的目錄名稱更名為 mvtest2

[root@www tmp]# mv mvtest mvtest2 <== 這樣就更名了！簡單∼

# 其實在 Linux 底下還有個有趣的指令，名稱為 rename ，

# 該指令專職進行多個檔名的同時更名，並非針對單一檔名變更，與mv不同。請man rename。

範例三：再建立兩個檔案，再全部移動到 /tmp/mvtest2 當中

[root@www tmp]# cp ~/.bashrc bashrc1

[root@www tmp]# cp ~/.bashrc bashrc2

[root@www tmp]# mv bashrc1 bashrc2 mvtest2

# 注意到這邊，如果有多個來源檔案或目錄，則最後一個目標檔一定是『目錄！』

# 意思是說，將所有的資料移動到該目錄的意思！

這是搬移 (move) 的意思！當你要移動檔案或目錄的時後，呵呵！這個指令就很重要啦！ 同樣的，你也可以使用 -u ( update )來測試新舊檔案，看看是否需要搬移囉！ 另外一個用途就是『變更檔名！』，我們可以很輕易的使用 mv 來變更一個檔案的檔名呢！不過，在 Linux 才有的指令當中，有個 rename ， 可以用來更改大量檔案的檔名，你可以利用 man rename 來查閱一下，也是挺有趣的指令喔！

取得路徑的檔案名稱與目錄名稱

我們前面介紹的完整檔名 (包含目錄名稱與檔案名稱) 當中提到，完整檔名最長可以到達 4096 個字元。 那麼你怎麼知道那個是檔名？那個是目錄名？嘿嘿！就是利用斜線 (/) 來分辨啊！ 其實，取得檔名或者是目錄名稱，一般的用途應該是在寫程式的時候，用來判斷之用的啦∼ 所以，這部分的指令可以用在第三篇內的 shell scripts 裡頭喔！ 底下我們簡單的以幾個範例來談一談 basename 與 dirname 的用途！

[root@www ~]# basename /etc/sysconfig/network

network         <== 很簡單！就取得最後的檔名∼

[root@www ~]# dirname /etc/sysconfig/network

/etc/sysconfig  <== 取得的變成目錄名了！

檔案內容查閱：

如果我們要查閱一個檔案的內容時，該如何是好呢？這裡有相當多有趣的指令可以來分享一下： 最常使用的顯示檔案內容的指令可以說是 cat 與 more 及 less 了！此外，如果我們要查看一個很大型的檔案 (好幾百MB時)，但是我們只需要後端的幾行字而已，那麼該如何是好？呵呵！用 tail 呀，此外， tac 這個指令也可以達到！好了，說說各個指令的用途吧！

- cat  由第一行開始顯示檔案內容

- tac  從最後一行開始顯示，可以看出 tac 是 cat 的倒著寫！

- nl   顯示的時候，順道輸出行號！

- more 一頁一頁的顯示檔案內容

- less 與 more 類似，但是比 more 更好的是，他可以往前翻頁！

- head 只看頭幾行

- tail 只看尾巴幾行

- od   以二進位的方式讀取檔案內容！

直接檢視檔案內容

直接查閱一個檔案的內容可以使用 cat/tac/nl 這幾個指令啊！

- cat (concatenate)

[root@www ~]# cat [-AbEnTv]

選項與參數：

-A  ：相當於 -vET 的整合選項，可列出一些特殊字符而不是空白而已；

-b  ：列出行號，僅針對非空白行做行號顯示，空白行不標行號！

-E  ：將結尾的斷行字元 $ 顯示出來；

-n  ：列印出行號，連同空白行也會有行號，與 -b 的選項不同；

-T  ：將 [tab] 按鍵以 ^I 顯示出來；

-v  ：列出一些看不出來的特殊字符

範例一：檢閱 /etc/issue 這個檔案的內容

[root@www ~]# cat /etc/issue

CentOS release 5.3 (Final)

Kernel \r on an \m

範例二：承上題，如果還要加印行號呢？

[root@www ~]# cat -n /etc/issue

1  CentOS release 5.3 (Final)

2  Kernel \r on an \m

3

# 看到了吧！可以印出行號呢！這對於大檔案要找某個特定的行時，有點用處！

# 如果不想要編排空白行的行號，可以使用『cat -b /etc/issue』，自己測試看看：

範例三：將 /etc/xinetd.conf 的內容完整的顯示出來(包含特殊字元)

[root@www ~]# cat -A /etc/xinetd.conf

#$

....(中間省略)....

$

defaults$

{$

# The next two items are intended to be a quick access place to$

....(中間省略)....

^Ilog_type^I= SYSLOG daemon info $

^Ilog_on_failure^I= HOST$

^Ilog_on_success^I= PID HOST DURATION EXIT$

....(中間省略)....

includedir /etc/xinetd.d$

$

# 上面的結果限於篇幅，鳥哥刪除掉很多資料了。另外，輸出的結果並不會有特殊字體，

# 鳥哥上面的特殊字體是要讓您發現差異點在哪裡就是了。基本上，在一般的環境中，

# 使用 [tab] 與空白鍵的效果差不多，都是一堆空白啊！我們無法知道兩者的差別。

# 此時使用 cat -A 就能夠發現那些空白的地方是啥鬼東西了！[tab]會以 ^I 表示，

# 斷行字元則是以 $ 表示，所以你可以發現每一行後面都是 $ 啊！不過斷行字元

# 在Windows/Linux則不太相同，Windows的斷行字元是 ^M$ 囉。

# 這部分我們會在第十章 vim 軟體的介紹時，再次的說明到喔！

嘿嘿！Linux 裡面有『貓』指令？喔！不是的， cat 是 Concatenate （連續）的簡寫， 主要的功能是將一個檔案的內容連續的印出在螢幕上面！例如上面的例子中，我們將 /etc/issue 印出來！如果加上 -n 或 -b 的話，則每一行前面還會加上行號呦！

鳥哥個人是比較少用 cat 啦！畢竟當你的檔案內容的行數超過 40 行以上，嘿嘿！根本來不及在螢幕上看到結果！ 所以，配合等一下要介紹的 more 或者是 less 來執行比較好！此外，如果是一般的 DOS 檔案時，就需要特別留意一些奇奇怪怪的符號了， 例如斷行與 [tab] 等，要顯示出來，就得加入 -A 之類的選項了！

- tac (反向列示)

[root@www ~]# tac /etc/issue

Kernel \r on an \m

CentOS release 5.3 (Final)

# 嘿嘿！與剛剛上面的範例一比較，是由最後一行先顯示喔！

tac 這個好玩了！怎麼說呢？詳細的看一下， cat 與 tac ，有沒有發現呀！對啦！ tac 剛好是將 cat 反寫過來，所以他的功能就跟 cat 相反啦， cat 是由『第一行到最後一行連續顯示在螢幕上』，而 tac 則是『 由最後一行到第一行反向在螢幕上顯示出來 』，很好玩吧！

- nl (添加行號列印)

[root@www ~]# nl [-bnw] 檔案

選項與參數：

-b  ：指定行號指定的方式，主要有兩種：

-b a ：表示不論是否為空行，也同樣列出行號(類似 cat -n)；

-b t ：如果有空行，空的那一行不要列出行號(預設值)；

-n  ：列出行號表示的方法，主要有三種：

-n ln ：行號在螢幕的最左方顯示；

-n rn ：行號在自己欄位的最右方顯示，且不加 0 ；

-n rz ：行號在自己欄位的最右方顯示，且加 0 ；

-w  ：行號欄位的佔用的位元數。

範例一：用 nl 列出 /etc/issue 的內容

[root@www ~]# nl /etc/issue

1  CentOS release 5.3 (Final)

2  Kernel \r on an \m

# 注意看，這個檔案其實有三行，第三行為空白(沒有任何字元)，

# 因為他是空白行，所以 nl 不會加上行號喔！如果確定要加上行號，可以這樣做：

[root@www ~]# nl -b a /etc/issue

1  CentOS release 5.3 (Final)

2  Kernel \r on an \m

3

# 呵呵！行號加上來囉∼那麼如果要讓行號前面自動補上 0 呢？可這樣

[root@www ~]# nl -b a -n rz /etc/issue

000001  CentOS release 5.3 (Final)

000002  Kernel \r on an \m

000003

# 嘿嘿！自動在自己欄位的地方補上 0 了∼預設欄位是六位數，如果想要改成 3 位數？

[root@www ~]# nl -b a -n rz -w 3 /etc/issue

001     CentOS release 5.3 (Final)

002     Kernel \r on an \m

003

# 變成僅有 3 位數囉∼

nl 可以將輸出的檔案內容自動的加上行號！其預設的結果與 cat -n 有點不太一樣， nl 可以將行號做比較多的顯示設計，包括位數與是否自動補齊 0 等等的功能呢。

可翻頁檢視

前面提到的 nl 與 cat, tac 等等，都是一次性的將資料一口氣顯示到螢幕上面，那有沒有可以進行一頁一頁翻動的指令啊？ 讓我們可以一頁一頁的觀察，才不會前面的資料看不到啊∼呵呵！有的！那就是 more 與 less 囉∼

- more (一頁一頁翻動)

[root@www ~]# more /etc/man.config

#

# Generated automatically from man.conf.in by the

# configure script.

#

# man.conf from man-1.6d

....(中間省略)....

--More--(28%)  <== 重點在這一行喔！你的游標也會在這裡等待你的指令

仔細的給他看到上面的範例，如果 more 後面接的檔案內容行數大於螢幕輸出的行數時， 就會出現類似上面的圖示。重點在最後一行，最後一行會顯示出目前顯示的百分比， 而且還可以在最後一行輸入一些有用的指令喔！在 more 這個程式的運作過程中，你有幾個按鍵可以按的：

- 空白鍵 (space)：代表向下翻一頁；

- Enter         ：代表向下翻『一行』；

- /字串         ：代表在這個顯示的內容當中，向下搜尋『字串』這個關鍵字；

- :f            ：立刻顯示出檔名以及目前顯示的行數；

- q             ：代表立刻離開 more ，不再顯示該檔案內容。

- b 或 [ctrl]-b ：代表往回翻頁，不過這動作只對檔案有用，對管線無用。

要離開 more 這個指令的顯示工作，可以按下 q 就能夠離開了。而要向下翻頁，就使用空白鍵即可。 比較有用的是搜尋字串的功能，舉例來說，我們使用『 more /etc/man.config 』來觀察該檔案， 若想要在該檔案內搜尋 MANPATH 這個字串時，可以這樣做：

[root@www ~]# more /etc/man.config

#

# Generated automatically from man.conf.in by the

# configure script.

#

# man.conf from man-1.6d

....(中間省略)....

/MANPATH   <== 輸入了 / 之後，游標就會自動跑到最底下一行等待輸入！

如同上面的說明，輸入了 / 之後，游標就會跑到最底下一行，並且等待你的輸入， 你輸入了字串並按下[enter]之後，嘿嘿！ more 就會開始向下搜尋該字串囉∼而重複搜尋同一個字串， 可以直接按下 n 即可啊！最後，不想要看了，就按下 q 即可離開 more 啦！

- less (一頁一頁翻動)

[root@www ~]# less /etc/man.config

#

# Generated automatically from man.conf.in by the

# configure script.

#

# man.conf from man-1.6d

....(中間省略)....

:   <== 這裡可以等待你輸入指令！

less 的用法比起 more 又更加的有彈性，怎麼說呢？在 more 的時候，我們並沒有辦法向前面翻， 只能往後面看，但若使用了 less 時，呵呵！就可以使用 [pageup] [pagedown] 等按鍵的功能來往前往後翻看文件，你瞧，是不是更容易使用來觀看一個檔案的內容了呢！

除此之外，在 less 裡頭可以擁有更多的『搜尋』功能喔！不止可以向下搜尋，也可以向上搜尋∼ 實在是很不錯用∼基本上，可以輸入的指令有：

- 空白鍵    ：向下翻動一頁；

- [pagedown]：向下翻動一頁；

- [pageup]  ：向上翻動一頁；

- /字串     ：向下搜尋『字串』的功能；

- ?字串     ：向上搜尋『字串』的功能；

- n         ：重複前一個搜尋 (與 / 或 ? 有關！)

- N         ：反向的重複前一個搜尋 (與 / 或 ? 有關！)

- q         ：離開 less 這個程式；

查閱檔案內容還可以進行搜尋的動作∼瞧∼ less 是否很不錯用啊！ 其實 less 還有很多的功能喔！詳細的使用方式請使用 man less 查詢一下啊！ ^_^

你是否會覺得 less 使用的畫面與環境與 man page 非常的類似呢？沒錯啦！因為man這個指令就是呼叫 less 來顯示說明文件的內容的！ 現在你是否覺得 less 很重要呢？ ^_^

資料擷取

我們可以將輸出的資料作一個最簡單的擷取，那就是取出前面 (head) 與取出後面 (tail) 文字的功能。 不過，要注意的是， head 與 tail 都是以『行』為單位來進行資料擷取的喔！

- head (取出前面幾行)

[root@www ~]# head [-n number] 檔案

選項與參數：

-n  ：後面接數字，代表顯示幾行的意思

[root@www ~]# head /etc/man.config

# 預設的情況中，顯示前面十行！若要顯示前 20 行，就得要這樣：

[root@www ~]# head -n 20 /etc/man.config

範例：如果後面100行的資料都不列印，只列印/etc/man.config的前面幾行，該如何是好？

[root@www ~]# head -n -100 /etc/man.config

head 的英文意思就是『頭』啦，那麼這個東西的用法自然就是顯示出一個檔案的前幾行囉！ 沒錯！就是這樣！若沒有加上 -n 這個選項時，預設只顯示十行，若只要一行呢？那就加入『 head -n 1 filename 』即可！

另外那個 -n 選項後面的參數較有趣，如果接的是負數，例如上面範例的-n -100時，代表列前的所有行數， 但不包括後面100行。舉例來說，/etc/man.config共有141行，則上述的指令『head -n -100 /etc/man.config』 就會列出前面41行，後面100行不會列印出來了。這樣說，比較容易懂了吧？ ^_^

- tail (取出後面幾行)

[root@www ~]# tail [-n number] 檔案

選項與參數：

-n  ：後面接數字，代表顯示幾行的意思

-f  ：表示持續偵測後面所接的檔名，要等到按下[ctrl]-c才會結束tail的偵測

[root@www ~]# tail /etc/man.config

# 預設的情況中，顯示最後的十行！若要顯示最後的 20 行，就得要這樣：

[root@www ~]# tail -n 20 /etc/man.config

範例一：如果不知道/etc/man.config有幾行，卻只想列出100行以後的資料時？

[root@www ~]# tail -n +100 /etc/man.config

範例二：持續偵測/var/log/messages的內容

[root@www ~]# tail -f /var/log/messages

<==要等到輸入[crtl]-c之後才會離開tail這個指令的偵測！

有 head 自然就有 tail ( 尾巴 ) 囉！沒錯！這個 tail 的用法跟 head 的用法差不多類似，只是顯示的是後面幾行就是了！預設也是顯示十行，若要顯示非十行，就加 -n number 的選項即可。

範例一的內容就有趣啦！其實與head -n -xx有異曲同工之妙。當下達『tail -n +100 /etc/man.config』 代表該檔案從100行以後都會被列出來，同樣的，在man.config共有141行，因此第100~141行就會被列出來啦！ 前面的99行都不會被顯示出來喔！

至於範例二中，由於/var/log/messages隨時會有資料寫入，你想要讓該檔案有資料寫入時就立刻顯示到螢幕上， 就利用 -f 這個選項，他可以一直偵測/var/log/messages這個檔案，新加入的資料都會被顯示到螢幕上。 直到你按下[crtl]-c才會離開tail的偵測喔！

例題：

假如我想要顯示 /etc/man.config 的第 11 到第 20 行呢？

答：

這個應該不算難，想一想，在第 11 到第 20 行，那麼我取前 20 行，再取後十行，所以結果就是：『 head -n 20 /etc/man.config | tail -n 10 』，這樣就可以得到第 11 到第 20 行之間的內容了！ 但是裡面涉及到管線命令，需要在第三篇的時候才講的到！

非純文字檔： od

我們上面提到的，都是在查閱純文字檔的內容。 那麼萬一我們想要查閱非文字檔，舉例來說，例如 /usr/bin/passwd 這個執行檔的內容時， 又該如何去讀出資訊呢？事實上，由於執行檔通常是 binary file ，使用上頭提到的指令來讀取他的內容時， 確實會產生類似亂碼的資料啊！那怎麼辦？沒關係，我們可以利用 od 這個指令來讀取喔！

[root@www ~]# od [-t TYPE] 檔案

選項或參數：

-t  ：後面可以接各種『類型 (TYPE)』的輸出，例如：

a       ：利用預設的字元來輸出；

c       ：使用 ASCII 字元來輸出

d[size] ：利用十進位(decimal)來輸出資料，每個整數佔用 size bytes ；

f[size] ：利用浮點數值(floating)來輸出資料，每個數佔用 size bytes ；

o[size] ：利用八進位(octal)來輸出資料，每個整數佔用 size bytes ；

x[size] ：利用十六進位(hexadecimal)來輸出資料，每個整數佔用 size bytes ；

範例一：請將/usr/bin/passwd的內容使用ASCII方式來展現！

[root@www ~]# od -t c /usr/bin/passwd

0000000 177   E   L   F 001 001 001  \0  \0  \0  \0  \0  \0  \0  \0  \0

0000020 002  \0 003  \0 001  \0  \0  \0 260 225 004  \b   4  \0  \0  \0

0000040 020   E  \0  \0  \0  \0  \0  \0   4  \0      \0  \a  \0   (  \0

0000060 035  \0 034  \0 006  \0  \0  \0   4  \0  \0  \0   4 200 004  \b

0000100   4 200 004  \b 340  \0  \0  \0 340  \0  \0  \0 005  \0  \0  \0

.....(後面省略)....

# 最左邊第一欄是以 8 進位來表示bytes數。以上面範例來說，第二欄0000020代表開頭是

# 第 16 個 byes (2x8) 的內容之意。

範例二：請將/etc/issue這個檔案的內容以8進位列出儲存值與ASCII的對照表

[root@www ~]# od -t oCc /etc/issue

0000000 103 145 156 164 117 123 040 162 145 154 145 141 163 145 040 065

C   e   n   t   O   S       r   e   l   e   a   s   e       5

0000020 056 062 040 050 106 151 156 141 154 051 012 113 145 162 156 145

.   2       (   F   i   n   a   l   )  \n   K   e   r   n   e

0000040 154 040 134 162 040 157 156 040 141 156 040 134 155 012 012

l       \   r       o   n       a   n       \   m  \n  \n

0000057

# 如上所示，可以發現每個字元可以對應到的數值為何！

# 例如e對應的記錄數值為145，轉成十進位：1x8^2+4x8+5=101。

利用這個指令，可以將 data file 或者是 binary file 的內容資料給他讀出來喔！ 雖然讀出的來數值預設是使用非文字檔，亦即是 16 進位的數值來顯示的， 不過，我們還是可以透過 -t c 的選項與參數來將資料內的字元以 ASCII 類型的字元來顯示， 雖然對於一般使用者來說，這個指令的用處可能不大，但是對於工程師來說， 這個指令可以將 binary file 的內容作一個大致的輸出，他們可以看得出東西的啦∼ ^_^

如果對純文字檔使用這個指令，你甚至可以發現到 ASCII 與字元的對照表！非常有趣！ 例如上述的範例二，你可以發現到每個英文字 e 對照到的數字都是 145，轉成十進位你就能夠發現那是 101 囉！ 如果你有任何程式語言的書，拿出來對照一下 ASCII 的對照表，就能夠發現真是正確啊！呵呵！

修改檔案時間或建置新檔： touch

我們在 ls 這個指令的介紹時，有稍微提到每個檔案在linux底下都會記錄許多的時間參數， 其實是有三個主要的變動時間，那麼三個時間的意義是什麼呢？

- modification time (mtime)：

當該檔案的『內容資料』變更時，就會更新這個時間！內容資料指的是檔案的內容，而不是檔案的屬性或權限喔！

- status time (ctime)：

當該檔案的『狀態 (status)』改變時，就會更新這個時間，舉例來說，像是權限與屬性被更改了，都會更新這個時間啊。

- access time (atime)：

當『該檔案的內容被取用』時，就會更新這個讀取時間 (access)。舉例來說，我們使用 cat 去讀取 /etc/man.config ， 就會更新該檔案的 atime 了。

這是個挺有趣的現象，舉例來說，我們來看一看你自己的 /etc/man.config 這個檔案的時間吧！

[root@www ~]# ls -l /etc/man.config

-rw-r--r-- 1 root root 4617 Jan  6  2007 /etc/man.config

[root@www ~]# ls -l --time=atime /etc/man.config

-rw-r--r-- 1 root root 4617 Sep 25 17:54 /etc/man.config

[root@www ~]# ls -l --time=ctime /etc/man.config

-rw-r--r-- 1 root root 4617 Sep  4 18:03 /etc/man.config

看到了嗎？在預設的情況下，ls 顯示出來的是該檔案的 mtime ，也就是這個檔案的內容上次被更動的時間。 至於鳥哥的系統是在 9 月 4 號的時候安裝的，因此，這個檔案被產生導致狀態被更動的時間就回溯到那個時間點了(ctime)！ 而還記得剛剛我們使用的範例當中，有使用到man.config這個檔案啊，所以啊，他的 atime 就會變成剛剛使用的時間了！

檔案的時間是很重要的，因為，如果檔案的時間誤判的話，可能會造成某些程式無法順利的運作。 OK！那麼萬一我發現了一個檔案來自未來，該如何讓該檔案的時間變成『現在』的時刻呢？ 很簡單啊！就用『touch』這個指令即可！

Tips:

嘿嘿！不要懷疑系統時間會『來自未來』喔！很多時候會有這個問題的！舉例來說在安裝過後系統時間可能會被改變！ 因為台灣時區在國際標準時間『格林威治時間, GMT』的右邊，所以會比較早看到陽光，也就是說，台灣時間比GMT時間快了八小時！ 如果安裝行為不當，我們的系統可能會有八小時快轉，你的檔案就有可能來自八小時後了。

至於某些情況下，由於BIOS的設定錯誤，導致系統時間跑到未來時間，並且你又建立了某些檔案。 等你將時間改回正確的時間時，該檔案不就變成來自未來了？^_^

[root@www ~]# touch [-acdmt] 檔案

選項與參數：

-a  ：僅修訂 access time；

-c  ：僅修改檔案的時間，若該檔案不存在則不建立新檔案；

-d  ：後面可以接欲修訂的日期而不用目前的日期，也可以使用 --date="日期或時間"

-m  ：僅修改 mtime ；

-t  ：後面可以接欲修訂的時間而不用目前的時間，格式為[YYMMDDhhmm]

範例一：新建一個空的檔案並觀察時間

[root@www ~]# cd /tmp

[root@www tmp]# touch testtouch

[root@www tmp]# ls -l testtouch

-rw-r--r-- 1 root root 0 Sep 25 21:09 testtouch

# 注意到，這個檔案的大小是 0 呢！在預設的狀態下，如果 touch 後面有接檔案，

# 則該檔案的三個時間 (atime/ctime/mtime) 都會更新為目前的時間。若該檔案不存在，

# 則會主動的建立一個新的空的檔案喔！例如上面這個例子！

範例二：將 ~/.bashrc 複製成為 bashrc，假設複製完全的屬性，檢查其日期

[root@www tmp]# cp -a ~/.bashrc bashrc

[root@www tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc

-rw-r--r-- 1 root root 176 Jan  6  2007 bashrc  <==這是 mtime

-rw-r--r-- 1 root root 176 Sep 25 21:11 bashrc  <==這是 atime

-rw-r--r-- 1 root root 176 Sep 25 21:12 bashrc  <==這是 ctime

在上面這個案例當中我們使用了『ll』這個指令(兩個英文L的小寫)，這個指令其實就是『ls -l』的意思， ll本身不存在，是被『做出來』的一個命令別名。相關的命令別名我們會在bash章節當中詳談的，這裡先知道ll="ls -l"即可。 至於分號『 ; 』則代表連續指令的下達啦！你可以在一行指令當中寫入多重指令， 這些指令可以『依序』執行。由上面的指令我們會知道ll那一行有三個指令被下達在同一行中。

至於執行的結果當中，我們可以發現資料的內容與屬性是被複製過來的，因此檔案內容時間(mtime)與原本檔案相同。 但是由於這個檔案是剛剛被建立的，因此狀態(ctime)與讀取時間就便呈現在的時間啦！ 那如果你想要變更這個檔案的時間呢？可以這樣做：

範例三：修改案例二的 bashrc 檔案，將日期調整為兩天前

[root@www tmp]# touch -d "2 days ago" bashrc

[root@www tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc

-rw-r--r-- 1 root root 176 Sep 23 21:23 bashrc

-rw-r--r-- 1 root root 176 Sep 23 21:23 bashrc

-rw-r--r-- 1 root root 176 Sep 25 21:23 bashrc

# 跟上個範例比較看看，本來是 25 日的變成了 23 日了 (atime/mtime)∼

# 不過， ctime 並沒有跟著改變喔！

範例四：將上個範例的 bashrc 日期改為 2007/09/15 2:02

[root@www tmp]# touch -t 0709150202 bashrc

[root@www tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc

-rw-r--r-- 1 root root 176 Sep 15  2007 bashrc

-rw-r--r-- 1 root root 176 Sep 15  2007 bashrc

-rw-r--r-- 1 root root 176 Sep 25 21:25 bashrc

# 注意看看，日期在 atime 與 mtime 都改變了，但是 ctime 則是記錄目前的時間！

透過 touch 這個指令，我們可以輕易的修訂檔案的日期與時間。並且也可以建立一個空的檔案喔！ 不過，要注意的是，即使我們複製一個檔案時，複製所有的屬性，但也沒有辦法複製 ctime 這個屬性的。 ctime 可以記錄這個檔案最近的狀態 (status) 被改變的時間。無論如何，還是要告知大家， 我們平時看的檔案屬性中，比較重要的還是屬於那個 mtime 啊！我們關心的常常是這個檔案的『內容』 是什麼時候被更動的說∼瞭乎？

無論如何， touch 這個指令最常被使用的情況是：

- 建立一個空的檔案；

- 將某個檔案日期修訂為目前 (mtime 與 atime)

檔案與目錄的預設權限與隱藏權限

由第六章、Linux檔案權限的內容我們可以知道一個檔案有若干個屬性， 包括讀寫執行(r, w, x)等基本權限，及是否為目錄 (d) 與檔案 (-) 或者是連結檔 (l) 等等的屬性！ 要修改屬性的方法在前面也約略提過了(chgrp, chown, chmod) ，本小節會再加強補充一下！

除了基本r, w, x權限外，在Linux的Ext2/Ext3檔案系統下，我們還可以設定其他的系統隱藏屬性， 這部份可使用 chattr 來設定，而以 lsattr 來查看，最重要的屬性就是可以設定其不可修改的特性！讓連檔案的擁有者都不能進行修改！ 這個屬性可是相當重要的，尤其是在安全機制上面 (security)！

首先，先來複習一下上一章談到的權限概念，將底下的例題看一看先：

例題：

你的系統有個一般身份使用者 dmtsai，他的群組屬於 users，他的家目錄在 /home/dmtsai， 你是root，你想將你的 ~/.bashrc 複製給他，可以怎麼作？

答：

由上一章的權限概念我們可以知道 root 雖然可以將這個檔案複製給 dmtsai，不過這個檔案在 dmtsai 的家目錄中卻可能讓 dmtsai 沒有辦法讀寫(因為該檔案屬於 root 的嘛！而 dmtsai 又不能使用 chown 之故)。 此外，我們又擔心覆蓋掉 dmtsai 自己的 .bashrc 設定檔，因此，我們可以進行如下的動作喔：

複製檔案： cp ~/.bashrc ~dmtsai/bashrc

修改屬性： chown dmtsai:users ~dmtsai/bashrc

例題：

我想在 /tmp 底下建立一個目錄，這個目錄名稱為 chapter7_1 ，並且這個目錄擁有者為 dmtsai， 群組為 users ，此外，任何人都可以進入該目錄瀏覽檔案，不過除了 dmtsai 之外，其他人都不能修改該目錄下的檔案。

答：

因為除了 dmtsai 之外，其他人不能修改該目錄下的檔案，所以整個目錄的權限應該是 drwxr-xr-x 才對！ 因此你應該這樣做：

建立目錄： mkdir /tmp/chapter7_1

修改屬性： chown -R dmtsai:users /tmp/chapter7_1

修改權限： chmod -R 755 /tmp/chapter7_1

在上面這個例題當中，如果你知道 755 那個分數是怎麼計算出來的，那麼你應該對於權限有一定程度的概念了。 如果你不知道 755 怎麼來的？那麼...趕快回去前一章看看 chmod 那個指令的介紹部分啊！這部分很重要喔！你得要先清楚的瞭解到才行∼否則就進行不下去囉∼ 假設你對於權限都認識的差不多了，那麼底下我們就要來談一談，『新增一個檔案或目錄時，預設的權限是什麼？』這個議題！

檔案預設權限：umask

OK！那麼現在我們知道如何建立或者是改變一個目錄或檔案的屬性了，不過， 你知道當你建立一個新的檔案或目錄時，他的預設權限會是什麼嗎？呵呵！那就與 umask 這個玩意兒有關了！那麼 umask 是在搞什麼呢？基本上， umask 就是指定 『目前使用者在建立檔案或目錄時候的權限預設值』， 那麼如何得知或設定 umask 呢？他的指定條件以底下的方式來指定：

[root@www ~]# umask

0022             <==與一般權限有關的是後面三個數字！

[root@www ~]# umask -S

u=rwx,g=rx,o=rx

查閱的方式有兩種，一種可以直接輸入 umask ，就可以看到數字型態的權限設定分數， 一種則是加入 -S (Symbolic) 這個選項，就會以符號類型的方式來顯示出權限了！ 奇怪的是，怎麼 umask 會有四組數字啊？不是只有三組嗎？是沒錯啦。 第一組是特殊權限用的，我們先不要理他，所以先看後面三組即可。

在預設權限的屬性上，目錄與檔案是不一樣的。從第六章我們知道 x 權限對於目錄是非常重要的！ 但是一般檔案的建立則不應該有執行的權限，因為一般檔案通常是用在於資料的記錄嘛！當然不需要執行的權限了。 因此，預設的情況如下：

- 若使用者建立為『檔案』則預設『沒有可執行( x )權限』，亦即只有 rw 這兩個項目，也就是最大為 666 分，預設權限如下：

-rw-rw-rw-

- 若使用者建立為『目錄』，則由於 x 與是否可以進入此目錄有關，因此預設為所有權限均開放，亦即為 777 分，預設權限如下：

drwxrwxrwx

要注意的是，umask 的分數指的是『該預設值需要減掉的權限！』因為 r、w、x 分別是 4、2、1 分，所以囉！也就是說，當要拿掉能寫的權限，就是輸入 2 分，而如果要拿掉能讀的權限，也就是 4 分，那麼要拿掉讀與寫的權限，也就是 6 分，而要拿掉執行與寫入的權限，也就是 3 分，這樣瞭解嗎？請問你， 5 分是什麼？呵呵！ 就是讀與執行的權限啦！

如果以上面的例子來說明的話，因為 umask 為 022 ，所以 user 並沒有被拿掉任何權限，不過 group 與 others 的權限被拿掉了 2 (也就是 w 這個權限)，那麼當使用者：

- 建立檔案時：(-rw-rw-rw-) - (-----w--w-) ==> -rw-r--r--

- 建立目錄時：(drwxrwxrwx) - (d----w--w-) ==> drwxr-xr-x

不相信嗎？我們就來測試看看吧！

[root@www ~]# umask

0022

[root@www ~]# touch test1

[root@www ~]# mkdir test2

[root@www ~]# ll

-rw-r--r-- 1 root root     0 Sep 27 00:25 test1

drwxr-xr-x 2 root root  4096 Sep 27 00:25 test2

呵呵！瞧見了吧！確定新建檔案的權限是沒有錯的。

- umask的利用與重要性：專題製作

想像一個狀況，如果你跟你的同學在同一部主機裡面工作時，因為你們兩個正在進行同一個專題， 老師也幫你們兩個的帳號建立好了相同群組的狀態，並且將 /home/class/ 目錄做為你們兩個人的專題目錄。 想像一下，有沒有可能你所製作的檔案你的同學無法編輯？果真如此的話，那就傷腦筋了！

這個問題很常發生啊！舉上面的案例來看就好了，你看一下 test1 的權限是幾分？ 644 呢！意思是『如果 umask 訂定為 022 ，那新建的資料只有使用者自己具有 w 的權限， 同群組的人只有 r 這個可讀的權限而已，並無法修改喔！』這樣要怎麼共同製作專題啊！您說是吧！

所以，當我們需要新建檔案給同群組的使用者共同編輯時，那麼 umask 的群組就不能拿掉 2 這個 w 的權限！ 所以囉， umask 就得要是 002 之類的才可以！這樣新建的檔案才能夠是 -rw-rw-r-- 的權限模樣喔！ 那麼如何設定 umask 呢？簡單的很，直接在 umask 後面輸入 002 就好了！

[root@www ~]# umask 002

[root@www ~]# touch test3

[root@www ~]# mkdir test4

[root@www ~]# ll

-rw-rw-r-- 1 root root     0 Sep 27 00:36 test3

drwxrwxr-x 2 root root  4096 Sep 27 00:36 test4

所以說，這個 umask 對於新建檔案與目錄的預設權限是很有關係的！這個概念可以用在任何伺服器上面， 尤其是未來在你架設檔案伺服器 (file server) ，舉例來說， SAMBA Server 或者是 FTP server 時， 都是很重要的觀念！這牽涉到你的使用者是否能夠將檔案進一步利用的問題喔！不要等閒視之！

例題：

假設你的 umask 為 003 ，請問該 umask 情況下，建立的檔案與目錄權限為？

答：

umask 為 003 ，所以拿掉的權限為 --------wx，因此：

檔案： (-rw-rw-rw-) - (--------wx) = -rw-rw-r--

目錄： (drwxrwxrwx) - (d-------wx) = drwxrwxr--

Tips:

關於 umask 與權限的計算方式中，教科書喜歡使用二進位的方式來進行 AND 與 NOT 的計算， 不過，鳥哥還是比較喜歡使用符號方式來計算∼聯想上面比較容易一點∼

但是，有的書籍或者是 BBS 上面的朋友，喜歡使用檔案預設屬性 666 與目錄預設屬性 777 來與 umask 進行相減的計算∼這是不好的喔！以上面例題來看， 如果使用預設屬性相加減，則檔案變成：666-003=663，亦即是 -rw-rw--wx ，這可是完全不對的喔！ 想想看，原本檔案就已經去除 x 的預設屬性了，怎麼可能突然間冒出來了？ 所以，這個地方得要特別小心喔！

在預設的情況中， root 的 umask 會拿掉比較多的屬性，root 的 umask 預設是 022 ， 這是基於安全的考量啦∼至於一般身份使用者，通常他們的 umask 為 002 ，亦即保留同群組的寫入權力！ 其實，關於預設 umask 的設定可以參考 /etc/bashrc 這個檔案的內容，不過，不建議修改該檔案， 你可以參考第十一章 bash shell 提到的環境參數設定檔 (~/.bashrc) 的說明！

檔案隱藏屬性：

什麼？檔案還有隱藏屬性？光是那九個權限就快要瘋掉了，竟然還有隱藏屬性，真是要命∼ 但是沒辦法，就是有檔案的隱藏屬性存在啊！不過，這些隱藏的屬性確實對於系統有很大的幫助的∼ 尤其是在系統安全 (Security) 上面，重要的緊呢！不過要先強調的是，底下的chattr指令只能在Ext2/Ext3的檔案系統上面生效， 其他的檔案系統可能就無法支援這個指令了。底下我們就來談一談如何設定與檢查這些隱藏的屬性吧！

- chattr (設定檔案隱藏屬性)

[root@www ~]# chattr [+-=][ASacdistu] 檔案或目錄名稱

選項與參數：

+   ：增加某一個特殊參數，其他原本存在參數則不動。

-   ：移除某一個特殊參數，其他原本存在參數則不動。

=   ：設定一定，且僅有後面接的參數

A  ：當設定了 A 這個屬性時，若你有存取此檔案(或目錄)時，他的存取時間 atime

將不會被修改，可避免I/O較慢的機器過度的存取磁碟。這對速度較慢的電腦有幫助

S  ：一般檔案是非同步寫入磁碟的(原理請參考第五章sync的說明)，如果加上 S 這個

屬性時，當你進行任何檔案的修改，該更動會『同步』寫入磁碟中。

a  ：當設定 a 之後，這個檔案將只能增加資料，而不能刪除也不能修改資料，只有root

才能設定這個屬性。

c  ：這個屬性設定之後，將會自動的將此檔案『壓縮』，在讀取的時候將會自動解壓縮，

但是在儲存的時候，將會先進行壓縮後再儲存(看來對於大檔案似乎蠻有用的！)

d  ：當 dump 程序被執行的時候，設定 d 屬性將可使該檔案(或目錄)不會被 dump 備份

i  ：這個 i 可就很厲害了！他可以讓一個檔案『不能被刪除、改名、設定連結也無法

寫入或新增資料！』對於系統安全性有相當大的助益！只有 root 能設定此屬性

s  ：當檔案設定了 s 屬性時，如果這個檔案被刪除，他將會被完全的移除出這個硬碟

空間，所以如果誤刪了，完全無法救回來了喔！

u  ：與 s 相反的，當使用 u 來設定檔案時，如果該檔案被刪除了，則資料內容其實還

存在磁碟中，可以使用來救援該檔案喔！

注意：屬性設定常見的是 a 與 i 的設定值，而且很多設定值必須要身為 root 才能設定

範例：請嘗試到/tmp底下建立檔案，並加入 i 的參數，嘗試刪除看看。

[root@www ~]# cd /tmp

[root@www tmp]# touch attrtest     <==建立一個空檔案

[root@www tmp]# chattr +i attrtest <==給予 i 的屬性

[root@www tmp]# rm attrtest        <==嘗試刪除看看

rm: remove write-protected regular empty file `attrtest'? y

rm: cannot remove `attrtest': Operation not permitted  <==操作不許可

# 看到了嗎？呼呼！連 root 也沒有辦法將這個檔案刪除呢！趕緊解除設定！

範例：請將該檔案的 i 屬性取消！

[root@www tmp]# chattr -i attrtest

這個指令是很重要的，尤其是在系統的資料安全上面！由於這些屬性是隱藏的性質，所以需要以 lsattr 才能看到該屬性呦！其中，個人認為最重要的當屬 +i 與 +a 這個屬性了。+i 可以讓一個檔案無法被更動，對於需要強烈的系統安全的人來說， 真是相當的重要的！裡頭還有相當多的屬性是需要 root 才能設定的呢！

此外，如果是 log file 這種的登錄檔，就更需要 +a 這個可以增加，但是不能修改舊有的資料與刪除的參數了！怎樣？很棒吧！ 未來提到登錄檔 (十九章) 的認知時，我們再來聊一聊如何設定他吧！

- lsattr (顯示檔案隱藏屬性)

[root@www ~]# lsattr [-adR] 檔案或目錄

選項與參數：

-a ：將隱藏檔的屬性也秀出來；

-d ：如果接的是目錄，僅列出目錄本身的屬性而非目錄內的檔名；

-R ：連同子目錄的資料也一併列出來！

[root@www tmp]# chattr +aij attrtest

[root@www tmp]# lsattr attrtest

----ia---j--- attrtest

使用 chattr 設定後，可以利用 lsattr 來查閱隱藏的屬性。不過， 這兩個指令在使用上必須要特別小心，否則會造成很大的困擾。例如：某天你心情好，突然將 /etc/shadow 這個重要的密碼記錄檔案給他設定成為具有 i 的屬性，那麼過了若干天之後， 你突然要新增使用者，卻一直無法新增！別懷疑，趕快去將 i 的屬性拿掉吧！

檔案特殊權限： SUID, SGID, SBIT

我們前面一直提到關於檔案的重要權限，那就是 rwx 這三個讀、寫、執行的權限。 但是，眼尖的朋友們在第六章的目錄樹章節中， 一定注意到了一件事，那就是，怎麼我們的 /tmp 權限怪怪的？ 還有，那個 /usr/bin/passwd 也怪怪的？怎麼回事啊？看看先：

[root@www ~]# ls -ld /tmp ; ls -l /usr/bin/passwd

drwxrwxrwt 7 root root 4096 Sep 27 18:23 /tmp

-rwsr-xr-x 1 root root 22984 Jan  7  2007 /usr/bin/passwd

不是應該只有 rwx 嗎？還有其他的特殊權限( s 跟 t )啊？啊.....頭又開始昏了∼ @_@ 因為 s 與 t 這兩個權限的意義與系統的帳號 (第十四章)及系統的程序(process, 第十七章)較為相關， 所以等到後面的章節談完後你才會比較有概念！底下的說明先看看就好，如果看不懂也沒有關係， 先知道s放在哪裡稱為SUID/SGID以及如何設定即可，等系統程序章節讀完後，再回來看看喔！

- Set UID

當 s 這個標誌出現在檔案擁有者的 x 權限上時，例如剛剛提到的 /usr/bin/passwd 這個檔案的權限狀態：『-rwsr-xr-x』，此時就被稱為 Set UID，簡稱為 SUID 的特殊權限。 那麼SUID的權限對於一個檔案的特殊功能是什麼呢？基本上SUID有這樣的限制與功能：

- SUID 權限僅對二進位程式(binary program)有效；

- 執行者對於該程式需要具有 x 的可執行權限；

- 本權限僅在執行該程式的過程中有效 (run-time)；

- 執行者將具有該程式擁有者 (owner) 的權限。

講這麼硬的東西你可能對於 SUID 還是沒有概念，沒關係，我們舉個例子來說明好了。 我們的 Linux 系統中，所有帳號的密碼都記錄在 /etc/shadow 這個檔案裡面，這個檔案的權限為：『-r-------- 1 root root』，意思是這個檔案僅有root可讀且僅有root可以強制寫入而已。 既然這個檔案僅有 root 可以修改，那麼鳥哥的 vbird 這個一般帳號使用者能否自行修改自己的密碼呢？ 你可以使用你自己的帳號輸入『passwd』這個指令來看看，嘿嘿！一般使用者當然可以修改自己的密碼了！

唔！有沒有衝突啊！明明 /etc/shadow 就不能讓 vbird 這個一般帳戶去存取的，為什麼 vbird 還能夠修改這個檔案內的密碼呢？ 這就是 SUID 的功能啦！藉由上述的功能說明，我們可以知道

1. vbird 對於 /usr/bin/passwd 這個程式來說是具有 x 權限的，表示 vbird 能執行 passwd；

2. passwd 的擁有者是 root 這個帳號；

3. vbird 執行 passwd 的過程中，會『暫時』獲得 root 的權限；

4. /etc/shadow 就可以被 vbird 所執行的 passwd 所修改。

但如果 vbird 使用 cat 去讀取 /etc/shadow 時，他能夠讀取嗎？因為 cat 不具有 SUID 的權限，所以 vbird 執行 『cat /etc/shadow』 時，是不能讀取 /etc/shadow 的。我們用一張示意圖來說明如下：

圖4.4.1、SUID程式執行的過程示意圖

另外，SUID 僅可用在binary program 上， 不能夠用在 shell script 上面！這是因為 shell script 只是將很多的 binary 執行檔叫進來執行而已！所以 SUID 的權限部分，還是得要看 shell script 呼叫進來的程式的設定， 而不是 shell script 本身。當然，SUID 對於目錄也是無效的∼這點要特別留意。

- Set GID

當 s 標誌在檔案擁有者的 x 項目為 SUID，那 s 在群組的 x 時則稱為 Set GID, SGID 囉！是這樣沒錯！^_^。 舉例來說，你可以用底下的指令來觀察到具有 SGID 權限的檔案喔：

[root@www ~]# ls -l /usr/bin/locate

-rwx--s--x 1 root slocate 23856 Mar 15  2007 /usr/bin/locate

與 SUID 不同的是，SGID 可以針對檔案或目錄來設定！如果是對檔案來說， SGID 有如下的功能：

- SGID 對二進位程式有用；

- 程式執行者對於該程式來說，需具備 x 的權限；

- 執行者在執行的過程中將會獲得該程式群組的支援！

舉例來說，上面的 /usr/bin/locate 這個程式可以去搜尋 /var/lib/mlocate/mlocate.db 這個檔案的內容 (詳細說明會在下節講述)， mlocate.db 的權限如下：

[root@www ~]# ll /usr/bin/locate /var/lib/mlocate/mlocate.db

-rwx--s--x 1 root slocate   23856 Mar 15  2007 /usr/bin/locate

-rw-r----- 1 root slocate 3175776 Sep 28 04:02 /var/lib/mlocate/mlocate.db

與 SUID 非常的類似，若我使用 vbird 這個帳號去執行 locate 時，那 vbird 將會取得 slocate 群組的支援， 因此就能夠去讀取 mlocate.db 啦！非常有趣吧！

除了 binary program 之外，事實上 SGID 也能夠用在目錄上，這也是非常常見的一種用途！ 當一個目錄設定了 SGID 的權限後，他將具有如下的功能：

- 使用者若對於此目錄具有 r 與 x 的權限時，該使用者能夠進入此目錄；

- 使用者在此目錄下的有效群組(effective group)將會變成該目錄的群組；

- 用途：若使用者在此目錄下具有 w 的權限(可以新建檔案)，則使用者所建立的新檔案，該新檔案的群組與此目錄的群組相同。

SGID 對於專案開發來說是非常重要的！因為這涉及群組權限的問題，您可以參考一下本章後續情境模擬的案例，應該就能夠對於 SGID 有一些瞭解的！^_^

- Sticky Bit

這個 Sticky Bit, SBIT 目前只針對目錄有效，對於檔案已經沒有效果了。 SBIT 對於目錄的作用是：

- 當使用者對於此目錄具有 w, x 權限，亦即具有寫入的權限時；

- 當使用者在該目錄下建立檔案或目錄時，僅有自己與 root 才有權力刪除該檔案

換句話說：當甲這個使用者於 A 目錄是具有群組或其他人的身份，並且擁有該目錄 w 的權限， 這表示『甲使用者對該目錄內任何人建立的目錄或檔案均可進行 "刪除/更名/搬移" 等動作。』 不過，如果將 A 目錄加上了 SBIT 的權限項目時， 則甲只能夠針對自己建立的檔案或目錄進行刪除/更名/移動等動作，而無法刪除他人的檔案。

舉例來說，我們的 /tmp 本身的權限是『drwxrwxrwt』， 在這樣的權限內容下，任何人都可以在 /tmp 內新增、修改檔案，但僅有該檔案/目錄建立者與 root 能夠刪除自己的目錄或檔案。這個特性也是挺重要的啊！你可以這樣做個簡單的測試：

1. 以 root 登入系統，並且進入 /tmp 當中；

2. touch test，並且更改 test 權限成為 777 ；

3. 以一般使用者登入，並進入 /tmp；

4. 嘗試刪除 test 這個檔案！

由於 SUID/SGID/SBIT 牽涉到程序的概念，因此再次強調，這部份的資料在您讀完第十七章關於程序方面的知識後，要再次的回來瞧瞧喔！ 目前，你先有個簡單的基礎概念就好了！文末的參考資料也建議閱讀一番喔！

- SUID/SGID/SBIT 權限設定

前面介紹過 SUID 與 SGID 的功能，那麼如何設定檔案使成為具有 SUID 與 SGID 的權限呢？ 這就需要第六章的數字更改權限的方法了！ 現在你應該已經知道數字型態更改權限的方式為『三個數字』的組合， 那麼如果在這三個數字之前再加上一個數字的話，最前面的那個數字就代表這幾個權限了！

- 4 為 SUID

- 2 為 SGID

- 1 為 SBIT

假設要將一個檔案權限改為『-rwsr-xr-x』時，由於 s 在使用者權限中，所以是 SUID ，因此， 在原先的 755 之前還要加上 4 ，也就是：『 chmod 4755 filename 』來設定！此外，還有大 S 與大 T 的產生喔！參考底下的範例啦！

Tips:

注意：底下的範例只是練習而已，所以鳥哥使用同一個檔案來設定，你必須瞭解 SUID 不是用在目錄上，而 SBIT 不是用在檔案上的喔！

[root@www ~]# cd /tmp

[root@www tmp]# touch test                  <==建立一個測試用空檔

[root@www tmp]# chmod 4755 test; ls -l test <==加入具有 SUID 的權限

-rwsr-xr-x 1 root root 0 Sep 29 03:06 test

[root@www tmp]# chmod 6755 test; ls -l test <==加入具有 SUID/SGID 的權限

-rwsr-sr-x 1 root root 0 Sep 29 03:06 test

[root@www tmp]# chmod 1755 test; ls -l test <==加入 SBIT 的功能！

-rwxr-xr-t 1 root root 0 Sep 29 03:06 test

[root@www tmp]# chmod 7666 test; ls -l test <==具有空的 SUID/SGID 權限

-rwSrwSrwT 1 root root 0 Sep 29 03:06 test

最後一個例子就要特別小心啦！怎麼會出現大寫的 S 與 T 呢？不都是小寫的嗎？ 因為 s 與 t 都是取代 x 這個權限的，但是你有沒有發現阿，我們是下達 7666 喔！也就是說， user, group 以及 others 都沒有 x 這個可執行的標誌( 因為 666 嘛 )，所以，這個 S, T 代表的就是『空的』啦！怎麼說？ SUID 是表示『該檔案在執行的時候，具有檔案擁有者的權限』，但是檔案 擁有者都無法執行了，哪裡來的權限給其他人使用？當然就是空的啦！ ^_^

而除了數字法之外，妳也可以透過符號法來處理喔！其中 SUID 為 u+s ，而 SGID 為 g+s ，SBIT 則是 o+t 囉！來看看如下的範例：

# 設定權限成為 -rws--x--x 的模樣：

[root@www tmp]# chmod u=rwxs,go=x test; ls -l test

-rws--x--x 1 root root 0 Aug 18 23:47 test

# 承上，加上 SGID 與 SBIT 在上述的檔案權限中！

[root@www tmp]# chmod g+s,o+t test; ls -l test

-rws--s--t 1 root root 0 Aug 18 23:47 test

觀察檔案類型：file

如果你想要知道某個檔案的基本資料，例如是屬於 ASCII 或者是 data 檔案，或者是 binary ， 且其中有沒有使用到動態函式庫 (share library) 等等的資訊，就可以利用 file 這個指令來檢閱喔！ 舉例來說：

[root@www ~]# file ~/.bashrc

/root/.bashrc: ASCII text  <==告訴我們是 ASCII 的純文字檔啊！

[root@www ~]# file /usr/bin/passwd

/usr/bin/passwd: setuid ELF 32-bit LSB executable, Intel 80386, version 1

(SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for

GNU/Linux 2.6.9, stripped

# 執行檔的資料可就多的不得了！包括這個檔案的 suid 權限、相容於 Intel 386

# 等級的硬體平台、使用的是 Linux 核心 2.6.9 的動態函式庫連結等等。

[root@www ~]# file /var/lib/mlocate/mlocate.db

/var/lib/mlocate/mlocate.db: data  <== 這是 data 檔案！

透過這個指令，我們可以簡單的先判斷這個檔案的格式為何喔！

指令與檔案的搜尋：

檔案的搜尋可就厲害了！因為我們常常需要知道那個檔案放在哪裡，才能夠對該檔案進行一些修改或維護等動作。 有些時候某些軟體設定檔的檔名是不變的，但是各 distribution 放置的目錄則不同。 此時就得要利用一些搜尋指令將該設定檔的完整檔名捉出來，這樣才能修改嘛！您說是吧！^_^

指令檔名的搜尋：

我們知道在終端機模式當中，連續輸入兩次[tab]按鍵就能夠知道使用者有多少指令可以下達。 那你知不知道這些指令的完整檔名放在哪裡？舉例來說，ls 這個常用的指令放在哪裡呢？ 就透過 which 或 type 來找尋吧！

- which (尋找『執行檔』)

[root@www ~]# which [-a] command

選項或參數：

-a ：將所有由 PATH 目錄中可以找到的指令均列出，而不止第一個被找到的指令名稱

範例一：分別用root與一般帳號搜尋 ifconfig 這個指令的完整檔名

[root@www ~]# which ifconfig

/sbin/ifconfig            <==用 root 可以找到正確的執行檔名喔！

[root@www ~]# su - vbird <==切換身份成為 vbird 去！

[vbird@www ~]$ which ifconfig

/usr/bin/which: no ifconfig in (/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin

:/home/vbird/bin)         <==見鬼了！竟然一般身份帳號找不到！

# 因為 which 是根據使用者所設定的 PATH 變數內的目錄去搜尋可執行檔的！所以，

# 不同的 PATH 設定內容所找到的指令當然不一樣啦！因為 /sbin 不在 vbird 的

# PATH 中，找不到也是理所當然的啊！瞭乎？

[vbird@www ~]$ exit      <==記得將身份切換回原本的 root

範例二：用 which 去找出 which 的檔名為何？

[root@www ~]# which which

alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot '

/usr/bin/which

# 竟然會有兩個 which ，其中一個是 alias 這玩意兒呢！那是啥？

# 那就是所謂的『命令別名』，意思是輸入 which 會等於後面接的那串指令啦！

# 更多的資料我們會在 bash 章節中再來談的！

範例三：請找出 cd 這個指令的完整檔名

[root@www ~]# which cd

/usr/bin/which: no cd in (/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin

:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)

# 瞎密？怎麼可能沒有 cd ，我明明就能夠用 root 執行 cd 的啊！

這個指令是根據『PATH』這個環境變數所規範的路徑，去搜尋『執行檔』的檔名∼ 所以，重點是找出『執行檔』而已！且 which 後面接的是『完整檔名』喔！若加上 -a 選項，則可以列出所有的可以找到的同名執行檔，而非僅顯示第一個而已！

最後一個範例最有趣，怎麼 cd 這個常用的指令竟然找不到啊！為什麼呢？這是因為 cd 是『bash 內建的指令』啦！ 但是 which 預設是找 PATH 內所規範的目錄，所以當然一定找不到的啊！那怎辦？沒關係！我們可以透過 type 這個指令喔！ 關於 type 的用法我們將在 第十一章的 bash 再來談！

檔案檔名的搜尋：

再來談一談怎麼搜尋檔案吧！在 Linux 底下也有相當優異的搜尋指令呦！通常 find 不很常用的！因為速度慢之外， 也很操硬碟！通常我們都是先使用 whereis 或者是 locate 來檢查，如果真的找不到了，才以 find 來搜尋呦！ 為什麼呢？因為 whereis 與 locate 是利用資料庫來搜尋資料，所以相當的快速，而且並沒有實際的搜尋硬碟， 比較省時間啦！

- whereis (尋找特定檔案)

[root@www ~]# whereis [-bmsu] 檔案或目錄名

選項與參數：

-b    :只找 binary 格式的檔案

-m    :只找在說明檔 manual 路徑下的檔案

-s    :只找 source 來源檔案

-u    :搜尋不在上述三個項目當中的其他特殊檔案

範例一：請用不同的身份找出 ifconfig 這個檔名

[root@www ~]# whereis ifconfig

ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz

[root@www ~]# su - vbird        <==切換身份成為 vbird

[vbird@www ~]$ whereis ifconfig <==找到同樣的結果喔！

ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz

[vbird@www ~]$ exit              <==回歸身份成為 root 去！

# 注意看，明明 which 一般使用者找不到的 ifconfig 卻可以讓 whereis 找到！

# 這是因為系統真的有 ifconfig 這個『檔案』，但是使用者的 PATH 並沒有加入 /sbin

# 所以，未來你找不到某些指令時，先用檔案搜尋指令找找看再說！

範例二：只找出跟 passwd 有關的『說明文件』檔名(man page)

[root@www ~]# whereis -m passwd

passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz

等一下我們會提到 find 這個搜尋指令， find 是很強大的搜尋指令，但時間花用的很大！ (因為 find 是直接搜尋硬碟，為如果你的硬碟比較老舊的話，嘿嘿！有的等！) 這個時候 whereis 就相當的好用了！另外， whereis 可以加入選項來找尋相關的資料， 例如如果你是要找可執行檔( binary )那麼加上 -b 就可以啦！ 如果不加任何選項的話，那麼就將所有的資料列出來囉！

那麼 whereis 到底是使用什麼咚咚呢？為何搜尋的速度會比 find 快這麼多？ 其實那也沒有什麼！這是因為 Linux 系統會將系統內的所有檔案都記錄在一個資料庫檔案裡面， 而當使用 whereis 或者是底下要說的 locate 時，都會以此資料庫檔案的內容為準， 因此，有的時後你還會發現使用這兩個執行檔時，會找到已經被殺掉的檔案！ 而且也找不到最新的剛剛建立的檔案呢！這就是因為這兩個指令是由資料庫當中的結果去搜尋檔案的所在啊！ 更多與這個資料庫有關的說明，請參考下列的 locate 指令。

- locate

[root@www ~]# locate [-ir] keyword

選項與參數：

-i  ：忽略大小寫的差異；

-r  ：後面可接正規表示法的顯示方式

範例一：找出系統中所有與 passwd 相關的檔名

[root@www ~]# locate passwd

/etc/passwd

/etc/passwd-

/etc/news/passwd.nntp

/etc/pam.d/passwd

....(底下省略)....

這個 locate 的使用更簡單，直接在後面輸入『檔案的部分名稱』後，就能夠得到結果。 舉上面的例子來說，我輸入 locate passwd ，那麼在完整檔名 (包含路徑名稱) 當中，只要有 passwd 在其中， 就會被顯示出來的！這也是個很方便好用的指令，如果你忘記某個檔案的完整檔名時∼∼

但是，這個東西還是有使用上的限制呦！為什麼呢？你會發現使用 locate 來尋找資料的時候特別的快， 這是因為 locate 尋找的資料是由『已建立的資料庫 /var/lib/mlocate/』 裡面的資料所搜尋到的，所以不用直接在去硬碟當中存取資料，呵呵！當然是很快速囉！

那麼有什麼限制呢？就是因為他是經由資料庫來搜尋的，而資料庫的建立預設是在每天執行一次 (每個 distribution 都不同，CentOS 5.x 是每天更新資料庫一次！)，所以當你新建立起來的檔案， 卻還在資料庫更新之前搜尋該檔案，那麼 locate 會告訴你『找不到！』呵呵！因為必須要更新資料庫呀！

那能否手動更新資料庫哪？當然可以啊！更新 locate 資料庫的方法非常簡單，直接輸入『 updatedb 』就可以了！ updatedb 指令會去讀取 /etc/updatedb.conf 這個設定檔的設定，然後再去硬碟裡面進行搜尋檔名的動作， 最後就更新整個資料庫檔案囉！因為 updatedb 會去搜尋硬碟，所以當你執行 updatedb 時，可能會等待數分鐘的時間喔！

- updatedb：根據 /etc/updatedb.conf 的設定去搜尋系統硬碟內的檔名，並更新 /var/lib/mlocate 內的資料庫檔案；

- locate：依據 /var/lib/mlocate 內的資料庫記載，找出使用者輸入的關鍵字檔名。

- find

[root@www ~]# find [PATH] [option] [action]

選項與參數：

1. 與時間有關的選項：共有 -atime, -ctime 與 -mtime ，以 -mtime 說明

-mtime  n ：n 為數字，意義為在 n 天之前的『一天之內』被更動過內容的檔案；

-mtime +n ：列出在 n 天之前(不含 n 天本身)被更動過內容的檔案檔名；

-mtime -n ：列出在 n 天之內(含 n 天本身)被更動過內容的檔案檔名。

-newer file ：file 為一個存在的檔案，列出比 file 還要新的檔案檔名

範例一：將過去系統上面 24 小時內有更動過內容 (mtime) 的檔案列出

[root@www ~]# find / -mtime 0

# 那個 0 是重點！0 代表目前的時間，所以，從現在開始到 24 小時前，

# 有變動過內容的檔案都會被列出來！那如果是三天前的 24 小時內？

# find / -mtime 3 有變動過的檔案都被列出的意思！

範例二：尋找 /etc 底下的檔案，如果檔案日期比 /etc/passwd 新就列出

[root@www ~]# find /etc -newer /etc/passwd

# -newer 用在分辨兩個檔案之間的新舊關係是很有用的！

時間參數真是挺有意思的！我們現在知道 atime, ctime 與 mtime 的意義，如果你想要找出一天內被更動過的檔案名稱， 可以使用上述範例一的作法。但如果我想要找出『4天內被更動過的檔案檔名』呢？那可以使用『 find /var -mtime -4 』。那如果是『4天前的那一天』就用『 find /var -mtime 4 』。有沒有加上『+, -』差別很大喔！我們可以用簡單的圖示來說明一下：

圖5.2.1、find 相關的時間參數意義

圖中最右邊為目前的時間，越往左邊則代表越早之前的時間軸啦。由圖5.2.1我們可以清楚的知道：

- +4代表大於等於5天前的檔名：ex> find /var -mtime +4

- -4代表小於等於4天內的檔案檔名：ex> find /var -mtime -4

- 4則是代表4-5那一天的檔案檔名：ex> find /var -mtime 4

非常有趣吧！你可以在 /var/ 目錄下搜尋一下，感受一下輸出檔案的差異喔！再來看看其他 find 的用法吧！

選項與參數：

2. 與使用者或群組名稱有關的參數：

-uid n ：n 為數字，這個數字是使用者的帳號 ID，亦即 UID ，這個 UID 是記錄在

/etc/passwd 裡面與帳號名稱對應的數字。這方面我們會在第四篇介紹。

-gid n ：n 為數字，這個數字是群組名稱的 ID，亦即 GID，這個 GID 記錄在

/etc/group，相關的介紹我們會第四篇說明∼

-user name ：name 為使用者帳號名稱喔！例如 dmtsai

-group name：name 為群組名稱喔，例如 users ；

-nouser    ：尋找檔案的擁有者不存在 /etc/passwd 的人！

-nogroup   ：尋找檔案的擁有群組不存在於 /etc/group 的檔案！

當你自行安裝軟體時，很可能該軟體的屬性當中並沒有檔案擁有者，

這是可能的！在這個時候，就可以使用 -nouser 與 -nogroup 搜尋。

範例三：搜尋 /home 底下屬於 vbird 的檔案

[root@www ~]# find /home -user vbird

# 這個東西也很有用的∼當我們要找出任何一個使用者在系統當中的所有檔案時，

# 就可以利用這個指令將屬於某個使用者的所有檔案都找出來喔！

範例四：搜尋系統中不屬於任何人的檔案

[root@www ~]# find / -nouser

# 透過這個指令，可以輕易的就找出那些不太正常的檔案。

# 如果有找到不屬於系統任何人的檔案時，不要太緊張，

# 那有時候是正常的∼尤其是你曾經以原始碼自行編譯軟體時。

如果你想要找出某個使用者在系統底下建立了啥咚咚，使用上述的選項與參數，就能夠找出來啦！ 至於那個 -nouser 或 -nogroup 的選項功能中，除了你自行由網路上面下載檔案時會發生之外， 如果你將系統裡面某個帳號刪除了，但是該帳號已經在系統內建立很多檔案時，就可能會發生無主孤魂的檔案存在！ 此時你就得使用這個 -nouser 來找出該類型的檔案囉！

選項與參數：

3. 與檔案權限及名稱有關的參數：

-name filename：搜尋檔案名稱為 filename 的檔案；

-size [+-]SIZE：搜尋比 SIZE 還要大(+)或小(-)的檔案。這個 SIZE 的規格有：

c: 代表 byte， k: 代表 1024bytes。所以，要找比 50KB

還要大的檔案，就是『 -size +50k 』

-type TYPE    ：搜尋檔案的類型為 TYPE 的，類型主要有：一般正規檔案 (f),

裝置檔案 (b, c), 目錄 (d), 連結檔 (l), socket (s),

及 FIFO (p) 等屬性。

-perm mode  ：搜尋檔案權限『剛好等於』 mode 的檔案，這個 mode 為類似 chmod

的屬性值，舉例來說， -rwsr-xr-x 的屬性為 4755 ！

-perm -mode ：搜尋檔案權限『必須要全部囊括 mode 的權限』的檔案，舉例來說，

我們要搜尋 -rwxr--r-- ，亦即 0744 的檔案，使用 -perm -0744，

當一個檔案的權限為 -rwsr-xr-x ，亦即 4755 時，也會被列出來，

因為 -rwsr-xr-x 的屬性已經囊括了 -rwxr--r-- 的屬性了。

-perm +mode ：搜尋檔案權限『包含任一 mode 的權限』的檔案，舉例來說，

我們搜尋

-rwxr-xr-x ，亦即 -perm +755 時，但一個檔案屬性為 -rw-------

也會被列出來，因為他有 -rw.... 的屬性存在！

範例五：找出檔名為 passwd 這個檔案

[root@www ~]# find / -name passwd

# 利用這個 -name 可以搜尋檔名啊！

範例六：找出 /var 目錄下，檔案類型為 Socket 的檔名有哪些？

[root@www ~]# find /var -type s

# 這個 -type 的屬性也很有幫助喔！尤其是要找出那些怪異的檔案，

# 例如 socket 與 FIFO 檔案，可以用 find /var -type p 或 -type s 來找！

範例七：搜尋檔案當中含有 SGID 或 SUID 或 SBIT 的屬性

[root@www ~]# find / -perm +7000

# 所謂的 7000 就是 ---s--s--t ，那麼只要含有 s 或 t 的就列出，

# 所以當然要使用 +7000 ，使用 -7000 表示要含有 ---s--s--t 的所有三個權限，

# 因此，就是 +7000 ∼瞭乎？

上述範例中比較有趣的就屬 -perm 這個選項啦！他的重點在找出特殊權限的檔案囉！ 我們知道 SUID 與 SGID 都可以設定在二進位程式上，假設我想要找出來 /bin, /sbin 這兩個目錄下， 只要具有 SUID 或 SGID 就列出來該檔案，你可以這樣做：

[root@www ~]# find /bin /sbin -perm +6000

因為 SUID 是 4 分，SGID 2 分，總共為 6 分，因此可用 +6000 來處理這個權限！ 至於 find 後面可以接多個目錄來進行搜尋！另外， find 本來就會搜尋次目錄，這個特色也要特別注意喔！ 最後，我們再來看一下 find 還有什麼特殊功能吧！

選項與參數：

4. 額外可進行的動作：

-exec command ：command 為其他指令，-exec 後面可再接額外的指令來處理搜尋到

的結果。

-print        ：將結果列印到螢幕上，這個動作是預設動作！

範例八：將上個範例找到的檔案使用 ls -l 列出來∼

[root@www ~]# find / -perm +7000 -exec ls -l {} \;

# 注意到，那個 -exec 後面的 ls -l 就是額外的指令，指令不支援命令別名，

# 所以僅能使用 ls -l 不可以使用 ll 喔！注意注意！

範例九：找出系統中，大於 1MB 的檔案

[root@www ~]# find / -size +1000k

# 雖然在 man page 提到可以使用 M 與 G 分別代表 MB 與 GB，

# 不過，俺卻試不出來這個功能∼所以，目前應該是僅支援到 c 與 k 吧！

find 的特殊功能就是能夠進行額外的動作(action)。我們將範例八的例子以圖解來說明如下：

圖5.2.2、find 相關的額外動作

該範例中特殊的地方有 {} 以及 \; 還有 -exec 這個關鍵字，這些東西的意義為：

- {} 代表的是『由 find 找到的內容』，如上圖所示，find 的結果會被放置到 {} 位置中；

- -exec 一直到 \; 是關鍵字，代表 find 額外動作的開始 (-exec) 到結束 (\;) ，在這中間的就是 find 指令內的額外動作。 在本例中就是『 ls -l {} 』囉！

- 因為『 ; 』在 bash 環境下是有特殊意義的，因此利用反斜線來跳脫。

透過圖 5.2.2 你應該就比較容易瞭解 -exec 到 \; 之間的意義了吧！

如果你要找的檔案是具有特殊屬性的，例如 SUID 、檔案擁有者、檔案大小等等， 那麼利用 locate 是沒有辦法達成你的搜尋的！此時 find 就顯的很重要啦！ 另外，find 還可以利用萬用字元來找尋檔名呢！舉例來說，你想要找出 /etc 底下檔名包含 httpd 的檔案， 那麼你就可以這樣做：

[root@www ~]# find /etc -name '*httpd*'

不但可以指定搜尋的目錄(連同次目錄)，並且可以利用額外的選項與參數來找到最正確的檔名！真是好好用！ 不過由於 find 在尋找資料的時後相當的操硬碟！所以沒事情不要使用 find 啦！有更棒的指令可以取代呦！那就是上面提到的 whereis 與 locate 囉！

極重要！權限與指令間的關係：

我們知道權限對於使用者帳號來說是非常重要的，因為他可以限制使用者能不能讀取/建立/刪除/修改檔案或目錄！ 在這一章我們介紹了很多檔案系統的管理指令，第六章則介紹了很多檔案權限的意義。在這個小節當中， 我們就將這兩者結合起來，說明一下什麼指令在什麼樣的權限下才能夠運作吧！^_^

一、讓使用者能進入某目錄成為『可工作目錄』的基本權限為何：

- 可使用的指令：例如 cd 等變換工作目錄的指令；

- 目錄所需權限：使用者對這個目錄至少需要具有 x 的權限

- 額外需求：如果使用者想要在這個目錄內利用 ls 查閱檔名，則使用者對此目錄還需要 r 的權限。

二、使用者在某個目錄內讀取一個檔案的基本權限為何？

- 可使用的指令：例如本章談到的 cat, more, less等等

- 目錄所需權限：使用者對這個目錄至少需要具有 x 權限；

- 檔案所需權限：使用者對檔案至少需要具有 r 的權限才行！

三、讓使用者可以修改一個檔案的基本權限為何？

- 可使用的指令：例如 nano 或未來要介紹的 vi 編輯器等；

- 目錄所需權限：使用者在該檔案所在的目錄至少要有 x 權限；

- 檔案所需權限：使用者對該檔案至少要有 r, w 權限

四、讓一個使用者可以建立一個檔案的基本權限為何？

- 目錄所需權限：使用者在該目錄要具有 w,x 的權限，重點在 w 啦！

五、讓使用者進入某目錄並執行該目錄下的某個指令之基本權限為何？

- 目錄所需權限：使用者在該目錄至少要有 x 的權限；

- 檔案所需權限：使用者在該檔案至少需要有 x 的權限

例題：

讓一個使用者 vbird 能夠進行『cp /dir1/file1 /dir2』的指令時，請說明 dir1, file1, dir2 的最小所需權限為何？

答：

執行 cp 時， vbird 要『能夠讀取來源檔，並且寫入目標檔！』所以應參考上述第二點與第四點的說明！ 因此各檔案/目錄的最小權限應該是：

- dir1 ：至少需要有 x 權限；

- file1：至少需要有 r 權限；

- dir2 ：至少需要有 w, x 權限。

例題：

有一個檔案全名為 /home/student/www/index.html ，各相關檔案/目錄的權限如下：

drwxr-xr-x 23 root    root    4096 Sep 22 12:09 /

drwxr-xr-x  6 root    root    4096 Sep 29 02:21 /home

drwx------  6 student student 4096 Sep 29 02:23 /home/student

drwxr-xr-x  6 student student 4096 Sep 29 02:24 /home/student/www

-rwxr--r--  6 student student  369 Sep 29 02:27 /home/student/www/index.html

請問 vbird 這個帳號(不屬於student群組)能否讀取 index.html 這個檔案呢？

答：

雖然 www 與 index.html 是可以讓 vbird 讀取的權限，但是因為目錄結構是由根目錄一層一層讀取的， 因此 vbird 可進入 /home 但是卻不可進入 /home/student/ ，既然連進入 /home/student 都不許了， 當然就讀不到 index.html 了！所以答案是『vbird不會讀取到 index.html 的內容』喔！

那要如何修改權限呢？其實只要將 /home/student 的權限修改為最小 711 ，或者直接給予 755 就可以囉！ 這可是很重要的概念喔！

重點回顧

- 絕對路徑：『一定由根目錄 / 寫起』；相對路徑：『不是由 / 寫起』

- 特殊目錄有：., .., -, ~, ~account需要注意；

- 與目錄相關的指令有：cd, mkdir, rmdir, pwd 等重要指令；

- rmdir 僅能刪除空目錄，要刪除非空目錄需使用『 rm -r 』指令；

- 使用者能使用的指令是依據 PATH 變數所規定的目錄去搜尋的；

- 不同的身份(root 與一般用戶)系統預設的 PATH 並不相同。差異較大的地方在於 /sbin, /usr/sbin ；

- ls 可以檢視檔案的屬性，尤其 -d, -a, -l 等選項特別重要！

- 檔案的複製、刪除、移動可以分別使用：cp, rm , mv等指令來操作；

- 檢查檔案的內容(讀檔)可使用的指令包括有：cat, tac, nl, more, less, head, tail, od 等

- cat -n 與 nl 均可顯示行號，但預設的情況下，空白行會不會編號並不相同；

- touch 的目的在修改檔案的時間參數，但亦可用來建立空檔案；

- 一個檔案記錄的時間參數有三種，分別是 access time(atime), status time (ctime), modification time(mtime)，ls 預設顯示的是 mtime。

- 除了傳統的rwx權限之外，在Ext2/Ext3檔案系統中，還可以使用chattr與lsattr設定及觀察隱藏屬性。 常見的包括只能新增資料的 +a 與完全不能更動檔案的 +i 屬性。

- 新建檔案/目錄時，新檔案的預設權限使用 umask 來規範。預設目錄完全權限為drwxrwxrwx， 檔案則為-rw-rw-rw-。

- 檔案具有SUID的特殊權限時，代表當使用者執行此一binary程式時，在執行過程中使用者會暫時具有程式擁有者的權限

- 目錄具有SGID的特殊權限時，代表使用者在這個目錄底下新建的檔案之群組都會與該目錄的群組名稱相同。

- 目錄具有SBIT的特殊權限時，代表在該目錄下使用者建立的檔案只有自己與root能夠刪除！

- 觀察檔案的類型可以使用 file 指令來觀察；

- 搜尋指令的完整檔名可用 which 或 type ，這兩個指令都是透過 PATH 變數來搜尋檔名；

- 搜尋檔案的完整檔名可以使用 whereis 或 locate 到資料庫檔案去搜尋，而不實際搜尋檔案系統；

- 利用 find 可以加入許多選項來直接查詢檔案系統，以獲得自己想要知道的檔名。

本章習題：

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

情境模擬題一：假設系統中有兩個帳號，分別是 alex 與 arod ，這兩個人除了自己群組之外還共同支援一個名為 project 的群組。假設這兩個用戶需要共同擁有 /srv/ahome/ 目錄的開發權，且該目錄不許其他人進入查閱。 請問該目錄的權限設定應為何？請先以傳統權限說明，再以 SGID 的功能解析。

- 目標：瞭解到為何專案開發時，目錄最好需要設定 SGID 的權限！

- 前提：多個帳號支援同一群組，且共同擁有目錄的使用權！

- 需求：需要使用 root 的身份來進行 chmod, chgrp 等幫用戶設定好他們的開發環境才行！ 這也是管理員的重要任務之一！

首先我們得要先製作出這兩個帳號的相關資料，帳號/群組的管理在後續我們會介紹， 您這裡先照著底下的指令來製作即可：

[root@www ~]# groupadd project        <==增加新的群組

[root@www ~]# useradd -G project alex <==建立 alex 帳號，且支援 project

[root@www ~]# useradd -G project arod <==建立 arod 帳號，且支援 project

[root@www ~]# id alex                 <==查閱 alex 帳號的屬性

uid=501(alex) gid=502(alex) groups=502(alex),501(project) <==確實有支援！

[root@www ~]# id arod

uid=502(arod) gid=503(arod) groups=503(arod),501(project)

然後開始來解決我們所需要的環境吧！

1. 首先建立所需要開發的專案目錄：

[root@www ~]# mkdir /srv/ahome

[root@www ~]# ll -d /srv/ahome

drwxr-xr-x 2 root root 4096 Sep 29 22:36 /srv/ahome

1. 從上面的輸出結果可發現 alex 與 arod 都不能在該目錄內建立檔案，因此需要進行權限與屬性的修改。 由於其他人均不可進入此目錄，因此該目錄的群組應為project，權限應為770才合理。

[root@www ~]# chgrp project /srv/ahome

[root@www ~]# chmod 770 /srv/ahome

[root@www ~]# ll -d /srv/ahome

drwxrwx--- 2 root project 4096 Sep 29 22:36 /srv/ahome

# 從上面的權限結果來看，由於 alex/arod 均支援 project，因此似乎沒問題了！

1. 實際分別以兩個使用者來測試看看，情況會是如何？先用 alex 建立檔案，然後用 arod 去處理看看。

[root@www ~]# su - alex       <==先切換身份成為 alex 來處理

[alex@www ~]$ cd /srv/ahome   <==切換到群組的工作目錄去

[alex@www ahome]$ touch abcd  <==建立一個空的檔案出來！

[alex@www ahome]$ exit        <==離開 alex 的身份

[root@www ~]# su - arod

[arod@www ~]$ cd /srv/ahome

[arod@www ahome]$ ll abcd

-rw-rw-r-- 1 alex alex 0 Sep 29 22:46 abcd

# 仔細看一下上面的檔案，由於群組是 alex ，arod並不支援！

# 因此對於 abcd 這個檔案來說， arod 應該只是其他人，只有 r 的權限而已啊！

[arod@www ahome]$ exit

由上面的結果我們可以知道，若單純使用傳統的 rwx 而已，則對剛剛 alex 建立的 abcd 這個檔案來說， arod 可以刪除他，但是卻不能編輯他！這不是我們要的樣子啊！趕緊來重新規劃一下。

1. 加入 SGID 的權限在裡面，並進行測試看看：

[root@www ~]# chmod 2770 /srv/ahome

[root@www ~]# ll -d /srv/ahome

drwxrws--- 2 root project 4096 Sep 29 22:46 /srv/ahome

測試：使用 alex 去建立一個檔案，並且查閱檔案權限看看：

[root@www ~]# su - alex

[alex@www ~]$ cd /srv/ahome

[alex@www ahome]$ touch 1234

[alex@www ahome]$ ll 1234

-rw-rw-r-- 1 alex project 0 Sep 29 22:53 1234

# 沒錯！這才是我們要的樣子！現在 alex, arod 建立的新檔案所屬群組都是 project，

# 由於兩人均屬於此群組，加上 umask 都是 002，這樣兩人才可以互相修改對方的檔案！

所以最終的結果顯示，此目錄的權限最好是『2770』，所屬檔案擁有者屬於root即可，至於群組必須要為兩人共同支援的project 這個群組才行！

簡答題部分：

- 什麼是絕對路徑與相對路徑

絕對路徑的寫法為由 / 開始寫，至於相對路徑則不由 / 開始寫！此外，相對路徑為相對於目前工作目錄的路徑！

- 如何更改一個目錄的名稱？例如由 /home/test 變為 /home/test2

mv /home/test /home/test2

- PATH 這個環境變數的意義？

這個是用來指定執行檔執行的時候，指令搜尋的目錄路徑。

- umask 有什麼用處與優點？

umask 可以拿掉一些權限，因此，適當的定義 umask 有助於系統的安全， 因為他可以用來建立預設的目錄或檔案的權限。

- 當一個使用者的 umask 分別為 033 與 044 他所建立的檔案與目錄的權限為何？

在 umask 為 033 時，則預設是拿掉 group 與 other 的 w(2)x(1) 權限，因此權限就成為『檔案 -rw-r--r-- ， 目錄 drwxr--r-- 』而當 umask 044 時，則拿掉 r 的屬性，因此就成為『檔案 -rw--w--w-，目錄 drwx-wx-wx』

- 什麼是 SUID ？

當一個指令具有 SUID 的功能時，則：

- SUID 權限僅對二進位程式(binary program)有效；

- 執行者對於該程式需要具有 x 的可執行權限；

- 本權限僅在執行該程式的過程中有效 (run-time)；

- 執行者將具有該程式擁有者 (owner) 的權限。

- 當我要查詢 /usr/bin/passwd 這個檔案的一些屬性時(1)傳統權限；(2)檔案類型與(3)檔案的隱藏屬性，可以使用什麼指令來查詢？

ls -al

file

lsattr

- 嘗試用 find 找出目前 linux 系統中，所有具有 SUID 的檔案有哪些？

find / -perm +4000 -print

- 找出 /etc 底下，檔案大小介於 50K 到 60K 之間的檔案，並且將權限完整的列出 (ls -l)：

find /etc -size +50k -a -size -60k -exec ls -l {} \;

注意到 -a ，那個 -a 是 and 的意思，為符合兩者才算成功

- 找出 /etc 底下，檔案容量大於 50K 且檔案所屬人不是 root 的檔名，且將權限完整的列出 (ls -l)；

find /etc -size +50k -a ! -user root -exec ls -ld {} \;

find /etc -size +50k -a ! -user root -type f -exec ls -l {} \;

上面兩式均可！注意到 ! ，那個 ! 代表的是反向選擇，亦即『不是後面的項目』之意！

- 找出 /etc 底下，容量大於 1500K 以及容量等於 0 的檔案：

find /etc -size +1500k -o -size 0

相對於 -a ，那個 -o 就是或 (or) 的意思囉！

參考資料與延伸閱讀

- 小洲大大回答 SUID/SGID 的一篇討論：

http://phorum.vbird.org/viewtopic.php?t=20256

2002/06/26：第一次完成 2003/02/06：重新編排與加入 FAQ

2003/02/07：加入 basename 與 dirname 的說明

2004/03/15：將連結檔的內容移動至下一章節：Linux 磁碟與硬體管理

2005/07/19：將舊的文章移動到 這裡 了。

2005/07/20：呼呼！好不容易啊∼在被颱風尾掃到的七月份，終於寫完這個咚咚∼

2005/07/21：在 find 部分，多增加了範例九，以及關於利用檔案大小 (size) 搜尋的功能。

2005/07/25：在 SUID/SGID/SBIT 部分，依據 netman 與 小州 兄的建議，修改了部分的敘述！

2006/04/09：在 rmdir 的範例內，少了一個 -p 的參數！

2006/06/15：經由討論區網友 dm421 的通知，發現 chattr 的部分關於 d 寫錯了，已訂正。

2006/08/22：增加 rm 的一些簡單的說明！尤其是『 rm ./-aaa- 』的刪除方法！

2008/09/23：將針對FC4版寫的資料移到此處

2008/09/29：加入權限與指令的關係一節，並新增情境模擬題目喔！大家幫忙除錯一下！

2009/08/18：加入符號法的方式來處理 SUID/SGID/SBIT 囉！

2009/08/26：感謝網友告知習題部分，找出 /etc 底下容量大於 50k 的那題，應使用 -type f 或 ls -ld 來避免目錄內重複顯示！

2002/03/13以來統計人數

第十四章、Linux 帳號管理與 ACL 權限設定

切換解析度為 800x600

最近更新日期：2009/09/09

要登入 Linux 系統一定要有帳號與密碼才行，否則怎麼登入，您說是吧？不過， 不同的使用者應該要擁有不同的權限才行吧？我們還可以透過 user/group 的特殊權限設定， 來規範出不同的群組開發專案呢∼在 Linux 的環境下，我們可以透過很多方式來限制使用者能夠使用的系統資源， 包括 十一章、bash 提到的 ulimit 限制、還有特殊權限限制，如 umask 等等。 透過這些舉動，我們可以規範出不同使用者的使用資源。另外，還記得系統管理員的帳號嗎？對！ 就是 root 。請問一下，除了 root 之外，是否可以有其他的系統管理員帳號？ 為什麼大家都要盡量避免使用數字型態的帳號？如何修改使用者相關的資訊呢？這些我們都得要瞭解瞭解的！

1. Linux 的帳號與群組

1.1 使用者識別碼： UID 與 GID

1.2 使用者帳號：/etc/passwd 檔案結構, /etc/shadow 檔案結構

1.3 關於群組： /etc/group 檔案結構, 有效與初始群組, groups, newgrp, /etc/gshadow

2. 帳號管理

2.1 新增與移除使用者： useradd, useradd 參考檔, passwd, chage, usermod, userdel

2.2 使用者功能：finger, chfn, chsh, id

2.3 新增與移除群組：groupadd, groupmod, groupdel, gpasswd 群組管理員

2.4 帳號管理實例

3. 主機的細部權限規劃：ACL 的使用

3.1 什麼是 ACL

3.2 如何啟動 ACL

3.3 ACL 的設定技巧： setfacl, getfacl, ACL 的設定(user, group mask, default)

4. 使用者身份切換

4.1 su

4.2 sudo： sudo 指令, visudo (/etc/sudoers) ( 帳號, 群組, 限制指令, 別名, 時間間隔, 配合 su )

5. 使用者的特殊 shell 與 PAM 模組

5.1 特殊的 shell :/sbin/nologin, nologin.txt

5.2 PAM 模組簡介

5.3 PAM 模組設定語法：驗證類別(type)、控制標準(flag)、模組與參數

5.4 常用模組簡介： securetty, nologin, pam_cracklib, login流程

5.5 其他相關檔案： limits.conf,

6. Linux 主機上的使用者訊息傳遞

6.1 查詢使用者： w, who, last, lastlog

6.2 使用者對談： write, mesg, wall

6.3 使用者郵件信箱： mail

7. 手動新增使用者

7.1 一些檢查工具：pwck, pwconv, pwunconv, chpasswd

7.2 特殊帳號，如純數字帳號的手工建立

7.3 大量建置帳號範本(適用 passwd --stdin 選項)

7.4 大量建置帳號的範例(適用於連續數字，如學號)

8. 重點回顧

9. 本章習題

10. 參考資料與延伸閱讀

11. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23887

Linux 的帳號與群組

管理員的工作中，相當重要的一環就是『管理帳號』啦！因為整個系統都是你在管理的， 並且所有一般用戶的帳號申請，都必須要透過你的協助才行！所以你就必須要瞭解一下如何管理好一個伺服器主機的帳號啦！ 在管理 Linux 主機的帳號時，我們必須先來瞭解一下 Linux 到底是如何辨別每一個使用者的！

使用者識別碼： UID 與 GID

雖然我們登入 Linux 主機的時候，輸入的是我們的帳號，但是其實 Linux 主機並不會直接認識你的『帳號名稱』的，他僅認識 ID 啊 (ID 就是一組號碼啦)。 由於電腦僅認識 0 與 1，所以主機對於數字比較有概念的；至於帳號只是為了讓人們容易記憶而已。 而你的 ID 與帳號的對應就在 /etc/passwd 當中哩。

Tips:

如果你曾經在網路上下載過 tarball 類型的檔案， 那麼應該不難發現，在解壓縮之後的檔案中，檔案擁有者的欄位竟然顯示『不明的數字』？奇怪吧？這沒什麼好奇怪的，因為 Linux 說實在話，他真的只認識代表你身份的號碼而已！

那麼到底有幾種 ID 呢？還記得我們在第六章內有提到過， 每一個檔案都具有『擁有人與擁有群組』的屬性嗎？沒錯啦∼每個登入的使用者至少都會取得兩個 ID ，一個是使用者 ID (User ID ，簡稱 UID)、一個是群組 ID (Group ID ，簡稱 GID)。

那麼檔案如何判別他的擁有者與群組呢？其實就是利用 UID 與 GID 啦！每一個檔案都會有所謂的擁有者 ID 與擁有群組 ID ，當我們有要顯示檔案屬性的需求時，系統會依據 /etc/passwd 與 /etc/group 的內容， 找到 UID / GID 對應的帳號與群組名稱再顯示出來！我們可以作個小實驗，你可以用 root 的身份 vi /etc/passwd ，然後將你的一般身份的使用者的 ID 隨便改一個號碼，然後再到你的一般身份的目錄下看看原先該帳號擁有的檔案，你會發現該檔案的擁有人變成了 『數字了』呵呵！這樣可以理解了嗎？來看看底下的例子：

# 1. 先察看一下，系統裡面有沒有一個名為 dmtsai 的用戶？

[root@www ~]# grep 'dmtsai' /etc/passwd

dmtsai:x:503:504::/home/dmtsai:/bin/bash   <==是有這個帳號喔！

[root@www ~]# ll -d /home/dmtsai

drwx------ 4 dmtsai dmtsai 4096 Feb  6 18:25 /home/dmtsai

# 瞧一瞧，使用者的欄位正是 dmtsai 本身喔！

# 2. 修改一下，將剛剛我們的 dmtsai 的 503 UID 改為 2000 看看：

[root@www ~]# vi /etc/passwd

....(前面省略)....

dmtsai:x:2000:504::/home/dmtsai:/bin/bash <==修改一下特殊字體部分，由 503 改過來

[root@www ~]# ll -d /home/dmtsai

drwx------ 4 503 dmtsai 4096 Feb  6 18:25 /home/dmtsai

# 很害怕吧！怎麼變成 503 了？因為檔案只會記錄數字而已！

# 因為我們亂改，所以導致 503 找不到對應的帳號，因此顯示數字！

# 3. 記得將剛剛的 2000 改回來！

[root@www ~]# vi /etc/passwd

....(前面省略)....

dmtsai:x:503:504::/home/dmtsai:/bin/bash <==趕緊改回來！

你一定要瞭解的是，上面的例子僅是在說明 UID 與帳號的對應性，在一部正常運作的 Linux 主機環境下，上面的動作不可隨便進行， 這是因為系統上已經有很多的資料被建立存在了，隨意修改系統上某些帳號的 UID 很可能會導致某些程序無法進行，這將導致系統無法順利運作的結果。 因為權限的問題啊！所以，瞭解了之後，請趕快回到 /etc/passwd 裡面，將數字改回來喔！

Tips:

舉例來說，如果上面的測試最後一個步驟沒有將 2000 改回原本的 UID，那麼當 dmtsai 下次登入時將沒有辦法進入自己的家目錄！ 因為他的 UID 已經改為 2000 ，但是他的家目錄 (/home/dmtsai) 卻記錄的是 503 ，由於權限是 700 ， 因此他將無法進入原本的家目錄！是否非常嚴重啊？

使用者帳號

Linux 系統上面的使用者如果需要登入主機以取得 shell 的環境來工作時，他需要如何進行呢？ 首先，他必須要在電腦前面利用 tty1~tty7 的終端機提供的 login 介面，並輸入帳號與密碼後才能夠登入。 如果是透過網路的話，那至少使用者就得要學習 ssh 這個功能了 (伺服器篇再來談)。 那麼你輸入帳號密碼後，系統幫你處理了什麼呢？

1. 先找尋 /etc/passwd 裡面是否有你輸入的帳號？如果沒有則跳出，如果有的話則將該帳號對應的 UID 與 GID (在 /etc/group 中) 讀出來，另外，該帳號的家目錄與 shell 設定也一併讀出；

2. 再來則是核對密碼表啦！這時 Linux 會進入 /etc/shadow 裡面找出對應的帳號與 UID，然後核對一下你剛剛輸入的密碼與裡頭的密碼是否相符？

3. 如果一切都 OK 的話，就進入 Shell 控管的階段囉！

大致上的情況就像這樣，所以當你要登入你的 Linux 主機的時候，那個 /etc/passwd 與 /etc/shadow 就必須要讓系統讀取啦 (這也是很多攻擊者會將特殊帳號寫到 /etc/passwd 裡頭去的緣故)，所以呢，如果你要備份 Linux 的系統的帳號的話，那麼這兩個檔案就一定需要備份才行呦！

由上面的流程我們也知道，跟使用者帳號有關的有兩個非常重要的檔案，一個是管理使用者 UID/GID 重要參數的 /etc/passwd ，一個則是專門管理密碼相關資料的 /etc/shadow 囉！那這兩個檔案的內容就非常值得進行研究啦！ 底下我們會簡單的介紹這兩個檔案，詳細的說明可以參考 man 5 passwd 及 man 5 shadow (註1)。

- /etc/passwd 檔案結構

這個檔案的構造是這樣的：每一行都代表一個帳號，有幾行就代表有幾個帳號在你的系統中！ 不過需要特別留意的是，裡頭很多帳號本來就是系統正常運作所必須要的，我們可以簡稱他為系統帳號， 例如 bin, daemon, adm, nobody 等等，這些帳號請不要隨意的殺掉他呢！ 這個檔案的內容有點像這樣：

Tips:

鳥哥在接觸 Linux 之前曾經碰過 Solaris 系統 (1999 年)，當時鳥哥啥也不清楚！由於『聽說』Linux 上面的帳號越複雜會導致系統越危險！所以鳥哥就將 /etc/passwd 上面的帳號全部刪除到只剩下 root 與鳥哥自己用的一般帳號！結果你猜發生什麼事？那就是....呼叫昇陽的工程師來維護系統 @_@！糗到一個不行！大家不要學啊！

[root@www ~]# head -n 4 /etc/passwd

root:x:0:0:root:/root:/bin/bash  <==等一下做為底下說明用

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

我們先來看一下每個 Linux 系統都會有的第一行，就是 root 這個系統管理員那一行好了， 你可以明顯的看出來，每一行使用『:』分隔開，共有七個咚咚，分別是：

1. 帳號名稱：

就是帳號啦！用來對應 UID 的。例如 root 的 UID 對應就是 0 (第三欄位)；

2. 密碼：

早期 Unix 系統的密碼就是放在這欄位上！但是因為這個檔案的特性是所有的程序都能夠讀取，這樣一來很容易造成密碼資料被竊取， 因此後來就將這個欄位的密碼資料給他改放到 /etc/shadow 中了。所以這裡你會看到一個『 x 』，呵呵！

3. UID：

這個就是使用者識別碼囉！通常 Linux 對於 UID 有幾個限制需要說給您瞭解一下：

id 範圍

該 ID 使用者特性

0

(系統管理員)

當 UID 是 0 時，代表這個帳號是『系統管理員』！ 所以當你要讓其他的帳號名稱也具有 root 的權限時，將該帳號的 UID 改為 0 即可。 這也就是說，一部系統上面的系統管理員不見得只有 root 喔！ 不過，很不建議有多個帳號的 UID 是 0 啦∼

1~499

(系統帳號)

保留給系統使用的 ID，其實除了 0 之外，其他的 UID 權限與特性並沒有不一樣。預設 500 以下的數字讓給系統作為保留帳號只是一個習慣。

由於系統上面啟動的服務希望使用較小的權限去運作，因此不希望使用 root 的身份去執行這些服務， 所以我們就得要提供這些運作中程式的擁有者帳號才行。這些系統帳號通常是不可登入的， 所以才會有我們在第十一章提到的 /sbin/nologin 這個特殊的 shell 存在。

根據系統帳號的由來，通常系統帳號又約略被區分為兩種：

1~99：由 distributions 自行建立的系統帳號；

100~499：若使用者有系統帳號需求時，可以使用的帳號 UID。

500~65535

(可登入帳號)

給一般使用者用的。事實上，目前的 linux 核心 (2.6.x 版)已經可以支援到 4294967295 (2^32-1) 這麼大的 UID 號碼喔！

1. 上面這樣說明可以瞭解了嗎？是的， UID 為 0 的時候，就是 root 呦！所以請特別留意一下你的 /etc/passwd 檔案！

2. GID：

這個與 /etc/group 有關！其實 /etc/group 的觀念與 /etc/passwd 差不多，只是他是用來規範群組名稱與 GID 的對應而已！

3. 使用者資訊說明欄：

這個欄位基本上並沒有什麼重要用途，只是用來解釋這個帳號的意義而已！不過，如果您提供使用 finger 的功能時， 這個欄位可以提供很多的訊息呢！本章後面的 chfn 指令會來解釋這裡的說明。

4. 家目錄：

這是使用者的家目錄，以上面為例， root 的家目錄在 /root ，所以當 root 登入之後，就會立刻跑到 /root 目錄裡頭啦！呵呵！ 如果你有個帳號的使用空間特別的大，你想要將該帳號的家目錄移動到其他的硬碟去該怎麼作？ 沒有錯！可以在這個欄位進行修改呦！預設的使用者家目錄在 /home/yourIDname

5. Shell：

我們在第十一章 BASH 提到很多次，當使用者登入系統後就會取得一個 Shell 來與系統的核心溝通以進行使用者的操作任務。那為何預設 shell 會使用 bash 呢？就是在這個欄位指定的囉！ 這裡比較需要注意的是，有一個 shell 可以用來替代成讓帳號無法取得 shell 環境的登入動作！那就是 /sbin/nologin 這個東西！這也可以用來製作純 pop 郵件帳號者的資料呢！

- /etc/shadow 檔案結構

我們知道很多程式的運作都與權限有關，而權限與 UID/GID 有關！因此各程式當然需要讀取 /etc/passwd 來瞭解不同帳號的權限。 因此 /etc/passwd 的權限需設定為 -rw-r--r-- 這樣的情況， 雖然早期的密碼也有加密過，但卻放置到 /etc/passwd 的第二個欄位上！這樣一來很容易被有心人士所竊取的， 加密過的密碼也能夠透過暴力破解法去 try and error (試誤) 找出來！

因為這樣的關係，所以後來發展出將密碼移動到 /etc/shadow 這個檔案分隔開來的技術， 而且還加入很多的密碼限制參數在 /etc/shadow 裡頭呢！在這裡，我們先來瞭解一下這個檔案的構造吧！ 鳥哥的 /etc/shadow 檔案有點像這樣：

[root@www ~]# head -n 4 /etc/shadow

root:$1$/30QpE5e$y9N/D0bh6rAACBEz.hqo00:14126:0:99999:7:::  <==底下說明用

bin:*:14126:0:99999:7:::

daemon:*:14126:0:99999:7:::

adm:*:14126:0:99999:7:::

基本上， shadow 同樣以『:』作為分隔符號，如果數一數，會發現共有九個欄位啊，這九個欄位的用途是這樣的：

1. 帳號名稱：

由於密碼也需要與帳號對應啊∼因此，這個檔案的第一欄就是帳號，必須要與 /etc/passwd 相同才行！

2. 密碼：

這個欄位內的資料才是真正的密碼，而且是經過編碼的密碼 (加密) 啦！ 你只會看到有一些特殊符號的字母就是了！需要特別留意的是，雖然這些加密過的密碼很難被解出來， 但是『很難』不等於『不會』，所以，這個檔案的預設權限是『-rw-------』或者是『-r--------』，亦即只有 root 才可以讀寫就是了！你得隨時注意，不要不小心更動了這個檔案的權限呢！

另外，由於各種密碼編碼的技術不一樣，因此不同的編碼系統會造成這個欄位的長度不相同。 舉例來說，舊式的 DES 編碼系統產生的密碼長度就與目前慣用的 MD5 不同(註2)！MD5 的密碼長度明顯的比較長些。由於固定的編碼系統產生的密碼長度必須一致，因此『當你讓這個欄位的長度改變後，該密碼就會失效(算不出來)』。 很多軟體透過這個功能，在此欄位前加上 ! 或 * 改變密碼欄位長度，就會讓密碼『暫時失效』了。

3. 最近更動密碼的日期：

這個欄位記錄了『更動密碼那一天』的日期，不過，很奇怪呀！在我的例子中怎麼會是 14126 呢？呵呵，這個是因為計算 Linux 日期的時間是以 1970 年 1 月 1 日作為 1 而累加的日期，1971 年 1 月 1 日則為 366 啦！ 得注意一下這個資料呦！上述的 14126 指的就是 2008-09-04 那一天啦！瞭解乎？ 而想要瞭解該日期可以使用本章後面 chage 指令的幫忙！至於想要知道某個日期的累積日數， 可使用如下的程式計算：

[root@www ~]# echo $(($(date --date="2008/09/04" +%s)/86400+1))

14126

上述指令中，2008/09/04 為你想要計算的日期，86400 為每一天的秒數， %s 為 1970/01/01 以來的累積總秒數。 由於 bash 僅支援整數，因此最終需要加上 1 補齊 1970/01/01 當天。

1. 密碼不可被更動的天數：(與第 3 欄位相比)

第四個欄位記錄了：這個帳號的密碼在最近一次被更改後需要經過幾天才可以再被變更！如果是 0 的話， 表示密碼隨時可以更動的意思。這的限制是為了怕密碼被某些人一改再改而設計的！如果設定為 20 天的話，那麼當你設定了密碼之後， 20 天之內都無法改變這個密碼呦！

2. 密碼需要重新變更的天數：(與第 3 欄位相比)

經常變更密碼是個好習慣！為了強制要求使用者變更密碼，這個欄位可以指定在最近一次更改密碼後， 在多少天數內需要再次的變更密碼才行。你必須要在這個天數內重新設定你的密碼，否則這個帳號的密碼將會『變為過期特性』。 而如果像上面的 99999 (計算為 273 年) 的話，那就表示，呵呵，密碼的變更沒有強制性之意。

3. 密碼需要變更期限前的警告天數：(與第 5 欄位相比)

當帳號的密碼有效期限快要到的時候 (第 5 欄位)，系統會依據這個欄位的設定，發出『警告』言論給這個帳號，提醒他『再過 n 天你的密碼就要過期了，請盡快重新設定你的密碼呦！』，如上面的例子，則是密碼到期之前的 7 天之內，系統會警告該用戶。

4. 密碼過期後的帳號寬限時間(密碼失效日)：(與第 5 欄位相比)

密碼有效日期為『更新日期(第3欄位)』+『重新變更日期(第5欄位)』，過了該期限後使用者依舊沒有更新密碼，那該密碼就算過期了。 雖然密碼過期但是該帳號還是可以用來進行其他工作的，包括登入系統取得 bash 。不過如果密碼過期了， 那當你登入系統時，系統會強制要求你必須要重新設定密碼才能登入繼續使用喔，這就是密碼過期特性。

那這個欄位的功能是什麼呢？是在密碼過期幾天後，如果使用者還是沒有登入更改密碼，那麼這個帳號的密碼將會『失效』， 亦即該帳號再也無法使用該密碼登入了。要注意密碼過期與密碼失效並不相同。

5. 帳號失效日期：

這個日期跟第三個欄位一樣，都是使用 1970 年以來的總日數設定。這個欄位表示： 這個帳號在此欄位規定的日期之後，將無法再使用。 就是所謂的『帳號失效』，此時不論你的密碼是否有過期，這個『帳號』都不能再被使用！ 這個欄位會被使用通常應該是在『收費服務』的系統中，你可以規定一個日期讓該帳號不能再使用啦！

6. 保留：

最後一個欄位是保留的，看以後有沒有新功能加入。

舉個例子來說好了，假如我的 dmtsai 這個使用者的密碼欄如下所示：

dmtsai:$1$vyUuj.eX$omt6lKJvMcIZHx4H7RI1V.:14299:5:60:7:5:14419:

這表示什麼呢？先要注意的是 14299 是 2009/02/24 。所以 dmtsai 這個使用者的密碼相關意義是：

- 由於密碼幾乎僅能單向運算(由明碼計算成為密碼，無法由密碼反推回明碼)，因此由上表的資料我們無法得知 dmstai 的實際密碼明文；

- 此帳號最近一次更動密碼的日期是 2009/02/24 (14299)；

- 能夠再次修改密碼的時間是 5 天以後，也就是 2009/03/01 以前 dmtsai 不能修改自己的密碼；如果使用者還是嘗試要更動自己的密碼，系統就會出現這樣的訊息：

You must wait longer to change your password

passwd: Authentication token manipulation error

畫面中告訴我們：你必須要等待更久的時間才能夠變更密碼之意啦！

- 由於密碼過期日期定義為 60 天後，亦即累積日數為： 14299+60=14359，經過計算得到此日數代表日期為 2009/04/25。 這表示：『使用者必須要在 2009/03/01 到 2009/04/25 之間的 60 天限制內去修改自己的密碼，若 2009/04/25 之後還是沒有變更密碼時，該密碼就宣告為過期』了！

- 警告日期設為 7 天，亦即是密碼過期日前的 7 天，在本例中則代表 2009/04/19 ~ 2009/04/25 這七天。 如果使用者一直沒有更改密碼，那麼在這 7 天中，只要 dmtsai 登入系統就會發現如下的訊息：

Warning: your password will expire in 5 days

- 如果該帳號一直到 2009/04/25 都沒有更改密碼，那麼密碼就過期了。但是由於有 5 天的寬限天數， 因此 dmtsai 在 2009/04/30 前都還可以使用舊密碼登入主機。 不過登入時會出現強制更改密碼的情況，畫面有點像底下這樣：

You are required to change your password immediately (password aged)

WARNING: Your password has expired.

You must change your password now and login again!

Changing password for user dmtsai.

Changing password for dmtsai

(current) UNIX password:

你必須要輸入一次舊密碼以及兩次新密碼後，才能夠開始使用系統的各項資源。如果你是在 2009/04/30 以後嘗試以 dmtsai 登入的話，那麼就會出現如下的錯誤訊息且無法登入，因為此時你的密碼就失效去啦！

Your account has expired; please contact your system administrator

- 如果使用者在 2009/04/25 以前變更過密碼，那麼第 3 個欄位的那個 14299 的天數就會跟著改變，因此， 所有的限制日期也會跟著相對變動喔！^_^

- 無論使用者如何動作，到了 14419 (大約是 2009/07/24 左右) 該帳號就失效了∼

透過這樣的說明，您應該會比較容易理解了吧？由於 shadow 有這樣的重要性，因此可不能隨意修改喔！ 但在某些情況底下你得要使用各種方法來處理這個檔案的！舉例來說，常常聽到人家說：『我的密碼忘記了』， 或者是『我的密碼不曉得被誰改過，跟原先的不一樣了』，這個時候怎麼辦？

- 一般用戶的密碼忘記了：這個最容易解決，請系統管理員幫忙， 他會重新設定好你的密碼而不需要知道你的舊密碼！利用 root 的身份使用 passwd 指令來處理即可。

- root 密碼忘記了：這就麻煩了！因為你無法使用 root 的身份登入了嘛！ 但我們知道 root 的密碼在 /etc/shadow 當中，因此你可以使用各種可行的方法開機進入 Linux 再去修改。 例如重新開機進入單人維護模式(第二十章)後，系統會主動的給予 root 權限的 bash 介面， 此時再以 passwd 修改密碼即可；或以 Live CD 開機後掛載根目錄去修改 /etc/shadow，將裡面的 root 的密碼欄位清空， 再重新開機後 root 將不用密碼即可登入！登入後再趕快以 passwd 指令去設定 root 密碼即可。

Tips:

曾經聽過一則笑話，某位老師主要是在教授 Linux 作業系統，但是他是兼任的老師，因此對於該系的電腦環境不熟。 由於當初安裝該電腦教室 Linux 作業系統的人員已經離職且找不到聯絡方式了，也就是說 root 密碼已經沒有人曉得了！ 此時該老師就對學生說：『在 Linux 裡面 root 密碼不見了，我們只能重新安裝』...感覺有點無力∼ 又是個被 Windows 制約的人才！

關於群組： 有效與初始群組、groups, newgrp

認識了帳號相關的兩個檔案 /etc/passwd 與 /etc/shadow 之後，你或許還是會覺得奇怪， 那麼群組的設定檔在哪裡？還有，在 /etc/passwd 的第四欄不是所謂的 GID 嗎？那又是啥？ 呵呵∼此時就需要瞭解 /etc/group 與 /etc/gshadow 囉∼

- /etc/group 檔案結構

這個檔案就是在記錄 GID 與群組名稱的對應了∼鳥哥測試機的 /etc/group 內容有點像這樣：

[root@www ~]# head -n 4 /etc/group

root:x:0:root

bin:x:1:root,bin,daemon

daemon:x:2:root,bin,daemon

sys:x:3:root,bin,adm

這個檔案每一行代表一個群組，也是以冒號『:』作為欄位的分隔符號，共分為四欄，每一欄位的意義是：

1. 群組名稱：

就是群組名稱啦！

2. 群組密碼：

通常不需要設定，這個設定通常是給『群組管理員』使用的，目前很少有這個機會設定群組管理員啦！ 同樣的，密碼已經移動到 /etc/gshadow 去，因此這個欄位只會存在一個『x』而已；

3. GID：

就是群組的 ID 啊。我們 /etc/passwd 第四個欄位使用的 GID 對應的群組名，就是由這裡對應出來的！

4. 此群組支援的帳號名稱：

我們知道一個帳號可以加入多個群組，那某個帳號想要加入此群組時，將該帳號填入這個欄位即可。 舉例來說，如果我想要讓 dmtsai 也加入 root 這個群組，那麼在第一行的最後面加上『,dmtsai』，注意不要有空格， 使成為『 root:x:0:root,dmtsai 』就可以囉∼

談完了 /etc/passwd, /etc/shadow, /etc/group 之後，我們可以使用一個簡單的圖示來瞭解一下 UID / GID 與密碼之間的關係， 圖示如下。其實重點是 /etc/passwd 啦，其他相關的資料都是根據這個檔案的欄位去找尋出來的。 下圖中， root 的 UID 是 0 ，而 GID 也是 0 ，去找 /etc/group 可以知道 GID 為 0 時的群組名稱就是 root 哩。 至於密碼的尋找中，會找到 /etc/shadow 與 /etc/passwd 內同帳號名稱的那一行，就是密碼相關資料囉。

圖 1.3.1 、帳號相關檔案之間的 UID/GID 與密碼相關性示意圖

至於在 /etc/group 比較重要的特色在於第四欄啦，因為每個使用者都可以擁有多個支援的群組，這就好比在學校唸書的時候， 我們可以加入多個社團一樣！ ^_^。不過這裡你或許會覺得奇怪的，那就是：『假如我同時加入多個群組，那麼我在作業的時候，到底是以那個群組為準？』 底下我們就來談一談這個『有效群組』的概念。

- 有效群組(effective group)與初始群組(initial group)

還記得每個使用者在他的 /etc/passwd 裡面的第四欄有所謂的 GID 吧？那個 GID 就是所謂的『初始群組 (initial group) 』！也就是說，當使用者一登入系統，立刻就擁有這個群組的相關權限的意思。 舉例來說，我們上面提到 dmtsai 這個使用者的 /etc/passwd 與 /etc/group 還有 /etc/gshadow 相關的內容如下：

[root@www ~]# usermod -G users dmtsai  <==先設定好次要群組

[root@www ~]# grep dmtsai /etc/passwd /etc/group /etc/gshadow

/etc/passwd:dmtsai:x:503:504::/home/dmtsai:/bin/bash

/etc/group:users:x:100:dmtsai  <==次要群組的設定

/etc/group:dmtsai:x:504:       <==因為是初始群組，所以第四欄位不需要填入帳號

/etc/gshadow:users:::dmtsai    <==次要群組的設定

/etc/gshadow:dmtsai:!::

仔細看到上面這個表格，在 /etc/passwd 裡面，dmtsai 這個使用者所屬的群組為 GID=504 ，搜尋一下 /etc/group 得到 504 是那個名為 dmtsai 的群組啦！這就是 initial group。因為是初始群組， 使用者一登入就會主動取得，不需要在 /etc/group 的第四個欄位寫入該帳號的！

但是非 initial group 的其他群組可就不同了。舉上面這個例子來說，我將 dmtsai 加入 users 這個群組當中，由於 users 這個群組並非是 dmtsai 的初始群組，因此， 我必須要在 /etc/group 這個檔案中，找到 users 那一行，並且將 dmtsai 這個帳號加入第四欄， 這樣 dmtsai 才能夠加入 users 這個群組啊。

那麼在這個例子當中，因為我的 dmtsai 帳號同時支援 dmtsai 與 users 這兩個群組， 因此，在讀取/寫入/執行檔案時，針對群組部分，只要是 users 與 dmtsai 這兩個群組擁有的功能， 我 dmtsai 這個使用者都能夠擁有喔！這樣瞭呼？不過，這是針對已經存在的檔案而言， 如果今天我要建立一個新的檔案或者是新的目錄，請問一下，新檔案的群組是 dmtsai 還是 users ？呵呵！這就得要檢查一下當時的有效群組了 (effective group)。

- groups: 有效與支援群組的觀察

如果我以 dmtsai 這個使用者的身份登入後，該如何知道我所有支援的群組呢？ 很簡單啊，直接輸入 groups 就可以了！注意喔，是 groups 有加 s 呢！結果像這樣：

[dmtsai@www ~]$ groups

dmtsai users

在這個輸出的訊息中，可知道 dmtsai 這個用戶同時屬於 dmtsai 及 users 這個兩個群組，而且， 第一個輸出的群組即為有效群組 (effective group) 了。 也就是說，我的有效群組為 dmtsai 啦∼此時，如果我以 touch 去建立一個新檔，例如： 『 touch test 』，那麼這個檔案的擁有者為 dmtsai ，而且群組也是 dmtsai 的啦。

[dmtsai@www ~]$ touch test

[dmtsai@www ~]$ ll

-rw-rw-r-- 1 dmtsai dmtsai 0 Feb 24 17:26 test

這樣是否可以瞭解什麼是有效群組了？通常有效群組的作用是在新建檔案啦！那麼有效群組是否能夠變換？

- newgrp: 有效群組的切換

那麼如何變更有效群組呢？就使用 newgrp 啊！不過使用 newgrp 是有限制的，那就是你想要切換的群組必須是你已經有支援的群組。舉例來說， dmtsai 可以在 dmtsai/users 這兩個群組間切換有效群組，但是 dmtsai 無法切換有效群組成為 sshd 啦！使用的方式如下：

[dmtsai@www ~]$ newgrp users

[dmtsai@www ~]$ groups

users dmtsai

[dmtsai@www ~]$ touch test2

[dmtsai@www ~]$ ll

-rw-rw-r-- 1 dmtsai dmtsai 0 Feb 24 17:26 test

-rw-r--r-- 1 dmtsai users  0 Feb 24 17:33 test2

此時，dmtsai 的有效群組就成為 users 了。 我們額外的來討論一下 newgrp 這個指令，這個指令可以變更目前使用者的有效群組， 而且是另外以一個 shell 來提供這個功能的喔，所以，以上面的例子來說， dmtsai 這個使用者目前是以另一個 shell 登入的，而且新的 shell 給予 dmtsai 有效 GID 為 users 就是了。如果以圖示來看就是如下所示：

圖 1.3.2 、newgrp 的運作示意圖

雖然使用者的環境設定(例如環境變數等等其他資料)不會有影響，但是使用者的『群組權限』將會重新被計算。 但是需要注意，由於是新取得一個 shell ，因此如果你想要回到原本的環境中，請輸入 exit 回到原本的 shell 喔！

既然如此，也就是說，只要我的用戶有支援的群組就是能夠切換成為有效群組！好了， 那麼如何讓一個帳號加入不同的群組就是問題的所在囉。你要加入一個群組有兩個方式，一個是透過系統管理員 (root) 利用 usermod 幫你加入，如果 root 太忙了而且你的系統有設定群組管理員，那麼你可以透過群組管理員以 gpasswd 幫你加入他所管理的群組中！詳細的作法留待下一小節再來介紹囉！

- /etc/gshadow

剛剛講了很多關於『有效群組』的概念，另外，也提到 newgrp 這個指令的用法， 但是，如果 /etc/gshadow 這個設定沒有搞懂得話，那麼 newgrp 是無法動作的呢！ 鳥哥測試機的 /etc/gshadow 的內容有點像這樣：

[root@www ~]# head -n 4 /etc/gshadow

root:::root

bin:::root,bin,daemon

daemon:::root,bin,daemon

sys:::root,bin,adm

這個檔案內同樣還是使用冒號『:』來作為欄位的分隔字元，而且你會發現，這個檔案幾乎與 /etc/group 一模一樣啊！是這樣沒錯∼不過，要注意的大概就是第二個欄位吧∼第二個欄位是密碼欄， 如果密碼欄上面是『!』時，表示該群組不具有群組管理員！至於第四個欄位也就是支援的帳號名稱囉∼ 這四個欄位的意義為：

1. 群組名稱

2. 密碼欄，同樣的，開頭為 ! 表示無合法密碼，所以無群組管理員

3. 群組管理員的帳號 (相關資訊在 gpasswd 中介紹)

4. 該群組的所屬帳號 (與 /etc/group 內容相同！)

以系統管理員的角度來說，這個 gshadow 最大的功能就是建立群組管理員啦！ 那麼什麼是群組管理員呢？由於系統上面的帳號可能會很多，但是我們 root 可能平時太忙碌，所以當有使用者想要加入某些群組時， root 或許會沒有空管理。此時如果能夠建立群組管理員的話，那麼該群組管理員就能夠將那個帳號加入自己管理的群組中！ 可以免去 root 的忙碌啦！不過，由於目前有類似 sudo 之類的工具， 所以這個群組管理員的功能已經很少使用了。我們會在後續的 gpasswd 中介紹這個實作。

帳號管理

好啦！既然要管理帳號，當然是由新增與移除使用者開始的囉∼底下我們就分別來談一談如何新增、 移除與更改使用者的相關資訊吧∼

新增與移除使用者： useradd, 相關設定檔, passwd, usermod, userdel

要如何在 Linux 的系統新增一個使用者啊？呵呵∼真是太簡單了∼我們登入系統時會輸入 (1)帳號與 (2)密碼， 所以建立一個可用的帳號同樣的也需要這兩個資料。那帳號可以使用 useradd 來新建使用者，密碼的給予則使用 passwd 這個指令！這兩個指令下達方法如下：

- useradd

[root@www ~]# useradd [-u UID] [-g 初始群組] [-G 次要群組] [-mM]\

>  [-c 說明欄] [-d 家目錄絕對路徑] [-s shell] 使用者帳號名

選項與參數：

-u  ：後面接的是 UID ，是一組數字。直接指定一個特定的 UID 給這個帳號；

-g  ：後面接的那個群組名稱就是我們上面提到的 initial group 啦∼

該群組的 GID 會被放置到 /etc/passwd 的第四個欄位內。

-G  ：後面接的群組名稱則是這個帳號還可以加入的群組。

這個選項與參數會修改 /etc/group 內的相關資料喔！

-M  ：強制！不要建立使用者家目錄！(系統帳號預設值)

-m  ：強制！要建立使用者家目錄！(一般帳號預設值)

-c  ：這個就是 /etc/passwd 的第五欄的說明內容啦∼可以隨便我們設定的啦∼

-d  ：指定某個目錄成為家目錄，而不要使用預設值。務必使用絕對路徑！

-r  ：建立一個系統的帳號，這個帳號的 UID 會有限制 (參考 /etc/login.defs)

-s  ：後面接一個 shell ，若沒有指定則預設是 /bin/bash 的啦∼

-e  ：後面接一個日期，格式為『YYYY-MM-DD』此項目可寫入 shadow 第八欄位，

亦即帳號失效日的設定項目囉；

-f  ：後面接 shadow 的第七欄位項目，指定密碼是否會失效。0為立刻失效，

-1 為永遠不失效(密碼只會過期而強制於登入時重新設定而已。)

範例一：完全參考預設值建立一個使用者，名稱為 vbird1

[root@www ~]# useradd vbird1

[root@www ~]# ll -d /home/vbird1

drwx------ 4 vbird1 vbird1 4096 Feb 25 09:38 /home/vbird1

# 預設會建立使用者家目錄，且權限為 700 ！這是重點！

[root@www ~]# grep vbird1 /etc/passwd /etc/shadow /etc/group

/etc/passwd:vbird1:x:504:505::/home/vbird1:/bin/bash

/etc/shadow:vbird1:!!:14300:0:99999:7:::

/etc/group:vbird1:x:505:    <==預設會建立一個與帳號一模一樣的群組名

其實系統已經幫我們規定好非常多的預設值了，所以我們可以簡單的使用『 useradd 帳號 』來建立使用者即可。 CentOS 這些預設值主要會幫我們處理幾個項目：

- 在 /etc/passwd 裡面建立一行與帳號相關的資料，包括建立 UID/GID/家目錄等；

- 在 /etc/shadow 裡面將此帳號的密碼相關參數填入，但是尚未有密碼；

- 在 /etc/group 裡面加入一個與帳號名稱一模一樣的群組名稱；

- 在 /home 底下建立一個與帳號同名的目錄作為使用者家目錄，且權限為 700

由於在 /etc/shadow 內僅會有密碼參數而不會有加密過的密碼資料，因此我們在建立使用者帳號時， 還需要使用『 passwd 帳號 』來給予密碼才算是完成了使用者建立的流程。如果由於特殊需求而需要改變使用者相關參數時， 就得要透過上述表格中的選項來進行建立了，參考底下的案例：

範例二：假設我已知道我的系統當中有個群組名稱為 users ，且 UID 700 並不存在，

請用 users 為初始群組，以及 uid 為 700 來建立一個名為 vbird2 的帳號

[root@www ~]# useradd -u 700 -g users vbird2

[root@www ~]# ll -d /home/vbird2

drwx------ 4 vbird2 users 4096 Feb 25 09:59 /home/vbird2

[root@www ~]# grep vbird2 /etc/passwd /etc/shadow /etc/group

/etc/passwd:vbird2:x:700:100::/home/vbird2:/bin/bash

/etc/shadow:vbird2:!!:14300:0:99999:7:::

# 看一下，UID 與 initial group 確實改變成我們需要的了！

在這個範例中，我們建立的是指定一個已經存在的群組作為使用者的初始群組，因為群組已經存在， 所以在 /etc/group 裡面就不會主動的建立與帳號同名的群組了！ 此外，我們也指定了特殊的 UID 來作為使用者的專屬 UID 喔！瞭解了一般帳號後，我們來瞧瞧那啥是系統帳號 (system account) 吧！

範例三：建立一個系統帳號，名稱為 vbird3

[root@www ~]# useradd -r vbird3

[root@www ~]# ll -d /home/vbird3

ls: /home/vbird3: No such file or directory  <==不會主動建立家目錄

[root@www ~]# grep vbird3 /etc/passwd /etc/shadow /etc/group

/etc/passwd:vbird3:x:100:103::/home/vbird3:/bin/bash

/etc/shadow:vbird3:!!:14300::::::

/etc/group:vbird3:x:103:

我們在談到 UID 的時候曾經說過一般帳號應該是 500 號以後，那使用者自己建立的系統帳號則一般是由 100 號以後起算的。 所以在這裡我們加上 -r 這個選項以後，系統就會主動將帳號與帳號同名群組的 UID/GID 都指定小於 500 以下， 在本案例中則是使用 100(UID) 與 103(GID) 囉！此外，由於系統帳號主要是用來進行運作系統所需服務的權限設定， 所以系統帳號預設都不會主動建立家目錄的！

由這幾個範例我們也會知道，使用 useradd 建立使用者帳號時，其實會更改不少地方，至少我們就知道底下幾個檔案：

- 使用者帳號與密碼參數方面的檔案：/etc/passwd, /etc/shadow

- 使用者群組相關方面的檔案：/etc/group, /etc/gshadow

- 使用者的家目錄：/home/帳號名稱

那請教一下，你有沒有想過，為何『 useradd vbird1 』會主動在 /home/vbird1 建立起使用者的家目錄？家目錄內有什麼資料且來自哪裡？為何預設使用的是 /bin/bash 這個 shell ？為何密碼欄位已經都規範好了 (0:99999:7 那一串)？呵呵！這就得要說明一下 useradd 所使用的參考檔案囉！

- useradd 參考檔

其實 useradd 的預設值可以使用底下的方法呼叫出來：

[root@www ~]# useradd -D

GROUP=100              <==預設的群組

HOME=/home             <==預設的家目錄所在目錄

INACTIVE=-1            <==密碼失效日，在 shadow 內的第 7 欄

EXPIRE=                <==帳號失效日，在 shadow 內的第 8 欄

SHELL=/bin/bash        <==預設的 shell

SKEL=/etc/skel         <==使用者家目錄的內容資料參考目錄

CREATE_MAIL_SPOOL=yes   <==是否主動幫使用者建立郵件信箱(mailbox)

這個資料其實是由 /etc/default/useradd 呼叫出來的！你可以自行用 vim 去觀察該檔案的內容。搭配上頭剛剛談過的範例一的運作結果，上面這些設定項目所造成的行為分別是：

- GROUP=100：新建帳號的初始群組使用 GID 為 100 者

系統上面 GID 為 100 者即是 users 這個群組，此設定項目指的就是讓新設使用者帳號的初始群組為 users 這一個的意思。 但是我們知道 CentOS 上面並不是這樣的，在 CentOS 上面預設的群組為與帳號名相同的群組。 舉例來說， vbird1 的初始群組為 vbird1 。怎麼會這樣啊？這是因為針對群組的角度有兩種不同的機制所致， 這兩種機制分別是：

- 私有群組機制：系統會建立一個與帳號一樣的群組給使用者作為初始群組。 這種群組的設定機制會比較有保密性，這是因為使用者都有自己的群組，而且家目錄權限將會設定為 700 (僅有自己可進入自己的家目錄) 之故。使用這種機制將不會參考 GROUP=100 這個設定值。代表性的 distributions 有 RHEL, Fedora, CentOS 等；

- 公共群組機制：就是以 GROUP=100 這個設定值作為新建帳號的初始群組，因此每個帳號都屬於 users 這個群組， 且預設家目錄通常的權限會是『 drwxr-xr-x ... username users ... 』，由於每個帳號都屬於 users 群組，因此大家都可以互相分享家目錄內的資料之故。代表 distributions 如 SuSE等。

由於我們的 CentOS 使用私有群組機制，因此這個設定項目是不會生效的！不要太緊張啊！

- HOME=/home：使用者家目錄的基準目錄(basedir)

使用者的家目錄通常是與帳號同名的目錄，這個目錄將會擺放在此設定值的目錄後。所以 vbird1 的家目錄就會在 /home/vbird1/ 了！很容易理解吧！

- INACTIVE=-1：密碼過期後是否會失效的設定值

我們在 shadow 檔案結構當中談過，第七個欄位的設定值將會影響到密碼過期後， 在多久時間內還可使用舊密碼登入。這個項目就是在指定該日數啦！如果是 0 代表密碼過期立刻失效， 如果是 -1 則是代表密碼永遠不會失效，如果是數字，如 30 ，則代表過期 30 天後才失效。

- EXPIRE=：帳號失效的日期

就是 shadow 內的第八欄位，你可以直接設定帳號在哪個日期後就直接失效，而不理會密碼的問題。 通常不會設定此項目，但如果是付費的會員制系統，或許這個欄位可以設定喔！

- SHELL=/bin/bash：預設使用的 shell 程式檔名

系統預設的 shell 就寫在這裡。假如你的系統為 mail server ，你希望每個帳號都只能使用 email 的收發信件功能， 而不許使用者登入系統取得 shell ，那麼可以將這裡設定為 /sbin/nologin ，如此一來，新建的使用者預設就無法登入！ 也免去後續使用 usermod 進行修改的手續！

- SKEL=/etc/skel：使用者家目錄參考基準目錄

這個咚咚就是指定使用者家目錄的參考基準目錄囉∼舉我們的範例一為例， vbird1 家目錄 /home/vbird1 內的各項資料，都是由 /etc/skel 所複製過去的∼所以呢，未來如果我想要讓新增使用者時，該使用者的環境變數 ~/.bashrc 就設定妥當的話，您可以到 /etc/skel/.bashrc 去編輯一下，也可以建立 /etc/skel/www 這個目錄，那麼未來新增使用者後，在他的家目錄下就會有 www 那個目錄了！這樣瞭呼？

- CREATE_MAIL_SPOOL=yes：建立使用者的 mailbox

你可以使用『 ll /var/spool/mail/vbird1 』看一下，會發現有這個檔案的存在喔！這就是使用者的郵件信箱！

除了這些基本的帳號設定值之外， UID/GID 還有密碼參數又是在哪裡參考的呢？那就得要看一下 /etc/login.defs 啦！ 這個檔案的內容有點像底下這樣：

MAIL_DIR        /var/spool/mail       <==使用者預設郵件信箱放置目錄

PASS_MAX_DAYS   99999  <==/etc/shadow 內的第 5 欄，多久需變更密碼日數

PASS_MIN_DAYS   0      <==/etc/shadow 內的第 4 欄，多久不可重新設定密碼日數

PASS_MIN_LEN    5      <==密碼最短的字元長度，已被 pam 模組取代，失去效用！

PASS_WARN_AGE   7      <==/etc/shadow 內的第 6 欄，過期前會警告的日數

UID_MIN         500    <==使用者最小的 UID，意即小於 500 的 UID 為系統保留

UID_MAX       60000    <==使用者能夠用的最大 UID

GID_MIN         500    <==使用者自訂群組的最小 GID，小於 500 為系統保留

GID_MAX       60000    <==使用者自訂群組的最大 GID

CREATE_HOME     yes    <==在不加 -M 及 -m 時，是否主動建立使用者家目錄？

UMASK           077     <==使用者家目錄建立的 umask ，因此權限會是 700

USERGROUPS_ENAB yes     <==使用 userdel 刪除時，是否會刪除初始群組

MD5_CRYPT_ENAB yes      <==密碼是否經過 MD5 的加密機制處理

這個檔案規範的資料則是如下所示：

- mailbox 所在目錄：

使用者的預設 mailbox 檔案放置的目錄在 /var/spool/mail，所以 vbird1 的 mailbox 就是在 /var/spool/mail/vbird1 囉！

- shadow 密碼第 4, 5, 6 欄位內容：

透過 PASS_MAX_DAYS 等等設定值來指定的！所以你知道為何預設的 /etc/shadow 內每一行都會有『 0:99999:7 』的存在了嗎？^_^！不過要注意的是，由於目前我們登入時改用 PAM 模組來進行密碼檢驗，所以那個 PASS_MIN_LEN 是失效的！

- UID/GID 指定數值：

雖然 Linux 核心支援的帳號可高達 2^32 這麼多個，不過一部主機要作出這麼多帳號在管理上也是很麻煩的！ 所以在這裡就針對 UID/GID 的範圍進行規範就是了。上表中的 UID_MIN 指的就是可登入系統的一般帳號的最小 UID ，至於 UID_MAX 則是最大 UID 之意。

要注意的是，系統給予一個帳號 UID 時，他是 (1)先參考 UID_MIN 設定值取得最小數值； (2)由 /etc/passwd 搜尋最大的 UID 數值， 將 (1) 與 (2) 相比，找出最大的那個再加一就是新帳號的 UID 了。我們上面已經作出 UID 為 700 的 vbird2 ， 如果再使用『 useradd vbird4 』時，你猜 vbird4 的 UID 會是多少？答案是： 701 。 所以中間的 505~699 的號碼就空下來啦！

而如果我是想要建立系統用的帳號，所以使用 useradd -r sysaccount 這個 -r 的選項時，就會找『比 500 小的最大的那個 UID + 1 』就是了。 ^_^

- 使用者家目錄設定值：

為何我們系統預設會幫使用者建立家目錄？就是這個『CREATE_HOME = yes』的設定值啦！這個設定值會讓你在使用 useradd 時， 主動加入『 -m 』這個產生家目錄的選項啊！如果不想要建立使用者家目錄，就只能強制加上『 -M 』的選項在 useradd 指令執行時啦！至於建立家目錄的權限設定呢？就透過 umask 這個設定值啊！因為是 077 的預設設定，因此使用者家目錄預設權限才會是『 drwx------ 』哩！

- 使用者刪除與密碼設定值：

使用『USERGROUPS_ENAB yes』這個設定值的功能是： 如果使用 userdel 去刪除一個帳號時，且該帳號所屬的初始群組已經沒有人隸屬於該群組了， 那麼就刪除掉該群組，舉例來說，我們剛剛有建立 vbird4 這個帳號，他會主動建立 vbird4 這個群組。 若 vbird4 這個群組並沒有其他帳號將他加入支援的情況下，若使用 userdel vbird4 時，該群組也會被刪除的意思。 至於『MD5_CRYPT_ENAB yes』則表示使用 MD5 來加密密碼明文，而不使用舊式的 DES(註2) 。

現在你知道啦，使用 useradd 這支程式在建立 Linux 上的帳號時，至少會參考：

- /etc/default/useradd

- /etc/login.defs

- /etc/skel/*

這些檔案，不過，最重要的其實是建立 /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow 還有使用者家目錄就是了∼所以，如果你瞭解整個系統運作的狀態，也是可以手動直接修改這幾個檔案就是了。 OK！帳號建立了，接下來處理一下使用者的密碼吧！

- passwd

剛剛我們講到了，使用 useradd 建立了帳號之後，在預設的情況下，該帳號是暫時被封鎖的， 也就是說，該帳號是無法登入的，你可以去瞧一瞧 /etc/shadow 內的第二個欄位就曉得囉∼ 那該如何是好？怕什麼？直接給他設定新密碼就好了嘛！對吧∼設定密碼就使用 passwd 囉！

[root@www ~]# passwd [--stdin]  <==所有人均可使用來改自己的密碼

[root@www ~]# passwd [-l] [-u] [--stdin] [-S] \

>  [-n 日數] [-x 日數] [-w 日數] [-i 日期] 帳號 <==root 功能

選項與參數：

--stdin ：可以透過來自前一個管線的資料，作為密碼輸入，對 shell script 有幫助！

-l  ：是 Lock 的意思，會將 /etc/shadow 第二欄最前面加上 ! 使密碼失效；

-u  ：與 -l 相對，是 Unlock 的意思！

-S  ：列出密碼相關參數，亦即 shadow 檔案內的大部分資訊。

-n  ：後面接天數，shadow 的第 4 欄位，多久不可修改密碼天數

-x  ：後面接天數，shadow 的第 5 欄位，多久內必須要更動密碼

-w  ：後面接天數，shadow 的第 6 欄位，密碼過期前的警告天數

-i  ：後面接『日期』，shadow 的第 7 欄位，密碼失效日期

範例一：請 root 給予 vbird2 密碼

[root@www ~]# passwd vbird2

Changing password for user vbird2.

New UNIX password: <==這裡直接輸入新的密碼，螢幕不會有任何反應

BAD PASSWORD: it is WAY too short <==密碼太簡單或過短的錯誤！

Retype new UNIX password:  <==再輸入一次同樣的密碼

passwd: all authentication tokens updated successfully.  <==竟然還是成功修改了！

root 果然是最偉大的人物！當我們要給予使用者密碼時，透過 root 來設定即可。 root 可以設定各式各樣的密碼，系統幾乎一定會接受！所以您瞧瞧，如同上面的範例一，明明鳥哥輸入的密碼太短了， 但是系統依舊可接受 vbird2 這樣的密碼設定。這個是 root 幫忙設定的結果，那如果是使用者自己要改密碼呢？ 包括 root 也是這樣修改的喔！

範例二：用 vbird2 登入後，修改 vbird2 自己的密碼

[vbird2@www ~]$ passwd   <==後面沒有加帳號，就是改自己的密碼！

Changing password for user vbird2.

Changing password for vbird2

(current) UNIX password: <==這裡輸入『原有的舊密碼』

New UNIX password: <==這裡輸入新密碼

BAD PASSWORD: it is based on a dictionary word <==密碼檢驗不通過，請再想個新密碼

New UNIX password: <==這裡再想個來輸入吧

Retype new UNIX password: <==通過密碼驗證！所以重複這個密碼的輸入

passwd: all authentication tokens updated successfully. <==有無成功看關鍵字

passwd 的使用真的要很注意，尤其是 root 先生啊！鳥哥在課堂上每次講到這裡，說是要幫自己的一般帳號建立密碼時， 有一小部分的學生就是會忘記加上帳號，結果就變成改變 root 自己的密碼，最後.... root 密碼就這樣不見去！唉∼ 要幫一般帳號建立密碼需要使用『 passwd 帳號 』的格式，使用『 passwd 』表示修改自己的密碼！拜託！千萬不要改錯！

與 root 不同的是，一般帳號在更改密碼時需要先輸入自己的舊密碼 (亦即 current 那一行)，然後再輸入新密碼 (New 那一行)。 要注意的是，密碼的規範是非常嚴格的，尤其新的 distributions 大多使用 PAM 模組來進行密碼的檢驗，包括太短、 密碼與帳號相同、密碼為字典常見字串等，都會被 PAM 模組檢查出來而拒絕修改密碼，此時會再重複出現『 New 』這個關鍵字！ 那時請再想個新密碼！若出現『 Retype 』才是你的密碼被接受了！重複輸入新密碼並且看到『 successfully 』這個關鍵字時才是修改密碼成功喔！

Tips:

與一般使用者不同的是， root 並不需要知道舊密碼就能夠幫使用者或 root 自己建立新密碼！ 但如此一來有困擾∼就是如果你的親密愛人老是告訴你『我的密碼真難記，幫我設定簡單一點的！』時， 千萬不要妥協啊！這是為了系統安全...

為何使用者要設訂自己的密碼會這麼麻煩啊？這是因為密碼的安全性啦！如果密碼設定太簡單， 一些有心人士就能夠很簡單的猜到你的密碼，如此一來人家就可能使用你的一般帳號登入你的主機或使用其他主機資源， 對主機的維護會造成困擾的！所以新的 distributions 是使用較嚴格的 PAM 模組來管理密碼，這個管理的機制寫在 /etc/pam.d/passwd 當中。而該檔案與密碼有關的測試模組就是使用：pam_cracklib.so，這個模組會檢驗密碼相關的資訊， 並且取代 /etc/login.defs 內的 PASS_MIN_LEN 的設定啦！關於 PAM 我們在本章後面繼續介紹，這裡先談一下， 理論上，你的密碼最好符合如下要求：

- 密碼不能與帳號相同；

- 密碼盡量不要選用字典裡面會出現的字串；

- 密碼需要超過 8 個字元；

- 密碼不要使用個人資訊，如身份證、手機號碼、其他電話號碼等；

- 密碼不要使用簡單的關係式，如 1+1=2， Iamvbird 等；

- 密碼盡量使用大小寫字元、數字、特殊字元($,_,-等)的組合。

為了方便系統管理，新版的 passwd 還加入了很多創意選項喔！鳥哥個人認為最好用的大概就是這個『 --stdin 』了！ 舉例來說，你想要幫 vbird2 變更密碼成為 abc543CC ，可以這樣下達指令呢！

範例三：使用 standard input 建立用戶的密碼

[root@www ~]# echo "abc543CC" | passwd --stdin vbird2

Changing password for user vbird2.

passwd: all authentication tokens updated successfully.

這個動作會直接更新使用者的密碼而不用再次的手動輸入！好處是方便處理，缺點是這個密碼會保留在指令中， 未來若系統被攻破，人家可以在 /root/.bash_history 找到這個密碼呢！所以這個動作通常僅用在 shell script 的大量建立使用者帳號當中！要注意的是，這個選項並不存在所有 distributions 版本中， 請使用 man passwd 確認你的 distribution 是否有支援此選項喔！

如果你想要讓 vbird2 的密碼具有相當的規則，舉例來說你要讓 vbird2 每 60 天需要變更密碼， 密碼過期後 10 天未使用就宣告帳號失效，那該如何處理？

範例四：管理 vbird2 的密碼使具有 60 天變更、密碼過期 10 天後帳號失效的設定

[root@www ~]# passwd -S vbird2

vbird2 PS 2009-02-26 0 99999 7 -1 (Password set, MD5 crypt.)

# 上面說明密碼建立時間 (2009-02-26)、0 最小天數、99999 變更天數、7 警告日數

# 與密碼不會失效 (-1) 。

[root@www ~]# passwd -x 60 -i 10 vbird2

[root@www ~]# passwd -S vbird2

vbird2 PS 2009-02-26 0 60 7 10 (Password set, MD5 crypt.)

那如果我想要讓某個帳號暫時無法使用密碼登入主機呢？舉例來說， vbird2 這傢伙最近老是胡亂在主機亂來， 所以我想要暫時讓她無法登入的話，最簡單的方法就是讓她的密碼變成不合法 (shadow 第 2 欄位長度變掉)！ 處理的方法就更簡單的！

範例五：讓 vbird2 的帳號失效，觀察完畢後再讓她失效

[root@www ~]# passwd -l vbird2

[root@www ~]# passwd -S vbird2

vbird2 LK 2009-02-26 0 60 7 10 (Password locked.)

# 嘿嘿！狀態變成『 LK, Lock 』了啦！無法登入喔！

[root@www ~]# grep vbird2 /etc/shadow

vbird2:!!$1$50MnwNFq$oChX.0TPanCq7ecE4HYEi.:14301:0:60:7:10::

# 其實只是在這裡加上 !! 而已！

[root@www ~]# passwd -u vbird2

[root@www ~]# grep vbird2 /etc/shadow

vbird2:$1$50MnwNFq$oChX.0TPanCq7ecE4HYEi.:14301:0:60:7:10::

# 密碼欄位恢復正常！

是否很有趣啊！您可以自行管理一下你的帳號的密碼相關參數喔！接下來讓我們用更簡單的方法來查閱密碼參數喔！

- chage

除了使用 passwd -S 之外，有沒有更詳細的密碼參數顯示功能呢？有的！那就是 chage 了！ 他的用法如下：

[root@www ~]# chage [-ldEImMW] 帳號名

選項與參數：

-l ：列出該帳號的詳細密碼參數；

-d ：後面接日期，修改 shadow 第三欄位(最近一次更改密碼的日期)，格式 YYYY-MM-DD

-E ：後面接日期，修改 shadow 第八欄位(帳號失效日)，格式 YYYY-MM-DD

-I ：後面接天數，修改 shadow 第七欄位(密碼失效日期)

-m ：後面接天數，修改 shadow 第四欄位(密碼最短保留天數)

-M ：後面接天數，修改 shadow 第五欄位(密碼多久需要進行變更)

-W ：後面接天數，修改 shadow 第六欄位(密碼過期前警告日期)

範例一：列出 vbird2 的詳細密碼參數

[root@www ~]# chage -l vbird2

Last password change                               : Feb 26, 2009

Password expires                                   : Apr 27, 2009

Password inactive                                  : May 07, 2009

Account expires                                    : never

Minimum number of days between password change     : 0

Maximum number of days between password change     : 60

Number of days of warning before password expires  : 7

我們在 passwd 的介紹中談到了處理 vbird2 這個帳號的密碼屬性流程，使用 passwd -S 卻無法看到很清楚的說明。如果使用 chage 那可就明白多了！如上表所示，我們可以清楚的知道 vbird2 的詳細參數呢！ 如果想要修改其他的設定值，就自己參考上面的選項，或者自行 man chage 一下吧！^_^

chage 有一個功能很不錯喔！如果你想要讓『使用者在第一次登入時， 強制她們一定要更改密碼後才能夠使用系統資源』，可以利用如下的方法來處理的！

範例二：建立一個名為 agetest 的帳號，該帳號第一次登入後使用預設密碼，

但必須要更改過密碼後，使用新密碼才能夠登入系統使用 bash 環境

[root@www ~]# useradd agetest

[root@www ~]# echo "agetest" | passwd --stdin agetest

[root@www ~]# chage -d 0 agetest

# 此時此帳號的密碼建立時間會被改為 1970/1/1 ，所以會有問題！

範例三：嘗試以 agetest 登入的情況

You are required to change your password immediately (root enforced)

WARNING: Your password has expired.

You must change your password now and login again!

Changing password for user agetest.

Changing password for agetest

(current) UNIX password:  <==這個帳號被強制要求必須要改密碼！

非常有趣吧！你會發現 agetest 這個帳號在第一次登入時可以使用與帳號同名的密碼登入， 但登入時就會被要求立刻更改密碼，更改密碼完成後就會被踢出系統。再次登入時就能夠使用新密碼登入了！ 這個功能對學校老師非常有幫助！因為我們不想要知道學生的密碼，那麼在初次上課時就使用與學號相同的帳號/密碼給學生， 讓她們登入時自行設定她們的密碼，如此一來就能夠避免其他同學隨意使用別人的帳號，也能夠保證學生知道如何更改自己的密碼！

- usermod

所謂這『人有失手，馬有亂蹄』，您說是吧？所以囉，當然有的時候會『不小心』在 useradd 的時候加入了錯誤的設定資料。或者是，在使用 useradd 後，發現某些地方還可以進行細部修改。 此時，當然我們可以直接到 /etc/passwd 或 /etc/shadow 去修改相對應欄位的資料， 不過，Linux 也有提供相關的指令讓大家來進行帳號相關資料的微調呢∼那就是 usermod 囉∼

[root@www ~]# usermod [-cdegGlsuLU] username

選項與參數：

-c  ：後面接帳號的說明，即 /etc/passwd 第五欄的說明欄，可以加入一些帳號的說明。

-d  ：後面接帳號的家目錄，即修改 /etc/passwd 的第六欄；

-e  ：後面接日期，格式是 YYYY-MM-DD 也就是在 /etc/shadow 內的第八個欄位資料啦！

-f  ：後面接天數，為 shadow 的第七欄位。

-g  ：後面接初始群組，修改 /etc/passwd 的第四個欄位，亦即是 GID 的欄位！

-G  ：後面接次要群組，修改這個使用者能夠支援的群組，修改的是 /etc/group 囉∼

-a  ：與 -G 合用，可『增加次要群組的支援』而非『設定』喔！

-l  ：後面接帳號名稱。亦即是修改帳號名稱， /etc/passwd 的第一欄！

-s  ：後面接 Shell 的實際檔案，例如 /bin/bash 或 /bin/csh 等等。

-u  ：後面接 UID 數字啦！即 /etc/passwd 第三欄的資料；

-L  ：暫時將使用者的密碼凍結，讓他無法登入。其實僅改 /etc/shadow 的密碼欄。

-U  ：將 /etc/shadow 密碼欄的 ! 拿掉，解凍啦！

如果你仔細的比對，會發現 usermod 的選項與 useradd 非常類似！ 這是因為 usermod 也是用來微調 useradd 增加的使用者參數嘛！不過 usermod 還是有新增的選項， 那就是 -L 與 -U ，不過這兩個選項其實與 passwd 的 -l, -u 是相同的！而且也不見得會存在所有的 distribution 當中！接下來，讓我們談談一些變更參數的實例吧！

範例一：修改使用者 vbird2 的說明欄，加上『VBird's test』的說明。

[root@www ~]# usermod -c "VBird's test" vbird2

[root@www ~]# grep vbird2 /etc/passwd

vbird2:x:700:100:VBird's test:/home/vbird2:/bin/bash

範例二：使用者 vbird2 這個帳號在 2009/12/31 失效。

[root@www ~]# usermod -e "2009-12-31" vbird2

[root@www ~]# grep vbird2 /etc/shadow

vbird2:$1$50MnwNFq$oChX.0TPanCq7ecE4HYEi.:14301:0:60:7:10:14609:

範例三：我們建立 vbird3 這個系統帳號時並沒有給予家目錄，請建立他的家目錄

[root@www ~]# ll -d ~vbird3

ls: /home/vbird3: No such file or directory  <==確認一下，確實沒有家目錄的存在！

[root@www ~]# cp -a /etc/skel /home/vbird3

[root@www ~]# chown -R vbird3:vbird3 /home/vbird3

[root@www ~]# chmod 700 /home/vbird3

[root@www ~]# ll -a ~vbird3

drwx------  4 vbird3 vbird3 4096 Sep  4 18:15 .  <==使用者家目錄權限

drwxr-xr-x 11 root   root   4096 Feb 26 11:45 ..

-rw-r--r--  1 vbird3 vbird3   33 May 25  2008 .bash_logout

-rw-r--r--  1 vbird3 vbird3  176 May 25  2008 .bash_profile

-rw-r--r--  1 vbird3 vbird3  124 May 25  2008 .bashrc

drwxr-xr-x  3 vbird3 vbird3 4096 Sep  4 18:11 .kde

drwxr-xr-x  4 vbird3 vbird3 4096 Sep  4 18:15 .mozilla

# 使用 chown -R 是為了連同家目錄底下的使用者/群組屬性都一起變更的意思；

# 使用 chmod 沒有 -R ，是因為我們僅要修改目錄的權限而非內部檔案的權限！

- userdel

這個功能就太簡單了，目的在刪除使用者的相關資料，而使用者的資料有：

- 使用者帳號/密碼相關參數：/etc/passwd, /etc/shadow

- 使用者群組相關參數：/etc/group, /etc/gshadow

- 使用者個人檔案資料： /home/username, /var/spool/mail/username..

整個指令的語法非常簡單：

[root@www ~]# userdel [-r] username

選項與參數：

-r  ：連同使用者的家目錄也一起刪除

範例一：刪除 vbird2 ，連同家目錄一起刪除

[root@www ~]# userdel -r vbird2

這個指令下達的時候要小心了！通常我們要移除一個帳號的時候，你可以手動的將 /etc/passwd 與 /etc/shadow 裡頭的該帳號取消即可！一般而言，如果該帳號只是『暫時不啟用』的話，那麼將 /etc/shadow 裡頭帳號失效日期 (第八欄位) 設定為 0 就可以讓該帳號無法使用，但是所有跟該帳號相關的資料都會留下來！ 使用 userdel 的時機通常是『你真的確定不要讓該用戶在主機上面使用任何資料了！』

另外，其實使用者如果在系統上面操作過一陣子了，那麼該使用者其實在系統內可能會含有其他檔案的。 舉例來說，他的郵件信箱 (mailbox) 或者是例行性工作排程 (crontab, 十六章) 之類的檔案。 所以，如果想要完整的將某個帳號完整的移除，最好可以在下達 userdel -r username 之前， 先以『 find / -user username 』查出整個系統內屬於 username 的檔案，然後再加以刪除吧！

使用者功能

不論是 useradd/usermod/userdel ，那都是系統管理員所能夠使用的指令， 如果我是一般身份使用者，那麼我是否除了密碼之外，就無法更改其他的資料呢？ 當然不是啦！這裡我們介紹幾個一般身份使用者常用的帳號資料變更與查詢指令囉！

- finger

finger 的中文字面意義是：『手指』或者是『指紋』的意思。這個 finger 可以查閱很多使用者相關的資訊喔！ 大部分都是在 /etc/passwd 這個檔案裡面的資訊啦！我們就先來檢查檢查使用者資訊吧！

[root@www ~]# finger [-s] username

選項與參數：

-s  ：僅列出使用者的帳號、全名、終端機代號與登入時間等等；

-m  ：列出與後面接的帳號相同者，而不是利用部分比對 (包括全名部分)

範例一：觀察 vbird1 的使用者相關帳號屬性

[root@www ~]# finger vbird1

Login: vbird1                           Name: (null)

Directory: /home/vbird1                 Shell: /bin/bash

Never logged in.

No mail.

No Plan.

由於 finger 類似指紋的功能，他會將使用者的相關屬性列出來！如上表所示，其實他列出來的幾乎都是 /etc/passwd 檔案裡面的東西。列出的資訊說明如下：

- Login：為使用者帳號，亦即 /etc/passwd 內的第一欄位；

- Name：為全名，亦即 /etc/passwd 內的第五欄位(或稱為註解)；

- Directory：就是家目錄了；

- Shell：就是使用的 Shell 檔案所在；

- Never logged in.：figner 還會調查使用者登入主機的情況喔！

- No mail.：調查 /var/spool/mail 當中的信箱資料；

- No Plan.：調查 ~vbird1/.plan 檔案，並將該檔案取出來說明！

不過是否能夠查閱到 Mail 與 Plan 則與權限有關了！因為 Mail / Plan 都是與使用者自己的權限設定有關， root 當然可以查閱到使用者的這些資訊，但是 vbird1 就不見得能夠查到 vbird3 的資訊， 因為 /var/spool/mail/vbird3 與 /home/vbird3/ 的權限分別是 660, 700 ，那 vbird1 當然就無法查閱的到！ 這樣解釋可以理解吧？此外，我們可以建立自己想要執行的預定計畫，當然，最多是給自己看的！可以這樣做：

範例二：利用 vbird1 建立自己的計畫檔

[vbird1@www ~]$ echo "I will study Linux during this year." > ~/.plan

[vbird1@www ~]$ finger vbird1

Login: vbird1                           Name: (null)

Directory: /home/vbird1                 Shell: /bin/bash

Never logged in.

No mail.

Plan:

I will study Linux during this year.

範例三：找出目前在系統上面登入的使用者與登入時間

[vbird1@www ~]$ finger

Login     Name       Tty      Idle  Login Time   Office     Office Phone

root      root       tty1           Feb 26 09:53

vbird1               tty2           Feb 26 15:21

在範例三當中，我們發現輸出的資訊還會有 Office, Office Phone 等資訊，那這些資訊要如何記錄呢？ 底下我們會介紹 chfn 這個指令！來看看如何修改使用者的 finger 資料吧！

- chfn

chfn 有點像是： change finger 的意思！這玩意的使用方法如下：

[root@www ~]# chfn [-foph] [帳號名]

選項與參數：

-f  ：後面接完整的大名；

-o  ：您辦公室的房間號碼；

-p  ：辦公室的電話號碼；

-h  ：家裡的電話號碼！

範例一：vbird1 自己更改一下自己的相關資訊！

[vbird1@www ~]$ chfn

Changing finger information for vbird1.

Password:                        <==確認身份，所以輸入自己的密碼

Name []: VBird Tsai test         <==輸入你想要呈現的全名

Office []: Dic in Ksu. Tainan    <==辦公室號碼

Office Phone []: 06-2727175#356  <==辦公室電話

Home Phone []: 06-1234567        <==家裡電話號碼

Finger information changed.

[vbird1@www ~]$ grep vbird1 /etc/passwd

vbird1:x:504:505:VBird Tsai test,Dic in Ksu. Tainan,06-2727175#356,06-1234567:

/home/vbird1:/bin/bash

# 其實就是改到第五個欄位，該欄位裡面用多個『 , 』分隔就是了！

[vbird1@www ~]$ finger vbird1

Login: vbird1                           Name: VBird Tsai test

Directory: /home/vbird1                 Shell: /bin/bash

Office: Dic in Ksu. Tainan              Office Phone: 06-2727175#356

Home Phone: 06-1234567

On since Thu Feb 26 15:21 (CST) on tty2

No mail.

Plan:

I will study Linux during this year.

# 就是上面特殊字體呈現的那些地方是由 chfn 所修改出來的！

這個指令說實在的，除非是你的主機有很多的用戶，否則倒真是用不著這個程式！這就有點像是 bbs 裡頭更改你『個人屬性』的那一個資料啦！不過還是可以自己玩一玩！尤其是用來提醒自己相關資料啦！ ^_^

- chsh

這就是 change shell 的簡寫！使用方法就更簡單了！

[vbird1@www ~]$ chsh [-ls]

選項與參數：

-l  ：列出目前系統上面可用的 shell ，其實就是 /etc/shells 的內容！

-s  ：設定修改自己的 Shell 囉

範例一：用 vbird1 的身份列出系統上所有合法的 shell，並且指定 csh 為自己的 shell

[vbird1@www ~]$ chsh -l

/bin/sh

/bin/bash

/sbin/nologin  <==所謂：合法不可登入的 Shell 就是這玩意！

/bin/tcsh

/bin/csh       <==這就是 C shell 啦！

/bin/ksh

# 其實上面的資訊就是我們在 bash 中談到的 /etc/shells 啦！

[vbird1@www ~]$ chsh -s /bin/csh; grep vbird1 /etc/passwd

Changing shell for vbird1.

Password:  <==確認身份，請輸入 vbird1 的密碼

Shell changed.

vbird1:x:504:505:VBird Tsai test,Dic in Ksu. Tainan,06-2727175#356,06-1234567:

/home/vbird1:/bin/csh

[vbird1@www ~]$ chsh -s /bin/bash

# 測試完畢後，立刻改回來！

[vbird1@www ~]$ ll $(which chsh)

-rws--x--x 1 root root 19128 May 25  2008 /usr/bin/chsh

不論是 chfn 與 chsh ，都是能夠讓一般使用者修改 /etc/passwd 這個系統檔的！所以你猜猜，這兩個檔案的權限是什麼？ 一定是 SUID 的功能啦！看到這裡，想到前面！ 這就是 Linux 的學習方法∼ ^_^

- id

id 這個指令則可以查詢某人或自己的相關 UID/GID 等等的資訊，他的參數也不少，不過， 都不需要記∼反正使用 id 就全部都列出囉∼ ^_^

[root@www ~]# id [username]

範例一：查閱 root 自己的相關 ID 資訊！

[root@www ~]# id

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),

10(wheel) context=root:system_r:unconfined_t:SystemLow-SystemHigh

# 上面資訊其實是同一行的資料！包括會顯示 UID/GID 以及支援的所有群組！

# 至於後面那個 context=... 則是 SELinux 的內容，先不要理會他！

範例二：查閱一下 vbird1 吧∼

[root@www ~]# id vbird1

uid=504(vbird1) gid=505(vbird1) groups=505(vbird1) context=root:system_r:

unconfined_t:SystemLow-SystemHigh

[root@www ~]# id vbird100

id: vbird100: No such user  <== id 這個指令也可以用來判斷系統上面有無某帳號！

新增與移除群組

OK！瞭解了帳號的新增、刪除、更動與查詢後，再來我們可以聊一聊群組的相關內容了。 基本上，群組的內容都與這兩個檔案有關：/etc/group, /etc/gshadow。 群組的內容其實很簡單，都是上面兩個檔案的新增、修改與移除而已， 不過，如果再加上有效群組的概念，那麼 newgrp 與 gpasswd 則不可不知呢！

- groupadd

[root@www ~]# groupadd [-g gid] [-r] 群組名稱

選項與參數：

-g  ：後面接某個特定的 GID ，用來直接給予某個 GID ∼

-r  ：建立系統群組啦！與 /etc/login.defs 內的 GID_MIN 有關。

範例一：新建一個群組，名稱為 group1

[root@www ~]# groupadd group1

[root@www ~]# grep group1 /etc/group /etc/gshadow

/etc/group:group1:x:702:

/etc/gshadow:group1:!::

# 群組的 GID 也是會由 500 以上最大 GID+1 來決定！

曾經有某些版本的教育訓練手冊談到，為了讓使用者的 UID/GID 成對，她們建議新建的與使用者私有群組無關的其他群組時，使用小於 500 以下的 GID 為宜。 也就是說，如果要建立群組的話，最好能夠使用『 groupadd -r 群組名』的方式來建立啦！ 不過，這見仁見智啦！看你自己的抉擇囉！

- groupmod

跟 usermod 類似的，這個指令僅是在進行 group 相關參數的修改而已。

[root@www ~]# groupmod [-g gid] [-n group_name] 群組名

選項與參數：

-g  ：修改既有的 GID 數字；

-n  ：修改既有的群組名稱

範例一：將剛剛上個指令建立的 group1 名稱改為 mygroup ， GID 為 201

[root@www ~]# groupmod -g 201 -n mygroup group1

[root@www ~]# grep mygroup /etc/group /etc/gshadow

/etc/group:mygroup:x:201:

/etc/gshadow:mygroup:!::

不過，還是那句老話，不要隨意的更動 GID ，容易造成系統資源的錯亂喔！

- groupdel

呼呼！ groupdel 自然就是在刪除群組的囉∼用法很簡單：

[root@www ~]# groupdel [groupname]

範例一：將剛剛的 mygroup 刪除！

[root@www ~]# groupdel mygroup

範例二：若要刪除 vbird1 這個群組的話？

[root@www ~]# groupdel vbird1

groupdel: cannot remove user's primary group.

為什麼 mygroup 可以刪除，但是 vbird1 就不能刪除呢？原因很簡單，『有某個帳號 (/etc/passwd) 的 initial group 使用該群組！』 如果查閱一下，你會發現在 /etc/passwd 內的 vbird1 第四欄的 GID 就是 /etc/group 內的 vbird1 那個群組的 GID ，所以囉，當然無法刪除∼否則 vbird1 這個使用者登入系統後， 就會找不到 GID ，那可是會造成很大的困擾的！那麼如果硬要刪除 vbird1 這個群組呢？ 你『必須要確認 /etc/passwd 內的帳號沒有任何人使用該群組作為 initial group 』才行喔！所以，你可以：

- 修改 vbird1 的 GID ，或者是：

- 刪除 vbird1 這個使用者。

- gpasswd：群組管理員功能

如果系統管理員太忙碌了，導致某些帳號想要加入某個專案時找不到人幫忙！這個時候可以建立『群組管理員』喔！ 什麼是群組管理員呢？就是讓某個群組具有一個管理員，這個群組管理員可以管理哪些帳號可以加入/移出該群組！ 那要如何『建立一個群組管理員』呢？就得要透過 gpasswd 囉！

# 關於系統管理員(root)做的動作：

[root@www ~]# gpasswd groupname

[root@www ~]# gpasswd [-A user1,...] [-M user3,...] groupname

[root@www ~]# gpasswd [-rR] groupname

選項與參數：

：若沒有任何參數時，表示給予 groupname 一個密碼(/etc/gshadow)

-A  ：將 groupname 的主控權交由後面的使用者管理(該群組的管理員)

-M  ：將某些帳號加入這個群組當中！

-r  ：將 groupname 的密碼移除

-R  ：讓 groupname 的密碼欄失效

# 關於群組管理員(Group administrator)做的動作：

[someone@www ~]$ gpasswd [-ad] user groupname

選項與參數：

-a  ：將某位使用者加入到 groupname 這個群組當中！

-d  ：將某位使用者移除出 groupname 這個群組當中。

範例一：建立一個新群組，名稱為 testgroup 且群組交由 vbird1 管理：

[root@www ~]# groupadd testgroup  <==先建立群組

[root@www ~]# gpasswd testgroup   <==給這個群組一個密碼吧！

Changing the password for group testgroup

New Password:

Re-enter new password:

# 輸入兩次密碼就對了！

[root@www ~]# gpasswd -A vbird1 testgroup  <==加入群組管理員為 vbird1

[root@www ~]# grep testgroup /etc/group /etc/gshadow

/etc/group:testgroup:x:702:

/etc/gshadow:testgroup:$1$I5ukIY1.$o5fmW.cOsc8.K.FHAFLWg0:vbird1:

# 很有趣吧！此時 vbird1 則擁有 testgroup 的主控權喔！身份有點像板主啦！

範例二：以 vbird1 登入系統，並且讓他加入 vbird1, vbird3 成為 testgroup 成員

[vbird1@www ~]$ id

uid=504(vbird1) gid=505(vbird1) groups=505(vbird1) ....

# 看得出來，vbird1 尚未加入 testgroup 群組喔！

[vbird1@www ~]$ gpasswd -a vbird1 testgroup

[vbird1@www ~]$ gpasswd -a vbird3 testgroup

[vbird1@www ~]$ grep testgroup /etc/group

testgroup:x:702:vbird1,vbird3

很有趣的一個小實驗吧！我們可以讓 testgroup 成為一個可以公開的群組，然後建立起群組管理員， 群組管理員可以有多個。在這個案例中，我將 vbird1 設定為 testgroup 的群組管理員，所以 vbird1 就可以自行增加群組成員囉∼呼呼！然後，該群組成員就能夠使用 newgrp 囉∼

帳號管理實例

帳號管理不是隨意建置幾個帳號就算了！有時候我們需要考量到一部主機上面可能有多個帳號在協同工作！ 舉例來說，在大學任教時，我們學校的專題生是需要分組的，這些同一組的同學間必須要能夠互相修改對方的資料檔案， 但是同時這些同學又需要保留自己的私密資料，因此直接公開家目錄是不適宜的。那該如何是好？ 為此，我們底下提供幾個例子來讓大家思考看看囉：

任務一：單純的完成上頭交代的任務，假設我們需要的帳號資料如下，你該如何實作？

帳號名稱

帳號全名

支援次要群組

是否可登入主機

密碼

myuser1

1st user

mygroup1

可以

password

myuser2

2nd user

mygroup1

可以

password

myuser3

3rd user

無額外支援

不可以

password

處理的方法如下所示：

# 先處理帳號相關屬性的資料：

[root@www ~]# groupadd mygroup1

[root@www ~]# useradd -G mygroup1 -c "1st user" myuser1

[root@www ~]# useradd -G mygroup1 -c "2nd user" myuser2

[root@www ~]# useradd -c "3rd user" -s /sbin/nologin myuser3

# 再處理帳號的密碼相關屬性的資料：

[root@www ~]# echo "password" | passwd --stdin myuser1

[root@www ~]# echo "password" | passwd --stdin myuser2

[root@www ~]# echo "password" | passwd --stdin myuser3

要注意的地方主要有：myuser1 與 myuser2 都有支援次要群組，但該群組不見得會存在，因此需要先手動建立他！ 然後 myuser3 是『不可登入系統』的帳號，因此需要使用 /sbin/nologin 這個 shell 來給予，這樣該帳號就無法登入囉！ 這樣是否理解啊！接下來再來討論比較難一些的環境！如果是專題環境該如何製作？

任務二：我的使用者 pro1, pro2, pro3 是同一個專案計畫的開發人員，我想要讓這三個用戶在同一個目錄底下工作， 但這三個用戶還是擁有自己的家目錄與基本的私有群組。假設我要讓這個專案計畫在 /srv/projecta 目錄下開發， 可以如何進行？

# 1. 假設這三個帳號都尚未建立，可先建立一個名為 projecta 的群組，

#    再讓這三個用戶加入其次要群組的支援即可：

[root@www ~]# groupadd projecta

[root@www ~]# useradd -G projecta -c "projecta user" pro1

[root@www ~]# useradd -G projecta -c "projecta user" pro2

[root@www ~]# useradd -G projecta -c "projecta user" pro3

[root@www ~]# echo "password" | passwd --stdin pro1

[root@www ~]# echo "password" | passwd --stdin pro2

[root@www ~]# echo "password" | passwd --stdin pro3

# 2. 開始建立此專案的開發目錄：

[root@www ~]# mkdir /srv/projecta

[root@www ~]# chgrp projecta /srv/projecta

[root@www ~]# chmod 2770 /srv/projecta

[root@www ~]# ll -d /srv/projecta

drwxrws--- 2 root projecta 4096 Feb 27 11:29 /srv/projecta

由於此專案計畫只能夠給 pro1, pro2, pro3 三個人使用，所以 /srv/projecta 的權限設定一定要正確才行！ 所以該目錄群組一定是 projecta ，但是權限怎麼會是 2770 呢還記得第七章談到的 SGID 吧？為了讓三個使用者能夠互相修改對方的檔案， 這個 SGID 是必須要存在的喔！如果連這裡都能夠理解，嘿嘿！您的帳號管理已經有一定程度的概念囉！ ^_^

但接下來有個困擾的問題發生了！假如任務一的 myuser1 是 projecta 這個專案的助理，他需要這個專案的內容， 但是他『不可以修改』專案目錄內的任何資料！那該如何是好？你或許可以這樣做：

- 將 myuser1 加入 projecta 這個群組的支援，但是這樣會讓 myuser1 具有完整的 /srv/projecta 的使用權限， myuser1 是可以刪除該目錄下的任何資料的！這樣是有問題的；

- 將 /srv/projecta 的權限改為 2775 ，讓 myuser1 可以進入查閱資料。但此時會發生所有其他人均可進入該目錄查閱的困擾！ 這也不是我們要的環境。

真要命！傳統的 Linux 權限無法針對某個個人設定專屬的權限嗎？其實是可以啦！接下來我們就來談談這個功能吧！

主機的細部權限規劃：ACL 的使用

從第六章開始，我們就一直強調 Linux 的權限概念是非常重要的！ 但是傳統的權限僅有三種身份 (owner, group, others) 搭配三種權限 (r,w,x) 而已，並沒有辦法單純的針對某一個使用者或某一個群組來設定特定的權限需求，例如前一小節最後的那個任務！ 此時就得要使用 ACL 這個機制啦！這玩意挺有趣的，底下我們就來談一談：

什麼是 ACL

ACL 是 Access Control List 的縮寫，主要的目的是在提供傳統的 owner,group,others 的 read,write,execute 權限之外的細部權限設定。ACL 可以針對單一使用者，單一檔案或目錄來進行 r,w,x 的權限規範，對於需要特殊權限的使用狀況非常有幫助。

那 ACL 主要可以針對哪些方面來控制權限呢？他主要可以針對幾個項目：

- 使用者 (user)：可以針對使用者來設定權限；

- 群組 (group)：針對群組為對象來設定其權限；

- 預設屬性 (mask)：還可以針對在該目錄下在建立新檔案/目錄時，規範新資料的預設權限；

好了，再來看看如何讓你的檔案系統可以支援 ACL 吧！

如何啟動 ACL

由於 ACL 是傳統的 Unix-like 作業系統權限的額外支援項目，因此要使用 ACL 必須要有檔案系統的支援才行。目前絕大部分的檔案系統都有支援 ACL 的功能，包括 ReiserFS, EXT2/EXT3, JFS, XFS 等等。在我們的 CentOS 5.x 當中，預設使用 Ext3 是啟動 ACL 支援的！至於察看你的檔案系統是否支援 ACL 可以這樣看：

[root@www ~]# mount  <==直接查閱掛載參數的功能

/dev/hda2 on / type ext3 (rw)

/dev/hda3 on /home type ext3 (rw)

# 其他項目鳥哥都將他省略了！假設我們只要看這兩個裝置。但沒有看到 acl 喔！

[root@www ~]# dumpe2fs -h /dev/hda2  <==由 superblock 內容去查詢

....(前面省略)....

Default mount options:    user_xattr acl

....(後面省略)....

由 mount 單純去查閱不見得可以看到實際的項目，由於目前新的 distributions 常常會主動加入某些預設功能， 如上表所示，其實 CentOS 5.x 在預設的情況下 (Default mount options:) 就幫你加入 acl 的支援了！ 那如果你的系統預設不會幫你加上 acl 的支援呢？那你可以這樣做：

[root@www ~]# mount -o remount,acl /

[root@www ~]# mount

/dev/hda2 on / type ext3 (rw,acl)

# 這樣就加入了！但是如果想要每次開機都生效，那就這樣做：

[root@www ~]# vi /etc/fstab

LABEL=/1   /   ext3    defaults,acl    1 1

如果你不確定或者是不會使用 dumpe2fs 觀察你的檔案系統，那麼建議直接將上述的 /etc/fstab 裡面的內容修改一下即可！

ACL 的設定技巧： getfacl, setfacl

好了，讓你的 filesystem 啟動 ACL 支援後，接下來該如何設定與觀察 ACL 呢？ 很簡單，利用這兩個指令就可以了：

- getfacl：取得某個檔案/目錄的 ACL 設定項目；

- setfacl：設定某個目錄/檔案的 ACL 規範。

先讓我們來瞧一瞧 setfacl 如何使用吧！

- setfacl 指令用法

[root@www ~]# setfacl [-bkRd] [{-m|-x} acl參數] 目標檔名

選項與參數：

-m ：設定後續的 acl 參數給檔案使用，不可與 -x 合用；

-x ：刪除後續的 acl 參數，不可與 -m 合用；

-b ：移除所有的 ACL 設定參數；

-k ：移除預設的 ACL 參數，關於所謂的『預設』參數於後續範例中介紹；

-R ：遞迴設定 acl ，亦即包括次目錄都會被設定起來；

-d ：設定『預設 acl 參數』的意思！只對目錄有效，在該目錄新建的資料會引用此預設值

上面談到的是 acl 的選項功能，那麼如何設定 ACL 的特殊權限呢？特殊權限的設定方法有很多， 我們先來談談最常見的，就是針對單一使用者的設定方式：

# 1. 針對特定使用者的方式：

# 設定規範：『 u:[使用者帳號列表]:[rwx] 』，例如針對 vbird1 的權限規範 rx ：

[root@www ~]# touch acl_test1

[root@www ~]# ll acl_test1

-rw-r--r-- 1 root root 0 Feb 27 13:28 acl_test1

[root@www ~]# setfacl -m u:vbird1:rx acl_test1

[root@www ~]# ll acl_test1

-rw-r-xr--+ 1 root root 0 Feb 27 13:28 acl_test1

# 權限部分多了個 + ，且與原本的權限 (644) 看起來差異很大！但要如何查閱呢？

[root@www ~]# setfacl -m u::rwx acl_test1

[root@www ~]# ll acl_test1

-rwxr-xr--+ 1 root root 0 Feb 27 13:28 acl_test1

# 無使用者列表，代表設定該檔案擁有者，所以上面顯示 root 的權限成為 rwx 了！

上述動作為最簡單的 ACL 設定，利用『 u:使用者:權限 』的方式來設定的啦！設定前請加上 -m 這個選項。 如果一個檔案設定了 ACL 參數後，他的權限部分就會多出一個 + 號了！但是此時你看到的權限與實際權限可能就會有點誤差！ 那要如何觀察呢？就透過 getfacl 吧！

- getfacl 指令用法

[root@www ~]# getfacl filename

選項與參數：

getfacl 的選項幾乎與 setfacl 相同！所以鳥哥這裡就免去了選項的說明啊！

# 請列出剛剛我們設定的 acl_test1 的權限內容：

[root@www ~]# getfacl acl_test1

# file: acl_test1   <==說明檔名而已！

# owner: root       <==說明此檔案的擁有者，亦即 ll 看到的第三使用者欄位

# group: root       <==此檔案的所屬群組，亦即 ll 看到的第四群組欄位

user::rwx           <==使用者列表欄是空的，代表檔案擁有者的權限

user:vbird1:r-x     <==針對 vbird1 的權限設定為 rx ，與擁有者並不同！

group::r--          <==針對檔案群組的權限設定僅有 r

mask::r-x           <==此檔案預設的有效權限 (mask)

other::r--          <==其他人擁有的權限囉！

上面的資料非常容易查閱吧？顯示的資料前面加上 # 的，代表這個檔案的預設屬性，包括檔名、檔案擁有者與檔案所屬群組。 底下出現的 user, group, mask, other 則是屬於不同使用者、群組與有效權限(mask)的設定值。 以上面的結果來看，我們剛剛設定的 vbird1 對於這個檔案具有 r 與 x 的權限啦！這樣看的懂嗎？ 如果看的懂的話，接下來讓我們在測試其他類型的 setfacl 設定吧！

# 2. 針對特定群組的方式：

# 設定規範：『 g:[群組列表]:[rwx] 』，例如針對 mygroup1 的權限規範 rx ：

[root@www ~]# setfacl -m g:mygroup1:rx acl_test1

[root@www ~]# getfacl acl_test1

# file: acl_test1

# owner: root

# group: root

user::rwx

user:vbird1:r-x

group::r--

group:mygroup1:r-x  <==這裡就是新增的部分！多了這個群組的權限設定！

mask::r-x

other::r--

基本上，群組與使用者的設定並沒有什麼太大的差異啦！如上表所示，非常容易瞭解意義。不過，你應該會覺得奇怪的是， 那個 mask 是什麼東西啊？其實他有點像是『有效權限』的意思！他的意義是： 使用者或群組所設定的權限必須要存在於 mask 的權限設定範圍內才會生效，此即『有效權限 (effective permission)』 我們舉個例子來看，如下所示：

# 3. 針對有效權限 mask 的設定方式：

# 設定規範：『 m:[rwx] 』，例如針對剛剛的檔案規範為僅有 r ：

[root@www ~]# setfacl -m m:r acl_test1

[root@www ~]# getfacl acl_test1

# file: acl_test1

# owner: root

# group: root

user::rwx

user:vbird1:r-x        #effective:r-- <==vbird1+mask均存在者，僅有 r 而已！

group::r--

group:mygroup1:r-x     #effective:r--

mask::r--

other::r--

您瞧，vbird1 與 mask 的集合發現僅有 r 存在，因此 vbird1 僅具有 r 的權限而已，並不存在 x 權限！這就是 mask 的功能了！我們可以透過使用 mask 來規範最大允許的權限，就能夠避免不小心開放某些權限給其他使用者或群組了。 不過，通常鳥哥都是將 mask 設定為 rwx 啦！然後再分別依據不同的使用者/群組去規範她們的權限就是了。

例題：

將前一小節任務二中 /srv/projecta 這個目錄，讓 myuser1 可以進入查閱，但 myuser1 不具有修改的權力。

答：

由於 myuser1 是獨立的使用者與群組，而 /srv 是附屬於 / 之下的，因此 /srv 已經具有 acl 的功能。 透過如下的設定即可搞定：

# 1. 先測試看看，使用 myuser1 能否進入該目錄？

[myuser1@www ~]$ cd /srv/projecta

-bash: cd: /srv/projecta: Permission denied  <==確實不可進入！

# 2. 開始用 root 的身份來設定一下該目錄的權限吧！

[root@www ~]# setfacl -m u:myuser1:rx /srv/projecta

[root@www ~]# getfacl /srv/projecta

# file: srv/projecta

# owner: root

# group: projecta

user::rwx

user:myuser1:r-x  <==還是要看看有沒有設定成功喔！

group::rwx

mask::rwx

other::---

# 3. 還是得要使用 myuser1 去測試看看結果！

[myuser1@www ~]$ cd /srv/projecta

[myuser1@www projecta]$ ll -a

drwxrws---+ 2 root projecta 4096 Feb 27 11:29 .  <==確實可以查詢檔名

drwxr-xr-x  4 root root     4096 Feb 27 11:29 ..

[myuser1@www projecta]$ touch testing

touch: cannot touch `testing': Permission denied <==確實不可以寫入！

請注意，上述的 1, 3 步驟使用 myuser1 的身份，2步驟才是使用 root 去設定的！

上面的設定我們就完成了之前任務二的後續需求喔！這麼簡單呢！接下來讓我們來測試一下，如果我用 root 或者是 pro1 的身份去 /srv/projecta 增加檔案或目錄時，該檔案或目錄是否能夠具有 ACL 的設定？ 意思就是說，ACL 的權限設定是否能夠被次目錄所『繼承？』先試看看：

[root@www ~]# cd /srv/projecta

[root@www ~]# touch abc1

[root@www ~]# mkdir abc2

[root@www ~]# ll -d abc*

-rw-r--r-- 1 root projecta    0 Feb 27 14:37 abc1

drwxr-sr-x 2 root projecta 4096 Feb 27 14:37 abc2

你可以明顯的發現，權限後面都沒有 + ，代表這個 acl 屬性並沒有繼承喔！如果你想要讓 acl 在目錄底下的資料都有繼承的功能，那就得如下這樣做了！

# 4. 針對預設權限的設定方式：

# 設定規範：『 d:[ug]:使用者列表:[rwx] 』

# 讓 myuser1 在 /srv/projecta 底下一直具有 rx 的預設權限！

[root@www ~]# setfacl -m d:u:myuser1:rx /srv/projecta

[root@www ~]# getfacl /srv/projecta

# file: srv/projecta

# owner: root

# group: projecta

user::rwx

user:myuser1:r-x

group::rwx

mask::rwx

other::---

default:user::rwx

default:user:myuser1:r-x

default:group::rwx

default:mask::rwx

default:other::---

[root@www ~]# cd /srv/projecta

[root@www projecta]# touch zzz1

[root@www projecta]# mkdir zzz2

[root@www projecta]# ll -d zzz*

-rw-rw----+ 1 root projecta    0 Feb 27 14:57 zzz1

drwxrws---+ 2 root projecta 4096 Feb 27 14:57 zzz2

# 看吧！確實有繼承喔！然後我們使用 getfacl 再次確認看看！

[root@www projecta]# getfacl zzz2

# file: zzz2

# owner: root

# group: projecta

user::rwx

user:myuser1:r-x

group::rwx

mask::rwx

other::---

default:user::rwx

default:user:myuser1:r-x

default:group::rwx

default:mask::rwx

default:other::---

透過這個『針對目錄來設定的預設 ACL 權限設定值』的項目，我們可以讓這些屬性繼承到次目錄底下呢！ 非常方便啊！那如果想要讓 ACL 的屬性全部消失又要如何處理？透過『 setfacl -b 檔名 』即可啦！ 太簡單了！鳥哥就不另外介紹了！請自行測試測試吧！

使用者身份切換

什麼？在 Linux 系統當中還要作身份的變換？這是為啥？可能有底下幾個原因啦！

第九章、檔案與檔案系統的壓縮與打包

切換解析度為 800x600

最近更新日期：2009/08/20

在 Linux 底下有相當多的壓縮指令可以運作喔！這些壓縮指令可以讓我們更方便從網路上面下載大型的檔案呢！ 此外，我們知道在 Linux 底下的副檔名是沒有什麼很特殊的意義的，不過，針對這些壓縮指令所做出來的壓縮檔， 為了方便記憶，還是會有一些特殊的命名方式啦！就讓我們來看看吧！

1. 壓縮檔案的用途與技術

2. Linux 系統常見的壓縮指令

2.1 compress

2.2 gzip, zcat

2.3 bzip2, bzcat

3. 打包指令: tar

4. 完整備份工具：dump, restore

5. 光碟寫入工具

5.1 mkisofs：建立映像檔

5.2 cdrecord：光碟燒錄工具

6. 其他常見的壓縮與備份工具

6.1 dd

6.2 cpio

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23882

壓縮檔案的用途與技術

你是否有過文件檔案太大，導致無法以一片軟碟將他複製完成的困擾？ 又，你是否有過，發現一個軟體裡面有好多檔案，這些檔案要將他複製與攜帶都很不方便的問題？ 還有，你是否有過要備份某些重要資料，偏偏這些資料量太大了，耗掉了你很多的磁碟空間呢？ 這個時候，那個好用的『檔案壓縮』技術可就派的上用場了！

因為這些比較大型的檔案透過所謂的檔案壓縮技術之後，可以將他的磁碟使用量降低， 可以達到減低檔案容量的效果，此外，有的壓縮程式還可以進行容量限制， 使一個大型檔案可以分割成為數個小型檔案，以方便軟碟片攜帶呢！

那麼什麼是『檔案壓縮』呢？我們來稍微談一談他的原理好了。目前我們使用的電腦系統中都是使用所謂的 bytes 單位來計量的！不過，事實上，電腦最小的計量單位應該是 bits 才對啊，此外，我們也知道 1 byte = 8 bits 。但是如果今天我們只是記憶一個數字，亦即是 1 這個數字呢？他會如何記錄？假設一個 byte 可以看成底下的模樣：

□□□□□□□□

Tips:

由於 1 byte = 8 bits ，所以每個 byte 當中會有 8 個空格，而每個空格可以是 0, 1 ，這裡僅是做為一個約略的介紹， 更多的詳細資料請參考第零章的計算機概論吧！

由於我們記錄數字是 1 ，考慮電腦所謂的二進位喔，如此一來， 1 會在最右邊佔據 1 個 bit ，而其他的 7 個 bits 將會自動的被填上 0 囉！你看看，其實在這樣的例子中，那 7 個 bits 應該是『空的』才對！不過，為了要滿足目前我們的作業系統資料的存取，所以就會將該資料轉為 byte 的型態來記錄了！而一些聰明的電腦工程師就利用一些複雜的計算方式， 將這些沒有使用到的空間『丟』出來，以讓檔案佔用的空間變小！這就是壓縮的技術啦！

另外一種壓縮技術也很有趣，他是將重複的資料進行統計記錄的。舉例來說，如果你的資料為『111....』共有100個1時， 那麼壓縮技術會記錄為『100個1』而不是真的有100個1的位元存在！這樣也能夠精簡檔案記錄的容量呢！ 非常有趣吧！

簡單的說，你可以將他想成，其實檔案裡面有相當多的『空間』存在，並不是完全填滿的， 而『壓縮』的技術就是將這些『空間』填滿，以讓整個檔案佔用的容量下降！ 不過，這些『壓縮過的檔案』並無法直接被我們的作業系統所使用的，因此， 若要使用這些被壓縮過的檔案資料，則必須將他『還原』回來未壓縮前的模樣， 那就是所謂的『解壓縮』囉！而至於壓縮前與壓縮後的檔案所佔用的磁碟空間大小， 就可以被稱為是『壓縮比』囉！更多的技術文件或許你可以參考一下：

- RFC 1952 文件：http://www.ietf.org/rfc/rfc1952.txt

- 鳥哥站上的備份：http://linux.vbird.org/linux_basic/0240tarcompress/0240tarcompress_gzip.php

這個『壓縮』與『解壓縮』的動作有什麼好處呢？最大的好處就是壓縮過的檔案容量變小了， 所以你的硬碟容量無形之中就可以容納更多的資料。此外，在一些網路資料的傳輸中，也會由於資料量的降低， 好讓網路頻寬可以用來作更多的工作！而不是老是卡在一些大型的檔案傳輸上面呢！目前很多的 WWW 網站也是利用檔案壓縮的技術來進行資料的傳送，好讓網站頻寬的可利用率上升喔！

Tips:

上述的WWW網站壓縮技術蠻有趣的！他讓你網站上面『看的到的資料』在經過網路傳輸時，使用的是『壓縮過的資料』， 等到這些壓縮過的資料到達你的電腦主機時，再進行解壓縮，由於目前的電腦運算速度相當的快速， 因此其實在網頁瀏覽的時候，時間都是花在『資料的傳輸』上面，而不是 CPU 的運算啦！如此一來，由於壓縮過的資料量降低了，自然傳送的速度就會增快不少！

若你是一位軟體工程師，那麼相信你也會喜歡將你自己的軟體壓縮之後提供大家下載來使用， 畢竟沒有人喜歡自己的網站天天都是頻寬滿載的吧？舉個例子來說， Linux 2.6.27.4 完整的核心大小約有 300 MB 左右，而由於核心主要多是 ASCII code 的純文字型態檔案，這種檔案的『多餘空間』最多了。而一個提供下載的壓縮過的 2.6.27.4 核心大約僅有 60MB 左右，差了幾倍呢？你可以自己算一算喔！

Linux 系統常見的壓縮指令：

在Linux的環境中，壓縮檔案的副檔名大多是：『*.tar, *.tar.gz, *.tgz, *.gz, *.Z, *.bz2』，為什麼會有這樣的副檔名呢？不是說 Linux 的副檔名沒有什麼作用嗎？

這是因為 Linux 支援的壓縮指令非常多，且不同的指令所用的壓縮技術並不相同，當然彼此之間可能就無法互通壓縮/解壓縮檔案囉。 所以，當你下載到某個壓縮檔時，自然就需要知道該檔案是由哪種壓縮指令所製作出來的，好用來對照著解壓縮啊！ 也就是說，雖然 Linux 檔案的屬性基本上是與檔名沒有絕對關係的， 但是為了幫助我們人類小小的腦袋瓜子，所以適當的副檔名還是必要的！ 底下我們就列出幾個常見的壓縮檔案副檔名吧：

*.Z         compress 程式壓縮的檔案；

*.gz        gzip 程式壓縮的檔案；

*.bz2       bzip2 程式壓縮的檔案；

*.tar       tar 程式打包的資料，並沒有壓縮過；

*.tar.gz    tar 程式打包的檔案，其中並且經過 gzip 的壓縮

*.tar.bz2   tar 程式打包的檔案，其中並且經過 bzip2 的壓縮

Linux上常見的壓縮指令就是 gzip 與 bzip2 ，至於 compress 已經退流行了。 gzip 是由 GNU 計畫所開發出來的壓縮指令，該指令已經取代了 compress 。 後來 GNU 又開發出 bzip2 這個壓縮比更好的壓縮指令！不過，這些指令通常僅能針對一個檔案來壓縮與解壓縮，如此一來， 每次壓縮與解壓縮都要一大堆檔案，豈不煩人？此時，那個所謂的『打包軟體, tar』就顯的很重要啦！

這個 tar 可以將很多檔案『打包』成為一個檔案！甚至是目錄也可以這麼玩。不過，單純的 tar 功能僅是『打包』而已，亦即是將很多檔案集結成為一個檔案， 事實上，他並沒有提供壓縮的功能，後來，GNU 計畫中，將整個 tar 與壓縮的功能結合在一起，如此一來提供使用者更方便並且更強大的壓縮與打包功能！ 底下我們就來談一談這些在 Linux 底下基本的壓縮指令吧！

compress

compress這個壓縮指令是非常老舊的一款，大概只有在非常舊的 Unix 機器上面還會找到這個軟體。 我們的 CentOS 預設並沒有安裝這個軟體到系統當中，所以想要瞭解這個軟體的使用時，請先安裝 ncompress 這個軟體。 不過，由於 gzip 已經可以解開使用 compress 壓縮的檔案，因此， compress 可以不用學習啦！ 但是，如果你所在的環境還是有老舊的系統，那麼還是得要學一學就是了。好了， 如果你有網路的話，那麼安裝其實很簡單喔！

[root@www ~]# yum install ncompress

base        100% |=========================| 1.1 kB    00:00

updates     100% |=========================|  951 B    00:00

addons      100% |=========================|  951 B    00:00

extras      100% |=========================| 1.1 kB    00:00

Setting up Install Process

Parsing package install arguments

Resolving Dependencies              <==開始分析相依性

--> Running transaction check

---> Package ncompress.i386 0:4.2.4-47 set to be updated

--> Finished Dependency Resolution

Dependencies Resolved

=======================================================

Package       Arch   Version     Repository     Size

=======================================================

Installing:

ncompress     i386   4.2.4-47    base            23 k

Transaction Summary

=======================================================

Install      1 Package(s)  <==最後分析所要安裝的軟體數

Update       0 Package(s)

Remove       0 Package(s)

Total download size: 23 k

Is this ok [y/N]: y    <==這裡請按下 y 來確認安裝

Downloading Packages:

(1/1): ncompress-4.2.4-47 100% |=========================|  23 kB    00:00

warning: rpmts_HdrFromFdno: Header V3 DSA signature: NOKEY, key ID e8562897

Importing GPG key 0xE8562897 "CentOS-5 Key (CentOS 5 Official Signing Key)

<centos-5-key@centos.org>" from http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5

Is this ok [y/N]: y    <==這裡則是與數位簽章有關

Running rpm_check_debug

Running Transaction Test

Finished Transaction Test

Transaction Test Succeeded

Running Transaction

Installing: ncompress          ######################### [1/1]

Installed: ncompress.i386 0:4.2.4-47

Complete!

關於 yum 更詳細的用法我們會在後續的章節介紹，這裡僅是提供一個大概的用法而已。 等你安裝好這個軟體後，接下來讓我們看看如何使用 compress 吧！

[root@www ~]# compress [-rcv] 檔案或目錄  <==這裡是壓縮

[root@www ~]# uncompress 檔案.Z           <==這裡是解壓縮

選項與參數：

-r  ：可以連同目錄下的檔案也同時給予壓縮呢！

-c  ：將壓縮資料輸出成為 standard output (輸出到螢幕)

-v  ：可以秀出壓縮後的檔案資訊以及壓縮過程中的一些檔名變化。

範例一：將 /etc/man.config 複製到 /tmp ，並加以壓縮

[root@www ~]# cd /tmp

[root@www tmp]# cp /etc/man.config .

[root@www tmp]# compress -v man.config

man.config:  -- replaced with man.config.Z Compression: 41.86%

[root@www tmp]# ls -l /etc/man.config /tmp/man*

-rw-r--r-- 1 root root 4617 Jan  6  2007 /etc/man.config   <==原有檔案

-rw-r--r-- 1 root root 2684 Nov 10 17:14 /tmp/man.config.Z <==經過壓縮的檔案！

不知道你有沒有發現，複製到 /tmp 的 man.config 不見了！因為被壓縮成為 man.config.Z 囉 也就是說，在預設的情況中，被 compress 壓縮的原始檔案會不見，而壓縮檔案會被建立起來， 而且副檔名會是 *.Z。仔細看一下，檔案由原本的 4617bytes 降低到 2684bytes左右，確實有減少一點啦！ 那麼如何解壓縮呢？

範例二：將剛剛的壓縮檔解開

[root@www tmp]# uncompress man.config.Z

[root@www tmp]# ll man*

-rw-r--r-- 1 root root 4617 Nov 10 17:14 man.config

解壓縮直接用 uncompress 即可！解壓縮完畢後該檔案就自動的變回來了！不過，那個壓縮檔卻又不存在囉∼ 這樣可以理解用法了嗎？那如果我想要保留原始檔案且又要建立壓縮檔呢？可以使用 -c 的語法！

範例三：將 man.config 壓縮成另外一個檔案來備份

[root@www tmp]# compress -c man.config > man.config.back.Z

[root@www tmp]# ll man*

-rw-r--r-- 1 root root 4617 Nov 10 17:14 man.config

-rw-r--r-- 1 root root 2684 Nov 10 17:24 man.config.back.Z

# 這個 -c 的選項比較有趣！他會將壓縮過程的資料輸出到螢幕上，而不是寫入成為

# *.Z 的壓縮檔。所以，我們可以透過資料流重導向的方法將資料輸出成為另一個檔名。

# 關於資料流重導向，我們會在第十一章 bash 詳細談論的啦！

再次強調，compress 已經很少人在使用了，因為這支程式無法解開 *.gz 的檔案，而 gzip 則可以解開 *.Z 的檔案， 所以，如果你的 distribution 上面沒有 compress 的話，那就不要進行上面的練習囉！ ^_^

gzip, zcat

gzip 可以說是應用度最廣的壓縮指令了！目前 gzip 可以解開 compress, zip 與 gzip 等軟體所壓縮的檔案。 至於 gzip 所建立的壓縮檔為 *.gz 的檔名喔！讓我們來看看這個指令的語法吧：

[root@www ~]# gzip [-cdtv#] 檔名

[root@www ~]# zcat 檔名.gz

選項與參數：

-c  ：將壓縮的資料輸出到螢幕上，可透過資料流重導向來處理；

-d  ：解壓縮的參數；

-t  ：可以用來檢驗一個壓縮檔的一致性∼看看檔案有無錯誤；

-v  ：可以顯示出原檔案/壓縮檔案的壓縮比等資訊；

-#  ：壓縮等級，-1 最快，但是壓縮比最差、-9 最慢，但是壓縮比最好！預設是 -6

範例一：將 /etc/man.config 複製到 /tmp ，並且以 gzip 壓縮

[root@www ~]# cd /tmp

[root@www tmp]# cp /etc/man.config .

[root@www tmp]# gzip -v man.config

man.config:      56.1% -- replaced with man.config.gz

[root@www tmp]# ll /etc/man.config /tmp/man*

-rw-r--r-- 1 root root 4617 Jan  6  2007 /etc/man.config

-rw-r--r-- 1 root root 2684 Nov 10 17:24 /tmp/man.config.back.Z

-rw-r--r-- 1 root root 2057 Nov 10 17:14 /tmp/man.config.gz  <==gzip壓縮比較佳

與 compress 類似的，當你使用 gzip 進行壓縮時，在預設的狀態下原本的檔案會被壓縮成為 .gz 的檔名， 原始檔案就不再存在了。您也可以發現，由於 gzip 的壓縮比要比 compress 好的多，所以當然建議使用 gzip 啦！ 此外，使用 gzip 壓縮的檔案在 Windows 系統中，竟然可以被 WinRAR 這個軟體解壓縮呢！很好用吧！至於其他的用法如下：

範例二：由於 man.config 是文字檔，請將範例一的壓縮檔的內容讀出來！

[root@www tmp]# zcat man.config.gz

# 由於 man.config 這個原本的檔案是是文字檔，因此我們可以嘗試使用 zcat  去讀取！

# 此時螢幕上會顯示 man.config.gz 解壓縮之後的檔案內容！

範例三：將範例一的檔案解壓縮

[root@www tmp]# gzip -d man.config.gz

# 不要使用 gunzip 這個指令，不好背！使用 gzip -d 來進行解壓縮！

# 與 gzip 相反， gzip -d 會將原本的 .gz 刪除，產生原本的 man.config 檔案。

範例四：將範例三解開的 man.config 用最佳的壓縮比壓縮，並保留原本的檔案

[root@www tmp]# gzip -9 -c man.config > man.config.gz

其實 gzip 的壓縮已經最佳化過了，所以雖然 gzip 提供 1~9 的壓縮等級，不過使用預設的 6 就非常好用了！ 因此上述的範例四可以不要加入那個 -9 的選項。範例四的重點在那個 -c 與 > 的使用囉！

cat 可以讀取純文字檔，那個 zcat 則可以讀取純文字檔被壓縮後的壓縮檔！ 由於 gzip 這個壓縮指令主要想要用來取代 compress 的，所以不但 compress 的壓縮檔案可以使用 gzip 來解開，同時 zcat 這個指令可以同時讀取 compress 與 gzip 的壓縮檔呦！

bzip2, bzcat

若說 gzip 是為了取代 compress 並提供更好的壓縮比而成立的，那麼 bzip2 則是為了取代 gzip 並提供更佳的壓縮比而來的。 bzip2 真是很不錯用的東西∼這玩意的壓縮比竟然比 gzip 還要好∼至於 bzip2 的用法幾乎與 gzip 相同！ 看看底下的用法吧！

[root@www ~]# bzip2 [-cdkzv#] 檔名

[root@www ~]# bzcat 檔名.bz2

選項與參數：

-c  ：將壓縮的過程產生的資料輸出到螢幕上！

-d  ：解壓縮的參數

-k  ：保留原始檔案，而不會刪除原始的檔案喔！

-z  ：壓縮的參數

-v  ：可以顯示出原檔案/壓縮檔案的壓縮比等資訊；

-#  ：與 gzip 同樣的，都是在計算壓縮比的參數， -9 最佳， -1 最快！

範例一：將剛剛的 /tmp/man.config 以 bzip2 壓縮

[root@www tmp]# bzip2 -z man.config

# 此時 man.config 會變成 man.config.bz2 ！

範例二：將範例一的檔案內容讀出來！

[root@www tmp]# bzcat man.config.bz2

# 此時螢幕上會顯示 man.config.bz2 解壓縮之後的檔案內容！！

範例三：將範例一的檔案解壓縮

[root@www tmp]# bzip2 -d man.config.bz2

範例四：將範例三解開的 man.config 用最佳的壓縮比壓縮，並保留原本的檔案

[root@www tmp]# bzip2 -9 -c man.config > man.config.bz2

使用 compress 副檔名自動建立為 .Z ，使用 gzip 副檔名自動建立為 .gz 。這裡的 bzip2 則是自動的將副檔名建置為 .bz2 囉！所以當我們使用具有壓縮功能的 bzip2 -z 時，那麼剛剛的 man.config 就會自動的變成了 man.config.bz2 這個檔名囉！

好了，那麼如果我想要讀取這個檔案的內容呢？ 是否一定要解開？當然不需要囉！可以使用簡便的 bzcat 這個指令來讀取內容即可！例如上面的例子中， 我們可以使用 bzcat man.config.bz2 來讀取資料而不需要解開！此外，當你要解開一個壓縮檔時， 這個檔案的名稱為 .bz, .bz2, .tbz, .tbz2 等等，那麼就可以嘗試使用 bzip2 來解看看啦！當然囉，也可以使用 bunzip2 這個指令來取代 bzip2 -d 囉。

打包指令： tar

前一小節談到的指令大多僅能針對單一檔案來進行壓縮，雖然 gzip 與 bzip2 也能夠針對目錄來進行壓縮， 不過，這兩個指令對目錄的壓縮指的是『將目錄內的所有檔案 "分別" 進行壓縮』的動作！ 而不像在 Windows 的系統，可以使用類似 WinRAR 這一類的壓縮軟體來將好多資料『包成一個檔案』的樣式。

這種將多個檔案或目錄包成一個大檔案的指令功能，我們可以稱呼他是一種『打包指令』啦！ 那 Linux 有沒有這種打包指令呢？是有的！那就是鼎鼎大名的 tar 這個玩意兒了！ tar 可以將多個目錄或檔案打包成一個大檔案，同時還可以透過 gzip/bzip2 的支援，將該檔案同時進行壓縮！ 更有趣的是，由於 tar 的使用太廣泛了，目前 Windows 的 WinRAR 也支援 .tar.gz 檔名的解壓縮呢！ 很不錯吧！所以底下我們就來玩一玩這個咚咚！

tar

tar 的選項與參數非常的多！我們只講幾個常用的選項，更多選項您可以自行 man tar 查詢囉！

[root@www ~]# tar [-j|-z] [cv] [-f 建立的檔名] filename... <==打包與壓縮

[root@www ~]# tar [-j|-z] [tv] [-f 建立的檔名]             <==察看檔名

[root@www ~]# tar [-j|-z] [xv] [-f 建立的檔名] [-C 目錄]   <==解壓縮

選項與參數：

-c  ：建立打包檔案，可搭配 -v 來察看過程中被打包的檔名(filename)

-t  ：察看打包檔案的內容含有哪些檔名，重點在察看『檔名』就是了；

-x  ：解打包或解壓縮的功能，可以搭配 -C (大寫) 在特定目錄解開

特別留意的是， -c, -t, -x 不可同時出現在一串指令列中。

-j  ：透過 bzip2 的支援進行壓縮/解壓縮：此時檔名最好為 *.tar.bz2

-z  ：透過 gzip  的支援進行壓縮/解壓縮：此時檔名最好為 *.tar.gz

-v  ：在壓縮/解壓縮的過程中，將正在處理的檔名顯示出來！

-f filename：-f 後面要立刻接要被處理的檔名！建議 -f 單獨寫一個選項囉！

-C 目錄    ：這個選項用在解壓縮，若要在特定目錄解壓縮，可以使用這個選項。

其他後續練習會使用到的選項介紹：

-p(小寫) ：保留備份資料的原本權限與屬性，常用於備份(-c)重要的設定檔

-P(大寫) ：保留絕對路徑，亦即允許備份資料中含有根目錄存在之意；

--exclude=FILE：在壓縮的過程中，不要將 FILE 打包！

其實最簡單的使用 tar 就只要記憶底下的方式即可：

- 壓　縮：tar -jcv -f filename.tar.bz2 要被壓縮的檔案或目錄名稱

- 查　詢：tar -jtv -f filename.tar.bz2

- 解壓縮：tar -jxv -f filename.tar.bz2 -C 欲解壓縮的目錄

那個 filename.tar.bz2 是我們自己取的檔名，tar 並不會主動的產生建立的檔名喔！我們要自訂啦！ 所以副檔名就顯的很重要了！如果不加 [-j|-z] 的話，檔名最好取為 *.tar 即可。如果是 -j 選項，代表有 bzip2 的支援，因此檔名最好就取為 *.tar.bz2 ，因為 bzip2 會產生 .bz2 的副檔名之故！ 至於如果是加上了 -z 的 gzip 的支援，那檔名最好取為 *.tar.gz 喔！瞭解乎？

另外，由於『 -f filename 』是緊接在一起的，過去很多文章常會寫成『-jcvf filename』，這樣是對的， 但由於選項的順序理論上是可以變換的，所以很多讀者會誤認為『-jvfc filename』也可以∼事實上這樣會導致產生的檔名變成 c ！ 因為 -fc 嘛！所以囉，建議您在學習 tar 時，將『 -f filename 』與其他選項獨立出來，會比較不容易發生問題。

閒話少說，讓我們來測試幾個常用的 tar 方法吧！

- 使用 tar 加入 -j 或 -z 的參數備份 /etc/ 目錄

有事沒事備份一下 /etc 這個目錄是件好事！備份 /etc 最簡單的方法就是使用 tar 囉！讓我們來玩玩先：

[root@www ~]# tar -zpcv -f /root/etc.tar.gz /etc

tar: Removing leading `/' from member names  <==注意這個警告訊息

/etc/

....中間省略....

/etc/esd.conf

/etc/crontab

# 由於加上 -v 這個選項，因此正在作用中的檔名就會顯示在螢幕上。

# 如果你可以翻到第一頁，會發現出現上面的錯誤訊息！底下會講解。

# 至於 -p 的選項，重點在於『保留原本檔案的權限與屬性』之意。

[root@www ~]# tar -jpcv -f /root/etc.tar.bz2 /etc

# 顯示的訊息會跟上面一模一樣囉！

[root@www ~]# ll /root/etc*

-rw-r--r-- 1 root root  8740252 Nov 15 23:07 /root/etc.tar.bz2

-rw-r--r-- 1 root root 13010999 Nov 15 23:01 /root/etc.tar.gz

[root@www ~]# du -sm /etc

118     /etc

# 為什麼建議您使用 -j 這個選項？從上面的數值你可以知道了吧？^_^

由上述的練習，我們知道使用 bzip2 亦即 -j 這個選項來製作備份時，能夠得到比較好的壓縮比！ 如上表所示，由原本的 /etc/ (118MBytes) 下降到 8.7Mbytes 左右！至於加上『 -p 』這個選項的原因是為了保存原本檔案的權限與屬性！我們曾在第七章的 cp 指令介紹時談到權限與檔案類型(例如連結檔)對複製的不同影響。 同樣的，在備份重要的系統資料時，這些原本檔案的權限需要做完整的備份比較好。此時 -p 這個選項就派的上用場了。 接下來讓我們看看打包檔案內有什麼資料存在？

- 查閱 tar 檔案的資料內容(可察看檔名)，與備份檔名有否根目錄的意義

要察看檔名非常的簡單！可以這樣做：

[root@www ~]# tar -jtv -f /root/etc.tar.bz2

....前面省略....

-rw-r--r-- root/root  1016 2008-05-25 14:06:20 etc/dbus-1/session.conf

-rw-r--r-- root/root   153 2007-01-07 19:20:54 etc/esd.conf

-rw-r--r-- root/root   255 2007-01-06 21:13:33 etc/crontab

如果加上 -v 這個選項時，詳細的檔案權限/屬性都會被列出來！如果只是想要知道檔名而已， 那麼就將 -v 拿掉即可。從上面的資料我們可以發現一件很有趣的事情，那就是每個檔名都沒了根目錄了！這也是上一個練習中出現的那個警告訊息『tar: Removing leading `/' from member names(移除了檔名開頭的 `/' )』所告知的情況！

那為什麼要拿掉根目錄呢？主要是為了安全！我們使用 tar 備份的資料可能會需要解壓縮回來使用， 在 tar 所記錄的檔名 (就是我們剛剛使用 tar -jtvf 所察看到的檔名) 那就是解壓縮後的實際檔名。 如果拿掉了根目錄，假設你將備份資料在 /tmp 解開，那麼解壓縮的檔名就會變成『/tmp/etc/xxx』。 但『如果沒有拿掉根目錄，解壓縮後的檔名就會是絕對路徑， 亦即解壓縮後的資料一定會被放置到 /etc/xxx 去！』如此一來，你的原本的 /etc/ 底下的資料， 就會被備份資料所覆蓋過去了！

Tips:

你會說：『既然是備份資料，那麼還原回來也沒有什麼問題吧？』想像一個狀況，你備份的資料是一年前的舊版 CentOS 4.x， 你只是想要瞭解一下過去的備份內容究竟有哪些資料而已，結果一解開該檔案，卻發現你目前新版的 CentOS 5.x 底下的 /etc 被舊版的備份資料覆蓋了！此時你該如何是好？所以囉，當然是拿掉根目錄比較安全一些的。

如果你確定你就是需要備份根目錄到 tar 的檔案中，那可以使用 -P (大寫) 這個選項，請看底下的例子分析：

範例：將檔名中的(根)目錄也備份下來，並察看一下備份檔的內容檔名

[root@www ~]# tar -jpPcv -f /root/etc.and.root.tar.bz2 /etc

....中間過程省略....

[root@www ~]# tar -jtf /root/etc.and.root.tar.bz2

/etc/dbus-1/session.conf

/etc/esd.conf

/etc/crontab

# 這次查閱檔名不含 -v 選項，所以僅有檔名而已！沒有詳細屬性/權限等參數。

有發現不同點了吧？如果加上 -P 選項，那麼檔名內的根目錄就會存在喔！不過，鳥哥個人建議，還是不要加上 -P 這個選項來備份！ 畢竟很多時候，我們備份是為了要未來追蹤問題用的，倒不一定需要還原回原本的系統中！ 所以拿掉根目錄後，備份資料的應用會比較有彈性！也比較安全呢！

- 將備份的資料解壓縮，並考慮特定目錄的解壓縮動作 (-C 選項的應用)

那如果想要解打包呢？很簡單的動作就是直接進行解打包嘛！

[root@www ~]# tar -jxv -f /root/etc.tar.bz2

[root@www ~]# ll

....(前面省略)....

drwxr-xr-x 105 root root    12288 Nov 11 04:02 etc

....(後面省略)....

此時該打包檔案會在『本目錄下進行解壓縮』的動作！ 所以，你等一下就會在家目錄底下發現一個名為 etc 的目錄囉！所以囉，如果你想要將該檔案在 /tmp 底下解開， 可以 cd /tmp 後，再下達上述的指令即可。不過，這樣好像很麻煩呢∼有沒有更簡單的方法可以『指定欲解開的目錄』呢？ 有的，可以使用 -C 這個選項喔！舉例來說：

[root@www ~]# tar -jxv -f /root/etc.tar.bz2 -C /tmp

[root@www ~]# ll /tmp

....(前面省略)....

drwxr-xr-x 105 root root    12288 Nov 11 04:02 etc

....(後面省略)....

這樣一來，你就能夠將該檔案在不同的目錄解開囉！鳥哥個人是認為，這個 -C 的選項務必要記憶一下的！ 好了，處理完畢後，請記得將這兩個目錄刪除一下呢！

[root@www ~]# rm -rf /root/etc /tmp/etc

再次強調，這個『 rm -rf 』是很危險的指令！下達時請務必要確認一下後面接的檔名。我們要刪除的是 /root/etc 與 /tmp/etc， 您可不要將 /etc/ 刪除掉了！系統會死掉的∼ ^_^

- 僅解開單一檔案的方法

剛剛上頭我們解壓縮都是將整個打包檔案的內容全部解開！想像一個情況，如果我只想要解開打包檔案內的其中一個檔案而已， 那該如何做呢？很簡單的，你只要使用 -jtv 找到你要的檔名，然後將該檔名解開即可。 我們用底下的例子來說明一下：

# 1. 先找到我們要的檔名，假設解開 shadow 檔案好了：

[root@www ~]# tar -jtv -f /root/etc.tar.bz2 | grep 'shadow'

-r-------- root/root  1230 2008-09-29 02:21:20 etc/shadow-

-r-------- root/root   622 2008-09-29 02:21:20 etc/gshadow-

-r-------- root/root   636 2008-09-29 02:21:25 etc/gshadow

-r-------- root/root  1257 2008-09-29 02:21:25 etc/shadow  <==這是我們要的！

# 先搜尋重要的檔名！其中那個 grep 是『擷取』關鍵字的功能！我們會在第三篇說明！

# 這裡您先有個概念即可！那個管線 | 配合 grep 可以擷取關鍵字的意思！

# 2. 將該檔案解開！語法與實際作法如下：

[root@www ~]# tar -jxv -f 打包檔.tar.bz2 待解開檔名

[root@www ~]# tar -jxv -f /root/etc.tar.bz2 etc/shadow

etc/shadow

[root@www ~]# ll etc

total 8

-r-------- 1 root root 1257 Sep 29 02:21 shadow  <==呦喝！只有一個檔案啦！

# 很有趣！此時只會解開一個檔案而已！不過，重點是那個檔名！你要找到正確的檔名。

# 在本例中，你不能寫成 /etc/shadow ！因為記錄在 etc.tar.bz2 內的檔名之故！

- 打包某目錄，但不含該目錄下的某些檔案之作法

假設我們想要打包 /etc/ /root 這幾個重要的目錄，但卻不想要打包 /root/etc* 開頭的檔案， 因為該檔案都是剛剛我們才建立的備份檔嘛！而且假設這個新的打包檔案要放置成為 /root/system.tar.bz2 ， 當然這個檔案自己不要打包自己 (因為這個檔案放置在 /root 底下啊！)，此時我們可以透過 --exclude 的幫忙！ 那個 exclude 就是不包含的意思！所以你可以這樣做：

[root@www ~]# tar -jcv  -f /root/system.tar.bz2 --exclude=/root/etc* \

> --exclude=/root/system.tar.bz2  /etc /root

上面的指令是一整列的∼其實你可以打成：『tar -jcv -f /root/system.tar.bz2 --exclude=/root/etc* --exclude=/root/system.tar.bz2 /etc /root』，如果想要兩行輸入時，最後面加上反斜線 (\) 並立刻按下 [enter] ， 就能夠到第二行繼續輸入了。這個指令下達的方式我們會在第三章再仔細說明。 透過這個 --exclude="file" 的動作，我們可以將幾個特殊的檔案或目錄移除在打包之列， 讓打包的動作變的更簡便喔！^_^

另外，在新版的 tar 指令中，鳥哥發現原本的『 --exclude file 』似乎無法實際運作了！使用 man tar 明明有看到這個選項的說， 但使用 info tar 才發現，選項功能已經變成了『 --exclude=file 』的模式！這個地方得要特別留意呢！

- 僅備份比某個時刻還要新的檔案

某些情況下你會想要備份新的檔案而已，並不想要備份舊檔案！此時 --newer-mtime 這個選項就粉重要啦！ 其實有兩個選項啦，一個是『 --newer 』另一個就是『 --newer-mtime 』，這兩個選項有何不同呢？ 我們在 第七章的 touch 介紹中談到過三種不同的時間參數， 當使用 --newer 時，表示後續的日期包含『 mtime 與 ctime 』，而 --newer-mtime 則僅是 mtime 而已！ 這樣知道了吧！ ^_^ 。那就讓我們來嘗試處理一下囉！

# 1. 先由 find 找出比 /etc/passwd 還要新的檔案

[root@www ~]# find /etc -newer /etc/passwd

....(過程省略)....

# 此時會顯示出比 /etc/passwd 這個檔案的 mtime 還要新的檔名，

# 這個結果在每部主機都不相同！您先自行查閱自己的主機即可，不會跟鳥哥一樣！

[root@www ~]# ll /etc/passwd

-rw-r--r-- 1 root root 1945 Sep 29 02:21 /etc/passwd

# 2. 好了，那麼使用 tar 來進行打包吧！日期為上面看到的 2008/09/29

[root@www ~]# tar -jcv -f /root/etc.newer.then.passwd.tar.bz2 \

> --newer-mtime="2008/09/29" /etc/*

....(中間省略)....

/etc/smartd.conf    <==真的有備份的檔案

....(中間省略)....

/etc/yum.repos.d/   <==目錄都會被記錄下來！

tar: /etc/yum.repos.d/CentOS-Base.repo: file is unchanged; not dumped

# 最後行顯示的是『沒有被備份的』，亦即 not dumped 的意思！

# 3. 顯示出檔案即可

[root@www ~]# tar -jtv -f /root/etc.newer.then.passwd.tar.bz2 | \

> grep -v '/$'

# 透過這個指令可以呼叫出 tar.bz2 內的結尾非 / 的檔名！就是我們要的啦！

現在你知道這個指令的好用了吧！甚至可以進行差異檔案的記錄與備份呢∼ 這樣子的備份就會顯的更容易囉！你可以這樣想像，如果我在一個月前才進行過一次完整的資料備份， 那麼這個月想要備份時，當然可以僅備份上個月進行備份的那個時間點之後的更新的檔案即可！ 為什麼呢？因為原本的檔案已經有備份了嘛！幹嘛還要進行一次？只要備份新資料即可。這樣可以降低備份的容量啊！

- 基本名稱： tarfile, tarball ？

另外值得一提的是，tar 打包出來的檔案有沒有進行壓縮所得到檔案稱呼不同喔！ 如果僅是打包而已，就是『 tar -cv -f file.tar 』而已，這個檔案我們稱呼為 tarfile 。 如果還有進行壓縮的支援，例如『 tar -jcv -f file.tar.bz2 』時，我們就稱呼為 tarball (tar 球？)！ 這只是一個基本的稱謂而已，不過很多書籍與網路都會使用到這個 tarball 的名稱！ 所以得要跟您介紹介紹。

此外，tar 除了可以將資料打包成為檔案之外，還能夠將檔案打包到某些特別的裝置去，舉例來說， 磁帶機 (tape) 就是一個常見的例子。磁帶機由於是一次性讀取/寫入的裝置，因此我們不能夠使用類似 cp 等指令來複製的！ 那如果想要將 /home, /root, /etc 備份到磁帶機 (/dev/st0) 時，就可以使用：『tar -cv -f /dev/st0 /home /root /etc』，很簡單容易吧！ 磁帶機用在備份 (尤其是企業應用) 是很常見的工作喔！

- 特殊應用：利用管線命令與資料流

在 tar 的使用中，有一種方式最特殊，那就是透過標準輸入輸出的資料流重導向(standard input/standard output)， 以及管線命令 (pipe) 的方式，將待處理的檔案一邊打包一邊解壓縮到目標目錄去。 關於資料流重導向與管線命令更詳細的資料我們會在第十一章 bash 再跟大家介紹， 底下先來看一個例子吧！

# 1. 將 /etc 整個目錄一邊打包一邊在 /tmp 解開

[root@www ~]# cd /tmp

[root@www tmp]# tar -cvf - /etc | tar -xvf -

# 這個動作有點像是 cp -r /etc /tmp 啦∼依舊是有其有用途的！

# 要注意的地方在於輸出檔變成 - 而輸入檔也變成 - ，又有一個 | 存在∼

# 這分別代表 standard output, standard input 與管線命令啦！

# 簡單的想法中，你可以將 - 想成是在記憶體中的一個裝置(緩衝區)。

# 更詳細的資料流與管線命令，請翻到 bash 章節囉！

在上面的例子中，我們想要『將 /etc 底下的資料直接 copy 到目前所在的路徑，也就是 /tmp 底下』，但是又覺得使用 cp -r 有點麻煩，那麼就直接以這個打包的方式來打包，其中，指令裡面的 - 就是表示那個被打包的檔案啦！ 由於我們不想要讓中間檔案存在，所以就以這一個方式來進行複製的行為啦！

- 例題：系統備份範例

系統上有非常多的重要目錄需要進行備份，而且其實我們也不建議你將備份資料放置到 /root 目錄下！ 假設目前你已經知道重要的目錄有底下這幾個：

- /etc/ (設定檔)

- /home/ (使用者的家目錄)

- /var/spool/mail/ (系統中，所有帳號的郵件信箱)

- /var/spool/cron/ (所有帳號的工作排成設定檔)

- /root (系統管理員的家目錄)

然後我們也知道，由於第八章曾經做過的練習的關係， /home/loop* 不需要備份，而且 /root 底下的壓縮檔也不需要備份，另外假設你要將備份的資料放置到 /backups ，並且該目錄僅有 root 有權限進入！ 此外，每次備份的檔名都希望不相同，例如使用：backup-system-20091130.tar.bz2 之類的檔名來處理。 那你該如何處理這個備份資料呢？(請先動手作看看，再來察看一下底下的參考解答！)

# 1. 先處理要放置備份資料的目錄與權限：

[root@www ~]# mkdir /backups

[root@www ~]# chmod 700 /backups

[root@www ~]# ll -d /backups

drwx------ 2 root root 4096 Nov 30 16:35 /backups

# 2. 假設今天是 2009/11/30 ，則建立備份的方式如下：

[root@www ~]# tar -jcv -f /backups/backup-system-20091130.tar.bz2 \

> --exclude=/root/*.bz2 --exclude=/root/*.gz --exclude=/home/loop* \

> /etc /home /var/spool/mail /var/spool/cron /root

....(過程省略)....

[root@www ~]# ll -h /backups/

-rw-r--r-- 1 root root 8.4M Nov 30 16:43 backup-system-20091130.tar.bz2

完整備份工具：dump

某些時刻你想要針對檔案系統進行備份或者是儲存的功能時，不能不談到這個 dump 指令！ 這玩意兒我們曾在前一章的 /etc/fstab 裡面稍微談過。 其實這個指令除了能夠針對整個 filesystem 備份之外，也能夠僅針對目錄來備份喔！ 底下就讓我們來談一談這個指令的用法吧！

dump

其實 dump 的功能頗強，他除了可以備份整個檔案系統之外，還可以制定等級喔！什麼意思啊！ 假設你的 /home 是獨立的一個檔案系統，那你第一次進行過 dump 後，再進行第二次 dump 時， 你可以指定不同的備份等級，假如指定等級為 1 時，此時新備份的資料只會記錄與第一次備份所有差異的檔案而已。 看不懂嗎？沒關係！我們用一張簡圖來說明。

圖 4.1.1、dump 運作的等級 (level)

如上圖所示，上方的『即時檔案系統』是一直隨著時間而變化的資料，例如在 /home 裡面的檔案資料會一直變化一樣。 而底下的方塊則是 dump 備份起來的資料，第一次備份時使用的是 level 0 ，這個等級也是完整的備份啦！ 等到第二次備份時，即時檔案系統內的資料已經與 level 0 不一樣了，而 level 1 僅只是比較目前的檔案系統與 level 0 之間的差異後，備份有變化過的檔案而已。至於 level 2 則是與 level 1 進行比較啦！這樣瞭解呼？

雖然 dump 支援整個檔案系統或者是單一各別目錄，但是對於目錄的支援是比較不足的，這也是 dump 的限制所在。 簡單的說，如果想要備份的資料如下時，則有不同的限制情況：

- 當待備份的資料為單一檔案系統：

如果是單一檔案系統 (filesystem) ，那麼該檔案系統可以使用完整的 dump 功能，包括利用 0~9 的數個 level 來備份， 同時，備份時可以使用掛載點或者是裝置檔名 (例如 /dev/sda5 之類的裝置檔名) 來進行備份！

- 待備份的資料只是目錄，並非單一檔案系統：

例如你僅想要備份 /home/someone/ ，但是該目錄並非獨立的檔案系統時。此時備份就有限制啦！包括：

- 所有的備份資料都必須要在該目錄 (本例為：/home/someone/) 底下；

- 且僅能使用 level 0 ，亦即僅支援完整備份而已；

- 不支援 -u 選項，亦即無法建立 /etc/dumpdates 這個各別 level 備份的時間記錄檔；

dump 的選項雖然非常的繁複，不過如果只是想要簡單的操作時，您只要記得底下的幾個選項就很夠用了！

[root@www ~]# dump [-Suvj] [-level] [-f 備份檔] 待備份資料

[root@www ~]# dump -W

選項與參數：

-S    ：僅列出後面的待備份資料需要多少磁碟空間才能夠備份完畢；

-u    ：將這次 dump 的時間記錄到 /etc/dumpdates 檔案中；

-v    ：將 dump 的檔案過程顯示出來；

-j    ：加入 bzip2 的支援！將資料進行壓縮，預設 bzip2 壓縮等級為 2

-level：就是我們談到的等級，從 -0 ~ -9 共十個等級；

-f    ：有點類似 tar 啦！後面接產生的檔案，亦可接例如 /dev/st0 裝置檔名等

-W    ：列出在 /etc/fstab 裡面的具有 dump 設定的 partition 是否有備份過？

- 用 dump 備份完整的檔案系統

現在就讓我們來做幾個範例吧！假如你要將系統的最小的檔案系統捉出來進行備份，那該如何進行呢？

# 1. 先找出系統中最小的那個檔案系統，如下所示：

[root@www ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdc2             9.5G  3.7G  5.3G  42% /

/dev/hdc3             4.8G  651M  3.9G  15% /home

/dev/hdc1              99M   11M   83M  12% /boot  <==看起來最小的就是他啦！

tmpfs                 363M     0  363M   0% /dev/shm

# 2. 先測試一下，如果要備份此檔案系統，需多少容量？

[root@www ~]# dump -S /dev/hdc1

5630976     <==注意一下，這個單位是 bytes ，所以差不多是 5.6MBytes。

# 3. 將完整備份的檔名記錄成為 /root/boot.dump ，同時更新記錄檔：

[root@www ~]# dump -0u -f /root/boot.dump /boot

DUMP: Date of this level 0 dump: Tue Dec  2 02:53:45 2008 <==記錄等級與備份時間

DUMP: Dumping /dev/hdc1 (/boot) to /root/boot.dump  <==dump的來源與目標

DUMP: Label: /boot                              <==檔案系統的 label

DUMP: Writing 10 Kilobyte records

DUMP: mapping (Pass I) [regular files]          <==開始進行檔案對應

DUMP: mapping (Pass II) [directories]

DUMP: estimated 5499 blocks.                    <==評估整體block數量

DUMP: Volume 1 started with block 1 at: Tue Dec  2 02:53:46 2008

DUMP: dumping (Pass III) [directories]          <==開始 dump 工作

DUMP: dumping (Pass IV) [regular files]

DUMP: Closing /root/boot.dump                   <==結束寫入備份檔

DUMP: Volume 1 completed at: Tue Dec  2 02:53:47 2008

DUMP: Volume 1 5550 blocks (5.42MB)             <==最終備份資料容量

DUMP: Volume 1 took 0:00:01

DUMP: Volume 1 transfer rate: 5550 kB/s

DUMP: 5550 blocks (5.42MB) on 1 volume(s)

DUMP: finished in 1 seconds, throughput 5550 kBytes/sec

DUMP: Date of this level 0 dump: Tue Dec  2 02:53:45 2008

DUMP: Date this dump completed:  Tue Dec  2 02:53:47 2008

DUMP: Average transfer rate: 5550 kB/s

DUMP: DUMP IS DONE

# 在指令的下達方面，dump 後面接 /boot 或 /dev/hdc1 都可以的！

# 而執行 dump 的過程中會出現如上的一些訊息，您可以自行仔細的觀察！

[root@www ~]# ll /root/boot.dump /etc/dumpdates

-rw-rw-r-- 1 root disk      43 Dec  2 02:53 /etc/dumpdates

-rw-r--r-- 1 root root 5683200 Dec  2 02:53 /root/boot.dump

# 由於加上 -u 的選項，因此 /etc/dumpdates 該檔案的內容會被更新！注意，

# 這個檔案僅有在 dump 完整的檔案系統時才有支援主動更新的功能。

# 4. 觀察一下系統主動建立的記錄檔：

[root@www ~]# cat /etc/dumpdates

/dev/hdc1     0   Tue Dec  2 02:53:47 2008 +0800

[檔案系統] [等級] [       ctime 的時間         ]

這樣很簡單的就建立起來 /root/boot.dump 檔案，該檔案將整個 /boot/ 檔案系統都備份下來了！ 並且將備份的時間寫入 /etc/dumpdates 檔案中，準備讓下次備份時可以作為一個參考依據。 現在讓我們來進行一個測試，檢查看看能否真的建立 level 1 的備份呢？

# 0. 看一下有沒有任何檔案系統被 dump 過的資料？

[root@www ~]# dump -W

Last dump(s) done (Dump '>' file systems):

> /dev/hdc2     (     /) Last dump: never

> /dev/hdc3     ( /home) Last dump: never

/dev/hdc1     ( /boot) Last dump: Level 0, Date Tue Dec  2 02:53:47 2008

# 如上列的結果，該結果會捉出 /etc/fstab 裡面第五欄位設定有需要 dump 的

# partition，然後與 /etc/dumpdates 進行比對，可以得到上面的結果啦！

# 尤其是第三行，可以顯示我們曾經對 /dev/hdc1 進行過 dump 的備份動作喔！

# 1. 先惡搞一下，建立一個大約 10 MB 的檔案在 /boot 內：

[root@www ~]# dd if=/dev/zero of=/boot/testing.img bs=1M count=10

10+0 records in

10+0 records out

10485760 bytes (10 MB) copied, 0.166128 seconds, 63.1 MB/s

# 2. 開始建立差異備份檔，此時我們使用 level 1 吧：

[root@www ~]# dump -1u -f /root/boot.dump.1 /boot

....(中間省略)....

[root@www ~]# ll /root/boot*

-rw-r--r-- 1 root root  5683200 Dec  2 02:53 /root/boot.dump

-rw-r--r-- 1 root root 10547200 Dec  2 02:56 /root/boot.dump.1

# 看看檔案大小，豈不是就是剛剛我們所建立的那個大檔案的容量嗎？ ^_^

# 3. 最後再看一下是否有記錄 level 1 備份的時間點呢？

[root@www ~]# dump -W

Last dump(s) done (Dump '>' file systems):

> /dev/hdc2     (     /) Last dump: never

> /dev/hdc3     ( /home) Last dump: never

> /dev/hdc1     ( /boot) Last dump: Level 1, Date Tue Dec  2 02:56:33 2008

....(中間省略)....

透過這個簡單的方式，我們就能夠僅備份差異檔案的部分囉！底下再來看看針對單一目錄的 dump 用途！

- 用 dump 備份非檔案系統，亦即單一目錄的方法

現在讓我們來處理一下 /etc 的 dump 備份吧！因為 /etc 並非單一檔案系統，他只是個目錄而已。 所以依據限制的說明， -u, level 1~9 都是不適用的。我們只能夠使用 level 0 的完整備份將 /etc 給他 dump 下來。因此作法就變的很簡單了！

# 讓我們將 /etc 整個目錄透過 dump 進行備份，且含壓縮功能

[root@www ~]# dump -0j -f /root/etc.dump.bz2 /etc

DUMP: Date of this level 0 dump: Tue Dec  2 12:08:22 2008

DUMP: Dumping /dev/hdc2 (/ (dir etc)) to /root/etc.dump.bz2

DUMP: Label: /1

DUMP: Writing 10 Kilobyte records

DUMP: Compressing output at compression level 2 (bzlib)

DUMP: mapping (Pass I) [regular files]

DUMP: mapping (Pass II) [directories]

DUMP: estimated 115343 blocks.

DUMP: Volume 1 started with block 1 at: Tue Dec  2 12:08:23 2008

DUMP: dumping (Pass III) [directories]

DUMP: dumping (Pass IV) [regular files]

DUMP: Closing /root/etc.dump.bz2

DUMP: Volume 1 completed at: Tue Dec  2 12:09:49 2008

DUMP: Volume 1 took 0:01:26

DUMP: Volume 1 transfer rate: 218 kB/s

DUMP: Volume 1 124680kB uncompressed, 18752kB compressed, 6.649:1

DUMP: 124680 blocks (121.76MB) on 1 volume(s)

DUMP: finished in 86 seconds, throughput 1449 kBytes/sec

DUMP: Date of this level 0 dump: Tue Dec  2 12:08:22 2008

DUMP: Date this dump completed:  Tue Dec  2 12:09:49 2008

DUMP: Average transfer rate: 218 kB/s

DUMP: Wrote 124680kB uncompressed, 18752kB compressed, 6.649:1

DUMP: DUMP IS DONE

# 上面特殊字體的部分顯示：原本有 124680kb  的容量，被壓縮成為 18752kb，

# 整個壓縮比為 6.649:1 ，還可以的壓縮情況啦！

一般來說 dump 不會使用包含壓縮的功能，不過如果你想要將備份的空間降低的話，那個 -j 的選項是可以使用的。 加上 -j 之後你的 dump 成果會使用較少的硬碟容量啦！如上述的情況來看，檔案容量由原本的 128MB 左右下滑到 18MB 左右，當然可以節省備份空間囉！

restore

備份檔就是在急用時可以回復系統的重要資料，所以有備份當然就得要學學如何復原了！ dump 的復原使用的是 restore 這個指令！這個指令的選項也非常的多∼您可以自行 man restore 瞧瞧！ 鳥哥在這裡僅作個簡單的介紹囉！

[root@www ~]# restore -t [-f dumpfile] [-h]        <==用來察看 dump 檔

[root@www ~]# restore -C [-f dumpfile] [-D 掛載點] <==比較dump與實際檔案

[root@www ~]# restore -i [-f dumpfile]             <==進入互動模式

[root@www ~]# restore -r [-f dumpfile]             <==還原整個檔案系統

選項與參數：

相關的各種模式，各種模式無法混用喔！例如不可以寫 -tC 啦！

-t  ：此模式用在察看 dump 起來的備份檔中含有什麼重要資料！類似 tar -t 功能；

-C  ：此模式可以將 dump 內的資料拿出來跟實際的檔案系統做比較，

最終會列出『在 dump 檔案內有記錄的，且目前檔案系統不一樣』的檔案；

-i  ：進入互動模式，可以僅還原部分檔案，用在 dump 目錄時的還原！

-r  ：將整個 filesystem 還原的一種模式，用在還原針對檔案系統的 dump 備份；

其他較常用到的選項功能：

-h  ：察看完整備份資料中的 inode 與檔案系統 label 等資訊

-f  ：後面就接你要處理的那個 dump 檔案囉！

-D  ：與 -C 進行搭配，可以查出後面接的掛載點與 dump 內有不同的檔案！

- 用 restore 觀察 dump 後的備份資料內容

要找出 dump 的內容就使用 restore -t 來查閱即可！例如我們將 boot.dump 的檔案內容捉出來看看！

[root@www ~]# restore -t -f /root/boot.dump

Dump   date: Tue Dec  2 02:53:45 2008              <==說明備份的日期

Dumped from: the epoch

Level 0 dump of /boot on www.vbird.tsai:/dev/hdc1  <==說明 level 狀態

Label: /boot                                       <==說明該 filesystem 的表頭！

2      .

11      ./lost+found

2009      ./grub

2011      ./grub/grub.conf

....底下省略....

[root@www ~]# restore -t -f /root/etc.dump

Dump tape is compressed.                          <==加註說明資料有壓縮

Dump   date: Tue Dec  2 12:08:22 2008

Dumped from: the epoch

Level 0 dump of / (dir etc) on www.vbird.tsai:/dev/hdc2 <==是目錄！

Label: /1

2      .

1912545      ./etc

1912549      ./etc/rpm

1912550      ./etc/rpm/platform

....底下省略....

這個查閱的資料其實顯示出的是檔名與原始檔案的 inode 狀態，所以我們可以說， dump 會參考 inode 的記錄哩！ 透過這個查詢我們也能知道 dump 的內容為何呢！再來查一查如何還原吧！

- 比較差異並且還原整個檔案系統

為什麼 dump 可以進行累積備份呢？就是因為他具有可以查詢檔案系統與備份檔案之間的差異， 並且將分析到的差異資料進行備份的緣故。所以我們先來看看，如何查詢有變動過的資訊呢？你可以使用如下的方法檢驗：

# 0. 先嘗試變更檔案系統的內容：

[root@www ~]# cd /boot

[root@www boot]# mv config-2.6.18-128.el5 config-2.6.18-128.el5-back

# 1. 看使進行檔案系統與備份檔案之間的差異！

[root@www boot]# restore -C -f /root/boot.dump

Dump   date: Tue Dec  2 02:53:45 2008

Dumped from: the epoch

Level 0 dump of /boot on www.vbird.tsai:/dev/hdc1

Label: /boot

filesys = /boot

restore: unable to stat ./config-2.6.18-128.el5: No such file or directory

Some files were modified!  1 compare errors

# 看到上面的特殊字體了吧！那就是有差異的部分！總共有一個檔案被變更！

# 我們剛剛確實有更動過該檔案，嘿嘿！這樣是否能瞭解？！

# 2. 將檔案系統改回來啊！

[root@www boot]# mv config-2.6.18-128.el5-back config-2.6.18-128.el5

[root@www boot]# cd /root

如同上面的動作，透過曾經備份過的資訊，也可以找到與目前實際檔案系統中有差異的資料呢！ 如果你不想要進行累積備份，但也能透過這個動作找出最近這一陣子有變動過的檔案說！瞭解乎？ 那如何還原呢？由於 dump 是記錄整個檔案系統的，因此還原時你也應該要給予一個全新的檔案系統才行。 因此底下我們先建立一個檔案系統，然後再來還原吧！

# 1. 先建立一個新的 partition 來使用，假設我們需要的是 150M 的容量

[root@www ~]# fdisk /dev/hdc

Command (m for help): n

First cylinder (2335-5005, default 2335): <==這裡按 Enter

Using default value 2335

Last cylinder or +size or +sizeM or +sizeK (2335-5005, default 5005): +150M

Command (m for help): p

....中間省略....

/dev/hdc8            2335        2353      152586   83  Linux

Command (m for help): w

[root@www ~]# partprobe   <==很重要的動作！別忘記！

# 這樣就能夠建立一個 /dev/hdc8 的 partition ，然後繼續格式化吧！

[root@www ~]# mkfs -t ext3 /dev/hdc8

[root@www ~]# mount /dev/hdc8 /mnt

# 2. 開始進行還原的動作！請您務必到新檔案系統的掛載點底下去！

[root@www ~]# cd /mnt

[root@www mnt]# restore -r -f /root/boot.dump

restore: ./lost+found: File exists

由於我們是備份整個檔案系統，因此你也可以建置一個全新的檔案系統 (partition) 來進行還原的動作！ 整個還原的動作也不難，如上表最後一個指令，就是將備份檔案中的資料還原到本目錄下。 你必須要變更目錄到掛載點所在的那個目錄才行啊！這樣還原的檔案才不會跑錯地方！如果你還想要將 level 1 的 /root/boot.dump.1 那個檔案的內容也還原的話，那就繼續使用『restore -r -f /root/boot.dump.1』去還原吧！

- 僅還原部分檔案的 restore 互動模式

某些時候你只是要將備份檔的某個內容捉出來而已，並不想要全部解開，那該如何是好？此時你可以進入 restore 的互動模式 (interactive mode)。在底下我們使用 etc.dump 來進行範例說明。假如你要將 etc.dump 內的 passwd 與 shadow 捉出來而已，該如何進行呢？

[root@www ~]# cd /mnt

[root@www mnt]# restore -i -f /root/etc.dump

restore >

# 此時你就已經進入 restore 的互動模式畫面中！要注意的是：

# 你目前已經在 etc.dump 這個檔案內了！所有的動作都是在 etc.dump 內！

restore > help

Available commands are:

ls [arg] - list directory          <==列出 etc.dump 內的檔案或目錄

cd arg - change directory          <==在 etc.dump 內變更目錄

pwd - print current directory      <==列出在 etc.dump 內的路徑檔名

add [arg] - add `arg' to list of files to be extracted

delete [arg] - delete `arg' from list of files to be extracted

extract - extract requested files

# 上面三個指令是重點！各指令的功能為：

# add file    ：將 file 加入等一下要解壓縮的檔案列表中

# delete file ：將 file 移除出解壓縮的列表，並非刪除 etc.dump 內的檔案！別誤會！^_^

# extract     ：開始將剛剛選擇的檔案列表解壓縮了去！

setmodes - set modes of requested directories

quit - immediately exit program

what - list dump header information

verbose - toggle verbose flag (useful with ``ls'')

prompt - toggle the prompt display

help or `?' - print this list

restore > ls

.:

etc/  <==會顯示出在 etc.dump 內主要的目錄，因為我們備份 /etc ，所以檔名為此！

restore > cd etc                  <==在 etc.dump 內變換路徑到 etc 目錄下

restore > pwd                     <==列出本目錄的檔名為？

/etc

restore > ls passwd shadow group  <==看看，真的有這三個檔案喔！

passwd

shadow

group

restore > add passwd shadow group <==加入解壓縮列表

restore > delete group            <==加錯了！將 group 移除解壓縮列表

restore > ls passwd shadow group

*passwd  <==有要被解壓縮的，檔名之前會出現 * 的符號呢！

*shadow

group

restore > extract                 <==開始進行解壓縮去！

You have not read any volumes yet.   <==這裡會詢問你需要的volume

Unless you know which volume your file(s) are on you should start

with the last volume and work towards the first.

Specify next volume # (none if no more volumes): 1 <==只有一個 volume

set owner/mode for '.'? [yn] n <==不需要修改權限

restore > quit                    <==離開 restore 的功能

[root@www ~]# ll -d etc

drwxr-xr-x 2 root root 1024 Dec 15 17:49 etc  <==解壓縮後，所建立出來的目錄啦！

[root@www ~]# ll etc

total 6

-rw-r--r-- 1 root root 1945 Sep 29 02:21 passwd

-r-------- 1 root root 1257 Sep 29 02:21 shadow

透過互動式的 restore 功能，可以讓你將備份的資料取出一部份，而不必全部都得解壓縮才能夠取得你想要的檔案資料。 而 restore 內的 add 除了可以增加檔案外，也能夠增加整個備份的『目錄』喔！還不錯玩吧！ 趕緊測試看看先！ ^_^

光碟寫入工具

某些時刻你可能會希望將系統上最重要的資料給他備份出來，雖然目前隨身碟已經有夠便宜，你可以使用這玩意兒來備份。 不過某些重要的、需要重複備份的資料(可能具有時間特性)，你可能會需要使用類似 DVD 之類的儲存媒體來備份出來！ 舉例來說，你的系統設定檔或者是討論區的資料庫檔案(變動性非常的頻繁)。雖然 Linux 圖形介面已經有不少的燒錄軟體可用， 但有時如果你希望系統自動在某些時刻幫你主動的進行燒錄時，那麼文字介面的燒錄行為就有幫助啦！

那麼文字模式的燒錄行為要怎麼處理呢？通常的作法是這樣的：

- 先將所需要備份的資料建置成為一個映像檔(iso)，利用 mkisofs 指令來處理；

- 將該映像檔燒錄至光碟或 DVD 當中，利用 cdrecord 指令來處理。

底下我們就分別來談談這兩個指令的用法吧！

mkisofs：建立映像檔

我們從 FTP 站捉下來的 Linux 映像檔 (不管是 CD 還是 DVD) 都得要繼續燒錄成為實體的光碟/DVD 後， 才能夠進一步的使用，包括安裝或更新你的 Linux 啦！同樣的道理，你想要利用燒錄機將你的資料燒錄到 DVD 時， 也得要先將你的資料包成一個映像檔，這樣才能夠寫入DVD片中。而將你的資料包成一個映像檔的方式就透過 mkisofs 這個指令即可。 mkisofs 的使用方式如下：

[root@www ~]# mkisofs [-o 映像檔] [-rv] [-m file] 待備份檔案.. [-V vol] \

>  -graft-point isodir=systemdir ...

選項與參數：

-o ：後面接你想要產生的那個映像檔檔名。

-r ：透過 Rock Ridge 產生支援 Unix/Linux 的檔案資料，可記錄較多的資訊；

-v ：顯示建置 ISO 檔案的過程

-m file ：-m 為排除檔案 (exclude) 的意思，後面的檔案不備份到映像檔中

-V vol  ：建立 Volume，有點像 Windows 在檔案總管內看到的 CD title 的東西

-graft-point：graft有轉嫁或移植的意思，相關資料在底下文章內說明。

其實 mkisofs 有非常多好用的選項可以選擇，不過如果我們只是想要製作資料光碟時，上述的選項也就夠用了。 光碟的格式一般稱為 iso9660 ，這種格式一般僅支援舊版的 DOS 檔名，亦即檔名只能以 8.3 (檔名8個字元，副檔名3個字元) 的方式存在。如果加上 -r 的選項之後，那麼檔案資訊能夠被記錄的比較完整，可包括UID/GID與權限等等！ 所以，記得加這個 -r 的選項。

此外，一般預設的情況下，所有要被加到映像檔中的檔案都會被放置到映象檔中的根目錄， 如此一來可能會造成燒錄後的檔案分類不易的情況。所以，你可以使用 -graft-point 這個選項，當你使用這個選項之後， 可以利用如下的方法來定義位於映像檔中的目錄，例如：

- 映像檔中的目錄所在=實際 Linux 檔案系統的目錄所在

- /movies/=/srv/movies/ (在 Linux 的 /srv/movies 內的檔案，加至映像檔中的 /movies/ 目錄)

- /linux/etc=/etc (將 Linux 中的 /etc/ 內的所有資料備份到映像檔中的 /linux/etc/ 目錄中)

我們透過一個簡單的範例來說明一下吧。如果你想要將 /root, /home, /etc 等目錄內的資料通通燒錄起來的話， 先得要處理一下映像檔，我們先不使用 -graft-point 的選項來處理這個映像檔試看看：

[root@www ~]# mkisofs -r -v -o /tmp/system.img /root /home /etc

INFO:   ISO-8859-1 character encoding detected by locale settings.

Assuming ISO-8859-1 encoded filenames on source filesystem,

use -input-charset to override.

mkisofs 2.01 (cpu-pc-linux-gnu)

Scanning /root

Scanning /root/test4

....中間省略....

97.01% done, estimate finish Tue Dec 16 17:07:14 2008  <==顯示百分比

98.69% done, estimate finish Tue Dec 16 17:07:15 2008

Total translation table size: 0

Total rockridge attributes bytes: 9840   <==額外記錄屬性所耗用之容量

Total directory bytes: 55296             <==目錄佔用容量

Path table size(bytes): 406

Done with: The File(s)              Block(s)    298728

Writing:   Ending Padblock          Start Block 298782

Done with: Ending Padblock          Block(s)    150

Max brk space used 0

298932 extents written (583 MB)

[root@www ~]# ll -h /tmp/system.img

-rw-r--r-- 1 root root 584M Dec 16 17:07 /tmp/system.img

[root@www ~]# mount -o loop /tmp/system.img /mnt

[root@www ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/tmp/system.img       584M  584M     0 100% /mnt  <==就是這玩意兒！

[root@www ~]# ls /mnt

alex             crontab2               etc.tar.gz          system.tar.bz2

anaconda-ks.cfg  etc                    install.log         test1

arod             etc.and.root.tar.bz2   install.log.syslog  test2

boot.dump        etc.dump               loopdev             test3

# 看吧！一堆資料都放置在一起！包括有的沒有的目錄與檔案等等！

[root@www ~]# umount /mnt

由上面的範例我們可以看到，三個目錄 (/root, /home, /etc) 的資料通通放置到了映像檔的最頂層目錄中！ 真是不方便∼尤其由於 /root/etc 的存在，導致那個 /etc 的資料似乎沒有被包含進來的樣子！真不合理∼ 而且還有 lost+found 的目錄存在！真是超不喜歡的！此時我們可以使用 -graft-point 來處理囉！

[root@www ~]# mkisofs -r -V 'linux_file' -o /tmp/system.img \

>  -m /home/lost+found -graft-point /root=/root /home=/home /etc=/etc

[root@www ~]# ll -h /tmp/system.img

-rw-r--r-- 1 root root 689M Dec 17 11:41 /tmp/system.img

# 上面的指令會建立一個大檔案，期中 -graft-point 後面接的就是我們要備份的資料。

# 必須要注意的是那個等號的兩邊，等號左邊是在映像檔內的目錄，右側則是實際的資料。

[root@www ~]# mount -o loop /tmp/system.img /mnt

[root@www ~]# ll /mnt

dr-xr-xr-x 105 root root 32768 Dec 17 11:40 etc

dr-xr-xr-x   5 root root  2048 Dec 17 11:40 home

dr-xr-xr-x   7 root root  4096 Dec 17 11:40 root

# 瞧！資料是分門別類的在各個目錄中喔這樣瞭解乎？最後將資料卸載一下：

[root@www ~]# umount /mnt

其實鳥哥一直覺得很奇怪，怎麼我的資料會這麼大(600多MB)？原來是 /home 裡面在第八章的時候，練習時多了一個 /home/loopdev 的大檔案！所以在重新製作一次 iso 檔，並多加一個『 -m /home/loopdev 』來排除該檔案的備份， 最終的檔案則僅有 176MB 囉！還好還好！ ^_^！接下來讓我們處理燒錄的動作了吧！

cdrecord：光碟燒錄工具

我們是透過 cdrecord 這個指令來進行文字介面的燒錄行為，這個指令常見的選項有底下數個：

[root@www ~]# cdrecord -scanbus dev=ATA                  <==查詢燒錄機位置

[root@www ~]# cdrecord -v dev=ATA:x,y,z blank=[fast|all] <==抹除重複讀寫片

[root@www ~]# cdrecord -v dev=ATA:x,y,z -format          <==格式化DVD+RW

[root@www ~]# cdrecord -v dev=ATA:x,y,z [可用選項功能] file.iso

選項與參數：

-scanbus        ：用在掃瞄磁碟匯流排並找出可用的燒錄機，後續的裝置為 ATA 介面

-v              ：在 cdrecord 運作的過程中，顯示過程而已。

dev=ATA:x,y,z   ：後續的 x, y, z 為你系統上燒錄機所在的位置，非常重要！

blank=[fast|all]：blank 為抹除可重複寫入的CD/DVD-RW，使用fast較快，all較完整

-format         ：僅針對 DVD+RW 這種格式的 DVD 而已；

[可用選項功能] 主要是寫入 CD/DVD 時可使用的選項，常見的選項包括有：

-data   ：指定後面的檔案以資料格式寫入，不是以 CD 音軌(-audio)方式寫入！

speed=X ：指定燒錄速度，例如CD可用 speed=40 為40倍數，DVD則可用 speed=4 之類

-eject  ：指定燒錄完畢後自動退出光碟

fs=Ym   ：指定多少緩衝記憶體，可用在將映像檔先暫存至緩衝記憶體。預設為 4m，

一般建議可增加到 8m ，不過，還是得視你的燒錄機而定。

針對 DVD 的選項功能：

driveropts=burnfree ：打開 Buffer Underrun Free 模式的寫入功能

-sao                ：支援 DVD-RW 的格式

- 偵測你的燒錄機所在位置：

文字模式的燒錄確實是比較麻煩的，因為沒有所見即所得的環境嘛！要燒錄首先就得要找到燒錄機才行！ 而由於早期的燒錄機都是使用 SCSI 介面，因此查詢燒錄機的方法就得要配合著 SCSI 介面的認定來處理了。 查詢燒錄機的方式為：

[root@www ~]# cdrecord -scanbus dev=ATA

Cdrecord-Clone 2.01 (cpu-pc-linux-gnu) Copyright (C) 1995-2004 J?rg Schilling

....中間省略....

scsibus1:

1,0,0   100) *

1,1,0   101) 'ASUS    ' 'DRW-2014S1      ' '1.01' Removable CD-ROM

1,2,0   102) *

1,3,0   103) *

1,4,0   104) *

1,5,0   105) *

1,6,0   106) *

1,7,0   107) *

利用 cdrecord -scanbus 就能夠找到正確的燒錄機！由於目前個人電腦上最常使用的磁碟機介面為 IDE 與 SATA ， 這兩種介面都能夠使用 dev=ATA 這種模式來查詢，因此上述的指令得要背一下啦！另外，在查詢的結果當中可以發現有一台燒錄機， 其中也顯示出這台燒錄機的型號，而最重要的就是上表中有底線的那三個數字！那三個數字就是代表這台燒錄機的位置！ 以上表的例子中，這部燒錄機的位置在『 ATA:1,1,0 』這個地方喔！

好了，那麼現在要如何將 /tmp/system.img 燒錄到 CD/DVD 裡面去呢？鳥哥這裡先以 CD 為例，鳥哥用的是 CD-RW (可重複讀寫) 的光碟片，說實在話，雖然 CD-RW 或 DVD-RW 比較貴一點，不過至少可以重複利用， 對環境的衝擊比較小啦！建議大家使用可重複讀寫的片子。由於 CD-RW 可能要先進行抹除的工作(將原本裡面的資料刪除)然後才能寫入， 因此，底下我們先來看看如何抹除一片 CD/DVD 的方法，然後直接寫入光碟吧！

Tips:

由於 CD/DVD 都是使用 cdrecord 這個指令，因此不論是 CD 還是 DVD 片，下達指令的方法都差不多！不過， DVD 的寫入需要額外的 driveropts=burnfree 或 -dao 等選項的輔助才行。 另外，CD 片有 CD-R(一次寫入) 與 CD-RW(重複寫入)，至於 DVD 則主要有兩種格式，分別是 DVD-R 及 DVD+R 兩種格式。 如果是可重複讀寫的則為： DVD-RW, DVD+RW 。除了 DVD+RW 的抹除方法可能不太一樣之外，其他寫入的方式則是一樣的。

- 進行 CD 的燒錄動作：

# 0. 先抹除光碟的原始內容：(非可重複讀寫則可略過此步驟)

[root@www ~]# cdrecord -v dev=ATA:1,1,0 blank=fast

# 中間會跑出一堆訊息告訴你抹除的進度，而且會有 10 秒鐘的時間等待你的取消！

# 可以避免『手滑』的情況！^_^

# 1. 開始燒錄：

[root@www ~]# cdrecord -v dev=ATA:1,1,0 fs=8m -dummy -data \

>  /tmp/system.img

....中間省略....

Track 01:  168 of  176 MB written (fifo 100%) [buf 100%]  10.5x. <==顯示百分比

# 上面會顯示進度，還有 10.5x 代表目前的燒錄速度！

cdrecord: fifo had 2919 puts and 2919 gets.

cdrecord: fifo was 0 times empty and 2776 times full, min fill was 97%.

# 2. 燒錄完畢後，測試掛載一下，檢驗內容：

[root@www ~]# mount -t iso9660 /dev/cdrom /mnt

[root@www ~]# df -h /mnt

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdd              177M  177M     0 100% /mnt      <==瞧！確實是光碟內容！

[root@www ~]# ll /mnt

dr-xr-xr-x 105 root root 32768 Dec 17 11:54 etc

dr-xr-xr-x   5 root root  2048 Dec 17 11:54 home

dr-xr-xr-x   7 root root  4096 Dec 17 11:54 root

[root@www ~]# umount /mnt    <==不要忘了卸載

事實上如果你忘記抹除可寫入光碟時，其實 cdrecord 很聰明的會主動的幫你抹除啦！ 因此上面的資訊你只要記得燒錄的功能即可。特別注意 -data 那個選項！因為如果沒有加上 -data 的選項時， 預設資料會以音軌格式寫入光碟中，所以最好能夠加上 -data 這個選項囉！ 上述的功能是針對 CD ，底下我們使用一片可重複讀寫的 DVD-RW 來測試一下寫入的功能！

- 進行 DVD-RW 的燒錄動作：

# 0. 同樣的，先來抹除一下原本的內容：

[root@www ~]# cdrecord -v dev=ATA:1,1,0 blank=fast

# 1. 開始寫入 DVD ，請注意，有些選項與 CD 並不相同了喔！

[root@www ~]# cdrecord -v dev=ATA:1,1,0 fs=8m -data -sao \

>  driveropts=burnfree /tmp/system.img

# 2. 同樣的，來給他測試測試！

[root@www ~]# mount /dev/cdrom /mnt

[root@www ~]# df -h /mnt

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdd              177M  177M     0 100% /mnt

[root@www ~]# umount /mnt

整體指令沒有差很多啦！只是 CD-RW 會自動抹除，但 DVD-RW 似乎得要自己手動某除才行！並不會主動進入自動抹除的功能！ 害鳥哥重新測試過好幾次∼傷腦筋∼ ^_^！好啦！現在你就知道如何將你的資料燒錄出來啦！

如果你的 Linux 是用來做為伺服器之用的話，那麼無時無刻的去想『如何備份重要資料』是相當重要的！ 關於備份我們會在第五篇再仔細的談一談，這裡你要會使用這些工具即可！

其他常見的壓縮與備份工具

還有一些很好用的工具得要跟大家介紹介紹，尤其是 dd 這個玩意兒呢！

dd

我們在第八章當中的特殊 loop 裝置掛載時使用過 dd 這個指令對吧？ 不過，這個指令可不只是製作一個檔案而已喔∼這個 dd 指令最大的功效，鳥哥認為，應該是在於『備份』啊！ 因為 dd 可以讀取磁碟裝置的內容(幾乎是直接讀取磁區"sector")，然後將整個裝置備份成一個檔案呢！真的是相當的好用啊∼ dd 的用途有很多啦∼但是我們僅講一些比較重要的選項，如下：

[root@www ~]# dd if="input_file" of="output_file" bs="block_size" \

> count="number"

選項與參數：

if   ：就是 input file 囉∼也可以是裝置喔！

of   ：就是 output file 喔∼也可以是裝置；

bs   ：規劃的一個 block 的大小，若未指定則預設是 512 bytes(一個 sector 的大小)

count：多少個 bs 的意思。

範例一：將 /etc/passwd 備份到 /tmp/passwd.back 當中

[root@www ~]# dd if=/etc/passwd of=/tmp/passwd.back

3+1 records in

3+1 records out

1945 bytes (1.9 kB) copied, 0.000332893 seconds, 5.8 MB/s

[root@www ~]# ll /etc/passwd /tmp/passwd.back

-rw-r--r-- 1 root root 1945 Sep 29 02:21 /etc/passwd

-rw-r--r-- 1 root root 1945 Dec 17 18:09 /tmp/passwd.back

# 仔細的看一下，我的 /etc/passwd 檔案大小為 1945 bytes，因為我沒有設定 bs ，

# 所以預設是 512 bytes 為一個單位，因此，上面那個 3+1 表示有 3 個完整的

# 512 bytes，以及未滿 512 bytes 的另一個 block 的意思啦！

# 事實上，感覺好像是 cp 這個指令啦∼

範例二：將自己的磁碟之第一個磁區備份下來

[root@www ~]# dd if=/dev/hdc of=/tmp/mbr.back bs=512 count=1

1+0 records in

1+0 records out

512 bytes (512 B) copied, 0.0104586 seconds, 49.0 kB/s

# 第一個磁區內含有 MBR 與 partition table ，透過這個動作，

# 我們可以一口氣將這個磁碟的 MBR 與 partition table 進行備份哩！

範例三：找出你系統最小的那個分割槽，並且將他備份下來：

[root@www ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdc2             9.5G  3.9G  5.1G  44% /

/dev/hdc3             4.8G  651M  3.9G  15% /home

/dev/hdc1              99M   21M   73M  23% /boot  <==就捉他好了！

[root@www ~]# dd if=/dev/hdc1 of=/tmp/boot.whole.disk

208782+0 records in

208782+0 records out

106896384 bytes (107 MB) copied, 6.24721 seconds, 17.1 MB/s

[root@www ~]# ll -h /tmp/boot.whole.disk

-rw-r--r-- 1 root root 102M Dec 17 18:14 /tmp/boot.whole.disk

# 等於是將整個 /dev/hdc1 通通捉下來的意思∼如果要還原呢？就反向回去！

# dd if=/tmp/boot.whole.disk of=/dev/hdc1 即可！非常簡單吧！

# 簡單的說，如果想要整個硬碟備份的話，就類似 Norton 的 ghost 軟體一般，

# 由 disk 到 disk ，嘿嘿∼利用 dd 就可以啦∼厲害厲害！

你可以說， tar 可以用來備份關鍵資料，而 dd 則可以用來備份整顆 partition 或 整顆 disk ，很不錯啊∼不過，如果要將資料填回到 filesystem 當中， 可能需要考慮到原本的 filesystem 才能成功啊！讓我們來完成底下的例題試看看：

例題：

你想要將你的 /dev/hdc1 進行完整的複製到另一個 partition 上，請使用你的系統上面未分割完畢的容量再建立一個與 /dev/hdc1 差不多大小的分割槽 (只能比 /dev/hdc1 大，不能比他小！)，然後將之進行完整的複製 (包括需要複製 boot sector 的區塊)。

答：

由於需要複製 boot sector 的區塊，所以使用 cp 或者是 tar 這種指令是無法達成需求的！ 此時那個 dd 就派的上用場了。你可以這樣做：

# 1. 先進行分割的動作

[root@www ~]# fdisk -l /dev/hdc

Device Boot   Start    End    Blocks   Id  System

/dev/hdc1   *        1     13    104391   83  Linux

# 上面鳥哥僅擷取重要的資料而已！我們可以看到 /dev/hdc1 僅有 13 個磁柱

[root@www ~]# fdisk /dev/hdc

Command (m for help): n

First cylinder (2354-5005, default 2354): 這裡按 enter

Using default value 2354

Last cylinder or +size or +sizeM or +sizeK (2354-5005, default 5005): 2366

Command (m for help): p

Device Boot   Start    End    Blocks   Id  System

/dev/hdc9         2354   2366    104391   83  Linux

Command (m for help): w

# 為什麼要使用 2366 呢？因為 /dev/hdc1 使用 13 個磁柱，因此新的 partition

# 我們也給她 13 個磁柱，因此 2354 + 13 -1 = 2366 囉！

[root@www ~]# partprobe

# 2. 不需要格式化，直接進行 sector 表面的複製！

[root@www ~]# dd if=/dev/hdc1 of=/dev/hdc9

208782+0 records in

208782+0 records out

106896384 bytes (107 MB) copied, 16.8797 seconds, 6.3 MB/s

[root@www ~]# mount /dev/hdc9 /mnt

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hdc1               101086     21408     74459  23% /boot

/dev/hdc9               101086     21408     74459  23% /mnt

# 這兩個玩意兒會『一模一樣』喔！

[root@www ~]# umount /mnt

非常有趣的範例吧！新分割出來的 partition 不需要經過格式化，因為 dd 可以將原本舊的 partition 上面，將 sector 表面的資料整個複製過來！ 當然連同 superblock, boot sector, meta data 等等通通也會複製過來！是否很有趣呢？未來你想要建置兩顆一模一樣的磁碟時， 只要下達類似： dd if=/dev/sda of=/dev/sdb ，就能夠讓兩顆磁碟一模一樣，甚至 /dev/sdb 不需要分割與格式化， 因為該指令可以將 /dev/sda 內的所有資料，包括 MBR 與 partition table 也複製到 /dev/sdb 說！ ^_^

cpio

這個指令挺有趣的，因為 cpio 可以備份任何東西，包括裝置設備檔案。不過 cpio 有個大問題， 那就是 cpio 不會主動的去找檔案來備份！啊！那怎辦？所以囉，一般來說， cpio 得要配合類似 find 等可以找到檔名的指令來告知 cpio 該被備份的資料在哪裡啊！ 有點小麻煩啦∼因為牽涉到我們在第三篇才會談到的資料流重導向說∼ 所以這裡你就先背一下語法，等到第三篇講完你就知道如何使用 cpio 囉！

[root@www ~]# cpio -ovcB  > [file|device] <==備份

[root@www ~]# cpio -ivcdu < [file|device] <==還原

[root@www ~]# cpio -ivct  < [file|device] <==察看

備份會使用到的選項與參數：

-o ：將資料 copy 輸出到檔案或裝置上

-B ：讓預設的 Blocks 可以增加至 5120 bytes ，預設是 512 bytes ！

這樣的好處是可以讓大檔案的儲存速度加快(請參考 i-nodes 的觀念)

還原會使用到的選項與參數：

-i ：將資料自檔案或裝置 copy 出來系統當中

-d ：自動建立目錄！使用 cpio 所備份的資料內容不見得會在同一層目錄中，因此我們

必須要讓 cpio 在還原時可以建立新目錄，此時就得要 -d 選項的幫助！

-u ：自動的將較新的檔案覆蓋較舊的檔案！

-t ：需配合 -i 選項，可用在"察看"以 cpio 建立的檔案或裝置的內容

一些可共用的選項與參數：

-v ：讓儲存的過程中檔案名稱可以在螢幕上顯示

-c ：一種較新的 portable format 方式儲存

你應該會發現一件事情，就是上述的選項與指令中怎麼會沒有指定需要備份的資料呢？還有那個大於 (>) 與小於 (<) 符號是怎麼回事啊？因為 cpio 會將資料整個顯示到螢幕上，因此我們可以透過將這些螢幕的資料重新導向 (>) 一個新的檔案！ 至於還原呢？就是將備份檔案讀進來 cpio (<) 進行處理之意！我們來進行幾個案例你就知道啥是啥了！

範例：找出 /boot 底下的所有檔案，然後將他備份到 /tmp/boot.cpio 去！

[root@www ~]# find /boot -print

/boot

/boot/message

/boot/initrd-2.6.18-128.el5.img

....以下省略....

# 透過這個 find 我們可以找到 /boot 底下應該要存在的檔名！包括檔案與目錄

[root@www ~]# find /boot | cpio -ocvB > /tmp/boot.cpio

[root@www ~]# ll -h /tmp/boot.cpio

-rw-r--r-- 1 root root 16M Dec 17 23:30 /tmp/boot.cpio

我們使用 find /boot 可以找出檔名，然後透過那條管線 (|, 亦即鍵盤上的 shift+\ 的組合)， 就能將檔名傳給 cpio 來進行處理！最終會得到 /tmp/boot.cpio 那個檔案喔！接下來讓我們來進行解壓縮看看。

範例：將剛剛的檔案給他在 /root/ 目錄下解開

[root@www ~]# cpio -idvc < /tmp/boot.cpio

[root@www ~]# ll /root/boot

# 你可以自行比較一下 /root/boot 與 /boot 的內容是否一模一樣！

事實上 cpio 可以將系統的資料完整的備份到磁帶機上頭去喔！如果你有磁帶機的話！

- 備份：find / | cpio -ocvB > /dev/st0

- 還原：cpio -idvc < /dev/st0

這個 cpio 好像不怎麼好用呦！但是，他可是備份的時候的一項利器呢！因為他可以備份任何的檔案， 包括 /dev 底下的任何裝置檔案！所以他可是相當重要的呢！而由於 cpio 必需要配合其他的程式，例如 find 來建立檔名，所以 cpio 與管線命令及資料流重導向的相關性就相當的重要了！

其實系統裡面已經含有一個使用 cpio 建立的檔案喔！那就是 /boot/initrd-xxx 這個檔案啦！ 現在讓我們來將這個檔案解壓縮看看，看你能不能發現該檔案的內容為何？

# 1. 我們先來看看該檔案是屬於什麼檔案格式，然後再加以處理：

[root@www ~]# file /boot/initrd-2.6.18-128.el5.img

/boot/initrd-2.6.18-128.el5.img: gzip compressed data, ...

# 唔！看起來似乎是使用 gzip 進行壓縮過∼那如何處理呢？

# 2. 透過更名，將該檔案增加副檔名，然後予以解壓縮看看：

[root@www ~]# mkdir initrd

[root@www ~]# cd initrd

[root@www initrd]# cp /boot/initrd-2.6.18-128.el5.img initrd.img.gz

[root@www initrd]# gzip -d initrd.img.gz

[root@www initrd]# ll

-rw------- 1 root root 5408768 Dec 17 23:53 initrd.img

[root@www initrd]# file initrd.img

initrd.img: ASCII cpio archive (SVR4 with no CRC)

# 嘿嘿！露出馬腳了吧！確實是 cpio 的文件檔喔！

# 3. 開始使用 cpio 解開此檔案：

[root@www initrd]# cpio -iduvc < initrd.img

sbin

init

sysroot

....以下省略....

# 瞧！這樣就將這個檔案解開囉！這樣瞭解乎？

重點回顧

- 壓縮指令為透過一些運算方法去將原本的檔案進行壓縮，以減少檔案所佔用的磁碟容量。 壓縮前與壓縮後的檔案所佔用的磁碟容量比值， 就可以被稱為是『壓縮比』

- 壓縮的好處是可以減少磁碟容量的浪費，在 WWW 網站也可以利用檔案壓縮的技術來進行資料的傳送，好讓網站頻寬的可利用率上升喔

- 壓縮檔案的副檔名大多是：『*.tar, *.tar.gz, *.tgz, *.gz, *.Z, *.bz2』

- 常見的壓縮指令有 gzip 與 bzip2 ，其中 bzip2 壓縮比較之 gzip 還要更好，建議使用 bzip2 ！

- tar 可以用來進行檔案打包，並可支援 gzip 或 bzip2 的壓縮。

- 壓　縮：tar -jcv -f filename.tar.bz2 要被壓縮的檔案或目錄名稱

- 查　詢：tar -jtv -f filename.tar.bz2

- 解壓縮：tar -jxv -f filename.tar.bz2 -C 欲解壓縮的目錄

- dump 指令可備份檔案系統或單一目錄

- dump 的備份若針對檔案系統時，可進行 0-9 的 level 差異備份！其中 level 0 為完整備份；

- restore 指令可還原被 dump 建置的備份檔；

- 要建立光碟燒錄資料時，可透過 mkisofs 指令來建置；

- 可透過 cdrecord 來寫入 CD 或 DVD 燒錄機

- dd 可備份完整的 partition 或 disk ，因為 dd 可讀取磁碟的 sector 表面資料

- cpio 為相當優秀的備份指令，不過必須要搭配類似 find 指令來讀入欲備份的檔名資料，方可進行備份動作。

本章習題

(要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

- 情境模擬題一：妳想要讓系統恢復到第八章情境模擬後的結果，亦即僅剩下 /dev/hdc6 以前的 partition， 本章練習產生的 partition 都需要恢復原狀。因此 /dev/hdc8, /dev/hdc9 (在本章練習過程中產生的) 請將他刪除！刪除的方法同第八章的情境模擬題一所示。

- 情境模擬題二：妳想要逐時備份 /srv/myproject 這個目錄內的資料，又擔心每次備份的資訊太多， 因此想要使用 dump 的方式來逐一備份資料到 /backups 這個目錄下。該如何處理？

- 目標：瞭解到 dump 以及各個不同 level 的作用；

- 前提：被備份的資料為單一 partition ，亦即本例中的 /srv/myproject

- 需求：/srv/myproject 為單一 filesystem ，且在 /etc/fstab 內此掛載點的 dump 欄位為 1

實際處理的方法其實還挺簡單的！我們可以這樣做看看：

- 先替該目錄製作一些資料，亦即複製一些東西過去吧！

cp -a /etc /boot /srv/myproject

- 開始進行 dump ，記得，一開始是使用 level 0 的完整備份喔！

mkdir /backups

dump -0u -j -f /backups/myproject.dump /srv/myproject

上面多了個 -j 的選項，目的是為了要進行壓縮，減少備份的資料量。

- 嘗試將 /srv/myproject 這個檔案系統加大，將 /var/log/ 的資料複製進去吧！

cp -a /var/log/ /srv/myproject

此時原本的 /srv/myproject 已經被改變了！繼續進行備份看看！

- 將 /srv/myproject 以 level 1 來進行備份：

dump -1u -j -f /backups/myproject.dump.1 /srv/myproject

ls -l /backups

妳應該就會看到兩個檔案，其中第二個檔案 (myproject.dump.1) 會小的多！這樣就搞定囉備份資料！

- 情境模擬三：假設過了一段時間後，妳的 /srv/myproject 變的怪怪的，妳想要將該 filesystem 以剛剛的備份資料還原， 此時該如何處理呢？妳可以這樣做的：

- 先將 /srv/myproject 卸載，並且將該 partition 重新格式化！

umount /dev/hdc6

mkfs -t ext3 /dev/hdc6

- 重新掛載原本的 partition ，此時該目錄內容應該是空的！

mount -a

妳可以自行使用 df 以及 ls -l /srv/myproject 查閱一下該目錄的內容，是空的啦！

- 將完整備份的 level 0 的檔案 /backups/myproject.dump 還原回來：

cd /srv/myproject

restore -r -f /backups/myproject.dump

此時該目錄的內容為第一次備份的狀態！還需要進行後續的處理才行！

- 將後續的 level 1 的備份也還原回來：

cd /srv/myproject

restore -r -f /backups/myproject.dump.1

此時才是恢復到最後一次備份的階段！如果還有 level 2, level 3 時，就得要一個一個的依序還原才行！

參考資料與延伸閱讀

- 台灣學術網路管理文件：Backup Tools in UNIX(Linux):

http://nmc.nchu.edu.tw/tanet/backup_tools_in_unix.htm

- 中文 How to 文件計畫 (CLDP)：http://www.linux.org.tw/CLDP/HOWTO/hardware/CD-Writing-HOWTO/CD-Writing-HOWTO-3.html

- 熊寶貝工作記錄之： Linux 燒錄實作：http://csc.ocean-pioneer.com/docum/linux_burn.html

- PHP5 網管實驗室： http://www.php5.idv.tw/html.php?mod=article&do=show&shid=26

- CentOS 5.x 之 man dump

- CentOS 5.x 之 man restore

2003/02/09：第一次完成

2003/05/05：修改 tar 的部分內容，尤其是 -P 這個參數的配合用法

2005/07/26：將舊有的文章移動到 這裡

2005/07/27：大略修改了一些風格，另外，動作較大的是在範例的部分！

2005/08/29：加入了 dd 這個有趣的指令喔！

2006/05/02：將原本『tar -zxvpf /tmp/etc.tar.gz /etc』修改為『tar -zcvpf /tmp/etc.tar.gz /etc』 感謝討論區網友 chinu 提供的資訊。

2008/10/31：將原本針對 FC4 的舊版本移動到此處

2008/12/18：這次的改版在這一章添加了不少東西！尤其是將 cpio 與 dd 的範例重新做個整理！並加入 dump/restore, mkisofs/cdrecord

2009/08/20：加入情境模擬的題目。

2003/02/09以來統計人數

第十章、vim 程式編輯器

切換解析度為 800x600

最近更新日期：2009/08/20

系統管理員的重要工作就是得要修改與設定某些重要軟體的設定檔，因此至少得要學會一種以上的文字介面的文書編輯器。 在所有的 Linux distributions 上頭都會有的一套文書編輯器就是 vi ，而且很多軟體預設也是使用 vi 做為他們編輯的介面， 因此鳥哥建議您務必要學會使用 vi 這個正規的文書編輯器。此外，vim 是進階版的 vi ， vim 不但可以用不同顏色顯示文字內容，還能夠進行諸如 shell script, C program 等程式編輯功能， 你可以將 vim 視為一種程式編輯器！鳥哥也是用 vim 編輯鳥站的網頁文章呢！ ^_^

1. vi 與 vim

1.1 為何要學 vim

2. vi 的使用

2.1 簡易執行範例

2.2 按鍵說明

2.3 一個案例的練習

2.4 vim 的暫存檔、救援回復與開啟時的警告訊息

3. vim 的額外功能

3.1 區塊選擇(Visual Block)

3.2 多檔案編輯

3.3 多視窗功能

3.4 vim 環境設定與記錄： ~/.vimrc, ~/.viminfo

3.5 vim 常用指令示意圖

4. 其他 vim 使用注意事項

4.1 中文編碼的問題

4.2 DOS 與 Linux 的斷行字元： dos2unix, unix2dos

4.3 語系編碼轉換： iconv

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23883

vi 與 vim

由前面一路走來，我們一直建議使用文字模式來處理 Linux 的系統設定問題，因為不但可以讓你比較容易瞭解到 Linux 的運作狀況，也比較容易瞭解整個設定的基本精神，更能『保證』你的修改可以順利的被運作。 所以，在 Linux 的系統中使用文字編輯器來編輯你的 Linux 參數設定檔，可是一件很重要的事情呦！也因此呢，系統管理員至少應該要熟悉一種文書處理器的！

Tips:

這裡要再次的強調，不同的 Linux distribution 各有其不同的附加軟體，例如 Red Hat Enterprise Linux 與 Fedora 的 ntsysv 與 setup 等，而 SuSE 則有 YAST 管理工具等等， 因此，如果你只會使用此種類型的軟體來控制你的 Linux 系統時，當接管不同的 Linux distributions 時，呵呵！那可就苦惱了！

在 Linux 的世界中，絕大部分的設定檔都是以 ASCII 的純文字形態存在，因此利用簡單的文字編輯軟體就能夠修改設定了！ 與微軟的 Windows 系統不同的是，如果你用慣了 Microsoft Word 或 Corel Wordperfect 的話，那麼除了 X window 裡面的圖形介面編輯程式(如 xemacs )用起來尚可應付外，在 Linux 的文字模式下，會覺得文書編輯程式都沒有視窗介面來的直觀與方便。

Tips:

什麼是純文字檔？其實檔案記錄的就是 0 與 1 ，而我們透過編碼系統來將這些 0 與 1 轉成我們認識的文字就是了。 在第零章裡面的資料表示方式有較多說明，請自行查閱。 ASCII 就是其中一種廣為使用的文字編碼系統，在 ASCII 系統中的圖示與代碼可以參考 http://zh.wikipedia.org/wiki/ASCII呢！

那麼 Linux 在文字介面下的文書編輯器有哪些呢？其實有非常多喔！常常聽到的就有： emacs, pico, nano, joe, 與 vim 等等(註1)。 既然有這麼多文字介面的文書編輯器，那麼我們為什麼一定要學 vi 啊？還有那個 vim 是做啥用的？底下就來談一談先！

為何要學 vim

文書編輯器那麼多，我們之前在第五章也曾經介紹過那簡單好用的 nano ，既然已經學會了 nano ，幹嘛鳥哥還一直要你學這不是很友善的 vi 呢？其實是有原因的啦！因為：

- 所有的 Unix Like 系統都會內建 vi 文書編輯器，其他的文書編輯器則不一定會存在；

- 很多個別軟體的編輯介面都會主動呼叫 vi (例如未來會談到的 crontab, visudo, edquota 等指令)；

- vim 具有程式編輯的能力，可以主動的以字體顏色辨別語法的正確性，方便程式設計；

- 因為程式簡單，編輯速度相當快速。

其實重點是上述的第二點，因為有太多 Linux 上面的指令都預設使用 vi 作為資料編輯的介面，所以你必須、一定要學會 vi ，否則很多指令你根本就無法操作呢！這樣說，有刺激到你務必要學會 vi 的熱情了嗎？ ^_^

那麼什麼是 vim 呢？其實你可以將 vim 視作 vi 的進階版本，vim 可以用顏色或底線等方式來顯示一些特殊的資訊。 舉例來說，當你使用 vim 去編輯一個 C 程式語言的檔案，或者是我們後續會談到的 shell script 程式時，vim 會依據檔案的副檔名或者是檔案內的開頭資訊， 判斷該檔案的內容而自動的呼叫該程式的語法判斷式，再以顏色來顯示程式碼與一般資訊。也就是說， 這個 vim 是個『程式編輯器』啦！甚至一些 Linux 基礎設定檔內的語法，都能夠用 vim 來檢查呢！ 例如我們在第八章談到的 /etc/fstab 這個檔案的內容。

簡單的來說， vi 是老式的文書處理器，不過功能已經很齊全了，但是還是有可以進步的地方。 vim 則可以說是程式開發者的一項很好用的工具，就連 vim 的官方網站 (http://www.vim.org) 自己也說 vim 是一個『程式開發工具』而不是文書處理軟體∼^_^。 因為 vim 裡面加入了很多額外的功能，例如支援正規表示法的搜尋架構、多檔案編輯、區塊複製等等。 這對於我們在 Linux 上面進行一些設定檔的修訂工作時，是很棒的一項功能呢！

Tips:

什麼時候會使用到 vim 呢？其實鳥哥的整個網站都是在 vim 的環境下一字一字的建立起來的喔！ 早期鳥哥使用網頁製作軟體在編寫網頁，但是老是發現網頁編輯軟體都不怎麼友善，尤其是寫到 PHP 方面的程式碼時。 後來就乾脆不使用所見即所得的編輯軟體，直接使用 vim ，然後標籤 (tag) 也都自行用鍵盤輸入！ 這樣整個檔案也比較乾淨！所以說，鳥哥我是很喜歡 vim 的啦！ ^_^

底下鳥哥會先就簡單的 vi 做個介紹，然後再跟大家報告一下 vim 的額外功能與用法呢！

vi 的使用

基本上 vi 共分為三種模式，分別是『一般模式』、『編輯模式』與『指令列命令模式』。 這三種模式的作用分別是：

- 一般模式：

以 vi 打開一個檔案就直接進入一般模式了(這是預設的模式)。在這個模式中， 你可以使用『上下左右』按鍵來移動游標，你可以使用『刪除字元』或『刪除整行』來處理檔案內容， 也可以使用『複製、貼上』來處理你的文件資料。

- 編輯模式：

在一般模式中可以進行刪除、複製、貼上等等的動作，但是卻無法編輯文件內容的！ 要等到你按下『i, I, o, O, a, A, r, R』等任何一個字母之後才會進入編輯模式。注意了！通常在 Linux 中，按下這些按鍵時，在畫面的左下方會出現『 INSERT 或 REPLACE 』的字樣，此時才可以進行編輯。而如果要回到一般模式時， 則必須要按下『Esc』這個按鍵即可退出編輯模式。

- 指令列命令模式：

在一般模式當中，輸入『 : / ? 』三個中的任何一個按鈕，就可以將游標移動到最底下那一行。在這個模式當中， 可以提供你『搜尋資料』的動作，而讀取、存檔、大量取代字元、離開 vi 、顯示行號等等的動作則是在此模式中達成的！

簡單的說，我們可以將這三個模式想成底下的圖示來表示：

圖 2.1、vi 三種模式的相互關係

注意到上面的圖示，你會發現一般模式可與編輯模式及指令列模式切換， 但編輯模式與指令列模式之間不可互相切換喔！這非常重要啦！ 閒話不多說，我們底下以一個簡單的例子來進行說明吧！

簡易執行範例

如果你想要使用 vi 來建立一個名為 test.txt 的檔案時，你可以這樣做：

1.      使用 vi 進入一般模式；

[root@www ~]# vi test.txt

直接輸入『 vi 檔名』就能夠進入 vi 的一般模式了。請注意，記得 vi 後面一定要加檔名，不管該檔名存在與否！ 整個畫面主要分為兩部份，上半部與最底下一行兩者可以視為獨立的。如下圖 2.1.1 所示，圖中那個虛線是不存在的， 鳥哥用來說明而已啦！上半部顯示的是檔案的實際內容，最底下一行則是狀態顯示列(如下圖的[New File]資訊)， 或者是命令下達列喔！

圖 2.1.1、用 vi 開啟一個新檔案

如果你開啟的檔案是舊檔(已經存在的檔案)，則可能會出現如下的資訊：

圖 2.1.2、用 vi 開啟一個舊檔案

如上圖 2.1.2 所示，箭頭所指的那個『"/etc/man.config" 141L, 4617C』代表的是『檔名為 /etc/man.conf， 檔案內有 141 行 以及具有 4617 個字元』的意思！ 那一行的內容並不是在檔案內，而是 vi 顯示一些資訊的地方喔！此時是在一般模式的環境下啦。 接下來開始來輸入吧！

2.      按下 i 進入編輯模式，開始編輯文字

在一般模式之中，只要按下 i, o, a 等字元就可以進入編輯模式了！在編輯模式當中，你可以發現在左下角狀態列中會出現 –INSERT- 的字樣，那就是可以輸入任意字元的提示囉！這個時候，鍵盤上除了 [Esc] 這個按鍵之外，其他的按鍵都可以視作為一般的輸入按鈕了，所以你可以進行任何的編輯囉！

圖 2.1.3、開始用 vi 來進行編輯

Tips:

在 vi 裡面， [tab] 這個按鈕所得到的結果與空白字元所得到的結果是不一樣的，特別強調一下！

3.      按下 [ESC] 按鈕回到一般模式

好了，假設我已經按照上面的樣式給他編輯完畢了，那麼應該要如何退出呢？是的！沒錯！就是給他按下 [Esc] 這個按鈕即可！馬上你就會發現畫面左下角的 – INSERT – 不見了！

4.      在一般模式中按下 :wq 儲存後離開 vi

OK，我們要存檔了，存檔並離開的指令很簡單，輸入『:wq』即可存檔離開！ (注意了，按下 : 該游標就會移動到最底下一行去！) 這時你在提示字元後面輸入『 ls -l 』即可看到我們剛剛建立的 test.txt 檔案啦！整個圖示有點像底下這樣：

圖 2.1.4、儲存並離開 vi 環境

如此一來，你的檔案 test.txt 就已經建立起來囉！需要注意的是，如果你的檔案權限不對，例如為 -r--r--r-- 時，那麼可能會無法寫入，此時可以使用『強制寫入』的方式嗎？可以！使用『 :wq! 』 多加一個驚嘆號即可！不過，需要特別注意呦！那個是在『你的權限可以改變』的情況下才能成立的！ 關於權限的概念，請自行回去翻一下第六章的內容吧！

按鍵說明

除了上面簡易範例的 i, [Esc], :wq 之外，其實 vim 還有非常多的按鍵可以使用喔！在介紹之前還是要再次強調， vim 的三種模式只有一般模式可以與編輯、指令列模式切換，編輯模式與指令列模式之間並不能切換的！ 這點在圖2.1裡面有介紹到，注意去看看喔！底下就來談談 vim 軟體中會用到的按鍵功能吧！

- 第一部份：一般模式可用的按鈕說明，游標移動、複製貼上、搜尋取代等

移動游標的方法

h 或 向左方向鍵(←)

游標向左移動一個字元

j 或 向下方向鍵(↓)

游標向下移動一個字元

k 或 向上方向鍵(↑)

游標向上移動一個字元

l 或 向右方向鍵(→)

游標向右移動一個字元

如果你將右手放在鍵盤上的話，你會發現 hjkl 是排列在一起的，因此可以使用這四個按鈕來移動游標。 如果想要進行多次移動的話，例如向下移動 30 行，可以使用 "30j" 或 "30↓" 的組合按鍵， 亦即加上想要進行的次數(數字)後，按下動作即可！

[Ctrl] + [f]

螢幕『向下』移動一頁，相當於 [Page Down]按鍵 (常用)

[Ctrl] + [b]

螢幕『向上』移動一頁，相當於 [Page Up] 按鍵 (常用)

[Ctrl] + [d]

螢幕『向下』移動半頁

[Ctrl] + [u]

螢幕『向上』移動半頁

+

游標移動到非空白字元的下一列

-

游標移動到非空白字元的上一列

n<space>

那個 n 表示『數字』，例如 20 。按下數字後再按空白鍵，游標會向右移動這一行的 n 個字元。例如 20<space> 則游標會向後面移動 20 個字元距離。

0 或功能鍵[Home]

這是數字『 0 』：移動到這一行的最前面字元處 (常用)

$ 或功能鍵[End]

移動到這一行的最後面字元處(常用)

H

游標移動到這個螢幕的最上方那一行的第一個字元

M

游標移動到這個螢幕的中央那一行的第一個字元

L

游標移動到這個螢幕的最下方那一行的第一個字元

G

移動到這個檔案的最後一行(常用)

nG

n 為數字。移動到這個檔案的第 n 行。例如 20G 則會移動到這個檔案的第 20 行(可配合 :set nu)

gg

移動到這個檔案的第一行，相當於 1G 啊！ (常用)

n<Enter>

n 為數字。游標向下移動 n 行(常用)

搜尋與取代

/word

向游標之下尋找一個名稱為 word 的字串。例如要在檔案內搜尋 vbird 這個字串，就輸入 /vbird 即可！ (常用)

?word

向游標之上尋找一個字串名稱為 word 的字串。

n

這個 n 是英文按鍵。代表『重複前一個搜尋的動作』。舉例來說， 如果剛剛我們執行 /vbird 去向下搜尋 vbird 這個字串，則按下 n 後，會向下繼續搜尋下一個名稱為 vbird 的字串。如果是執行 ?vbird 的話，那麼按下 n 則會向上繼續搜尋名稱為 vbird 的字串！

N

這個 N 是英文按鍵。與 n 剛好相反，為『反向』進行前一個搜尋動作。 例如 /vbird 後，按下 N 則表示『向上』搜尋 vbird 。

使用 /word 配合 n 及 N 是非常有幫助的！可以讓你重複的找到一些你搜尋的關鍵字！

:n1,n2s/word1/word2/g

n1 與 n2 為數字。在第 n1 與 n2 行之間尋找 word1 這個字串，並將該字串取代為 word2 ！舉例來說，在 100 到 200 行之間搜尋 vbird 並取代為 VBIRD 則：

『:100,200s/vbird/VBIRD/g』。(常用)

:1,$s/word1/word2/g

從第一行到最後一行尋找 word1 字串，並將該字串取代為 word2 ！(常用)

:1,$s/word1/word2/gc

從第一行到最後一行尋找 word1 字串，並將該字串取代為 word2 ！且在取代前顯示提示字元給使用者確認 (confirm) 是否需要取代！(常用)

刪除、複製與貼上

x, X

在一行字當中，x 為向後刪除一個字元 (相當於 [del] 按鍵)， X 為向前刪除一個字元(相當於 [backspace] 亦即是倒退鍵) (常用)

nx

n 為數字，連續向後刪除 n 個字元。舉例來說，我要連續刪除 10 個字元， 『10x』。

dd

刪除游標所在的那一整列(常用)

ndd

n 為數字。刪除游標所在的向下 n 列，例如 20dd 則是刪除 20 列 (常用)

d1G

刪除游標所在到第一行的所有資料

dG

刪除游標所在到最後一行的所有資料

d$

刪除游標所在處，到該行的最後一個字元

d0

那個是數字的 0 ，刪除游標所在處，到該行的最前面一個字元

yy

複製游標所在的那一行(常用)

nyy

n 為數字。複製游標所在的向下 n 列，例如 20yy 則是複製 20 列(常用)

y1G

複製游標所在列到第一列的所有資料

yG

複製游標所在列到最後一列的所有資料

y0

複製游標所在的那個字元到該行行首的所有資料

y$

複製游標所在的那個字元到該行行尾的所有資料

p, P

p 為將已複製的資料在游標下一行貼上，P 則為貼在游標上一行！ 舉例來說，我目前游標在第 20 行，且已經複製了 10 行資料。則按下 p 後， 那 10 行資料會貼在原本的 20 行之後，亦即由 21 行開始貼。但如果是按下 P 呢？ 那麼原本的第 20 行會被推到變成 30 行。 (常用)

J

將游標所在列與下一列的資料結合成同一列

c

重複刪除多個資料，例如向下刪除 10 行，[ 10cj ]

u

復原前一個動作。(常用)

[Ctrl]+r

重做上一個動作。(常用)

這個 u 與 [Ctrl]+r 是很常用的指令！一個是復原，另一個則是重做一次∼ 利用這兩個功能按鍵，你的編輯，嘿嘿！很快樂的啦！

.

不要懷疑！這就是小數點！意思是重複前一個動作的意思。 如果你想要重複刪除、重複貼上等等動作，按下小數點『.』就好了！ (常用)

- 第二部份：一般模式切換到編輯模式的可用的按鈕說明

進入插入或取代的編輯模式

i, I

進入插入模式(Insert mode)：

i 為『從目前游標所在處插入』， I 為『在目前所在行的第一個非空白字元處開始插入』。 (常用)

a, A

進入插入模式(Insert mode)：

a 為『從目前游標所在的下一個字元處開始插入』， A 為『從游標所在行的最後一個字元處開始插入』。(常用)

o, O

進入插入模式(Insert mode)：

這是英文字母 o 的大小寫。o 為『在目前游標所在的下一行處插入新的一行』； O 為在目前游標所在處的上一行插入新的一行！(常用)

r, R

進入取代模式(Replace mode)：

r 只會取代游標所在的那一個字元一次；R會一直取代游標所在的文字，直到按下 ESC 為止；(常用)

上面這些按鍵中，在 vi 畫面的左下角處會出現『--INSERT--』或『--REPLACE--』的字樣。 由名稱就知道該動作了吧！！特別注意的是，我們上面也提過了，你想要在檔案裡面輸入字元時， 一定要在左下角處看到 INSERT 或 REPLACE 才能輸入喔！

[Esc]

退出編輯模式，回到一般模式中(常用)

- 第三部份：一般模式切換到指令列模式的可用的按鈕說明

指令列的儲存、離開等指令

:w

將編輯的資料寫入硬碟檔案中(常用)

:w!

若檔案屬性為『唯讀』時，強制寫入該檔案。不過，到底能不能寫入， 還是跟你對該檔案的檔案權限有關啊！

:q

離開 vi (常用)

:q!

若曾修改過檔案，又不想儲存，使用 ! 為強制離開不儲存檔案。

注意一下啊，那個驚嘆號 (!) 在 vi 當中，常常具有『強制』的意思∼

:wq

儲存後離開，若為 :wq! 則為強制儲存後離開 (常用)

ZZ

這是大寫的 Z 喔！若檔案沒有更動，則不儲存離開，若檔案已經被更動過，則儲存後離開！

:w [filename]

將編輯的資料儲存成另一個檔案（類似另存新檔）

:r [filename]

在編輯的資料中，讀入另一個檔案的資料。亦即將 『filename』 這個檔案內容加到游標所在行後面

:n1,n2 w [filename]

將 n1 到 n2 的內容儲存成 filename 這個檔案。

:! command

暫時離開 vi 到指令列模式下執行 command 的顯示結果！例如

『:! ls /home』即可在 vi 當中察看 /home 底下以 ls 輸出的檔案資訊！

vim 環境的變更

:set nu

顯示行號，設定之後，會在每一行的字首顯示該行的行號

:set nonu

與 set nu 相反，為取消行號！

特別注意，在 vi 中，『數字』是很有意義的！數字通常代表重複做幾次的意思！ 也有可能是代表去到第幾個什麼什麼的意思。舉例來說，要刪除 50 行，則是用 『50dd』 對吧！ 數字加在動作之前∼那我要向下移動 20 行呢？那就是『20j』或者是『20↓』即可。

OK！會這些指令就已經很厲害了，因為常用到的指令也只有不到一半！通常 vi 的指令除了上面鳥哥註明的常用的幾個外，其他是不用背的，你可以做一張簡單的指令表在你的螢幕牆上， 一有疑問可以馬上的查詢呦！這也是當初鳥哥使用 vim 的方法啦！

一個案例練習

來來來！趕緊測試一下你是否已經熟悉 vi 這個指令呢？請依照底下的需求進行指令動作。 (底下的操作為使用 CentOS 5.2 中的 man.config 來做練習的，該檔案你可以在這裡下載： http://linux.vbird.org/linux_basic/0310vi/man.config。) 看看你的顯示結果與鳥哥的結果是否相同啊？

1. 請在 /tmp 這個目錄下建立一個名為 vitest 的目錄；

2. 進入 vitest 這個目錄當中；

3. 將 /etc/man.config 複製到本目錄底下(或由上述的連結下載 man.config 檔案)；

4. 使用 vi 開啟本目錄下的 man.config 這個檔案；

5. 在 vi 中設定一下行號；

6. 移動到第 58 行，向右移動 40 個字元，請問你看到的雙引號內是什麼目錄？

7. 移動到第一行，並且向下搜尋一下『 bzip2 』這個字串，請問他在第幾行？

8. 接著下來，我要將 50 到 100 行之間的『小寫 man 字串』改為『大寫 MAN 字串』，並且一個一個挑選是否需要修改，如何下達指令？如果在挑選過程中一直按『y』， 結果會在最後一行出現改變了幾個 man 呢？

9. 修改完之後，突然反悔了，要全部復原，有哪些方法？

10. 我要複製 65 到 73 這九行的內容(含有MANPATH_MAP)，並且貼到最後一行之後；

11. 21 到 42 行之間的開頭為 # 符號的註解資料我不要了，要如何刪除？

12. 將這個檔案另存成一個 man.test.config 的檔名；

13. 去到第 27 行，並且刪除 15 個字元，結果出現的第一個單字是什麼？

14. 在第一行新增一行，該行內容輸入『I am a student...』；

15. 儲存後離開吧！

整個步驟可以如下顯示：

1. 『mkdir /tmp/vitest』

2. 『cd /tmp/vitest』

3. 『cp /etc/man.config .』

4. 『vi man.config』

5. 『:set nu』然後你會在畫面中看到左側出現數字即為行號。

6. 先按下『58G』再按下『40→』會看到『/dir/bin/foo』這個字樣在雙引號內；

7. 先執行『1G』或『gg』後，直接輸入『/bzip2』，則會去到第 118 行才對！

8. 直接下達『 :50,100s/man/MAN/gc 』即可！若一直按『y』最終會出現『在 23 行內置換 25 個字串』的說明。

9. (1)簡單的方法可以一直按『 u 』回復到原始狀態，(2)使用不儲存離開『 :q! 』之後，再重新讀取一次該檔案；

10. 『65G』 然後再『 9yy 』之後最後一行會出現『複製九行』之類的說明字樣。 按下『 G 』到最後一行，再給他『 p 』貼上九行！

11. 因為 21~42 22 行，因此『 21G 』→『 22dd 』就能刪除 22 行，此時你會發現游標所在 21 行的地方變成 MANPATH 開頭囉， 註解的 # 符號那幾行都被刪除了。

12. 『 :w man.test.config 』，你會發現最後一行出現 "man.test.config" [New].. 的字樣。

13. 『27G』 之後，再給他『 15x 』即可刪除 15 個字元，出現『 you 』的字樣；

14. 先『 1G 』去到第一行，然後按下大寫的『 O 』便新增一行且在插入模式；開始輸入『I am a student...』後， 按下[Esc]回到一般模式等待後續工作；

15. 『:wq』

如果你的結果都可以查的到，那麼 vi 的使用上面應該沒有太大的問題啦！剩下的問題會是在…打字練習…。

vim 的暫存檔、救援回復與開啟時的警告訊息

在目前主要的編輯軟體都會有『回復』的功能，亦即當你的系統因為某些原因而導致類似當機的情況時， 還可以透過某些特別的機制來讓你將之前未儲存的資料『救』回來！這就是鳥哥這裡所謂的『回復』功能啦！ 那麼 vim 有沒有回復功能呢？有的！ vim 就是透過『暫存檔』來救援的啦！

當我們在使用 vim 編輯時， vim 會在與被編輯的檔案的目錄下，再建立一個名為 .filename.swp 的檔案。 比如說我們在上一個小節談到的編輯 /tmp/vitest/man.config 這個檔案時， vim 會主動的建立 /tmp/vitest/.man.config.swp 的暫存檔，你對 man.config 做的動作就會被記錄到這個 .man.config.swp 當中喔！如果你的系統因為某些原因斷線了， 導致你編輯的檔案還沒有儲存，這個時候 .man.config.swp 就能夠發會救援的功能了！我們來測試一下吧！ 底下的練習有些部分的指令我們尚未談到，沒關係，你先照著做，後續再回來瞭解囉！

[root@www ~]# cd /tmp/vitest

[root@www vitest]# vim man.config

# 此時會進入到 vim 的畫面，請在 vim 的一般模式下按下『 [ctrl]-z 』的組合鍵

[1]+  Stopped             vim man.config  <==按下 [ctrl]-z 會告訴你這個訊息

當我們在 vim 的一般模式下按下 [ctrl]-z 的組合按鍵時，你的 vim 會被丟到背景去執行！ 這部份的功能我們會在第十七章的程序管理當中談到， 你這裡先知道一下即可。回到命令提示字元後，接下來我們來模擬將 vim 的工作不正常的中斷吧！

[root@www vitest]# ls -al

total 48

drwxr-xr-x 2 root root 4096 Jan 12 14:48 .

drwxrwxrwt 7 root root 4096 Jan 12 13:26 ..

-rw-r--r-- 1 root root 4101 Jan 12 13:55 man.config

-rw-r--r-- 1 root root 4096 Jan 12 14:48 .man.config.swp  <==就是他，暫存檔

-rw-r--r-- 1 root root 4101 Jan 12 13:43 man.test.config

[root@www vitest]# kill -9 %1 <==這裡模擬斷線停止 vim 工作

[root@www vitest]# ls -al .man.config.swp

-rw-r--r-- 1 root root 4096 Jan 12 14:48 .man.config.swp  <==暫存檔還是會存在！

那個 kill 可以模擬將系統的 vim 工作刪除的情況，你可以假裝當機了啦！ 由於 vim 的工作被不正常的中斷，導致暫存檔無法藉由正常流程來結束， 所以暫存檔就不會消失，而繼續保留下來。此時如果你繼續編輯那個 man.config ，會出現什麼情況呢？ 會出現如下所示的狀態喔：

[root@www vitest]# vim man.config

E325: ATTENTION  <==錯誤代碼

Found a swap file by the name ".man.config.swp"  <==底下數行說明有暫存檔的存在

owned by: root   dated: Mon Jan 12 14:48:24 2009

file name: /tmp/vitest/man.config  <==這個暫存檔屬於哪個實際的檔案？

modified: no

user name: root   host name: www.vbird.tsai

process ID: 11539

While opening file "man.config"

dated: Mon Jan 12 13:55:07 2009

底下說明可能發生這個錯誤的兩個主要原因與解決方案！

(1) Another program may be editing the same file.

If this is the case, be careful not to end up with two

different instances of the same file when making changes.

Quit, or continue with caution.

(2) An edit session for this file crashed.

If this is the case, use ":recover" or "vim -r man.config"

to recover the changes (see ":help recovery").

If you did this already, delete the swap file ".man.config.swp"

to avoid this message.

Swap file ".man.config.swp" already exists!底下說明你可進行的動作

[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:

由於暫存檔存在的關係，因此 vim 會主動的判斷你的這個檔案可能有些問題，在上面的圖示中 vim 提示兩點主要的問題與解決方案，分別是這樣的：

- 問題一：可能有其他人或程式同時在編輯這個檔案：

由於 Linux 是多人多工的環境，因此很可能有很多人同時在編輯同一個檔案。如果在多人共同編輯的情況下， 萬一大家同時儲存，那麼這個檔案的內容將會變的亂七八糟！為了避免這個問題，因此 vim 會出現這個警告視窗！ 解決的方法則是：

- 找到另外那個程式或人員，請他將該 vim 的工作結束，然後你再繼續處理。

- 如果你只是要看該檔案的內容並不會有任何修改編輯的行為，那麼可以選擇開啟成為唯讀(O)檔案， 亦即上述畫面反白部分輸入英文『 o 』即可，其實就是 [O]pen Read-Only 的選項啦！

- 問題二：在前一個 vim 的環境中，可能因為某些不知名原因導致 vim 中斷 (crashed)：

這就是常見的不正常結束 vim 產生的後果。解決方案依據不同的情況而不同喔！常見的處理方法為：

- 如果你之前的 vim 處理動作尚未儲存，此時你應該要按下『R』，亦即使用 (R)ecover 的項目， 此時 vim 會載入 .man.config.swp 的內容，讓你自己來決定要不要儲存！這樣就能夠救回來你之前未儲存的工作。 不過那個 .man.config.swp 並不會在你結束 vim 後自動刪除，所以你離開 vim 後還得要自行刪除 .man.config.swp 才能避免每次打開這個檔案都會出現這樣的警告！

- 如果你確定這個暫存檔是沒有用的，那麼你可以直接按下『D』刪除掉這個暫存檔，亦即 (D)elete it 這個項目即可。 此時 vim 會載入 man.config ，並且將舊的 .man.config.swp 刪除後，建立這次會使用的新的 .man.config.swp 喔！

至於這個發現暫存檔警告訊息的畫面中，有出現六個可用按鈕，各按鈕的說明如下：

- [O]pen Read-Only：打開此檔案成為唯讀檔， 可以用在你只是想要查閱該檔案內容並不想要進行編輯行為時。一般來說，在上課時，如果你是登入到同學的電腦去看他的設定檔， 結果發現其實同學他自己也在編輯時，可以使用這個模式；

- (E)dit anyway：還是用正常的方式打開你要編輯的那個檔案， 並不會載入暫存檔的內容。不過很容易出現兩個使用者互相改變對方的檔案等問題！不好不好！

- (R)ecover：就是載入暫存檔的內容，用在你要救回之前未儲存的工作。 不過當你救回來並且儲存離開 vim 後，還是要手動自行刪除那個暫存檔喔！

- (D)elete it：你確定那個暫存檔是無用的！那麼開啟檔案前會先將這個暫存檔刪除！ 這個動作其實是比較常做的！因為你可能不確定這個暫存檔是怎麼來的，所以就刪除掉他吧！哈哈！

- (Q)uit：按下 q 就離開 vim ，不會進行任何動作回到命令提示字元。

- (A)bort：忽略這個編輯行為，感覺上與 quit 非常類似！ 也會送你回到命令提示字元就是囉！

vim 的額外功能

其實，目前大部分的 distributions 都以 vim 取代 vi 的功能了！如果你使用 vi 後，卻看到畫面的右下角有顯示目前游標所在的行列號碼，那麼你的 vi 已經被 vim 所取代囉∼ 為什麼要用 vim 呢？因為 vim 具有顏色顯示的功能，並且還支援許多的程式語法 (syntax)， 因此，當你使用 vim 編輯程式時( 不論是 C 語言，還是 shell script )， 我們的 vim 將可幫你直接進行『程式除錯 (debug)』的功能！真的很不賴吧！^_^

如果你在文字模式下，輸入 alias 時，出現這樣的畫面：

[root@www ~]# alias

....其他省略....

alias vi='vim'  <==重點在這行啊！

這表示當你使用 vi 這個指令時，其實就是執行 vim 啦！如果你沒有這一行，那麼你就必須要使用 vim filename 來啟動 vim 囉！基本上， vim 的一般用法與 vi 完全一模一樣∼沒有不同啦！那麼我們就來看看 vim 的畫面是怎樣囉！假設我想要編輯 /etc/man.config ，則輸入『vim /etc/man.config』

圖3.0.1、 vim 的圖示示意

上面是 vim 的畫面示意圖，在這個畫面中有幾點特色要說明喔：

1. 由於 man.config 是系統規劃的設定檔，因此 vim 會進行語法檢驗，所以你會看到畫面中內部主要為深藍色， 且深藍色那一行是以註解符號 (#) 為開頭；

2. 最底下一行的左邊顯示該檔案的屬性，包括 141行與 4617 字元；

3. 最底下一行的右邊出現的 1,1 表示游標所在為第一行, 第一個字元位置之意(請看一下上圖中的游標所在)；

所以，如果你向下移動到其他位置時，出現的非註解的資料就會有點像這樣：

圖3.0.2、 vim 的圖示示意

看到了喔！除了註解之外，其他的行就會有特別的顏色顯示呢！可以避免你打錯字啊！而且， 最右下角的 30% 代表目前這個畫面佔整體檔案的 30% 之意！這樣瞭乎？

區塊選擇(Visual Block)

剛剛我們提到的簡單的 vi 操作過程中，幾乎提到的都是以行為單位的操作。那麼如果我想要搞定的是一個區塊範圍呢？ 舉例來說，像底下這種格式的檔案：

192.168.1.1    host1.class.net

192.168.1.2    host2.class.net

192.168.1.3    host3.class.net

192.168.1.4    host4.class.net

.....中間省略......

這個檔案我將他放置到 http://linux.vbird.org/linux_basic/0310vi/hosts ，你可以自行下載來看一看這個檔案啊！現在我們來玩一玩這個檔案吧！假設我想要將 host1, host2... 等等複製起來， 並且加到每一行的後面，亦即每一行的結果要是『 192.168.1.2 host2.class.net host2 』這樣的情況時， 在傳統或現代的視窗型編輯器似乎不容易達到這個需求，但是咱們的 vim 是辦的到的喔！那就使用區塊選擇 (Visual Block) 吧！當我們按下 v 或者 V 或者 [Ctrl]+v 時， 這個時候游標移動過的地方就會開始反白，這三個按鍵的意義分別是：

區塊選擇的按鍵意義

v

字元選擇，會將游標經過的地方反白選擇！

V

行選擇，會將游標經過的行反白選擇！

[Ctrl]+v

區塊選擇，可以用長方形的方式選擇資料

y

將反白的地方複製起來

d

將反白的地方刪除掉

來實際進行我們需要的動作吧！就是將 host 再加到每一行的最後面，你可以這樣做：

1. 使用 vim hosts 來開啟該檔案，記得該檔案請由上述的連結下載先！

2. 將游標移動到第一行的 host 那個 h 上頭，然後按下 [ctrl]-v ，左下角出現區塊示意字樣：

圖 3.1.1、進入區塊功能的示意圖

1. 將游標移動到最底部，此時游標移動過的區域會反白！如下圖所示：

圖 3.1.2、區塊選擇的結果示意圖

1. 此時你可以按下『 y 』來進行複製，當你按下 y 之後，反白的區塊就會消失不見囉！

2. 最後，將游標移動到第一行的最右邊，並且再用編輯模式向右按兩個空白鍵，回到一般模式後， 再按下『 p 』後，你會發現很有趣！如下圖所示：

圖 3.1.3、將區塊的資料貼上後的結果

透過上述的功能，你可以複製一個區塊，並且是貼在某個『區塊的範圍』內，而不是以行為單位來處理你的整份文件喔！ 鳥哥個人是覺得這玩意兒非常的有幫助啦！至少在進行排列整齊的文字檔案中複製/刪除區塊時，會是一個非常棒的功能！

多檔案編輯

假設一個例子，你想要將剛剛我們的 hosts 內的 IP 複製到你的 /etc/hosts 這個檔案去， 那麼該如何編輯？我們知道在 vi 內可以使用 :r filename 來讀入某個檔案的內容， 不過，這樣畢竟是將整個檔案讀入啊！如果我只是想要部分內容呢？呵呵！這個時候多檔案同時編輯就很有用了。 我們可以使用 vim 後面同時接好幾個檔案來同時開啟喔！相關的按鍵有：

多檔案編輯的按鍵

:n

編輯下一個檔案

:N

編輯上一個檔案

:files

列出目前這個 vim 的開啟的所有檔案

在過去，鳥哥想要將 A 檔案內的十條消息『移動』到 B 檔案去，通常要開兩個 vim 視窗來複製， 偏偏每個 vim 都是獨立的，因此並沒有辦法在 A 檔案下達『 nyy 』再跑到 B 檔案去『 p 』啦！ 在這種情況下最常用的方法就是透過滑鼠圈選， 複製後貼上。不過這樣一來還是有問題，因為鳥哥超級喜歡使用 [Tab] 按鍵進行編排對齊動作， 透過滑鼠卻會將 [Tab] 轉成空白鍵，這樣內容就不一樣了！此時這個多檔案編輯就派上用場了！

現在你可以做一下練習看看說！假設你要將剛剛鳥哥提供的 hosts 內的前四行 IP 資料複製到你的 /etc/hosts 檔案內，那可以怎麼進行呢？可以這樣啊：

1. 透過『 vim hosts /etc/hosts 』指令來使用一個 vim 開啟兩個檔案；

2. 在 vim 中先使用『 :files 』察看一下編輯的檔案資料有啥？結果如下所示。 至於下圖的最後一行顯示的是『按下任意鍵』就會回到 vim 的一般模式中！

圖 3.2.1、多檔案編輯示意圖"

1. 在第一行輸入『 4yy 』複製四行；

2. 在 vim 的環境下輸入『 :n 』會來到第二個編輯的檔案，亦即 /etc/hosts 內；

3. 在 /etc/hosts 下按『 G 』到最後一行，再輸入『 p 』貼上；

4. 按下多次的『 u 』來還原原本的檔案資料；

5. 最終按下『 :q 』來離開 vim 的多檔案編輯吧！

看到了吧？利用多檔案編輯的功能，可以讓你很快速的就將需要的資料複製到正確的檔案內。 當然囉，這個功能也可以利用視窗介面來達到，那就是底下要提到的多視窗功能。

多視窗功能

在開始這個小節前，先來想像兩個情況：

- 當我有一個檔案非常的大，我查閱到後面的資料時，想要『對照』前面的資料， 是否需要使用 [ctrl]+f 與 [ctrl]+b (或 pageup, pagedown 功能鍵) 來跑前跑後查閱？

- 我有兩個需要對照著看的檔案，不想使用前一小節提到的多檔案編輯功能；

在一般視窗介面下的編輯軟體大多有『分割視窗』或者是『凍結視窗』的功能來將一個檔案分割成多個視窗的展現， 那麼 vim 能不能達到這個功能啊？可以啊！但是如何分割視窗並放入檔案呢？ 很簡單啊！在指令列模式輸入『:sp {filename}』即可！那個 filename 可有可無， 如果想要在新視窗啟動另一個檔案，就加入檔名，否則僅輸入 :sp 時， 出現的則是同一個檔案在兩個視窗間！

讓我們來測試一下，你先使用『 vim /etc/man.config 』打開這個檔案，然後『 1G 』去到第一行，之後輸入『 :sp 』 再次的打開這個檔案一次，然後再輸入『 G 』，結果會變成底下這樣喔：

圖 3.3.1、視窗分割的示意圖

萬一你再輸入『 :sp /etc/hosts 』時，就會變成下圖這樣喔：

圖 3.3.2、視窗分割的示意圖

怎樣？帥吧！兩個檔案同時在一個螢幕上面顯示，你還可以利用『[ctrl]+w+↑』及『[ctrl]+w+↓』 在兩個視窗之間移動呢！這樣的話，複製啊、查閱啊等等的，就變的很簡單囉∼ 分割視窗的相關指令功能有很多，不過你只要記得這幾個就好了：

多視窗情況下的按鍵功能

:sp [filename]

開啟一個新視窗，如果有加 filename， 表示在新視窗開啟一個新檔案，否則表示兩個視窗為同一個檔案內容(同步顯示)。

[ctrl]+w+ j

[ctrl]+w+↓

按鍵的按法是：先按下 [ctrl] 不放， 再按下 w 後放開所有的按鍵，然後再按下 j (或向下方向鍵)，則游標可移動到下方的視窗。

[ctrl]+w+ k

[ctrl]+w+↑

同上，不過游標移動到上面的視窗。

[ctrl]+w+ q

其實就是 :q 結束離開啦！ 舉例來說，如果我想要結束下方的視窗，那麼利用 [ctrl]+w+↓ 移動到下方視窗後，按下 :q 即可離開， 也可以按下 [ctrl]+w+q 啊！

鳥哥第一次玩 vim 的分割視窗時，真是很高興啊！竟然有這種功能！太棒了！ ^_^

vim 環境設定與記錄： ~/.vimrc, ~/.viminfo

有沒有發現，如果我們以 vim 軟體來搜尋一個檔案內部的某個字串時，這個字串會被反白， 而下次我們再次以 vim 編輯這個檔案時，該搜尋的字串反白情況還是存在呢！甚至於在編輯其他檔案時， 如果其他檔案內也存在這個字串，哇！竟然還是主動反白耶！真神奇！ 另外，當我們重複編輯同一個檔案時，當第二次進入該檔案時， 游標竟然就在上次離開的那一行上頭呢！真是好方便啊∼但是，怎麼會這樣呢？

這是因為我們的 vim 會主動的將你曾經做過的行為登錄下來，好讓你下次可以輕鬆的作業啊！ 那個記錄動作的檔案就是： ~/.viminfo ！如果你曾經使用過 vim， 那你的家目錄應該會存在這個檔案才對。這個檔案是自動產生的， 你不必自行建立。而你在 vim 裡頭所做過的動作，就可以在這個檔案內部查詢到囉∼ ^_^

此外，每個 distributions 對 vim 的預設環境都不太相同，舉例來說，某些版本在搜尋到關鍵字時並不會高亮度反白， 有些版本則會主動的幫你進行縮排的行為。但這些其實都可以自行設定的，那就是 vim 的環境設定囉∼ vim 的環境設定參數有很多，如果你想要知道目前的設定值，可以在一般模式時輸入『 :set all 』 來查閱，不過.....設定項目實在太多了∼所以，鳥哥在這裡僅列出一些平時比較常用的一些簡單的設定值， 提供給你參考啊。

Tips:

所謂的縮排，就是當你按下 Enter 編輯新的一行時，游標不會在行首，而是在與上一行的第一個非空白字元處對齊！

vim 的環境設定參數

:set nu

:set nonu

就是設定與取消行號啊！

:set hlsearch

:set nohlsearch

hlsearch 就是 high light search(高亮度搜尋)。 這個就是設定是否將搜尋的字串反白的設定值。預設值是 hlsearch

:set autoindent

:set noautoindent

是否自動縮排？autoindent 就是自動縮排。

:set backup

是否自動儲存備份檔？一般是 nobackup 的， 如果設定 backup 的話，那麼當你更動任何一個檔案時，則原始檔案會被另存成一個檔名為 filename~ 的檔案。 舉例來說，我們編輯 hosts ，設定 :set backup ，那麼當更動 hosts 時，在同目錄下，就會產生 hosts~ 檔名的檔案，記錄原始的 hosts 檔案內容

:set ruler

還記得我們提到的右下角的一些狀態列說明嗎？ 這個 ruler 就是在顯示或不顯示該設定值的啦！

:set showmode

這個則是，是否要顯示 --INSERT-- 之類的字眼在左下角的狀態列。

:set backspace=(012)

一般來說， 如果我們按下 i 進入編輯模式後，可以利用倒退鍵 (backspace) 來刪除任意字元的。 但是，某些 distribution 則不許如此。此時，我們就可以透過 backspace 來設定囉∼ 當 backspace 為 2 時，就是可以刪除任意值；0 或 1 時，僅可刪除剛剛輸入的字元， 而無法刪除原本就已經存在的文字了！

:set all

顯示目前所有的環境參數設定值。

:set

顯示與系統預設值不同的設定參數， 一般來說就是你有自行變動過的設定參數啦！

:syntax on

:syntax off

是否依據程式相關語法顯示不同顏色？ 舉例來說，在編輯一個純文字檔時，如果開頭是以 # 開始，那麼該行就會變成藍色。 如果你懂得寫程式，那麼這個 :syntax on 還會主動的幫你除錯呢！但是， 如果你僅是編寫純文字檔案，要避免顏色對你的螢幕產生的干擾，則可以取消這個設定 。

:set bg=dark

:set bg=light

可用以顯示不同的顏色色調，預設是『 light 』。如果你常常發現註解的字體深藍色實在很不容易看， 那麼這裡可以設定為 dark 喔！試看看，會有不同的樣式呢！

總之，這些設定值很有用處的啦！但是......我是否每次使用 vim 都要重新設定一次各個參數值？ 這不太合理吧？沒錯啊！所以，我們可以透過設定檔來直接規定我們習慣的 vim 操作環境呢！ 整體 vim 的設定值一般是放置在 /etc/vimrc 這個檔案，不過，不建議你修改他！ 你可以修改 ~/.vimrc 這個檔案 (預設不存在，請你自行手動建立！)，將你所希望的設定值寫入！ 舉例來說，可以是這樣的一個檔案：

[root@www ~]# vim ~/.vimrc

"這個檔案的雙引號 (") 是註解

set hlsearch            "高亮度反白

set backspace=2         "可隨時用倒退鍵刪除

set autoindent          "自動縮排

set ruler               "可顯示最後一行的狀態

set showmode            "左下角那一行的狀態

set nu                  "可以在每一行的最前面顯示行號啦！

set bg=dark             "顯示不同的底色色調

syntax on               "進行語法檢驗，顏色顯示。

在這個檔案中，使用『 set hlsearch 』或『 :set hlsearch 』，亦即最前面有沒有冒號『 : 』效果都是一樣的！ 至於雙引號則是註解符號！不要用錯註解符號，否則每次使用 vim 時都會發生警告訊息喔！ 建立好這個檔案後，當你下次重新以 vim 編輯某個檔案時，該檔案的預設環境設定就是上頭寫的囉∼ 這樣，是否很方便你的操作啊！多多利用 vim 的環境設定功能呢！^_^

vim 常用指令示意圖

為了方便大家查詢在不同的模式下可以使用的 vim 指令，鳥哥查詢了一些 vim 與 Linux 教育訓練手冊， 發現底下這張圖非常值得大家參考！可以更快速有效的查詢到需要的功能喔！看看吧！

圖 3.5.1 、 vim 常用指令示意圖

其他 vim 使用注意事項

vim 其實不是那麼好學，雖然他的功能確實非常強大！所以底下我們還有一些需要注意的地方要來跟大家分享喔！

中文編碼的問題

很多朋友常常哀嚎，說他們的 vim 裡面怎麼無法顯示正常的中文啊？其實這很有可能是因為編碼的問題！ 因為中文編碼有 big5 與 utf8 兩種，如果你的檔案是使用 big5 編碼製作的，但在 vim 的終端介面中你使用的是萬國碼(utf8)， 由於編碼的不同，你的中文檔案內容當然就是一堆亂碼了！怎麼辦？這時你得要考慮許多東西啦！有這些：

1. 你的 Linux 系統預設支援的語系資料：這與 /etc/sysconfig/i18n 有關；

2. 你的終端介面 (bash) 的語系： 這與 LANG 這個變數有關；

3. 你的檔案原本的編碼；

4. 開啟終端機的軟體，例如在 GNOME 底下的視窗介面。

事實上最重要的是上頭的第三與第四點，只要這兩點的編碼一致，你就能夠正確的看到與編輯你的中文檔案。 否則就會看到一堆亂碼啦！

一般來說，中文編碼使用 big5 時，在寫入某些資料庫系統中，在『許、蓋、功』這些字體上面會發生錯誤！ 所以近期以來大多希望大家能夠使用萬國碼 utf8 來進行中文編碼！但是在 Windows XP 上的軟體常常預設使用 big5 的編碼， 包括鳥哥由於沿用以前的文件資料檔案，也大多使用 big5 的編碼。此時就得要注意上述的這些咚咚囉。

在 Linux 本機前的 tty1~tty6 原本預設就不支援中文編碼，所以不用考慮這個問題！因為你一定會看到亂碼！呵呵！ 現在鳥哥假設俺的文件檔案內編碼為 big5 時，而且我的環境是使用 Linux 的 GNOME ，啟動的終端介面為 GNOME-terminal 軟體， 那鳥哥通常是這樣來修正語系編碼的行為：

[root@www ~]# LANG=zh_TW.big5

然後在終端介面工具列的『終端機』-->『設定字元編碼』 -->『中文 (正體) (BIG5)』項目點選一下， 如果一切都沒有問題了，再用 vim 去開啟那個 big5 編碼的檔案，就沒有問題了！以上！報告完畢！

DOS 與 Linux 的斷行字元

我們在第七章裡面談到 cat 這個指令時，曾經提到過 DOS 與 Linux 斷行字元的不同。 而我們也可以利用 cat -A 來觀察以 DOS (Windows 系統) 建立的檔案的特殊格式， 也可以發現在 DOS 使用的斷行字元為 ^M$ ，我們稱為 CR 與 LF 兩個符號。 而在 Linux 底下，則是僅有 LF ($) 這個斷行符號。這個斷行符號對於 Linux 的影響很大喔！ 為什麼呢？

我們說過，在 Linux 底下的指令在開始執行時，他的判斷依據是 『Enter』，而 Linux 的 Enter 為 LF 符號， 不過，由於 DOS 的斷行符號是 CRLF ，也就是多了一個 ^M 的符號出來， 在這樣的情況下，如果是一個 shell script 的程式檔案，呵呵∼將可能造成『程式無法執行』的狀態∼ 因為他會誤判程式所下達的指令內容啊！這很傷腦筋吧！

那怎麼辦啊？很簡單啊，將格式轉換成為 Linux 即可啊！『廢話』，這當然大家都知道，但是， 要以 vi 進入該檔案，然後一個一個刪除每一行的 CR 嗎？當然沒有這麼沒人性啦！ 我們可以透過簡單的指令來進行格式的轉換啊！

[root@www ~]# dos2unix [-kn] file [newfile]

[root@www ~]# unix2dos [-kn] file [newfile]

選項與參數：

-k  ：保留該檔案原本的 mtime 時間格式 (不更新檔案上次內容經過修訂的時間)

-n  ：保留原本的舊檔，將轉換後的內容輸出到新檔案，如： dos2unix -n old new

範例一：將剛剛上述練習的 /tmp/vitest/man.config 修改成為 dos 斷行

[root@www ~]# cd /tmp/vitest

[root@www vitest]# cp -a /etc/man.config .

[root@www vitest]# ll man.config

-rw-r--r-- 1 root root 4617 Jan  6  2007 man.config

[root@www vitest]# unix2dos -k man.config

unix2dos: converting file man.config to DOS format ...

# 螢幕會顯示上述的訊息，說明斷行轉為 DOS 格式了！

[root@www vitest]# ll man.config

-rw-r--r-- 1 root root 4758 Jan  6  2007 man.config

# 斷行字元多了 ^M ，所以容量增加了！

範例二：將上述的 man.config 轉成 man.config.linux 的 Linux 斷行字元

[root@www vitest]# dos2unix -k -n man.config man.config.linux

dos2unix: converting file man.config to file man.config.linux in UNIX format ...

[root@www vitest]# ll man.config*

-rw-r--r-- 1 root root 4758 Jan  6  2007 man.config

-rw------- 1 root root 4617 Jan  6  2007 man.config.linux

因為斷行字符以及 DOS 與 Linux 作業系統底下一些字符的定義不同，因此， 不建議你在 Windows 系統當中將檔案編輯好之後，才上傳到 Linux 系統，會容易發生錯誤問題。 而且，如果你在不同的系統之間複製一些純文字檔案時，千萬記得要使用 unix2dos 或 dos2unix 來轉換一下斷行格式啊！

語系編碼轉換

很多朋友都會有的問題，就是想要將語系編碼進行轉換啦！舉例來說，想要將 big5 編碼轉成 utf8 。 這個時候怎麼辦？難不成要每個檔案打開會轉存成 utf8 嗎？不需要這樣做啦！使用 iconv 這個指令即可！ 鳥哥將之前的 vi 章節做成 big5 編碼的檔案，你可以照底下的連結來下載先：

- http://linux.vbird.org/linux_basic/0310vi/vi.big5

在終端機的環境下你可以使用『 wget 網址』來下載上述的檔案喔！鳥哥將他下載在 /tmp/vitest 目錄下。 接下來讓我們來使用 iconv 這個指令來玩一玩編碼轉換吧！

[root@www ~]# iconv --list

[root@www ~]# iconv -f 原本編碼 -t 新編碼 filename [-o newfile]

選項與參數：

--list ：列出 iconv 支援的語系資料

-f     ：from ，亦即來源之意，後接原本的編碼格式；

-t     ：to ，亦即後來的新編碼要是什麼格式；

-o file：如果要保留原本的檔案，那麼使用 -o 新檔名，可以建立新編碼檔案。

範例一：將 /tmp/vitest/vi.big5 轉成 utf8 編碼吧！

[root@www ~]# cd /tmp/vitest

[root@www vitest]# iconv -f big5 -t utf8 vi.big5 -o vi.utf8

[root@www vitest]# file vi*

vi.big5: ISO-8859 text, with CRLF line terminators

vi.utf8: UTF-8 Unicode text, with CRLF line terminators

# 是吧！有明顯的不同吧！ ^_^

這指令支援的語系非常之多，除了正體中文的 big5, utf8 編碼之外，也支援簡體中文的 gb2312 ， 所以對岸的朋友可以簡單的將鳥站的網頁資料下載後，利用這個指令來轉成簡體，就能夠輕鬆的讀取文件資料囉！ 不過，不要將轉成簡體的檔案又上傳成為您自己的網頁啊！這明明是鳥哥寫的不是嗎？ ^_^

不過如果是要將正體中文的 utf8 轉成簡體中文的 utf8 編碼時，那就得費些功夫了！ 舉例來說，如果要將剛剛那個 vi.utf8 轉成簡體的 utf8 時，可以這樣做：

[root@www vitest]# iconv -f utf8 -t big5 vi.utf8 | \

> iconv -f big5 -t gb2312 | iconv -f gb2312 -t utf8 -o vi.gb.utf8

重點回顧

- Linux 底下的設定檔多為文字檔，故使用 vim 即可進行設定編輯；

- vim 可視為程式編輯器，可用以編輯 shell script, 設定檔等，避免打錯字；

- vi 為所有 unix like 的作業系統都會存在的編輯器，且執行速度快速；

- vi 有三種模式，一般模式可變換到編輯與指令列模式，但編輯模式與指令列模式不能互換；

- 常用的按鍵有i, [Esc], :wq 等；

- vi 的畫面大略可分為兩部份，(1)上半部的本文與(2)最後一行的狀態+指令列模式；

- 數字是有意義的，用來說明重複進行幾次動作的意思，如 5yy 為複製 5 行之意；

- 游標的移動中，大寫的 G 經常使用，尤其是 1G, G 移動到文章的頭/尾功能！

- vi 的取代功能也很棒！ :n1,n2s/old/new/g 要特別注意學習起來；

- 小數點『 . 』為重複進行前一次動作，也是經常使用的按鍵功能！

- 進入編輯模式幾乎只要記住： i, o, R 三個按鈕即可！尤其是新增一行的 o 與取代的 R

- vim 會主動的建立 swap 暫存檔，所以不要隨意斷線！

- 如果在文章內有對齊的區塊，可以使用 [ctrl]-v 進行複製/貼上/刪除的行為

- 使用 :sp 功能可以分割視窗

- vim 的環境設定可以寫入在 ~/.vimrc 檔案中；

- 可以使用 iconv 進行檔案語系編碼的轉換

- 使用 dos2unix 及 unix2dos 可以變更檔案每一行的行尾斷行字元。

本章練習

(要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

實作題部分：

- 在第八章的情境模擬題二的第五點，編寫 /etc/fstab 時，當時使用 nano 這個指令， 請嘗試使用 vim 去編輯 /etc/fstab ，並且將第八章新增的那一行的 defatuls 改成 default ，會出現什麼狀態？ 離開前請務必要修訂成原本正確的資訊。此外，如果將該行註解 (最前面加 #)，你會發現字體顏色也有變化喔！

- 嘗試在你的系統中，你慣常使用的那個帳號的家目錄下，將本章介紹的 vimrc 內容進行一些常用設定，包括：

- 設定搜尋高亮度反白

- 設定語法檢驗啟動

- 設定預設啟動行號顯示

- 設定有兩行狀態列 (一行狀態+一行指令列) :set laststatus=2

簡答題部分：

- 我用 vi 開啟某個檔案後，要在第 34 行向右移動 15 個字元，應該在一般模式中下達什麼指令？

(1)先按下 34G 到第 34 行；(2)再按下 [ 15 + 向右鍵 ]，或 [ 15l ] 亦可！

- 在 vi 開啟的檔案中，如何去到該檔案的頁首或頁尾？

去頁首按下 1G 或 gg ；去頁尾按下 G 即可

- 在 vi 開啟的檔案中，如何在游標所在行中，移動到行頭及行尾？

移動到行頭，按 0 ，移動到行尾按 $ 即可！

- vi 的一般模式情況下，按下『 r 』有什麼功能？

取代游標所在的那個字元

- 在 vi 的環境中，如何將目前正在編輯的檔案另存新檔名為 newfilename？

:w newfilename

- 在 linux 底下最常使用的文書編輯器為 vi ，請問如何進入編輯模式？

在一般模式底下輸入： i, I, a, A 為在本行當中輸入新字元；(出現 –Insert- )

在一般模式當中輸入： o, O 為在一個新的一行輸入新字元；

在一般模式當中輸入： r, R 為取代字元！（左下角出現 –Replace-）

- 在 vi 軟體中，如何由編輯模式跳回一般模式？

可以按下[Esc]

- 在 vi 環境中，若上下左右鍵無法使用時，請問如何在一般模式移動游標？

[h, j, k, l]分別代表[左、下、上、右]

- 在 vi 的一般模式中，如何刪除一行、n行；如何刪除一個字元？

分別為 dd, ndd, x 或 X （dG 及 d1G 分別表示刪除到頁首及頁尾）

- 在 vi 的一般模式中，如何複製一行、n行並加以貼上？

分別為 yy, nyy, p 或 P

- 在 vi 的一般模式中如何搜尋 string 這個字串？

?string (往前搜尋)

/string (往後搜尋)

- 在 vi 的一般模式中，如何取代 word1 成為 word2，而若需要使用者確認機制，又該如何？

:1,$s/word1/word2/g 或

:1,$s/word1/word2/gc （需要使用者確認）

- 在 vi 目前的編輯檔案中，在一般模式下，如何讀取一個檔案 filename 進來目前這個檔案？

:r filename

- 在 vi 的一般模式中，如何存檔、離開、存檔後離開、強制存檔後離開？

:w； :q： :wq； :wq!

- 在 vi 底下作了很多的編輯動作之後，卻想還原成原來的檔案內容，應該怎麼進行？

直接按下 :e! 即可恢復成檔案的原始狀態！

- 我在 vi 這個程式當中，不想離開 vi ，但是想執行 ls /home 這個指令，vi 有什麼額外的功能可以達到這個目的：

事實上，可以使用[ :! ls /home ]不過，如果你學過後面的章節之後，你會發現，執行[ ctrl + z ]亦可暫時退出 vi 讓你在指令列模式當中執行指令喔！

參考資料與延伸閱讀

- 維基百科：ASCII 的代碼與圖示對應表：http://zh.wikipedia.org/wiki/ASCII

- 註1：常見文書編輯器專案計畫連結：

- emacs: http://www.gnu.org/software/emacs/

- pico: http://www.ece.uwaterloo.ca/~ece250/Online/Unix/pico/

- nano: http://sourceforge.net/projects/nano/

- joe: http://sourceforge.net/projects/joe-editor/

- vim: http://www.vim.org

- 常見文書編輯器比較：http://encyclopedia.thefreedictionary.com/List+of+text+editors

- 維基百科的文書編輯器比較：http://en.wikipedia.org/wiki/Comparison_of_text_editors

- 關於 vim 是什麼的『中文』說明：http://www.vim.org/6k/features.zh.txt。

- 李果正兄的：大家來學 vim (http://info.sayya.org/~edt1023/vim/)

- 麥克星球 Linux Fedora 心得筆記：

正體/簡體中文的轉換方法：http://blog.xuite.net/michaelr/linux/15650102

2002/04/05：第一次完成

2003/02/07：重新編排與加入 FAQ

2003/02/25：新加入本章節與 LPI 的相關性說明！

2005/07/28：將舊文章移動到 這裡 。

2005/08/01：加入果正兄文章的參考，還有查閱 vim 官方網站的資料！

2008/12/18：將原本針對 FC4 版本的文章移動到 此處

2009/01/13：這麼簡單的一篇改寫，竟改了一個月！原因只是期末考將近太忙了∼

2009/08/20：加入實作題，編輯簡答題，加入 vim 指令示意圖等

2002/01/21以來統計人數

第十一章、認識與學習 BASH

切換解析度為 800x600

最近更新日期：2009/08/25

在 Linux 的環境下，如果你不懂 bash 是什麼，那麼其他的東西就不用學了！因為前面幾章我們使用終端機下達指令的方式， 就是透過 bash 的環境來處理的喔！所以說，他很重要吧！bash 的東西非常的多，包括變數的設定與使用、 bash 操作環境的建置、資料流重導向的功能，還有那好用的管線命令！好好清一清腦門，準備用功去囉∼ ^_^ 這個章節幾乎是所有指令列模式 (command line) 與未來主機維護與管理的重要基礎，一定要好好仔細的閱讀喔！

1. 認識 BASH 這個 Shell

1.1 硬體、核心與 Shell

1.2 為何要學文字介面的 shell

1.3 系統的合法 shell 與 /etc/shells 功能

1.4 Bash shell 的功能

1.5 Bash shell 的內建命令： type

1.6 指令的下達

2. Shell 的變數功能

2.1 什麼是變數？

2.2 變數的取用與設定：echo, 變數設定規則, unset

2.3 環境變數的功能： env 與常見環境變數說明, set, export

2.4 影響顯示結果的語系變數 (locale)

2.5 變數的有效範圍：

2.6 變數鍵盤讀取、陣列與宣告： read, declare, array

2.7 與檔案系統及程序的限制關係： ulimit

2.8 變數內容的刪除、取代與替換：, 刪除與取代, 測試與替換

3. 命令別名與歷史命令

3.1 命令別名設定： alias, unalias

3.2 歷史命令： history, HISTSIZE

4. Bash shell 的操作環境

4.1 路徑與指令搜尋順序

4.2 bash 的進站與歡迎訊息： /etc/issue, /etc/motd

4.3 環境設定檔: login, non-login shell, /etc/profile, ~/.bash_profile, source, ~/.bashrc

4.4 終端機的環境設定： stty, set

4.5 萬用字元與特殊符號

5. 資料流重導向 (Redirection)

5.1 何謂資料流重導向？

5.2 命令執行的判斷依據： ; , &&, ||

6. 管線命令 (pipe)

6.1 擷取命令： cut, grep

6.2 排序命令： sort, uniq, wc

6.3 雙向重導向： tee

6.4 字元轉換命令： tr, col, join, paste, expand

6.5 分割命令： split

6.6 參數代換： xargs

6.7 關於減號 - 的用途

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23884

認識 BASH 這個 Shell

我們在第一章 Linux 是什麼當中提到了： 管理整個電腦硬體的其實是作業系統的核心 (kernel)，這個核心是需要被保護的！ 所以我們一般使用者就只能透過 shell 來跟核心溝通，以讓核心達到我們所想要達到的工作。 那麼系統有多少 shell 可用呢？為什麼我們要使用 bash 啊？底下分別來談一談喔！

硬體、核心與 Shell

這應該是個蠻有趣的話題：『什麼是 Shell 』？相信只要摸過電腦，對於作業系統 (不論是 Linux 、 Unix 或者是 Windows) 有點概念的朋友們大多聽過這個名詞，因為只要有『作業系統』那麼就離不開 Shell 這個東西。不過，在討論 Shell 之前，我們先來瞭解一下電腦的運作狀況吧！ 舉個例子來說：當你要電腦傳輸出來『音樂』的時候，你的電腦需要什麼東西呢？

1. 硬體：當然就是需要你的硬體有『音效卡晶片』這個配備，否則怎麼會有聲音；

2. 核心管理：作業系統的核心可以支援這個晶片組，當然還需要提供晶片的驅動程式囉；

3. 應用程式：需要使用者 (就是你) 輸入發生聲音的指令囉！

這就是基本的一個輸出聲音所需要的步驟！也就是說，你必須要『輸入』一個指令之後， 『硬體』才會透過你下達的指令來工作！那麼硬體如何知道你下達的指令呢？那就是 kernel (核心) 的控制工作了！也就是說，我們必須要透過『 Shell 』將我們輸入的指令與 Kernel 溝通，好讓 Kernel 可以控制硬體來正確無誤的工作！ 基本上，我們可以透過底下這張圖來說明一下：

圖 1.1.1、硬體、核心與使用者的相關性圖示

我們在第零章內的作業系統小節曾經提到過， 作業系統其實是一組軟體，由於這組軟體在控制整個硬體與管理系統的活動監測， 如果這組軟體能被使用者隨意的操作，若使用者應用不當，將會使得整個系統崩潰！因為作業系統管理的就是整個硬體功能嘛！ 所以當然不能夠隨便被一些沒有管理能力的終端用戶隨意使用囉！

但是我們總是需要讓使用者操作系統的，所以就有了在作業系統上面發展的應用程式啦！使用者可以透過應用程式來指揮核心， 讓核心達成我們所需要的硬體任務！如果考慮如第零章所提供的作業系統圖示(圖4.2.1)， 我們可以發現應用程式其實是在最外層，就如同雞蛋的外殼一樣，因此這個咚咚也就被稱呼為殼程式 (shell) 囉！

其實殼程式的功能只是提供使用者操作系統的一個介面，因此這個殼程式需要可以呼叫其他軟體才好。 我們在第五章到第十章提到過很多指令，包括 man, chmod, chown, vi, fdisk, mkfs 等等指令，這些指令都是獨立的應用程式， 但是我們可以透過殼程式 (就是指令列模式) 來操作這些應用程式，讓這些應用程式呼叫核心來運作所需的工作哩！ 這樣對於殼程式是否有了一定的概念了？

Tips:

也就是說，只要能夠操作應用程式的介面都能夠稱為殼程式。狹義的殼程式指的是指令列方面的軟體，包括本章要介紹的 bash 等。 廣義的殼程式則包括圖形介面的軟體！因為圖形介面其實也能夠操作各種應用程式來呼叫核心工作啊！ 不過在本章中，我們主要還是在使用 bash 啦！

為何要學文字介面的 shell？

文字介面的 shell 是很不好學的，但是學了之後好處多多！所以， 在這裡鳥哥要先對您進行一些心理建設，先來瞭解一下為啥學習 shell 是有好處的，這樣你才會有信心繼續玩下去 ^_^

- 文字介面的 shell：大家都一樣！

鳥哥常常聽到這個問題：『我幹嘛要學習 shell 呢？ 不是已經有很多的工具可以提供我設定我的主機了？我為何要花這麼多時間去學指令呢？不是以 X Window 按一按幾個按鈕就可以搞定了嗎？』唉∼還是得一再地強調， X Window 還有 Web 介面的設定工具例如 Webmin (註1) 是真的好用的傢伙， 他真的可以幫助我們很簡易的設定好我們的主機，甚至是一些很進階的設定都可以幫我們搞定。

但是鳥哥在前面的章節裡面也已經提到過相當多次了， X Window 與 web 介面的工具，他的介面雖然親善，功能雖然強大， 但畢竟他是將所有利用到的軟體都整合在一起的一組應用程式而已， 並非是一個完整的套件，所以某些時候當你升級或者是使用其他套件管理模組 (例如 tarball 而非 rpm 檔案等等) 時，就會造成設定的困擾了。甚至不同的 distribution 所設計的 X window 介面也都不相同，這樣也造成學習方面的困擾。

文字介面的 shell 就不同了！幾乎各家 distributions 使用的 bash 都是一樣的！如此一來， 你就能夠輕輕鬆鬆的轉換不同的 distributions ，就像武俠小說裡面提到的『一法通、萬法通！』

- 遠端管理：文字介面就是比較快！

此外，Linux 的管理常常需要透過遠端連線，而連線時文字介面的傳輸速度一定比較快， 而且，較不容易出現斷線或者是資訊外流的問題，因此，shell 真的是得學習的一項工具。而且，他可以讓您更深入 Linux ，更瞭解他，而不是只會按一按滑鼠而已！所謂『天助自助者！』多摸一點文字模式的東西，會讓你與 Linux 更親近呢！

- Linux 的任督二脈： shell 是也！

有些朋友也很可愛，常會說：『我學這麼多幹什麼？ 又不常用，也用不到！』嘿嘿！有沒有聽過『書到用時方恨少？』 當你的主機一切安然無恙的時候，您當然會覺得好像學這麼多的東西一點幫助也沒有呀！ 萬一，某一天真的不幸給他中標了，您該如何是好？是直接重新安裝？ 還是先追蹤入侵來源後進行漏洞的修補？或者是乾脆就關站好了？這當然涉及很多的考量， 但就以鳥哥的觀點來看，多學一點總是好的，尤其我們可以有備而無患嘛！甚至學的不精也沒有關係，瞭解概念也就 OK 啦！畢竟沒有人要您一定要背這麼多的內容啦！瞭解概念就很了不起了！

此外，如果你真的有心想要將您的主機管理的好，那麼良好的 shell 程式編寫是一定需要的啦！就鳥哥自己來說，鳥哥管理的主機雖然還不算多， 只有區區不到十部，但是如果每部主機都要花上幾十分鐘來查閱他的登錄檔資訊以及相關的訊息， 那麼鳥哥可能會瘋掉！基本上，也太沒有效率了！這個時候，如果能夠藉由 shell 提供的資料流重導向以及管線命令，呵呵！ 那麼鳥哥分析登錄資訊只要花費不到十分鐘就可以看完所有的主機之重要資訊了！相當的好用呢！

由於學習 shell 的好處真的是多多啦！所以，如果你是個系統管理員，或者有心想要管理系統的話，那麼 shell 與 shell scripts 這個東西真的有必要看一看！因為他就像『打通任督二脈，任何武功都能隨你應用』的說！

系統的合法 shell 與 /etc/shells 功能

知道什麼是 Shell 之後，那麼我們來瞭解一下 Linux 使用的是哪一個 shell 呢？什麼！哪一個？難道說 shell 不就是『一個 shell 嗎？』哈哈！那可不！由於早年的 Unix 年代，發展者眾，所以由於 shell 依據發展者的不同就有許多的版本，例如常聽到的 Bourne SHell (sh) 、在 Sun 裡頭預設的 C SHell、 商業上常用的 K SHell、, 還有 TCSH 等等，每一種 Shell 都各有其特點。至於 Linux 使用的這一種版本就稱為『 Bourne Again SHell (簡稱 bash) 』，這個 Shell 是 Bourne Shell 的增強版本，也是基準於 GNU 的架構下發展出來的呦！

在介紹 shell 的優點之前，先來說一說 shell 的簡單歷史吧(註2)：第一個流行的 shell 是由 Steven Bourne 發展出來的，為了紀念他所以就稱為 Bourne shell ，或直接簡稱為 sh ！而後來另一個廣為流傳的 shell 是由柏克萊大學的 Bill Joy 設計依附於 BSD 版的 Unix 系統中的 shell ，這個 shell 的語法有點類似 C 語言，所以才得名為 C shell ，簡稱為 csh ！由於在學術界 Sun 主機勢力相當的龐大，而 Sun 主要是 BSD 的分支之一，所以 C shell 也是另一個很重要而且流傳很廣的 shell 之一 。

Tips:

由於 Linux 為 C 程式語言撰寫的，很多程式設計師使用 C 來開發軟體，因此 C shell 相對的就很熱門了。 另外，還記得我們在第一章、Linux 是什麼提到的吧？ Sun 公司的創始人就是 Bill Joy，而 BSD 最早就是 Bill Joy 發展出來的啊。

那麼目前我們的 Linux (以 CentOS 5.x 為例) 有多少我們可以使用的 shells 呢？ 你可以檢查一下 /etc/shells 這個檔案，至少就有底下這幾個可以用的 shells：

- /bin/sh (已經被 /bin/bash 所取代)

- /bin/bash (就是 Linux 預設的 shell)

- /bin/ksh (Kornshell 由 AT&T Bell lab. 發展出來的，相容於 bash)

- /bin/tcsh (整合 C Shell ，提供更多的功能)

- /bin/csh (已經被 /bin/tcsh 所取代)

- /bin/zsh (基於 ksh 發展出來的，功能更強大的 shell)

雖然各家 shell 的功能都差不多，但是在某些語法的下達方面則有所不同，因此建議你還是得要選擇某一種 shell 來熟悉一下較佳。 Linux 預設就是使用 bash ，所以最初你只要學會 bash 就非常了不起了！ ^_^！ 另外，咦！為什麼我們系統上合法的 shell 要寫入 /etc/shells 這個檔案啊？ 這是因為系統某些服務在運作過程中，會去檢查使用者能夠使用的 shells ，而這些 shell 的查詢就是藉由 /etc/shells 這個檔案囉！

舉例來說，某些 FTP 網站會去檢查使用者的可用 shell ，而如果你不想要讓這些使用者使用 FTP 以外的主機資源時，可能會給予該使用者一些怪怪的 shell，讓使用者無法以其他服務登入主機。 這個時候，你就得將那些怪怪的 shell 寫到 /etc/shells 當中了。舉例來說，我們的 CentOS 5.x 的 /etc/shells 裡頭就有個 /sbin/nologin 檔案的存在，這個就是我們說的怪怪的 shell 囉∼

那麼，再想一想，我這個使用者什麼時候可以取得 shell 來工作呢？還有， 我這個使用者預設會取得哪一個 shell 啊？還記得我們在第五章的在終端介面登入linux小節當中提到的登入動作吧？ 當我登入的時候，系統就會給我一個 shell 讓我來工作了。 而這個登入取得的 shell 就記錄在 /etc/passwd 這個檔案內！這個檔案的內容是啥？

[root@www ~]# cat /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

.....(底下省略).....

如上所示，在每一行的最後一個資料，就是你登入後可以取得的預設的 shell 啦！那你也會看到， root 是 /bin/bash ，不過，系統帳號 bin 與 daemon 等等，就使用那個怪怪的 /sbin/nologin 囉∼關於使用者這部分的內容，我們留在第十四章的帳號管理時提供更多的說明。

Bash shell 的功能

既然 /bin/bash 是 Linux 預設的 shell ，那麼總是得瞭解一下這個玩意兒吧！bash 是 GNU 計畫中重要的工具軟體之一，目前也是 Linux distributions 的標準 shell 。 bash 主要相容於 sh ，並且依據一些使用者需求，而加強的 shell 版本。不論你使用的是那個 distribution ，你都難逃需要學習 bash 的宿命啦！那麼這個 shell 有什麼好處，幹嘛 Linux 要使用他作為預設的 shell 呢？ bash 主要的優點有底下幾個：

- 命令編修能力 (history)：

bash 的功能裡頭，鳥哥個人認為相當棒的一個就是『他能記憶使用過的指令！』 這功能真的相當的棒！因為我只要在指令列按『上下鍵』就可以找到前/後一個輸入的指令！而在很多 distribution 裡頭，預設的指令記憶功能可以到達 1000 個！也就是說， 你曾經下達過的指令幾乎都被記錄下來了。

這麼多的指令記錄在哪裡呢？在你的家目錄內的 .bash_history 啦！ 不過，需要留意的是，~/.bash_history 記錄的是前一次登入以前所執行過的指令， 而至於這一次登入所執行的指令都被暫存在記憶體中，當你成功的登出系統後，該指令記憶才會記錄到 .bash_history 當中！

這有什麼功能呢？最大的好處就是可以『查詢曾經做過的舉動！』 如此可以知道你的執行步驟，那麼就可以追蹤你曾下達過的指令，以作為除錯的工具！ 但如此一來也有個煩惱，就是如果被駭客入侵了，那麼他只要翻你曾經執行過的指令， 剛好你的指令又跟系統有關 (例如直接輸入 MySQL 的密碼在指令列上面)，那你的主機可就傷腦筋了！ 到底記錄指令的數目越多還是越少越好？這部份是見仁見智啦，沒有一定的答案的。

- 命令與檔案補全功能： ([tab] 按鍵的好處)

還記得我們在第五章內的重要的幾個熱鍵小節當中提到的 [tab] 這個按鍵嗎？這個按鍵的功能就是在 bash 裡頭才有的啦！常常在 bash 環境中使用 [tab] 是個很棒的習慣喔！因為至少可以讓你 1)少打很多字； 2)確定輸入的資料是正確的！ 使用 [tab] 按鍵的時機依據 [tab] 接在指令後或參數後而有所不同。我們再複習一次：

- [Tab] 接在一串指令的第一個字的後面，則為命令補全；

- [Tab] 接在一串指令的第二個字以後時，則為『檔案補齊』！

所以說，如果我想要知道我的環境中，所有可以執行的指令有幾個？ 就直接在 bash 的提示字元後面連續按兩次 [tab] 按鍵就能夠顯示所有的可執行指令了。 那如果想要知道系統當中所有以 c 為開頭的指令呢？就按下『 c[tab][tab] 』就好啦！ ^_^

是的！真的是很方便的功能，所以，有事沒事，在 bash shell 底下，多按幾次 [tab] 是一個不錯的習慣啦！

- 命令別名設定功能： (alias)

假如我需要知道這個目錄底下的所有檔案 (包含隱藏檔) 及所有的檔案屬性，那麼我就必須要下達『 ls -al 』這樣的指令串，唉！真麻煩，有沒有更快的取代方式？呵呵！就使用命令別名呀！例如鳥哥最喜歡直接以 lm 這個自訂的命令來取代上面的命令，也就是說， lm 會等於 ls -al 這樣的一個功能，嘿！那麼要如何作呢？就使用 alias 即可！你可以在指令列輸入 alias 就可以知道目前的命令別名有哪些了！也可以直接下達命令來設定別名呦：

alias lm='ls -al'

- 工作控制、前景背景控制： (job control, foreground, background)

這部分我們在第十七章 Linux 程序控制中再提及！ 使用前、背景的控制可以讓工作進行的更為順利！至於工作控制(jobs)的用途則更廣， 可以讓我們隨時將工作丟到背景中執行！而不怕不小心使用了 [Ctrl] + c 來停掉該程序！真是好樣的！此外，也可以在單一登入的環境中，達到多工的目的呢！

- 程式化腳本： (shell scripts)

在 DOS 年代還記得將一堆指令寫在一起的所謂的『批次檔』吧？在 Linux 底下的 shell scripts 則發揮更為強大的功能，可以將你平時管理系統常需要下達的連續指令寫成一個檔案， 該檔案並且可以透過對談互動式的方式來進行主機的偵測工作！也可以藉由 shell 提供的環境變數及相關指令來進行設計，哇！整個設計下來幾乎就是一個小型的程式語言了！該 scripts 的功能真的是超乎我的想像之外！以前在 DOS 底下需要程式語言才能寫的東西，在 Linux 底下使用簡單的 shell scripts 就可以幫你達成了！真的厲害！這部分我們在第十三章再來談！

- 萬用字元： (Wildcard)

除了完整的字串之外， bash 還支援許多的萬用字元來幫助使用者查詢與指令下達。 舉例來說，想要知道 /usr/bin 底下有多少以 X 為開頭的檔案嗎？使用：『 ls -l /usr/bin/X* 』就能夠知道囉∼此外，還有其他可供利用的萬用字元， 這些都能夠加快使用者的操作呢！

Bash shell 的內建命令： type

我們在第五章提到關於 Linux 的線上說明文件部分，也就是 man page 的內容，那麼 bash 有沒有什麼說明文件啊？開玩笑∼ 這麼棒的東西怎麼可能沒有說明文件！請你在 shell 的環境下，直接輸入 man bash 瞧一瞧， 嘿嘿！不是蓋的吧！讓你看個幾天幾夜也無法看完的 bash 說明文件，可是很詳盡的資料啊！ ^_^

不過，在這個 bash 的 man page 當中，不知道你是否有察覺到，咦！ 怎麼這個說明文件裡面有其他的檔案說明啊？舉例來說，那個 cd 指令的說明就在這個 man page 內？ 然後我直接輸入 man cd 時，怎麼出現的畫面中，最上方竟然出現一堆指令的介紹？這是怎麼回事？ 為了方便 shell 的操作，其實 bash 已經『內建』了很多指令了，例如上面提到的 cd ， 還有例如 umask 等等的指令，都是內建在 bash 當中的呢！

那我怎麼知道這個指令是來自於外部指令(指的是其他非 bash 所提供的指令) 或是內建在 bash 當中的呢？ 嘿嘿！利用 type 這個指令來觀察即可！舉例來說：

[root@www ~]# type [-tpa] name

選項與參數：

：不加任何選項與參數時，type 會顯示出 name 是外部指令還是 bash 內建指令

-t  ：當加入 -t 參數時，type 會將 name 以底下這些字眼顯示出他的意義：

file    ：表示為外部指令；

alias   ：表示該指令為命令別名所設定的名稱；

builtin ：表示該指令為 bash 內建的指令功能；

-p  ：如果後面接的 name 為外部指令時，才會顯示完整檔名；

-a  ：會由 PATH 變數定義的路徑中，將所有含 name 的指令都列出來，包含 alias

範例一：查詢一下 ls 這個指令是否為 bash 內建？

[root@www ~]# type ls

ls is aliased to `ls --color=tty' <==未加任何參數，列出 ls 的最主要使用情況

[root@www ~]# type -t ls

alias                             <==僅列出 ls 執行時的依據

[root@www ~]# type -a ls

ls is aliased to `ls --color=tty' <==最先使用 aliase

ls is /bin/ls                     <==還有找到外部指令在 /bin/ls

範例二：那麼 cd 呢？

[root@www ~]# type cd

cd is a shell builtin             <==看到了嗎？ cd 是 shell 內建指令

透過 type 這個指令我們可以知道每個指令是否為 bash 的內建指令。 此外，由於利用 type 搜尋後面的名稱時，如果後面接的名稱並不能以執行檔的狀態被找到， 那麼該名稱是不會被顯示出來的。也就是說， type 主要在找出『執行檔』而不是一般檔案檔名喔！ 呵呵！所以，這個 type 也可以用來作為類似 which 指令的用途啦！找指令用的！

指令的下達

我們在第五章的開始下達指令小節已經提到過在 shell 環境下的指令下達方法，如果你忘記了請回到第五章再去回憶一下！這裡不重複說明了。 鳥哥這裡僅就反斜線 (\) 來說明一下指令下達的方式囉！

範例：如果指令串太長的話，如何使用兩行來輸出？

[vbird@www ~]# cp /var/spool/mail/root /etc/crontab \

> /etc/fstab /root

上面這個指令用途是將三個檔案複製到 /root 這個目錄下而已。不過，因為指令太長， 於是鳥哥就利用『 \[Enter] 』來將 [Enter] 這個按鍵『跳脫！』開來，讓 [Enter] 按鍵不再具有『開始執行』的功能！好讓指令可以繼續在下一行輸入。 需要特別留意， [Enter] 按鍵是緊接著反斜線 (\) 的，兩者中間沒有其他字元。 因為 \ 僅跳脫『緊接著的下一個字符』而已！所以，萬一我寫成： 『 \ [Enter] 』，亦即 [Enter] 與反斜線中間有一個空格時，則 \ 跳脫的是『空白鍵』而不是 [Enter] 按鍵！這個地方請再仔細的看一遍！很重要！

如果順利跳脫 [Enter] 後，下一行最前面就會主動出現 > 的符號， 你可以繼續輸入指令囉！也就是說，那個 > 是系統自動出現的，你不需要輸入。

總之，當我們順利的在終端機 (tty) 上面登入後， Linux 就會依據 /etc/passwd 檔案的設定給我們一個 shell (預設是 bash)，然後我們就可以依據上面的指令下達方式來操作 shell， 之後，我們就可以透過 man 這個線上查詢來查詢指令的使用方式與參數說明， 很不錯吧！那麼我們就趕緊更進一步來操作 bash 這個好玩的東西囉！

Shell 的變數功能

變數是 bash 環境中非常重要的一個玩意兒，我們知道 Linux 是多人多工的環境，每個人登入系統都能取得一個 bash ， 每個人都能夠使用 bash 下達 mail 這個指令來收受『自己』的郵件，問題是， bash 是如何得知你的郵件信箱是哪個檔案？ 這就需要『變數』的幫助啦！所以，你說變數重不重要呢？底下我們將介紹重要的環境變數、變數的取用與設定等資料， 呼呼！動動腦時間又來到囉！^_^

什麼是變數？

那麼，什麼是『變數』呢？簡單的說，就是讓某一個特定字串代表不固定的內容就是了。舉個大家在國中都會學到的數學例子， 那就是：『 y = ax + b 』這東西，在等號左邊的(y)就是變數，在等號右邊的(ax+b)就是變數內容。 要注意的是，左邊是未知數，右邊是已知數喔！ 講的更簡單一點，我們可以『用一個簡單的 "字眼" 來取代另一個比較複雜或者是容易變動的資料』。這有什麼好處啊？最大的好處就是『方便！』。

- 變數的可變性與方便性

舉例來說，我們每個帳號的郵件信箱預設是以 MAIL 這個變數來進行存取的， 當 dmtsai 這個使用者登入時，他便會取得 MAIL 這個變數，而這個變數的內容其實就是 /var/spool/mail/dmtsai， 那如果 vbird 登入呢？他取得的 MAIL 這個變數的內容其實就是 /var/spool/mail/vbird 。 而我們使用信件讀取指令 mail 來讀取自己的郵件信箱時，嘿嘿，這支程式可以直接讀取 MAIL 這個變數的內容， 就能夠自動的分辨出屬於自己的信箱信件囉！這樣一來，設計程式的設計師就真的很方便的啦！

圖 2.1.1、程式、變數與不同使用者的關係

如上圖所示，由於系統已經幫我們規劃好 MAIL 這個變數，所以使用者只要知道 mail 這個指令如何使用即可， mail 會主動的取用 MAIL 這個變數，就能夠如上圖所示的取得自己的郵件信箱了！(注意大小寫，小寫的 mail 是指令， 大寫的 MAIL 則是變數名稱喔！)

那麼使用變數真的比較好嗎？這是當然的！想像一個例子，如果 mail 這個指令將 root 收信的郵件信箱 (mailbox) 檔名為 /var/spool/mail/root 直接寫入程式碼中。那麼當 dmtsai 要使用 mail 時，將會取得 /var/spool/mail/root 這個檔案的內容！ 不合理吧！所以你就需要幫 dmtsai 也設計一個 mail 的程式，將 /var/spool/mail/dmtsai 寫死到 mail 的程式碼當中！ 天吶！那系統要有多少個 mail 指令啊？反過來說，使用變數就變的很簡單了！因為你不需要更動到程式碼啊！ 只要將 MAIL 這個變數帶入不同的內容即可讓所有使用者透過 mail 取得自己的信件！當然簡單多了！

- 影響 bash 環境操作的變數

某些特定變數會影響到 bash 的環境喔！舉例來說，我們前面已經提到過很多次的那個 PATH 變數！ 你能不能在任何目錄下執行某個指令，與 PATH 這個變數有很大的關係。例如你下達 ls 這個指令時，系統就是透過 PATH 這個變數裡面的內容所記錄的路徑順序來搜尋指令的呢！如果在搜尋完 PATH 變數內的路徑還找不到 ls 這個指令時， 就會在螢幕上顯示『 command not found 』的錯誤訊息了。

如果說的學理一點，那麼由於在 Linux System 下面，所有的執行緒都是需要一個執行碼， 而就如同上面提到的，你『真正以 shell 來跟 Linux 溝通，是在正確的登入 Linux 之後！』這個時候你就有一個 bash 的執行程序，也才可以真正的經由 bash 來跟系統溝通囉！而在進入 shell 之前，也正如同上面提到的，由於系統需要一些變數來提供他資料的存取 (或者是一些環境的設定參數值， 例如是否要顯示彩色等等的) ，所以就有一些所謂的『環境變數』 需要來讀入系統中了！這些環境變數例如 PATH、HOME、MAIL、SHELL 等等，都是很重要的， 為了區別與自訂變數的不同，環境變數通常以大寫字元來表示呢！

- 腳本程式設計 (shell script) 的好幫手

這些還都只是系統預設的變數的目的，如果是個人的設定方面的應用呢：例如你要寫一個大型的 script 時，有些資料因為可能由於使用者習慣的不同而有差異，比如說路徑好了，由於該路徑在 script 被使用在相當多的地方，如果下次換了一部主機，都要修改 script 裡面的所有路徑，那麼我一定會瘋掉！ 這個時候如果使用變數，而將該變數的定義寫在最前面，後面相關的路徑名稱都以變數來取代， 嘿嘿！那麼你只要修改一行就等於修改整篇 script 了！方便的很！所以，良好的程式設計師都會善用變數的定義！

圖 2.1.2、變數應用於 shell script 的示意圖

最後我們就簡單的對『什麼是變數』作個簡單定義好了： 『變數就是以一組文字或符號等，來取代一些設定或者是一串保留的資料！』， 例如：我設定了『myname』就是『VBird』，所以當你讀取 myname 這個變數的時候，系統自然就會知道！哈！那就是 VBird 啦！ 那麼如何『顯示變數』呢？這就需要使用到 echo 這個指令啦！

變數的取用與設定：echo, 變數設定規則, unset

說的口沫橫飛的，也不知道『變數』與『變數代表的內容』有啥關係？ 那我們就將『變數』的『內容』拿出來給您瞧瞧好了。你可以利用 echo 這個指令來取用變數， 但是，變數在被取用時，前面必須要加上錢字號『 $ 』才行，舉例來說，要知道 PATH 的內容，該如何是好？

- 變數的取用: echo

[root@www ~]# echo $variable

[root@www ~]# echo $PATH

/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

[root@www ~]# echo ${PATH}

變數的取用就如同上面的範例，利用 echo 就能夠讀出，只是需要在變數名稱前面加上 $ ， 或者是以 ${變數} 的方式來取用都可以！當然啦，那個 echo 的功能可是很多的， 我們這裡單純是拿 echo 來讀出變數的內容而已，更多的 echo 使用，請自行給他 man echo 吧！ ^_^

例題：

請在螢幕上面顯示出您的環境變數 HOME 與 MAIL：

答：

echo $HOME 或者是 echo ${HOME}

echo $MAIL 或者是 echo ${MAIL}

現在我們知道了變數與變數內容之間的相關性了，好了，那麼我要如何『設定』或者是『修改』 某個變數的內容啊？很簡單啦！用『等號(=)』連接變數與他的內容就好啦！舉例來說： 我要將 myname 這個變數名稱的內容設定為 VBird ，那麼：

[root@www ~]# echo $myname

<==這裡並沒有任何資料∼因為這個變數尚未被設定！是空的！

[root@www ~]# myname=VBird

[root@www ~]# echo $myname

VBird  <==出現了！因為這個變數已經被設定了！

瞧！如此一來，這個變數名稱 myname 的內容就帶有 VBird 這個資料囉∼ 而由上面的例子當中，我們也可以知道： 在 bash 當中，當一個變數名稱尚未被設定時，預設的內容是『空』的。 另外，變數在設定時，還是需要符合某些規定的，否則會設定失敗喔！ 這些規則如下所示啊！

- 變數的設定規則

1. 變數與變數內容以一個等號『=』來連結，如下所示：

『myname=VBird』

2. 等號兩邊不能直接接空白字元，如下所示為錯誤：

『myname = VBird』或『myname=VBird Tsai』

3. 變數名稱只能是英文字母與數字，但是開頭字元不能是數字，如下為錯誤：

『2myname=VBird』

4. 變數內容若有空白字元可使用雙引號『"』或單引號『'』將變數內容結合起來，但

- 雙引號內的特殊字元如 $ 等，可以保有原本的特性，如下所示：

『var="lang is $LANG"』則『echo $var』可得『lang is en_US』

- 單引號內的特殊字元則僅為一般字元 (純文字)，如下所示：

『var='lang is $LANG'』則『echo $var』可得『lang is $LANG』

1. 可用跳脫字元『 \ 』將特殊符號(如 [Enter], $, \, 空白字元, '等)變成一般字元；

2. 在一串指令中，還需要藉由其他的指令提供的資訊，可以使用反單引號『`指令`』或 『$(指令)』。特別注意，那個 ` 是鍵盤上方的數字鍵 1 左邊那個按鍵，而不是單引號！ 例如想要取得核心版本的設定：

『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』

3. 若該變數為擴增變數內容時，則可用 "$變數名稱" 或 ${變數} 累加內容，如下所示：

『PATH="$PATH":/home/bin』

4. 若該變數需要在其他子程序執行，則需要以 export 來使變數變成環境變數：

『export PATH』

5. 通常大寫字元為系統預設變數，自行設定變數可以使用小寫字元，方便判斷 (純粹依照使用者興趣與嗜好) ；

6. 取消變數的方法為使用 unset ：『unset 變數名稱』例如取消 myname 的設定：

『unset myname』

底下讓鳥哥舉幾個例子來讓你試看看，就知道怎麼設定好你的變數囉！

範例一：設定一變數 name ，且內容為 VBird

[root@www ~]# 12name=VBird

-bash: 12name=VBird: command not found  <==螢幕會顯示錯誤！因為不能以數字開頭！

[root@www ~]# name = VBird            <==還是錯誤！因為有空白！

[root@www ~]# name=VBird              <==OK 的啦！

範例二：承上題，若變數內容為 VBird's name 呢，就是變數內容含有特殊符號時：

[root@www ~]# name=VBird's name

# 單引號與雙引號必須要成對，在上面的設定中僅有一個單引號，因此當你按下 enter 後，

# 你還可以繼續輸入變數內容。這與我們所需要的功能不同，失敗啦！

# 記得，失敗後要復原請按下 [ctrl]-c 結束！

[root@www ~]# name="VBird's name"    <==OK 的啦！

# 指令是由左邊向右找→，先遇到的引號先有用，因此如上所示，單引號會失效！

[root@www ~]# name='VBird's name'    <==失敗的啦！

# 因為前兩個單引號已成對，後面就多了一個不成對的單引號了！因此也就失敗了！

[root@www ~]# name=VBird\'s\ name     <==OK 的啦！

# 利用反斜線 (\) 跳脫特殊字元，例如單引號與空白鍵，這也是 OK 的啦！

範例三：我要在 PATH 這個變數當中『累加』:/home/dmtsai/bin 這個目錄

[root@www ~]# PATH=$PATH:/home/dmtsai/bin

[root@www ~]# PATH="$PATH":/home/dmtsai/bin

[root@www ~]# PATH=${PATH}:/home/dmtsai/bin

# 上面這三種格式在 PATH 裡頭的設定都是 OK 的！但是底下的例子就不見得囉！

範例四：承範例三，我要將 name 的內容多出 "yes" 呢？

[root@www ~]# name=$nameyes

# 知道了吧？如果沒有雙引號，那麼變數成了啥？name 的內容是 $nameyes 這個變數！

# 呵呵！我們可沒有設定過 nameyes 這個變數吶！所以，應該是底下這樣才對！

[root@www ~]# name="$name"yes

[root@www ~]# name=${name}yes  <==以此例較佳！

範例五：如何讓我剛剛設定的 name=VBird 可以用在下個 shell 的程序？

[root@www ~]# name=VBird

[root@www ~]# bash        <==進入到所謂的子程序

[root@www ~]# echo $name  <==子程序：再次的 echo 一下；

<==嘿嘿！並沒有剛剛設定的內容喔！

[root@www ~]# exit        <==子程序：離開這個子程序

[root@www ~]# export name

[root@www ~]# bash        <==進入到所謂的子程序

[root@www ~]# echo $name  <==子程序：在此執行！

VBird  <==看吧！出現設定值了！

[root@www ~]# exit        <==子程序：離開這個子程序

什麼是『子程序』呢？就是說，在我目前這個 shell 的情況下，去啟用另一個新的 shell ，新的那個 shell 就是子程序啦！在一般的狀態下，父程序的自訂變數是無法在子程序內使用的。但是透過 export 將變數變成環境變數後，就能夠在子程序底下應用了！很不賴吧！至於程序的相關概念， 我們會在第十七章程序管理當中提到的喔！

範例六：如何進入到您目前核心的模組目錄？

[root@www ~]# cd /lib/modules/`uname -r`/kernel

[root@www ~]# cd /lib/modules/$(uname -r)/kernel

每個 Linux 都能夠擁有多個核心版本，且幾乎 distribution 的核心版本都不相同。以 CentOS 5.3 (未更新前) 為例，他的預設核心版本是 2.6.18-128.el5 ，所以核心模組目錄在 /lib/modules/2.6.18-128.el5/kernel/ 內。 也由於每個 distributions 的這個值都不相同，但是我們卻可以利用 uname -r 這個指令先取得版本資訊。所以囉，就可以透過上面指令當中的內含指令 `uname -r` 先取得版本輸出到 cd ... 那個指令當中，就能夠順利的進入目前核心的驅動程式所放置的目錄囉！很方便吧！

其實上面的指令可以說是作了兩次動作，亦即是：

1. 先進行反單引號內的動作『uname -r』並得到核心版本為 2.6.18-128.el5

2. 將上述的結果帶入原指令，故得指令為：『cd /lib/modules/2.6.18-128.el5/kernel/』

範例七：取消剛剛設定的 name 這個變數內容

[root@www ~]# unset name

根據上面的案例你可以試試看！就可以瞭解變數的設定囉！這個是很重要的呦！請勤加練習！ 其中，較為重要的一些特殊符號的使用囉！例如單引號、雙引號、跳脫字元、錢字號、反單引號等等，底下的例題想一想吧！

例題：

在變數的設定當中，單引號與雙引號的用途有何不同？

答：

單引號與雙引號的最大不同在於雙引號仍然可以保有變數的內容，但單引號內僅能是一般字元 ，而不會有特殊符號。我們以底下的例子做說明：假設您定義了一個變數， name=VBird ，現在想以 name 這個變數的內容定義出 myname 顯示 VBird its me 這個內容，要如何訂定呢？

[root@www ~]# name=VBird

[root@www ~]# echo $name

VBird

[root@www ~]# myname="$name its me"

[root@www ~]# echo $myname

VBird its me

[root@www ~]# myname='$name its me'

[root@www ~]# echo $myname

$name its me

發現了嗎？沒錯！使用了單引號的時候，那麼 $name 將失去原有的變數內容，僅為一般字元的顯示型態而已！這裡必需要特別小心在意！

例題：

在指令下達的過程中，反單引號( ` )這個符號代表的意義為何？

答：

在一串指令中，在 ` 之內的指令將會被先執行，而其執行出來的結果將做為外部的輸入資訊！例如 uname -r 會顯示出目前的核心版本，而我們的核心版本在 /lib/modules 裡面，因此，你可以先執行 uname -r 找出核心版本，然後再以『 cd 目錄』到該目錄下，當然也可以執行如同上面範例六的執行內容囉。

另外再舉個例子，我們也知道， locate 指令可以列出所有的相關檔案檔名，但是，如果我想要知道各個檔案的權限呢？舉例來說，我想要知道每個 crontab 相關檔名的權限：

[root@www ~]# ls -l `locate crontab`

如此一來，先以 locate 將檔名資料都列出來，再以 ls 指令來處理的意思啦！瞭了嗎？ ^_^

例題：

若你有一個常去的工作目錄名稱為：『/cluster/server/work/taiwan_2005/003/』，如何進行該目錄的簡化？

答：

在一般的情況下，如果你想要進入上述的目錄得要『cd /cluster/server/work/taiwan_2005/003/』， 以鳥哥自己的案例來說，鳥哥跑數值模式常常會設定很長的目錄名稱(避免忘記)，但如此一來變換目錄就很麻煩。 此時，鳥哥習慣利用底下的方式來降低指令下達錯誤的問題：

[root@www ~]# work="/cluster/server/work/taiwan_2005/003/"

[root@www ~]# cd $work

未來我想要使用其他目錄作為我的模式工作目錄時，只要變更 work 這個變數即可！而這個變數又可以在 bash 的設定檔中直接指定，那我每次登入只要執行『 cd $work 』就能夠去到數值模式模擬的工作目錄了！是否很方便呢？ ^_^

Tips:

老實說，使用『 version=$(uname -r) 』來取代『 version=`uname -r` 』比較好，因為反單引號大家老是容易打錯或看錯！ 所以現在鳥哥都習慣使用 $( 指令 ) 來介紹這個功能！

環境變數的功能

環境變數可以幫我們達到很多功能∼包括家目錄的變換啊、提示字元的顯示啊、執行檔搜尋的路徑啊等等的， 還有很多很多啦！那麼，既然環境變數有那麼多的功能，問一下，目前我的 shell 環境中， 有多少預設的環境變數啊？我們可以利用兩個指令來查閱，分別是 env 與 export 呢！

- 用 env 觀察環境變數與常見環境變數說明

範例一：列出目前的 shell 環境下的所有環境變數與其內容。

[root@www ~]# env

HOSTNAME=www.vbird.tsai    <== 這部主機的主機名稱

TERM=xterm                 <== 這個終端機使用的環境是什麼類型

SHELL=/bin/bash            <== 目前這個環境下，使用的 Shell 是哪一個程式？

HISTSIZE=1000              <== 『記錄指令的筆數』在 CentOS 預設可記錄 1000 筆

USER=root                  <== 使用者的名稱啊！

LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:

or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0

0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=

00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3

1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00

;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些顏色顯示

MAIL=/var/spool/mail/root  <== 這個使用者所取用的 mailbox 位置

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:

/root/bin                  <== 不再多講啊！是執行檔指令搜尋路徑

INPUTRC=/etc/inputrc       <== 與鍵盤按鍵功能有關。可以設定特殊按鍵！

PWD=/root                  <== 目前使用者所在的工作目錄 (利用 pwd 取出！)

LANG=en_US                 <== 這個與語系有關，底下會再介紹！

HOME=/root                 <== 這個使用者的家目錄啊！

_=/bin/env                 <== 上一次使用的指令的最後一個參數(或指令本身)

env 是 environment (環境) 的簡寫啊，上面的例子當中，是列出來所有的環境變數。當然，如果使用 export 也會是一樣的內容∼ 只不過， export 還有其他額外的功能就是了，我們等一下再提這個 export 指令。 那麼上面這些變數有些什麼功用呢？底下我們就一個一個來分析分析！

- HOME

代表使用者的家目錄。還記得我們可以使用 cd ~ 去到自己的家目錄嗎？或者利用 cd 就可以直接回到使用者家目錄了。那就是取用這個變數啦∼ 有很多程式都可能會取用到這個變數的值！

- SHELL

告知我們，目前這個環境使用的 SHELL 是哪支程式？ Linux 預設使用 /bin/bash 的啦！

- HISTSIZE

這個與『歷史命令』有關，亦即是， 我們曾經下達過的指令可以被系統記錄下來，而記錄的『筆數』則是由這個值來設定的。

- MAIL

當我們使用 mail 這個指令在收信時，系統會去讀取的郵件信箱檔案 (mailbox)。

- PATH

就是執行檔搜尋的路徑啦∼目錄與目錄中間以冒號(:)分隔， 由於檔案的搜尋是依序由 PATH 的變數內的目錄來查詢，所以，目錄的順序也是重要的喔。

- LANG

這個重要！就是語系資料囉∼很多訊息都會用到他， 舉例來說，當我們在啟動某些 perl 的程式語言檔案時，他會主動的去分析語系資料檔案， 如果發現有他無法解析的編碼語系，可能會產生錯誤喔！一般來說，我們中文編碼通常是 zh_TW.Big5 或者是 zh_TW.UTF-8，這兩個編碼偏偏不容易被解譯出來，所以，有的時候，可能需要修訂一下語系資料。 這部分我們會在下個小節做介紹的！

- RANDOM

這個玩意兒就是『隨機亂數』的變數啦！目前大多數的 distributions 都會有亂數產生器，那就是 /dev/random 這個檔案。 我們可以透過這個亂數檔案相關的變數 ($RANDOM) 來隨機取得亂數值喔。在 BASH 的環境下，這個 RANDOM 變數的內容，介於 0~32767 之間，所以，你只要 echo $RANDOM 時，系統就會主動的隨機取出一個介於 0~32767 的數值。萬一我想要使用 0~9 之間的數值呢？呵呵∼利用 declare 宣告數值類型， 然後這樣做就可以了：

[root@www ~]# declare -i number=$RANDOM*10/32768 ; echo $number

8   <== 此時會隨機取出 0~9 之間的數值喔！

大致上是有這些環境變數啦∼裡面有些比較重要的參數，在底下我們都會另外進行一些說明的∼

- 用 set 觀察所有變數 (含環境變數與自訂變數)

bash 可不只有環境變數喔，還有一些與 bash 操作介面有關的變數，以及使用者自己定義的變數存在的。 那麼這些變數如何觀察呢？這個時候就得要使用 set 這個指令了。 set 除了環境變數之外， 還會將其他在 bash 內的變數通通顯示出來哩！資訊很多，底下鳥哥僅列出幾個重要的內容：

[root@www ~]# set

BASH=/bin/bash           <== bash 的主程式放置路徑

BASH_VERSINFO=([0]="3" [1]="2" [2]="25" [3]="1" [4]="release"

[5]="i686-redhat-linux-gnu")      <== bash 的版本啊！

BASH_VERSION='3.2.25(1)-release'  <== 也是 bash 的版本啊！

COLORS=/etc/DIR_COLORS.xterm      <== 使用的顏色紀錄檔案

COLUMNS=115              <== 在目前的終端機環境下，使用的欄位有幾個字元長度

HISTFILE=/root/.bash_history      <== 歷史命令記錄的放置檔案，隱藏檔

HISTFILESIZE=1000        <== 存起來(與上個變數有關)的檔案之指令的最大紀錄筆數。

HISTSIZE=1000            <== 目前環境下，可記錄的歷史命令最大筆數。

HOSTTYPE=i686            <== 主機安裝的軟體主要類型。我們用的是 i686 相容機器軟體

IFS=$' \t\n'             <== 預設的分隔符號

LINES=35                 <== 目前的終端機下的最大行數

MACHTYPE=i686-redhat-linux-gnu    <== 安裝的機器類型

MAILCHECK=60             <== 與郵件有關。每 60 秒去掃瞄一次信箱有無新信！

OLDPWD=/home             <== 上個工作目錄。我們可以用 cd - 來取用這個變數。

OSTYPE=linux-gnu         <== 作業系統的類型！

PPID=20025               <== 父程序的 PID (會在後續章節才介紹)

PS1='[\u@\h \W]\$ '      <== PS1 就厲害了。這個是命令提示字元，也就是我們常見的

[root@www ~]# 或 [dmtsai ~]$ 的設定值啦！可以更動的！

PS2='> '                 <== 如果你使用跳脫符號 (\) 第二行以後的提示字元也

name=VBird               <== 剛剛設定的自訂變數也可以被列出來喔！

$                        <== 目前這個 shell 所使用的 PID

?                        <== 剛剛執行完指令的回傳值。

一般來說，不論是否為環境變數，只要跟我們目前這個 shell 的操作介面有關的變數， 通常都會被設定為大寫字元，也就是說，『基本上，在 Linux 預設的情況中，使用{大寫的字母}來設定的變數一般為系統內定需要的變數』。 OK！OK！那麼上頭那些變數當中，有哪些是比較重要的？大概有這幾個吧！

- PS1：(提示字元的設定)

這是 PS1 (數字的 1 不是英文字母)，這個東西就是我們的『命令提示字元』喔！ 當我們每次按下 [Enter] 按鍵去執行某個指令後，最後要再次出現提示字元時， 就會主動去讀取這個變數值了。上頭 PS1 內顯示的是一些特殊符號，這些特殊符號可以顯示不同的資訊， 每個 distributions 的 bash 預設的 PS1 變數內容可能有些許的差異，不要緊，『習慣你自己的習慣』就好了。 你可以用 man bash (註3)去查詢一下 PS1 的相關說明，以理解底下的一些符號意義。

- \d ：可顯示出『星期 月 日』的日期格式，如："Mon Feb 2"

- \H ：完整的主機名稱。舉例來說，鳥哥的練習機為『www.vbird.tsai』

- \h ：僅取主機名稱在第一個小數點之前的名字，如鳥哥主機則為『www』後面省略

- \t ：顯示時間，為 24 小時格式的『HH:MM:SS』

- \T ：顯示時間，為 12 小時格式的『HH:MM:SS』

- \A ：顯示時間，為 24 小時格式的『HH:MM』

- \@ ：顯示時間，為 12 小時格式的『am/pm』樣式

- \u ：目前使用者的帳號名稱，如『root』；

- \v ：BASH 的版本資訊，如鳥哥的測試主機版本為 3.2.25(1)，僅取『3.2』顯示

- \w ：完整的工作目錄名稱，由根目錄寫起的目錄名稱。但家目錄會以 ~ 取代；

- \W ：利用 basename 函數取得工作目錄名稱，所以僅會列出最後一個目錄名。

- \# ：下達的第幾個指令。

- \$ ：提示字元，如果是 root 時，提示字元為 # ，否則就是 $ 囉∼

好了，讓我們來看看 CentOS 預設的 PS1 內容吧：『[\u@\h \W]\$ 』，現在你知道那些反斜線後的資料意義了吧？ 要注意喔！那個反斜線後的資料為 PS1 的特殊功能，與 bash 的變數設定沒關係啦！不要搞混了喔！ 那你現在知道為何你的命令提示字元是：『 [root@www ~]# 』了吧？ 好了，那麼假設我想要有類似底下的提示字元：

[root@www /home/dmtsai 16:50 #12]#

那個 # 代表第 12 次下達的指令。那麼應該如何設定 PS1 呢？可以這樣啊：

[root@www ~ ]# cd /home

[root@www home]# PS1='[\u@\h \w \A #\#]\$ '

[root@www /home 17:02 #85]#

# 看到了嗎？提示字元變了！變的很有趣吧！其中，那個 #85 比較有趣，

# 如果您再隨便輸入幾次 ls 後，該數字就會增加喔！為啥？上面有說明滴！

- $：(關於本 shell 的 PID)

錢字號本身也是個變數喔！這個咚咚代表的是『目前這個 Shell 的執行緒代號』，亦即是所謂的 PID (Process ID)。 更多的程序觀念，我們會在第四篇的時候提及。想要知道我們的 shell 的 PID ，就可以用：『 echo $$ 』即可！出現的數字就是你的 PID 號碼。

- ?：(關於上個執行指令的回傳值)

蝦密？問號也是一個特殊的變數？沒錯！在 bash 裡面這個變數可重要的很！ 這個變數是：『上一個執行的指令所回傳的值』， 上面這句話的重點是『上一個指令』與『回傳值』兩個地方。當我們執行某些指令時， 這些指令都會回傳一個執行後的代碼。一般來說，如果成功的執行該指令， 則會回傳一個 0 值，如果執行過程發生錯誤，就會回傳『錯誤代碼』才對！一般就是以非為 0 的數值來取代。 我們以底下的例子來看看：

[root@www ~]# echo $SHELL

/bin/bash                                  <==可順利顯示！沒有錯誤！

[root@www ~]# echo $?

0                                          <==因為沒問題，所以回傳值為 0

[root@www ~]# 12name=VBird

-bash: 12name=VBird: command not found     <==發生錯誤了！bash回報有問題

[root@www ~]# echo $?

127                                        <==因為有問題，回傳錯誤代碼(非為0)

# 錯誤代碼回傳值依據軟體而有不同，我們可以利用這個代碼來搜尋錯誤的原因喔！

[root@www ~]# echo $?

0

# 咦！怎麼又變成正確了？這是因為 "?" 只與『上一個執行指令』有關，

# 所以，我們上一個指令是執行『 echo $? 』，當然沒有錯誤，所以是 0 沒錯！

- OSTYPE, HOSTTYPE, MACHTYPE：(主機硬體與核心的等級)

我們在第零章、計算機概論內的 CPU 等級說明中談過 CPU ， 目前個人電腦的 CPU 主要分為 32/64 位元，其中 32 位元又可分為 i386, i586, i686，而 64 位元則稱為 x86_64。 由於不同等級的 CPU 指令集不太相同，因此你的軟體可能會針對某些 CPU 進行最佳化，以求取較佳的軟體性能。 所以軟體就有 i386, i686 及 x86_64 之分。以目前 (2009) 的主流硬體來說，幾乎都是 x86_64 的天下！ 但是畢竟舊機器還是非常多，以鳥哥的環境來說，我用 P-III 等級的電腦，所以上頭就發現我的等級是 i686 啦！

要留意的是，較高階的硬體通常會向下相容舊有的軟體，但較高階的軟體可能無法在舊機器上面安裝！ 我們在第三章就曾說明過， 這裡再強調一次，你可以在 x86_64 的硬體上安裝 i386 的 Linux 作業系統，但是你無法在 i686 的硬體上安裝 x86_64 的 Linux 作業系統！這點得要牢記在心！

- export： 自訂變數轉成環境變數

談了 env 與 set 現在知道有所謂的環境變數與自訂變數，那麼這兩者之間有啥差異呢？其實這兩者的差異在於『 該變數是否會被子程序所繼續引用』啦！唔！那麼啥是父程序？子程序？ 這就得要瞭解一下指令的下達行為了。

當你登入 Linux 並取得一個 bash 之後，你的 bash 就是一個獨立的程序，被稱為 PID 的就是。 接下來你在這個 bash 底下所下達的任何指令都是由這個 bash 所衍生出來的，那些被下達的指令就被稱為子程序了。 我們可以用底下的圖示來簡單的說明一下父程序與子程序的概念：

圖 2.3.1、程序相關性示意圖

如上所示，我們在原本的 bash 底下執行另一個 bash ，結果操作的環境介面會跑到第二個 bash 去(就是子程序)， 那原本的 bash 就會在暫停的情況 (睡著了，就是 sleep)。整個指令運作的環境是實線的部分！若要回到原本的 bash 去， 就只有將第二個 bash 結束掉 (下達 exit 或 logout) 才行。更多的程序概念我們會在第四篇談及，這裡只要有這個概念即可。

這個程序概念與變數有啥關係啊？關係可大了！因為子程序僅會繼承父程序的環境變數， 子程序不會繼承父程序的自訂變數啦！所以你在原本 bash 的自訂變數在進入了子程序後就會消失不見， 一直到你離開子程序並回到原本的父程序後，這個變數才會又出現！

換個角度來想，也就是說，如果我能將自訂變數變成環境變數的話，那不就可以讓該變數值繼續存在於子程序了？ 呵呵！沒錯！此時，那個 export 指令就很有用啦！如你想要讓該變數內容繼續的在子程序中使用，那麼就請執行：

[root@www ~]# export 變數名稱

這東西用在『分享自己的變數設定給後來呼叫的檔案或其他程序』啦！ 像鳥哥常常在自己的主檔案後面呼叫其他附屬檔案(類似函式的功能)，但是主檔案與附屬檔案內都有相同的變數名稱， 若一再重複設定時，要修改也很麻煩，此時只要在原本的第一個檔案內設定好『 export 變數 』， 後面所呼叫的檔案就能夠使用這個變數設定了！而不需要重複設定，這非常實用於 shell script 當中喔！ 如果僅下達 export 而沒有接變數時，那麼此時將會把所有的『環境變數』秀出來喔！例如：

[root@www ~]# export

declare -x HISTSIZE="1000"

declare -x HOME="/root"

declare -x HOSTNAME="www.vbird.tsai"

declare -x INPUTRC="/etc/inputrc"

declare -x LANG="en_US"

declare -x LOGNAME="root"

# 後面的鳥哥就都直接省略了！不然....浪費版面∼ ^_^

那如何將環境變數轉成自訂變數呢？可以使用本章後續介紹的 declare 呢！

影響顯示結果的語系變數 (locale)

還記得我們在第五章裡面提到的語系問題嗎？ 就是當我們使用 man command 的方式去查詢某個資料的說明檔時，該說明檔的內容可能會因為我們使用的語系不同而產生亂碼。 另外，利用 ls 查詢檔案的時間時，也可能會有亂碼出現在時間的部分。那個問題其實就是語系的問題啦。

目前大多數的 Linux distributions 已經都是支援日漸流行的萬國碼了，也都支援大部分的國家語系。 這有賴於 i18n (註4) 支援的幫助呢！ 那麼我們的 Linux 到底支援了多少的語系呢？這可以由 locale 這個指令來查詢到喔！

[root@www ~]# locale -a

....(前面省略)....

zh_TW

zh_TW.big5     <==大五碼的中文編碼

zh_TW.euctw

zh_TW.utf8     <==萬國碼的中文編碼

zu_ZA

zu_ZA.iso88591

zu_ZA.utf8

正體中文語系至少支援了兩種以上的編碼，一種是目前還是很常見的 big5 ，另一種則是越來越熱門的 utf-8 編碼。 那麼我們如何修訂這些編碼呢？其實可以透過底下這些變數的說：

[root@www ~]# locale  <==後面不加任何選項與參數即可！

LANG=en_US                   <==主語言的環境

LC_CTYPE="en_US"             <==字元(文字)辨識的編碼

LC_NUMERIC="en_US"           <==數字系統的顯示訊息

LC_TIME="en_US"              <==時間系統的顯示資料

LC_COLLATE="en_US"           <==字串的比較與排序等

LC_MONETARY="en_US"          <==幣值格式的顯示等

LC_MESSAGES="en_US"          <==訊息顯示的內容，如功能表、錯誤訊息等

LC_ALL=                      <==整體語系的環境

....(後面省略)....

基本上，你可以逐一設定每個與語系有關的變數資料，但事實上，如果其他的語系變數都未設定， 且你有設定 LANG 或者是 LC_ALL 時，則其他的語系變數就會被這兩個變數所取代！ 這也是為什麼我們在 Linux 當中，通常說明僅設定 LANG 這個變數而已，因為他是最主要的設定變數！ 好了，那麼你應該要覺得奇怪的是，為什麼在 Linux 主機的終端機介面 (tty1 ~ tty6) 的環境下，如果設定『 LANG=zh_TW.big5 』這個設定值生效後，使用 man 或者其他訊息輸出時， 都會有一堆亂碼，尤其是使用 ls -l 這個參數時？

因為在 Linux 主機的終端機介面環境下是無法顯示像中文這麼複雜的編碼文字， 所以就會產生亂碼了。也就是如此，我們才會必須要在 tty1 ~ tty6 的環境下， 加裝一些中文化介面的軟體，才能夠看到中文啊！不過，如果你是在 MS Windows 主機以遠端連線伺服器的軟體連線到主機的話，那麼，嘿嘿！其實文字介面確實是可以看到中文的。 此時反而你得要在 LANG 設定中文編碼才好呢！

Tips:

無論如何，如果發生一些亂碼的問題，那麼設定系統裡面保有的語系編碼， 例如： en_US 或 en_US.utf8 等等的設定，應該就 OK 的啦！好了，那麼系統預設支援多少種語系呢？ 當我們使用 locale 時，系統是列出目前 Linux 主機內保有的語系檔案， 這些語系檔案都放置在： /usr/lib/locale/ 這個目錄中。

你當然可以讓每個使用者自己去調整自己喜好的語系，但是整體系統預設的語系定義在哪裡呢？ 其實就是在 /etc/sysconfig/i18n 囉！這個檔案在 CentOS 5.x 的內容有點像這樣：

[root@www ~]# cat /etc/sysconfig/i18n

LANG="zh_TW.UTF-8"

因為鳥哥在第四章的安裝時選擇的是中文語系安裝畫面， 所以這個檔案預設就會使用中文編碼啦！你也可以自行將他改成你想要的語系編碼即可。

Tips:

假設你有一個純文字檔案原本是在 Windows 底下建立的，那麼這個檔案預設應該是 big5 的編碼格式。 在你將這個檔案上傳到 Linux 主機後，在 X window 底下打開時，咦！怎麼中文字通通變成亂碼了？ 別擔心！因為如上所示， i18n 預設是萬國碼系統嘛！你只要將開啟該檔案的軟體編碼由 utf8 改成 big5 就能夠看到正確的中文了！

變數的有效範圍

蝦密？變數也有使用的『範圍』？沒錯啊∼我們在上頭的 export 指令說明中，就提到了這個概念了。如果在跑程式的時候，有父程序與子程序的不同程序關係時， 則『變數』可否被引用與 export 有關。被 export 後的變數，我們可以稱他為『環境變數』！ 環境變數可以被子程序所引用，但是其他的自訂變數內容就不會存在於子程序中。

Tips:

在某些不同的書籍會談到『全域變數, global variable』與『區域變數, local variable』。 基本上你可以這樣看待：

環境變數=全域變數

自訂變數=區域變數

在學理方面，為什麼環境變數的資料可以被子程序所引用呢？這是因為記憶體配置的關係！理論上是這樣的：

- 當啟動一個 shell，作業系統會分配一記憶區塊給 shell 使用，此記憶體內之變數可讓子程序取用

- 若在父程序利用 export 功能，可以讓自訂變數的內容寫到上述的記憶區塊當中(環境變數)；

- 當載入另一個 shell 時 (亦即啟動子程序，而離開原本的父程序了)，子 shell 可以將父 shell 的環境變數所在的記憶區塊導入自己的環境變數區塊當中。

透過這樣的關係，我們就可以讓某些變數在相關的程序之間存在，以幫助自己更方便的操作環境喔！ 不過要提醒的是，這個『環境變數』與『bash 的操作環境』意思不太一樣，舉例來說， PS1 並不是環境變數， 但是這個 PS1 會影響到 bash 的介面 (提示字元嘛)！相關性要釐清喔！^_^

變數鍵盤讀取、陣列與宣告： read, array, declare

我們上面提到的變數設定功能，都是由指令列直接設定的，那麼，可不可以讓使用者能夠經由鍵盤輸入？ 什麼意思呢？是否記得某些程式執行的過程當中，會等待使用者輸入 "yes/no" 之類的訊息啊？ 在 bash 裡面也有相對應的功能喔！此外，我們還可以宣告這個變數的屬性， 例如：陣列或者是數字等等的。底下就來看看吧！

- read

要讀取來自鍵盤輸入的變數，就是用 read 這個指令了。這個指令最常被用在 shell script 的撰寫當中， 想要跟使用者對談？用這個指令就對了。關於 script 的寫法，我們會在第十三章介紹，底下先來瞧一瞧 read 的相關語法吧！

[root@www ~]# read [-pt] variable

選項與參數：

-p  ：後面可以接提示字元！

-t  ：後面可以接等待的『秒數！』這個比較有趣∼不會一直等待使用者啦！

範例一：讓使用者由鍵盤輸入一內容，將該內容變成名為 atest 的變數

[root@www ~]# read atest

This is a test        <==此時游標會等待你輸入！請輸入左側文字看看

[root@www ~]# echo $atest

This is a test          <==你剛剛輸入的資料已經變成一個變數內容！

範例二：提示使用者 30 秒內輸入自己的大名，將該輸入字串作為名為 named 的變數內容

[root@www ~]# read -p "Please keyin your name: " -t 30 named

Please keyin your name: VBird Tsai   <==注意看，會有提示字元喔！

[root@www ~]# echo $named

VBird Tsai        <==輸入的資料又變成一個變數的內容了！

read 之後不加任何參數，直接加上變數名稱，那麼底下就會主動出現一個空白行等待你的輸入(如範例一)。 如果加上 -t 後面接秒數，例如上面的範例二，那麼 30 秒之內沒有任何動作時， 該指令就會自動略過了∼如果是加上 -p ，嘿嘿！在輸入的游標前就會有比較多可以用的提示字元給我們參考！ 在指令的下達裡面，比較美觀啦！ ^_^

- declare / typeset

declare 或 typeset 是一樣的功能，就是在『宣告變數的類型』。如果使用 declare 後面並沒有接任何參數，那麼 bash 就會主動的將所有的變數名稱與內容通通叫出來，就好像使用 set 一樣啦！ 那麼 declare 還有什麼語法呢？看看先：

[root@www ~]# declare [-aixr] variable

選項與參數：

-a  ：將後面名為 variable 的變數定義成為陣列 (array) 類型

-i  ：將後面名為 variable 的變數定義成為整數數字 (integer) 類型

-x  ：用法與 export 一樣，就是將後面的 variable 變成環境變數；

-r  ：將變數設定成為 readonly 類型，該變數不可被更改內容，也不能 unset

範例一：讓變數 sum 進行 100+300+50 的加總結果

[root@www ~]# sum=100+300+50

[root@www ~]# echo $sum

100+300+50  <==咦！怎麼沒有幫我計算加總？因為這是文字型態的變數屬性啊！

[root@www ~]# declare -i sum=100+300+50

[root@www ~]# echo $sum

450         <==瞭乎？？

由於在預設的情況底下， bash 對於變數有幾個基本的定義：

- 變數類型預設為『字串』，所以若不指定變數類型，則 1+2 為一個『字串』而不是『計算式』。 所以上述第一個執行的結果才會出現那個情況的；

- bash 環境中的數值運算，預設最多僅能到達整數形態，所以 1/3 結果是 0；

現在你曉得為啥你需要進行變數宣告了吧？如果需要非字串類型的變數，那就得要進行變數的宣告才行啦！ 底下繼續來玩些其他的 declare 功能。

範例二：將 sum 變成環境變數

[root@www ~]# declare -x sum

[root@www ~]# export | grep sum

declare -ix sum="450"  <==果然出現了！包括有 i 與 x 的宣告！

範例三：讓 sum 變成唯讀屬性，不可更動！

[root@www ~]# declare -r sum

[root@www ~]# sum=tesgting

-bash: sum: readonly variable  <==老天爺∼不能改這個變數了！

範例四：讓 sum 變成非環境變數的自訂變數吧！

[root@www ~]# declare +x sum  <== 將 - 變成 + 可以進行『取消』動作

[root@www ~]# declare -p sum  <== -p 可以單獨列出變數的類型

declare -ir sum="450" <== 看吧！只剩下 i, r 的類型，不具有 x 囉！

declare 也是個很有用的功能∼尤其是當我們需要使用到底下的陣列功能時， 他也可以幫我們宣告陣列的屬性喔！不過，老話一句，陣列也是在 shell script 比較常用的啦！ 比較有趣的是，如果你不小心將變數設定為『唯讀』，通常得要登出再登入才能復原該變數的類型了！ @_@

- 陣列 (array) 變數類型

某些時候，我們必須使用陣列來宣告一些變數，這有什麼好處啊？在一般人的使用上， 果然是看不出來有什麼好處的！不過，如果您曾經寫過程式的話，那才會比較瞭解陣列的意義∼ 陣列對寫數值程式的設計師來說，可是不能錯過學習的重點之一哩！好！不囉唆∼ 那麼要如何設定陣列的變數與內容呢？在 bash 裡頭，陣列的設定方式是：

var[index]=content

意思是說，我有一個陣列名稱為 var ，而這個陣列的內容為 var[1]=小明， var[2]=大明， var[3]=好明 .... 等等，那個 index 就是一些數字啦，重點是用中刮號 ([ ]) 來設定的。 目前我們 bash 提供的是一維陣列。老實說，如果您不必寫一些複雜的程式， 那麼這個陣列的地方，可以先略過，等到有需要再來學習即可！因為要製作出陣列， 通常與迴圈或者其他判斷式交互使用才有比較高的存在意義！

範例：設定上面提到的 var[1] ∼ var[3] 的變數。

[root@www ~]# var[1]="small min"

[root@www ~]# var[2]="big min"

[root@www ~]# var[3]="nice min"

[root@www ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"

small min, big min, nice min

陣列的變數類型比較有趣的地方在於『讀取』，一般來說，建議直接以 ${陣列} 的方式來讀取，比較正確無誤的啦！

與檔案系統及程序的限制關係： ulimit

想像一個狀況：我的 Linux 主機裡面同時登入了十個人，這十個人不知怎麼搞的， 同時開啟了 100 個檔案，每個檔案的大小約 10MBytes ，請問一下， 我的 Linux 主機的記憶體要有多大才夠？ 10*100*10 = 10000 MBytes = 10GBytes ... 老天爺，這樣，系統不掛點才有鬼哩！為了要預防這個情況的發生，所以我們的 bash 是可以『限制使用者的某些系統資源』的，包括可以開啟的檔案數量， 可以使用的 CPU 時間，可以使用的記憶體總量等等。如何設定？用 ulimit 吧！

[root@www ~]# ulimit [-SHacdfltu] [配額]

選項與參數：

-H  ：hard limit ，嚴格的設定，必定不能超過這個設定的數值；

-S  ：soft limit ，警告的設定，可以超過這個設定值，但是若超過則有警告訊息。

在設定上，通常 soft 會比 hard 小，舉例來說，soft 可設定為 80 而 hard

設定為 100，那麼你可以使用到 90 (因為沒有超過 100)，但介於 80~100 之間時，

系統會有警告訊息通知你！

-a  ：後面不接任何選項與參數，可列出所有的限制額度；

-c  ：當某些程式發生錯誤時，系統可能會將該程式在記憶體中的資訊寫成檔案(除錯用)，

這種檔案就被稱為核心檔案(core file)。此為限制每個核心檔案的最大容量。

-f  ：此 shell 可以建立的最大檔案容量(一般可能設定為 2GB)單位為 Kbytes

-d  ：程序可使用的最大斷裂記憶體(segment)容量；

-l  ：可用於鎖定 (lock) 的記憶體量

-t  ：可使用的最大 CPU 時間 (單位為秒)

-u  ：單一使用者可以使用的最大程序(process)數量。

範例一：列出你目前身份(假設為root)的所有限制資料數值

[root@www ~]# ulimit -a

core file size          (blocks, -c) 0          <==只要是 0 就代表沒限制

data seg size           (kbytes, -d) unlimited

scheduling priority             (-e) 0

file size               (blocks, -f) unlimited  <==可建立的單一檔案的大小

pending signals                 (-i) 11774

max locked memory       (kbytes, -l) 32

max memory size         (kbytes, -m) unlimited

open files                      (-n) 1024       <==同時可開啟的檔案數量

pipe size            (512 bytes, -p) 8

POSIX message queues     (bytes, -q) 819200

real-time priority              (-r) 0

stack size              (kbytes, -s) 10240

cpu time               (seconds, -t) unlimited

max user processes              (-u) 11774

virtual memory          (kbytes, -v) unlimited

file locks                      (-x) unlimited

範例二：限制使用者僅能建立 10MBytes 以下的容量的檔案

[root@www ~]# ulimit -f 10240

[root@www ~]# ulimit -a

file size               (blocks, -f) 10240 <==最大量為10240Kbyes，相當10Mbytes

[root@www ~]# dd if=/dev/zero of=123 bs=1M count=20

File size limit exceeded <==嘗試建立 20MB 的檔案，結果失敗了！

還記得我們在第八章 Linux 磁碟檔案系統裡面提到過，單一 filesystem 能夠支援的單一檔案大小與 block 的大小有關。例如 block size 為 1024 byte 時，單一檔案可達 16GB 的容量。但是，我們可以用 ulimit 來限制使用者可以建立的檔案大小喔！ 利用 ulimit -f 就可以來設定了！例如上面的範例二，要注意單位喔！單位是 Kbytes。 若改天你一直無法建立一個大容量的檔案，記得瞧一瞧 ulimit 的資訊喔！

Tips:

想要復原 ulimit 的設定最簡單的方法就是登出再登入，否則就是得要重新以 ulimit 設定才行！ 不過，要注意的是，一般身份使用者如果以 ulimit 設定了 -f 的檔案大小， 那麼他『只能繼續減小檔案容量，不能增加檔案容量喔！』另外，若想要管控使用者的 ulimit 限值， 可以參考第十四章的 pam 的介紹。

變數內容的刪除、取代與替換

變數除了可以直接設定來修改原本的內容之外，有沒有辦法透過簡單的動作來將變數的內容進行微調呢？ 舉例來說，進行變數內容的刪除、取代與替換等！是可以的！我們可以透過幾個簡單的小步驟來進行變數內容的微調喔！ 底下就來試試看！

- 變數內容的刪除與取代

變數的內容可以很簡單的透過幾個咚咚來進行刪除喔！我們使用 PATH 這個變數的內容來做測試好了。 請你依序進行底下的幾個例子來玩玩，比較容易感受的到鳥哥在這裡想要表達的意義：

範例一：先讓小寫的 path 自訂變數設定的與 PATH 內容相同

[root@www ~]# path=${PATH}

[root@www ~]# echo $path

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

/usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

範例二：假設我不喜歡 kerberos，所以要將前兩個目錄刪除掉，如何顯示？

[root@www ~]# echo ${path#/*kerberos/bin:}

/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

上面這個範例很有趣的！他的重點可以用底下這張表格來說明：

${variable#/*kerberos/bin:}

上面的特殊字體部分是關鍵字！用在這種刪除模式所必須存在的

${variable#/*kerberos/bin:}

這就是原本的變數名稱，以上面範例二來說，這裡就填寫 path 這個『變數名稱』啦！

${variable#/*kerberos/bin:}

這是重點！代表『從變數內容的最前面開始向右刪除』，且僅刪除最短的那個

${variable#/*kerberos/bin:}

代表要被刪除的部分，由於 # 代表由前面開始刪除，所以這裡便由開始的 / 寫起。

需要注意的是，我們還可以透過萬用字元 * 來取代 0 到無窮多個任意字元

以上面範例二的結果來看， path 這個變數被刪除的內容如下所示：

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

/usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

很有趣吧！這樣瞭解了 # 的功能了嗎？接下來讓我們來看看底下的範例三！

範例三：我想要刪除前面所有的目錄，僅保留最後一個目錄

[root@www ~]# echo ${path#/*:}

/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:

/root/bin     <==這兩行其實是同一行啦！

# 由於一個 # 僅刪除掉最短的那個，因此他刪除的情況可以用底下的刪除線來看：

# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

# /usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

[root@www ~]# echo ${path##/*:}

/root/bin

# 嘿！多加了一個 # 變成 ## 之後，他變成『刪除掉最長的那個資料』！亦即是：

# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

# /usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

非常有趣！不是嗎？因為在 PATH 這個變數的內容中，每個目錄都是以冒號『:』隔開的， 所以要從頭刪除掉目錄就是介於斜線 (/) 到冒號 (:) 之間的資料！但是 PATH 中不止一個冒號 (:) 啊！ 所以 # 與 ## 就分別代表：

- # ：符合取代文字的『最短的』那一個；

- ##：符合取代文字的『最長的』那一個

上面談到的是『從前面開始刪除變數內容』，那麼如果想要『從後面向前刪除變數內容』呢？ 這個時候就得使用百分比 (%) 符號了！來看看範例四怎麼做吧！

範例四：我想要刪除最後面那個目錄，亦即從 : 到 bin 為止的字串

[root@www ~]# echo ${path%:*bin}

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

/usr/sbin:/usr/bin  <==注意啊！最後面一個目錄不見去！

# 這個 % 符號代表由最後面開始向前刪除！所以上面得到的結果其實是來自如下：

# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

# /usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

範例五：那如果我只想要保留第一個目錄呢？

[root@www ~]# echo ${path%%:*bin}

/usr/kerberos/sbin

# 同樣的， %% 代表的則是最長的符合字串，所以結果其實是來自如下：

# /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

# /usr/sbin:/usr/bin:/root/bin  <==這兩行其實是同一行啦！

由於我是想要由變數內容的後面向前面刪除，而我這個變數內容最後面的結尾是『/root/bin』， 所以你可以看到上面我刪除的資料最終一定是『bin』，亦即是『:*bin』那個 * 代表萬用字元！ 至於 % 與 %% 的意義其實與 # 及 ## 類似！這樣理解否？

例題：

假設你是 root ，那你的 MAIL 變數應該是 /var/spool/mail/root 。假設你只想要保留最後面那個檔名 (root)， 前面的目錄名稱都不要了，如何利用 $MAIL 變數來達成？

答：

題意其實是這樣『/var/spool/mail/root』，亦即刪除掉兩條斜線間的所有資料(最長符合)。 這個時候你就可以這樣做即可：

[root@www ~]# echo ${MAIL##/*/}

相反的，如果你只想要拿掉檔名，保留目錄的名稱，亦即是『/var/spool/mail/root』 (最短符合)。但假設你並不知道結尾的字母為何，此時你可以利用萬用字元來處理即可，如下所示：

[root@www ~]# echo ${MAIL%/*}

瞭解了刪除功能後，接下來談談取代吧！繼續玩玩範例六囉！

範例六：將 path 的變數內容內的 sbin 取代成大寫 SBIN：

[root@www ~]# echo ${path/sbin/SBIN}

/usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:

/usr/sbin:/usr/bin:/root/bin

# 這個部分就容易理解的多了！關鍵字在於那兩個斜線，兩斜線中間的是舊字串

# 後面的是新字串，所以結果就會出現如上述的特殊字體部分囉！

[root@www ~]# echo ${path//sbin/SBIN}

/usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/SBIN:/usr/local/bin:/SBIN:/bin:

/usr/SBIN:/usr/bin:/root/bin

# 如果是兩條斜線，那麼就變成所有符合的內容都會被取代喔！

我們將這部份作個總結說明一下：

變數設定方式

說明

${變數#關鍵字}

${變數##關鍵字}

若變數內容從頭開始的資料符合『關鍵字』，則將符合的最短資料刪除

若變數內容從頭開始的資料符合『關鍵字』，則將符合的最長資料刪除

${變數%關鍵字}

${變數%%關鍵字}

若變數內容從尾向前的資料符合『關鍵字』，則將符合的最短資料刪除

若變數內容從尾向前的資料符合『關鍵字』，則將符合的最長資料刪除

${變數/舊字串/新字串}

${變數//舊字串/新字串}

若變數內容符合『舊字串』則『第一個舊字串會被新字串取代』

若變數內容符合『舊字串』則『全部的舊字串會被新字串取代』

- 變數的測試與內容替換

在某些時刻我們常常需要『判斷』某個變數是否存在，若變數存在則使用既有的設定，若變數不存在則給予一個常用的設定。 我們舉底下的例子來說明好了，看看能不能較容易被你所理解呢！

範例一：測試一下是否存在 username 這個變數，若不存在則給予 username 內容為 root

[root@www ~]# echo $username

<==由於出現空白，所以 username 可能不存在，也可能是空字串

[root@www ~]# username=${username-root}

[root@www ~]# echo $username

root       <==因為 username 沒有設定，所以主動給予名為 root 的內容。

[root@www ~]# username="vbird tsai" <==主動設定 username 的內容

[root@www ~]# username=${username-root}

[root@www ~]# echo $username

vbird tsai <==因為 username 已經設定了，所以使用舊有的設定而不以 root 取代

在上面的範例中，重點在於減號『 - 』後面接的關鍵字！基本上你可以這樣理解：

new_var=${old_var-content}

新的變數，主要用來取代舊變數。新舊變數名稱其實常常是一樣的

new_var=${old_var-content}

這是本範例中的關鍵字部分！必須要存在的哩！

new_var=${old_var-content}

舊的變數，被測試的項目！

new_var=${old_var-content}

變數的『內容』，在本範例中，這個部分是在『給予未設定變數的內容』

不過這還是有點問題！因為 username 可能已經被設定為『空字串』了！果真如此的話，那你還可以使用底下的範例來給予 username 的內容成為 root 喔！

範例二：若 username 未設定或為空字串，則將 username 內容設定為 root

[root@www ~]# username=""

[root@www ~]# username=${username-root}

[root@www ~]# echo $username

<==因為 username 被設定為空字串了！所以當然還是保留為空字串！

[root@www ~]# username=${username:-root}

[root@www ~]# echo $username

root  <==加上『 : 』後若變數內容為空或者是未設定，都能夠以後面的內容替換！

在大括號內有沒有冒號『 : 』的差別是很大的！加上冒號後，被測試的變數未被設定或者是已被設定為空字串時， 都能夠用後面的內容 (本例中是使用 root 為內容) 來替換與設定！這樣可以瞭解了嗎？除了這樣的測試之外， 還有其他的測試方法喔！鳥哥將他整理如下：

Tips:

底下的例子當中，那個 var 與 str 為變數，我們想要針對 str 是否有設定來決定 var 的值喔！ 一般來說， str: 代表『str 沒設定或為空的字串時』；至於 str 則僅為『沒有該變數』。

變數設定方式

str 沒有設定

str 為空字串

str 已設定非為空字串

var=${str-expr}

var=expr

var=

var=$str

var=${str:-expr}

var=expr

var=expr

var=$str

var=${str+expr}

var=

var=expr

var=expr

var=${str:+expr}

var=

var=

var=expr

var=${str=expr}

str=expr

var=expr

str 不變

var=

str 不變

var=$str

var=${str:=expr}

str=expr

var=expr

str=expr

var=expr

str 不變

var=$str

var=${str?expr}

expr 輸出至 stderr

var=

var=$str

var=${str:?expr}

expr 輸出至 stderr

expr 輸出至 stderr

var=$str

根據上面這張表，我們來進行幾個範例的練習吧！ ^_^！首先讓我們來測試一下，如果舊變數 (str) 不存在時， 我們要給予新變數一個內容，若舊變數存在則新變數內容以舊變數來替換，結果如下：

測試：先假設 str 不存在 (用 unset) ，然後測試一下減號 (-) 的用法：

[root@www ~]# unset str; var=${str-newvar}

[root@www ~]# echo var="$var", str="$str"

var=newvar, str=        <==因為 str 不存在，所以 var 為 newvar

測試：若 str 已存在，測試一下 var 會變怎樣？：

[root@www ~]# str="oldvar"; var=${str-newvar}

[root@www ~]# echo var="$var", str="$str"

var=oldvar, str=oldvar  <==因為 str 存在，所以 var 等於 str 的內容

關於減號 (-) 其實上面我們談過了！這裡的測試只是要讓你更加瞭解，這個減號的測試並不會影響到舊變數的內容。 如果你想要將舊變數內容也一起替換掉的話，那麼就使用等號 (=) 吧！

測試：先假設 str 不存在 (用 unset) ，然後測試一下等號 (=) 的用法：

[root@www ~]# unset str; var=${str=newvar}

[root@www ~]# echo var="$var", str="$str"

var=newvar, str=newvar  <==因為 str 不存在，所以 var/str 均為 newvar

測試：如果 str 已存在了，測試一下 var 會變怎樣？

[root@www ~]# str="oldvar"; var=${str=newvar}

[root@www ~]# echo var="$var", str="$str"

var=oldvar, str=oldvar  <==因為 str 存在，所以 var 等於 str 的內容

那如果我只是想知道，如果舊變數不存在時，整個測試就告知我『有錯誤』，此時就能夠使用問號『 ? 』的幫忙啦！ 底下這個測試練習一下先！

測試：若 str 不存在時，則 var 的測試結果直接顯示 "無此變數"

[root@www ~]# unset str; var=${str?無此變數}

-bash: str: 無此變數    <==因為 str 不存在，所以輸出錯誤訊息

測試：若 str 存在時，則 var 的內容會與 str 相同！

[root@www ~]# str="oldvar"; var=${str?novar}

[root@www ~]# echo var="$var", str="$str"

var=oldvar, str=oldvar  <==因為 str 存在，所以 var 等於 str 的內容

基本上這種變數的測試也能夠透過 shell script 內的 if...then... 來處理， 不過既然 bash 有提供這麼簡單的方法來測試變數，那我們也可以多學一些嘛！ 不過這種變數測試通常是在程式設計當中比較容易出現，如果這裡看不懂就先略過，未來有用到判斷變數值時，再回來看看吧！ ^_^

命令別名與歷史命令：

我們知道在早期的 DOS 年代，清除螢幕上的資訊可以使用 cls 來清除，但是在 Linux 裡面， 我們則是使用 clear 來清除畫面的。那麼可否讓 cls 等於 clear 呢？可以啊！用啥方法？ link file 還是什麼的？別急！底下我們介紹不用 link file 的命令別名來達成。那麼什麼又是歷史命令？ 曾經做過的舉動我們可以將他記錄下來喔！那就是歷史命令囉∼底下分別來談一談這兩個玩意兒。

命令別名設定： alias, unalias

命令別名是一個很有趣的東西，特別是你的慣用指令特別長的時候！還有， 增設預設的選項在一些慣用的指令上面，可以預防一些不小心誤殺檔案的情況發生的時候！ 舉個例子來說，如果你要查詢隱藏檔，並且需要長的列出與一頁一頁翻看，那麼需要下達『 ls -al | more 』這個指令，我是覺得很煩啦！ 要輸入好幾個單字！那可不可以使用 lm 來簡化呢？當然可以，你可以在命令列下面下達：

[root@www ~]# alias lm='ls -al | more'

立刻多出了一個可以執行的指令喔！這個指令名稱為 lm ，且其實他是執行 ls -al | more 啊！真是方便。不過， 要注意的是：『alias 的定義規則與變數定義規則幾乎相同』， 所以你只要在 alias 後面加上你的 {『別名』='指令 選項...' }， 以後你只要輸入 lm 就相當於輸入了 ls -al|more 這一串指令！很方便吧！

另外，命令別名的設定還可以取代既有的指令喔！舉例來說，我們知道 root 可以移除 (rm) 任何資料！所以當你以 root 的身份在進行工作時，需要特別小心， 但是總有失手的時候，那麼 rm 提供了一個選項來讓我們確認是否要移除該檔案，那就是 -i 這個選項！所以，你可以這樣做：

[root@www ~]# alias rm='rm -i'

那麼以後使用 rm 的時候，就不用太擔心會有錯誤刪除的情況了！這也是命令別名的優點囉！ 那麼如何知道目前有哪些的命令別名呢？就使用 alias 呀！

[root@www ~]# alias

alias cp='cp -i'

alias l.='ls -d .* --color=tty'

alias ll='ls -l --color=tty'

alias lm='ls -l | more'

alias ls='ls --color=tty'

alias mv='mv -i'

alias rm='rm -i'

alias which='alias | /usr/bin/which --tty-only --show-dot --show-tilde'

由上面的資料當中，你也會發現一件事情啊，我們在第十章的 vim 程式編輯器裡面提到 vi 與 vim 是不太一樣的，vim 可以多作一些額外的語法檢驗與顏色顯示，預設的 root 是單純使用 vi 而已。 如果你想要使用 vi 就直接以 vim 來開啟檔案的話，使用『 alias vi='vim' 』這個設定即可。 至於如果要取消命令別名的話，那麼就使用 unalias 吧！例如要將剛剛的 lm 命令別名拿掉，就使用：

[root@www ~]# unalias lm

那麼命令別名與變數有什麼不同呢？命令別名是『新創一個新的指令， 你可以直接下達該指令』的，至於變數則需要使用類似『 echo 』指令才能夠呼叫出變數的內容！ 這兩者當然不一樣！很多初學者在這裡老是搞不清楚！要注意啊！ ^_^

例題：

DOS 年代，列出目錄與檔案就是 dir ，而清除螢幕就是 cls ，那麼如果我想要在 linux 裡面也使用相同的指令呢？

答：

很簡單，透過 clear 與 ls 來進行命令別名的建置：

alias cls='clear'

alias dir='ls -l'

歷史命令：history

前面我們提過 bash 有提供指令歷史的服務！那麼如何查詢我們曾經下達過的指令呢？就使用 history 囉！當然，如果覺得 histsory 要輸入的字元太多太麻煩，可以使用命令別名來設定呢！ 不要跟我說還不會設定呦！ ^_^

[root@www ~]# alias h='history'

如此則輸入 h 等於輸入 history 囉！好了，我們來談一談 history 的用法吧！

[root@www ~]# history [n]

[root@www ~]# history [-c]

[root@www ~]# history [-raw] histfiles

選項與參數：

n   ：數字，意思是『要列出最近的 n 筆命令列表』的意思！

-c  ：將目前的 shell 中的所有 history 內容全部消除

-a  ：將目前新增的 history 指令新增入 histfiles 中，若沒有加 histfiles ，

則預設寫入 ~/.bash_history

-r  ：將 histfiles 的內容讀到目前這個 shell 的 history 記憶中；

-w  ：將目前的 history 記憶內容寫入 histfiles 中！

範例一：列出目前記憶體內的所有 history 記憶

[root@www ~]# history

# 前面省略

1017  man bash

1018  ll

1019  history

1020  history

# 列出的資訊當中，共分兩欄，第一欄為該指令在這個 shell 當中的代碼，

# 另一個則是指令本身的內容喔！至於會秀出幾筆指令記錄，則與 HISTSIZE 有關！

範例二：列出目前最近的 3 筆資料

[root@www ~]# history 3

1019  history

1020  history

1021  history 3

範例三：立刻將目前的資料寫入 histfile 當中

[root@www ~]# history -w

# 在預設的情況下，會將歷史紀錄寫入 ~/.bash_history 當中！

[root@www ~]# echo $HISTSIZE

1000

在正常的情況下，歷史命令的讀取與記錄是這樣的：

- 當我們以 bash 登入 Linux 主機之後，系統會主動的由家目錄的 ~/.bash_history 讀取以前曾經下過的指令，那麼 ~/.bash_history 會記錄幾筆資料呢？這就與你 bash 的 HISTFILESIZE 這個變數設定值有關了！

- 假設我這次登入主機後，共下達過 100 次指令，『等我登出時， 系統就會將 101~1100 這總共 1000 筆歷史命令更新到 ~/.bash_history 當中。』 也就是說，歷史命令在我登出時，會將最近的 HISTFILESIZE 筆記錄到我的紀錄檔當中啦！

- 當然，也可以用 history -w 強制立刻寫入的！那為何用『更新』兩個字呢？ 因為 ~/.bash_history 記錄的筆數永遠都是 HISTFILESIZE 那麼多，舊的訊息會被主動的拿掉！ 僅保留最新的！

那麼 history 這個歷史命令只可以讓我查詢命令而已嗎？呵呵！當然不止啊！ 我們可以利用相關的功能來幫我們執行命令呢！舉例來說囉：

[root@www ~]# !number

[root@www ~]# !command

[root@www ~]# !!

選項與參數：

number  ：執行第幾筆指令的意思；

command ：由最近的指令向前搜尋『指令串開頭為 command』的那個指令，並執行；

!!      ：就是執行上一個指令(相當於按↑按鍵後，按 Enter)

[root@www ~]# history

66  man rm

67  alias

68  man history

69  history

[root@www ~]# !66  <==執行第 66 筆指令

[root@www ~]# !!   <==執行上一個指令，本例中亦即 !66

[root@www ~]# !al  <==執行最近以 al 為開頭的指令(上頭列出的第 67 個)

經過上面的介紹，瞭乎？歷史命令用法可多了！如果我想要執行上一個指令， 除了使用上下鍵之外，我可以直接以『 !! 』 來下達上個指令的內容，此外， 我也可以直接選擇下達第 n 個指令，『 !n 』來執行，也可以使用指令標頭，例如 『 !vi 』來執行最近指令開頭是 vi 的指令列！相當的方便而好用！

基本上 history 的用途很大的！但是需要小心安全的問題！尤其是 root 的歷史紀錄檔案，這是 Cracker 的最愛！因為不小心的 root 會將很多的重要資料在執行的過程中會被紀錄在 ~/.bash_history 當中，如果這個檔案被解析的話，後果不堪吶！無論如何，使用 history 配合『 ! 』曾經使用過的指令下達是很有效率的一個指令下達方法！

- 同一帳號同時多次登入的 history 寫入問題

有些朋友在練習 linux 的時候喜歡同時開好幾個 bash 介面，這些 bash 的身份都是 root 。 這樣會有 ~/.bash_history 的寫入問題嗎？想一想，因為這些 bash 在同時以 root 的身份登入， 因此所有的 bash 都有自己的 1000 筆記錄在記憶體中。因為等到登出時才會更新記錄檔，所以囉， 最後登出的那個 bash 才會是最後寫入的資料。唔！如此一來其他 bash 的指令操作就不會被記錄下來了 (其實有被記錄，只是被後來的最後一個 bash 所覆蓋更新了) 。

由於多重登入有這樣的問題，所以很多朋友都習慣單一 bash 登入，再用工作控制 (job control, 第四篇會介紹) 來切換不同工作！ 這樣才能夠將所有曾經下達過的指令記錄下來，也才方便未來系統管理員進行指令的 debug 啊！

- 無法記錄時間

歷史命令還有一個問題，那就是無法記錄指令下達的時間。由於這 1000 筆歷史命令是依序記錄的， 但是並沒有記錄時間，所以在查詢方面會有一些不方便。如果讀者們有興趣，其實可以透過 ~/.bash_logout 來進行 history 的記錄，並加上 date 來增加時間參數，也是一個可以應用的方向喔！ 有興趣的朋友可以先看看情境模擬題一吧！

Bash Shell 的操作環境：

是否記得我們登入主機的時候，螢幕上頭會有一些說明文字，告知我們的 Linux 版本啊什麼的， 還有，登入的時候我們還可以給予使用者一些訊息或者歡迎文字呢。此外， 我們習慣的環境變數、命令別名等等的，是否可以登入就主動的幫我設定好？ 這些都是需要注意的。另外，這些設定值又可以分為系統整體設定值與各人喜好設定值， 僅是一些檔案放置的地點不同啦！這我們後面也會來談一談的！

路徑與指令搜尋順序

我們在第六章與第七章都曾談過『相對路徑與絕對路徑』的關係， 在本章的前幾小節也談到了 alias 與 bash 的內建命令。現在我們知道系統裡面其實有不少的 ls 指令， 或者是包括內建的 echo 指令，那麼來想一想，如果一個指令 (例如 ls) 被下達時， 到底是哪一個 ls 被拿來運作？很有趣吧！基本上，指令運作的順序可以這樣看：

1. 以相對/絕對路徑執行指令，例如『 /bin/ls 』或『 ./ls 』；

2. 由 alias 找到該指令來執行；

3. 由 bash 內建的 (builtin) 指令來執行；

4. 透過 $PATH 這個變數的順序搜尋到的第一個指令來執行。

舉例來說，你可以下達 /bin/ls 及單純的 ls 看看，會發現使用 ls 有顏色但是 /bin/ls 則沒有顏色。 因為 /bin/ls 是直接取用該指令來下達，而 ls 會因為『 alias ls='ls --color=tty' 』這個命令別名而先使用！ 如果想要瞭解指令搜尋的順序，其實透過 type -a ls 也可以查詢的到啦！上述的順序最好先瞭解喔！

例題：

設定 echo 的命令別名成為 echo -n ，然後再觀察 echo 執行的順序

答：

[root@www ~]# alias echo='echo -n'

[root@www ~]# type -a echo

echo is aliased to `echo -n'

echo is a shell builtin

echo is /bin/echo

瞧！很清楚吧！先 alias 再 builtin 再由 $PATH 找到 /bin/echo 囉！

bash 的進站與歡迎訊息： /etc/issue, /etc/motd

蝦密！ bash 也有進站畫面與歡迎訊息喔？真假？真的啊！ 還記得在終端機介面 (tty1 ~ tty6) 登入的時候，會有幾行提示的字串嗎？那就是進站畫面啊！ 那個字串寫在哪裡啊？呵呵！在 /etc/issue 裡面啊！先來看看：

[root@www ~]# cat /etc/issue

CentOS release 5.3 (Final)

Kernel \r on an \m

鳥哥是以完全未更新過的 CentOS 5.3 作為範例，裡面預設有三行，較有趣的地方在於 \r 與 \m。 就如同 $PS1 這變數一樣，issue 這個檔案的內容也是可以使用反斜線作為變數取用喔！你可以 man issue 配合 man mingetty 得到底下的結果：

issue 內的各代碼意義

\d 本地端時間的日期；

\l 顯示第幾個終端機介面；

\m 顯示硬體的等級 (i386/i486/i586/i686...)；

\n 顯示主機的網路名稱；

\o 顯示 domain name；

\r 作業系統的版本 (相當於 uname -r)

\t 顯示本地端時間的時間；

\s 作業系統的名稱；

\v 作業系統的版本。

做一下底下這個練習，看看能不能取得你要的進站畫面？

例題：

如果你在 tty3 的進站畫面看到如下顯示，該如何設定才能得到如下畫面？

CentOS release 5.3 (Final) (terminal: tty3)

Date: 2009-02-05 17:29:19

Kernel 2.6.18-128.el5 on an i686

Welcome!

注意，tty3 在不同的 tty 有不同顯示，日期則是再按下 [enter] 後就會所有不同。

答：

很簡單，參考上述的反斜線功能去修改 /etc/issue 成為如下模樣即可(共五行)：

CentOS release 5.3 (Final) (terminal: \l)

Date: \d \t

Kernel \r on an \m

Welcome!

曾有鳥哥的學生在這個 /etc/issue 內修改資料，光是利用簡單的英文字母作出屬於他自己的進站畫面， 畫面裡面有他的中文名字呢！非常厲害！也有學生做成類似很大一個『囧』在進站畫面，都非常有趣！

你要注意的是，除了 /etc/issue 之外還有個 /etc/issue.net 呢！這是啥？這個是提供給 telnet 這個遠端登入程式用的。 當我們使用 telnet 連接到主機時，主機的登入畫面就會顯示 /etc/issue.net 而不是 /etc/issue 呢！

至於如果您想要讓使用者登入後取得一些訊息，例如您想要讓大家都知道的訊息， 那麼可以將訊息加入 /etc/motd 裡面去！例如：當登入後，告訴登入者， 系統將會在某個固定時間進行維護工作，可以這樣做：

[root@www ~]# vi /etc/motd

Hello everyone,

Our server will be maintained at 2009/02/28 0:00 ~ 24:00.

Please don't login server at that time. ^_^

那麼當你的使用者(包括所有的一般帳號與 root)登入主機後，就會顯示這樣的訊息出來：

Last login: Thu Feb  5 22:35:47 2009 from 127.0.0.1

Hello everyone,

Our server will be maintained at 2009/02/28 0:00 ~ 24:00.

Please don't login server at that time. ^_^

bash 的環境設定檔

你是否會覺得奇怪，怎麼我們什麼動作都沒有進行，但是一進入 bash 就取得一堆有用的變數了？ 這是因為系統有一些環境設定檔案的存在，讓 bash 在啟動時直接讀取這些設定檔，以規劃好 bash 的操作環境啦！ 而這些設定檔又可以分為全體系統的設定檔以及使用者個人偏好設定檔。要注意的是， 我們前幾個小節談到的命令別名啦、自訂的變數啦，在你登出 bash 後就會失效，所以你想要保留你的設定， 就得要將這些設定寫入設定檔才行。底下就讓我們來聊聊吧！

- login 與 non-login shell

在開始介紹 bash 的設定檔前，我們一定要先知道的就是 login shell 與 non-login shell！ 重點在於有沒有登入 (login) 啦！

- login shell：取得 bash 時需要完整的登入流程的，就稱為 login shell。舉例來說，你要由 tty1 ~ tty6 登入，需要輸入使用者的帳號與密碼，此時取得的 bash 就稱為『 login shell 』囉；

- non-login shell：取得 bash 介面的方法不需要重複登入的舉動，舉例來說，(1)你以 X window 登入 Linux 後， 再以 X 的圖形化介面啟動終端機，此時那個終端介面並沒有需要再次的輸入帳號與密碼，那個 bash 的環境就稱為 non-login shell了。(2)你在原本的 bash 環境下再次下達 bash 這個指令，同樣的也沒有輸入帳號密碼， 那第二個 bash (子程序) 也是 non-login shell 。

為什麼要介紹 login, non-login shell 呢？這是因為這兩個取得 bash 的情況中，讀取的設定檔資料並不一樣所致。 由於我們需要登入系統，所以先談談 login shell 會讀取哪些設定檔？一般來說，login shell 其實只會讀取這兩個設定檔：

1. /etc/profile：這是系統整體的設定，你最好不要修改這個檔案；

2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile：屬於使用者個人設定，你要改自己的資料，就寫入這裡！

那麼，就讓我們來聊一聊這兩個檔案吧！這兩個檔案的內容可是非常繁複的喔！

- /etc/profile (login shell 才會讀)

你可以使用 vim 去閱讀一下這個檔案的內容。這個設定檔可以利用使用者的識別碼 (UID) 來決定很多重要的變數資料， 這也是每個使用者登入取得 bash 時一定會讀取的設定檔！ 所以如果你想要幫所有使用者設定整體環境，那就是改這裡囉！不過，沒事還是不要隨便改這個檔案喔 這個檔案設定的變數主要有：

- PATH：會依據 UID 決定 PATH 變數要不要含有 sbin 的系統指令目錄；

- MAIL：依據帳號設定好使用者的 mailbox 到 /var/spool/mail/帳號名；

- USER：根據使用者的帳號設定此一變數內容；

- HOSTNAME：依據主機的 hostname 指令決定此一變數內容；

- HISTSIZE：歷史命令記錄筆數。CentOS 5.x 設定為 1000 ；

/etc/profile 可不止會做這些事而已，他還會去呼叫外部的設定資料喔！在 CentOS 5.x 預設的情況下， 底下這些資料會依序的被呼叫進來：

- /etc/inputrc

其實這個檔案並沒有被執行啦！/etc/profile 會主動的判斷使用者有沒有自訂輸入的按鍵功能，如果沒有的話， /etc/profile 就會決定設定『INPUTRC=/etc/inputrc』這個變數！此一檔案內容為 bash 的熱鍵啦、[tab]要不要有聲音啦等等的資料！ 因為鳥哥覺得 bash 預設的環境已經很棒了，所以不建議修改這個檔案！

- /etc/profile.d/*.sh

其實這是個目錄內的眾多檔案！只要在 /etc/profile.d/ 這個目錄內且副檔名為 .sh ，另外，使用者能夠具有 r 的權限， 那麼該檔案就會被 /etc/profile 呼叫進來。在 CentOS 5.x 中，這個目錄底下的檔案規範了 bash 操作介面的顏色、 語系、ll 與 ls 指令的命令別名、vi 的命令別名、which 的命令別名等等。如果你需要幫所有使用者設定一些共用的命令別名時， 可以在這個目錄底下自行建立副檔名為 .sh 的檔案，並將所需要的資料寫入即可喔！

- /etc/sysconfig/i18n

這個檔案是由 /etc/profile.d/lang.sh 呼叫進來的！這也是我們決定 bash 預設使用何種語系的重要設定檔！ 檔案裡最重要的就是 LANG 這個變數的設定啦！我們在前面的 locale 討論過這個檔案囉！ 自行回去瞧瞧先！

反正你只要記得，bash 的 login shell 情況下所讀取的整體環境設定檔其實只有 /etc/profile，但是 /etc/profile 還會呼叫出其他的設定檔，所以讓我們的 bash 操作介面變的非常的友善啦！ 接下來，讓我們來瞧瞧，那麼個人偏好的設定檔又是怎麼回事？

- ~/.bash_profile (login shell 才會讀)

bash 在讀完了整體環境設定的 /etc/profile 並藉此呼叫其他設定檔後，接下來則是會讀取使用者的個人設定檔。 在 login shell 的 bash 環境中，所讀取的個人偏好設定檔其實主要有三個，依序分別是：

1. ~/.bash_profile

2. ~/.bash_login

3. ~/.profile

其實 bash 的 login shell 設定只會讀取上面三個檔案的其中一個， 而讀取的順序則是依照上面的順序。也就是說，如果 ~/.bash_profile 存在，那麼其他兩個檔案不論有無存在，都不會被讀取。 如果 ~/.bash_profile 不存在才會去讀取 ~/.bash_login，而前兩者都不存在才會讀取 ~/.profile 的意思。 會有這麼多的檔案，其實是因應其他 shell 轉換過來的使用者的習慣而已。 先讓我們來看一下 root 的 /root/.bash_profile 的內容是怎樣呢？

[root@www ~]# cat ~/.bash_profile

# .bash_profile

# Get the aliases and functions

if [ -f ~/.bashrc ]; then   <==底下這三行在判斷並讀取 ~/.bashrc

. ~/.bashrc

fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin        <==底下這幾行在處理個人化設定

export PATH

unset USERNAME

這個檔案內有設定 PATH 這個變數喔！而且還使用了 export 將 PATH 變成環境變數呢！ 由於 PATH 在 /etc/profile 當中已經設定過，所以在這裡就以累加的方式增加使用者家目錄下的 ~/bin/ 為額外的執行檔放置目錄。這也就是說，你可以將自己建立的執行檔放置到你自己家目錄下的 ~/bin/ 目錄啦！ 那就可以直接執行該執行檔而不需要使用絕對/相對路徑來執行該檔案。

這個檔案的內容比較有趣的地方在於 if ... then ... 那一段！那一段程式碼我們會在第十三章 shell script 談到，假設你現在是看不懂的。 該段的內容指的是『判斷家目錄下的 ~/.bashrc 存在否，若存在則讀入 ~/.bashrc 的設定』。 bash 設定檔的讀入方式比較有趣，主要是透過一個指令『 source 』來讀取的！ 也就是說 ~/.bash_profile 其實會再呼叫 ~/.bashrc 的設定內容喔！最後，我們來看看整個 login shell 的讀取流程：

圖 4.3.1、login shell 的設定檔讀取流程

實線的的方向是主線流程，虛線的方向則是被呼叫的設定檔！從上面我們也可以清楚的知道，在 CentOS 的 login shell 環境下，最終被讀取的設定檔是『 ~/.bashrc 』這個檔案喔！所以，你當然可以將自己的偏好設定寫入該檔案即可。 底下我們還要討論一下 source 與 ~/.bashrc 喔！

- source ：讀入環境設定檔的指令

由於 /etc/profile 與 ~/.bash_profile 都是在取得 login shell 的時候才會讀取的設定檔，所以， 如果你將自己的偏好設定寫入上述的檔案後，通常都是得登出再登入後，該設定才會生效。那麼，能不能直接讀取設定檔而不登出登入呢？ 可以的！那就得要利用 source 這個指令了！

[root@www ~]# source 設定檔檔名

範例：將家目錄的 ~/.bashrc 的設定讀入目前的 bash 環境中

[root@www ~]# source ~/.bashrc  <==底下這兩個指令是一樣的！

[root@www ~]#  .  ~/.bashrc

利用 source 或小數點 (.) 都可以將設定檔的內容讀進來目前的 shell 環境中！ 舉例來說，我修改了 ~/.bashrc ，那麼不需要登出，立即以 source ~/.bashrc 就可以將剛剛最新設定的內容讀進來目前的環境中！很不錯吧！還有，包括 ~/bash_profile 以及 /etc/profile 的設定中， 很多時候也都是利用到這個 source (或小數點) 的功能喔！

有沒有可能會使用到不同環境設定檔的時候？有啊！ 最常發生在一個人的工作環境分為多種情況的時候了！舉個例子來說，在鳥哥的大型主機中， 常常需要負責兩到三個不同的案子，每個案子所需要處理的環境變數訂定並不相同， 那麼鳥哥就將這兩三個案子分別編寫屬於該案子的環境變數設定檔案，當需要該環境時，就直接『 source 變數檔 』，如此一來，環境變數的設定就變的更簡便而靈活了！

- ~/.bashrc (non-login shell 會讀)

談完了 login shell 後，那麼 non-login shell 這種非登入情況取得 bash 操作介面的環境設定檔又是什麼？ 當你取得 non-login shell 時，該 bash 設定檔僅會讀取 ~/.bashrc 而已啦！那麼預設的 ~/.bashrc 內容是如何？

[root@www ~]# cat ~/.bashrc

# .bashrc

# User specific aliases and functions

alias rm='rm -i'             <==使用者的個人設定

alias cp='cp -i'

alias mv='mv -i'

# Source global definitions

if [ -f /etc/bashrc ]; then  <==整體的環境設定

. /etc/bashrc

fi

特別注意一下，由於 root 的身份與一般使用者不同，鳥哥是以 root 的身份取得上述的資料， 如果是一般使用者的 ~/.bashrc 會有些許不同。看一下，你會發現在 root 的 ~/.bashrc 中其實已經規範了較為保險的命令別名了。 此外，咱們的 CentOS 5.x 還會主動的呼叫 /etc/bashrc 這個檔案喔！為什麼需要呼叫 /etc/bashrc 呢？ 因為 /etc/bashrc 幫我們的 bash 定義出底下的資料：

第十二章、正規表示法與文件格式化處理

切換解析度為 800x600

最近更新日期：2009/08/26

正規表示法 (Regular Expression, RE, 或稱為常規表示法)是透過一些特殊字元的排列，用以『搜尋/取代/刪除』一列或多列文字字串， 簡單的說，正規表示法就是用在字串的處理上面的一項『表示式』。正規表示法並不是一個工具程式， 而是一個字串處理的標準依據，如果您想要以正規表示法的方式處理字串，就得要使用支援正規表示法的工具程式才行， 這類的工具程式很多，例如 vi, sed, awk 等等。

正規表示法對於系統管理員來說實在是很重要！因為系統會產生很多的訊息，這些訊息有的重要有的僅是告知， 此時，管理員可以透過正規表示法的功能來將重要訊息擷取出來，並產生便於查閱的報表來簡化管理流程。此外， 很多的套裝軟體也都支援正規表示法的分析，例如郵件伺服器的過濾機制(過濾垃圾信件)就是很重要的一個例子。 所以，您最好要瞭解正規表示法的相關技能，在未來管理主機時，才能夠更精簡處理您的日常事務！

註：本章節使用者需要多加練習，因為目前很多的套件都是使用正規表示法來達成其『過濾、分析』的目的， 為了未來主機管理的便利性，使用者至少要能看的懂正規表示法的意義！

1. 前言： 什麼是正規表示法

1.1 什麼是正規表示法

1.2 正規表示法對於系統管理員的用途

1.3 正規表示法的廣泛用途

1.4 正規表示法與 Shell 在 Linux 當中的角色定位

1.5 延伸的正規表示法

2. 基礎正規表示法

2.1 語系對正規表示法的影響

2.2 grep 的一些進階選項

2.3 基礎正規表示法練習

2.4 基礎正規表示法字符彙整(characters)

2.5 sed 工具： 行的新增/刪除, 行的取代/顯示, 搜尋並取代, 直接改檔

3. 延伸正規表示法

4. 文件的格式化與相關處理

4.1 printf： 格式化列印

4.2 awk：好用的資料處理工具

4.3 檔案比對工具：, diff, cmp, patch

4.4 檔案列印準備工具： pr

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23885

前言：什麼是正規表示法

約略瞭解了 Linux 的基本指令 (BASH) 並且熟悉了 vim 之後，相信你對於敲擊鍵盤的打字與指令下達比較不陌生了吧？ 接下來，底下要開始介紹一個很重要的觀念，那就是所謂的『正規表示法 (Regular Expression)』囉！

什麼是正規表示法

任何一個有經驗的系統管理員，都會告訴你：『正規表示法真是挺重要的！』 為什麼很重要呢？因為日常生活就使用的到啊！舉個例子來說， 在你日常使用 vim 作文書處理或程式撰寫時使用到的『搜尋/取代』等等的功能， 這些舉動要作的漂亮，就得要配合正規表示法來處理囉！

簡單的說，正規表示法就是處理字串的方法，他是以行為單位來進行字串的處理行為， 正規表示法透過一些特殊符號的輔助，可以讓使用者輕易的達到『搜尋/刪除/取代』某特定字串的處理程序！

舉例來說，我只想找到 VBird(前面兩個大寫字元) 或 Vbird(僅有一個大寫字元) 這個字樣，但是不要其他的字串 (例如 VBIRD, vbird 等不需要)，該如何辦理？如果在沒有正規表示法的環境中(例如 MS word)，你或許就得要使用忽略大小寫的辦法， 或者是分別以 VBird 及 Vbird 搜尋兩遍。但是，忽略大小寫可能會搜尋到 VBIRD/vbird/VbIrD 等等的不需要的字串而造成困擾。

再舉個系統常見的例子好了，假設妳發現系統在開機的時候，老是會出現一個關於 mail 程式的錯誤， 而開機過程的相關程序都是在 /etc/init.d/ 底下，也就是說，在該目錄底下的某個檔案內具有 mail 這個關鍵字，你想要將該檔案捉出來進行查詢修改的動作。此時你怎麼找出來含有這個關鍵字的檔案？ 你當然可以一個檔案一個檔案的開啟，然後去搜尋 mail 這個關鍵字，只是.....該目錄底下的檔案可能不止 100 個說∼ 如果瞭解正規表示法的相關技巧，那麼只要一行指令就找出來啦：『grep 'mail' /etc/init.d/*』 那個 grep 就是支援正規表示法的工具程式之一！如何∼很簡單吧！

談到這裡就得要進一步說明了，正規表示法基本上是一種『表示法』， 只要工具程式支援這種表示法，那麼該工具程式就可以用來作為正規表示法的字串處理之用。 例如 vi, grep, awk ,sed 等等工具，因為她們有支援正規表示法， 所以，這些工具就可以使用正規表示法的特殊字元來進行字串的處理。但例如 cp, ls 等指令並未支援正規表示法， 所以就只能使用 bash 自己本身的萬用字元而已。

正規表示法對於系統管理員的用途

那麼為何我需要學習正規表示法呢？對於一般使用者來說，由於使用到正規表示法的機會可能不怎麼多， 因此感受不到他的魅力，不過，對於身為系統管理員的你來說，正規表示法則是一個『不可不學的好東西！』 怎麼說呢？由於系統如果在繁忙的情況之下，每天產生的訊息資訊會多到你無法想像的地步， 而我們也都知道，系統的『錯誤訊息登錄檔案 (第十九章)』 的內容記載了系統產生的所有訊息，當然，這包含你的系統是否被『入侵』的記錄資料。

但是系統的資料量太大了，要身為系統管理員的你每天去看這麼多的訊息資料， 從千百行的資料裡面找出一行有問題的訊息，呵呵∼光是用肉眼去看，想不瘋掉都很難！ 這個時候，我們就可以透過『正規表示法』的功能，將這些登錄的資訊進行處理， 僅取出『有問題』的資訊來進行分析，哈哈！如此一來，你的系統管理工作將會 『快樂得不得了』啊！當然，正規表示法的優點還不止於此，等你有一定程度的瞭解之後，你會愛上他喔！

正規表示法的廣泛用途

正規表示法除了可以讓系統管理員管理主機更為便利之外，事實上，由於正規表示法強大的字串處理能力， 目前一堆軟體都支援正規表示法呢！最常見的就是『郵件伺服器』啦！

如果你留意網際網路上的消息，那麼應該不難發現，目前造成網路大塞車的主因之一就是『垃圾/廣告信件』了， 而如果我們可以在伺服器端，就將這些問題郵件剔除的話，用戶端就會減少很多不必要的頻寬耗損了。 那麼如何剔除廣告信件呢？由於廣告信件幾乎都有一定的標題或者是內容，因此， 只要每次有來信時，都先將來信的標題與內容進行特殊字串的比對，發現有不良信件就予以剔除！ 嘿！這個工作怎麼達到啊？就使用正規表示法啊！目前兩大郵件伺服器軟體 sendmail 與 postfix 以及支援郵件伺服器的相關分析軟體，都支援正規表示法的比對功能！

當然還不止於此啦，很多的伺服器軟體都支援正規表示法呢！當然， 雖然各家軟體都支援他，不過，這些『字串』的比對還是需要系統管理員來加入比對規則的， 所以啦！身為系統管理員的你，為了自身的工作以及用戶端的需求， 正規表示法實在是很需要也很值得學習的一項工具呢！

正規表示法與 Shell 在 Linux 當中的角色定位

說實在的，我們在學數學的時候，一個很重要、但是粉難的東西是一定要『背』的， 那就是九九乘法表，背成功了之後，未來在數學應用的路途上，真是一帆風順啊！ 這個九九乘法表我們在小學的時候幾乎背了一整年才背下來，並不是這麼好背的呢！ 但他卻是基礎當中的基礎！你現在一定受惠相當的多呢 ^_^！

而我們談到的這個正規表示法，與前一章的 BASH 就有點像是數學的九九乘法表一樣，是 Linux 基礎當中的基礎，雖然也是最難的部分， 不過，如果學成了之後，一定是『大大的有幫助』的！這就好像是金庸小說裡面的學武難關：任督二脈！ 打通任督二脈之後，武功立刻成倍成長！所以啦， 不論是對於系統的認識與系統的管理部分，他都有很棒的輔助啊！請好好的學習這個基礎吧！ ^_^

延伸的正規表示法

唔！正規表示法還有分喔？沒錯喔！正規表示法的字串表示方式依照不同的嚴謹度而分為： 基礎正規表示法與延伸正規表示法。延伸型正規表示法除了簡單的一組字串處理之外，還可以作群組的字串處理， 例如進行搜尋 VBird 或 netman 或 lman 的搜尋，注意，是『或(or)』而不是『和(and)』的處理， 此時就需要延伸正規表示法的幫助啦！藉由特殊的『 ( 』與『 | 』等字元的協助， 就能夠達到這樣的目的！不過，我們在這裡主力僅是介紹最基礎的基礎正規表示法而已啦！好啦！清清腦門，咱們用功去囉！

Tips:

有一點要向大家報告的，那就是：『正規表示法與萬用字元是完全不一樣的東西！』 這很重要喔！因為『萬用字元 (wildcard) 代表的是 bash 操作介面的一個功能』，但正規表示法則是一種字串處理的表示方式！ 這兩者要分的很清楚才行喔！所以，學習本章，請將前一章 bash 的萬用字元意義先忘掉吧！

老實說，鳥哥以前剛接觸正規表示法時，老想著要將這兩者歸納在一起，結果就是...錯誤認知一大堆∼ 所以才會建議您學習本章先忘記萬用字元再來學習吧！

基礎正規表示法

既然正規表示法是處理字串的一種表示方式，那麼對字元排序有影響的語系資料就會對正規表示法的結果有影響！ 此外，正規表示法也需要支援工具程式來輔助才行！所以，我們這裡就先介紹一個最簡單的字串擷取功能的工具程式，那就是 grep 囉！ 前一章已經介紹過 grep 的相關選項與參數，本章著重在較進階的 grep 選項說明囉！ 介紹完 grep 的功能之後，就進入正規表示法的特殊字符的處理能力了。

語系對正規表示法的影響

為什麼語系的資料會影響到正規表示法的輸出結果呢？我們在第零章計算機概論的文字編碼系統裡面談到，檔案其實記錄的僅有 0 與 1，我們看到的字元文字與數字都是透過編碼表轉換來的。由於不同語系的編碼資料並不相同，所以就會造成資料擷取結果的差異了。 舉例來說，在英文大小寫的編碼順序中，zh_TW.big5 及 C 這兩種語系的輸出結果分別如下：

- LANG=C     時：0 1 2 3 4 ... A B C D ... Z a b c d ...z

- LANG=zh_TW 時：0 1 2 3 4 ... a A b B c C d D ... z Z

上面的順序是編碼的順序，我們可以很清楚的發現這兩種語系明顯就是不一樣！如果你想要擷取大寫字元而使用 [A-Z] 時， 會發現 LANG=C 確實可以僅捉到大寫字元 (因為是連續的) ，但是如果 LANG=zh_TW.big5 時，就會發現到， 連同小寫的 b-z 也會被擷取出來！因為就編碼的順序來看， big5 語系可以擷取到『 A b B c C ... z Z 』這一堆字元哩！ 所以，使用正規表示法時，需要特別留意當時環境的語系為何， 否則可能會發現與別人不相同的擷取結果喔！

由於一般我們在練習正規表示法時，使用的是相容於 POSIX 的標準，因此就使用『 C 』這個語系(註1)！ 因此，底下的很多練習都是使用『 LANG=C 』這個語系資料來進行的喔！ 另外，為了要避免這樣編碼所造成的英文與數字的擷取問題，因此有些特殊的符號我們得要瞭解一下的！ 這些符號主要有底下這些意義：(註1)

特殊符號

代表意義

[:alnum:]

代表英文大小寫字元及數字，亦即 0-9, A-Z, a-z

[:alpha:]

代表任何英文大小寫字元，亦即 A-Z, a-z

[:blank:]

代表空白鍵與 [Tab] 按鍵兩者

[:cntrl:]

代表鍵盤上面的控制按鍵，亦即包括 CR, LF, Tab, Del.. 等等

[:digit:]

代表數字而已，亦即 0-9

[:graph:]

除了空白字元 (空白鍵與 [Tab] 按鍵) 外的其他所有按鍵

[:lower:]

代表小寫字元，亦即 a-z

[:print:]

代表任何可以被列印出來的字元

[:punct:]

代表標點符號 (punctuation symbol)，亦即：" ' ? ! ; : # $...

[:upper:]

代表大寫字元，亦即 A-Z

[:space:]

任何會產生空白的字元，包括空白鍵, [Tab], CR 等等

[:xdigit:]

代表 16 進位的數字類型，因此包括： 0-9, A-F, a-f 的數字與字元

尤其上表中的[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 這幾個一定要知道代表什麼意思，因為他要比 a-z 或 A-Z 的用途要確定的很！好了，底下就讓我們開始來玩玩進階版的 grep 吧！

grep 的一些進階選項

我們在第十一章 BASH 裡面的 grep 談論過一些基礎用法， 但其實 grep 還有不少的進階用法喔！底下我們僅列出較進階的 grep 選項與參數給大家參考， 基礎的 grep 用法請參考前一章的說明囉！

[root@www ~]# grep [-A] [-B] [--color=auto] '搜尋字串' filename

選項與參數：

-A ：後面可加數字，為 after 的意思，除了列出該行外，後續的 n 行也列出來；

-B ：後面可加數字，為 befer 的意思，除了列出該行外，前面的 n 行也列出來；

--color=auto 可將正確的那個擷取資料列出顏色

範例一：用 dmesg 列出核心訊息，再以 grep 找出內含 eth 那行

[root@www ~]# dmesg | grep 'eth'

eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10

eth0:  Identified 8139 chip type 'RTL-8139C'

eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1

eth0: no IPv6 routers present

# dmesg 可列出核心產生的訊息！透過 grep 來擷取網路卡相關資訊 (eth) ，

# 就可發現如上資訊。不過沒有行號與特殊顏色顯示！看看下個範例吧！

範例二：承上題，要將捉到的關鍵字顯色，且加上行號來表示：

[root@www ~]# dmesg | grep -n --color=auto 'eth'

247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10

248:eth0:  Identified 8139 chip type 'RTL-8139C'

294:eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1

305:eth0: no IPv6 routers present

# 你會發現除了 eth 會有特殊顏色來表示之外，最前面還有行號喔！

範例三：承上題，在關鍵字所在行的前兩行與後三行也一起捉出來顯示

[root@www ~]# dmesg | grep -n -A3 -B2 --color=auto 'eth'

245-PCI: setting IRQ 10 as level-triggered

246-ACPI: PCI Interrupt 0000:00:0e.0[A] -> Link [LNKB] ...

247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10

248:eth0:  Identified 8139 chip type 'RTL-8139C'

249-input: PC Speaker as /class/input/input2

250-ACPI: PCI Interrupt 0000:00:01.4[B] -> Link [LNKB] ...

251-hdb: ATAPI 48X DVD-ROM DVD-R-RAM CD-R/RW drive, 2048kB Cache, UDMA(66)

# 如上所示，你會發現關鍵字 247 所在的前兩行及 248 後三行也都被顯示出來！

# 這樣可以讓你將關鍵字前後資料捉出來進行分析啦！

grep 是一個很常見也很常用的指令，他最重要的功能就是進行字串資料的比對，然後將符合使用者需求的字串列印出來。 需要說明的是『grep 在資料中查尋一個字串時，是以 "整行" 為單位來進行資料的擷取的！』也就是說，假如一個檔案內有 10 行，其中有兩行具有你所搜尋的字串，則將那兩行顯示在螢幕上，其他的就丟棄了！

在關鍵字的顯示方面，grep 可以使用 --color=auto 來將關鍵字部分使用顏色顯示。 這可是個很不錯的功能啊！但是如果每次使用 grep 都得要自行加上 --color=auto 又顯的很麻煩∼ 此時那個好用的 alias 就得來處理一下啦！你可以在 ~/.bashrc 內加上這行：『alias grep='grep --color=auto'』再以『 source ~/.bashrc 』來立即生效即可喔！ 這樣每次執行 grep 他都會自動幫你加上顏色顯示啦！

基礎正規表示法練習

要瞭解正規表示法最簡單的方法就是由實際練習去感受啦！所以在彙整正規表示法特殊符號前， 我們先以底下這個檔案的內容來進行正規表示法的理解吧！先說明一下，底下的練習大前提是：

- 語系已經使用『 export LANG=C 』的設定值；

- grep 已經使用 alias 設定成為『 grep --color=auto 』

至於本章的練習用檔案請由底下的連結來下載。需要特別注意的是，底下這個檔案是鳥哥在 MS Windows 系統下編輯的， 並且已經特殊處理過，因此，他雖然是純文字檔，但是內含一些 Windows 系統下的軟體常常自行加入的一些特殊字元，例如斷行字元 (^M) 就是一例！ 所以，你可以直接將底下的文字以 vi 儲存成 regular_express.txt 這個檔案， 不過，還是比較建議直接點底下的連結：

http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

如果你的 Linux 可以直接連上 Internet 的話，那麼使用如下的指令來捉取即可：

wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

至於這個檔案的內容如下：

[root@www ~]# vi regular_express.txt

"Open Source" is a good mechanism to develop programs.

apple is my favorite food.

Football game is not use feet only.

this dress doesn't fit me.

However, this dress is about $ 3183 dollars.^M

GNU is free air not free beer.^M

Her hair is very beauty.^M

I can't finish the test.^M

Oh! The soup taste good.^M

motorcycle is cheap than car.

This window is clear.

the symbol '*' is represented as start.

Oh!     My god!

The gd software is a library for drafting programs.^M

You are the best is mean you are the no. 1.

The world <Happy> is the same with "glad".

I like dog.

google is the best tools for search keyword.

goooooogle yes!

go! go! Let's go.

# I am VBird

這檔案共有 22 行，最底下一行為空白行！現在開始我們一個案例一個案例的來介紹吧！

- 例題一、搜尋特定字串

搜尋特定字串很簡單吧？假設我們要從剛剛的檔案當中取得 the 這個特定字串，最簡單的方式就是這樣：

[root@www ~]# grep -n 'the' regular_express.txt

8:I can't finish the test.

12:the symbol '*' is represented as start.

15:You are the best is mean you are the no. 1.

16:The world <Happy> is the same with "glad".

18:google is the best tools for search keyword.

那如果想要『反向選擇』呢？也就是說，當該行沒有 'the' 這個字串時才顯示在螢幕上，那就直接使用：

[root@www ~]# grep -vn 'the' regular_express.txt

你會發現，螢幕上出現的行列為除了 8,12,15,16,18 五行之外的其他行列！ 接下來，如果你想要取得不論大小寫的 the 這個字串，則：

[root@www ~]# grep -in 'the' regular_express.txt

8:I can't finish the test.

9:Oh! The soup taste good.

12:the symbol '*' is represented as start.

14:The gd software is a library for drafting programs.

15:You are the best is mean you are the no. 1.

16:The world <Happy> is the same with "glad".

18:google is the best tools for search keyword.

除了多兩行 (9, 14行) 之外，第 16 行也多了一個 The 的關鍵字被擷取到喔！

- 例題二、利用中括號 [] 來搜尋集合字元

如果我想要搜尋 test 或 taste 這兩個單字時，可以發現到，其實她們有共通的 't?st' 存在∼這個時候，我可以這樣來搜尋：

[root@www ~]# grep -n 't[ae]st' regular_express.txt

8:I can't finish the test.

9:Oh! The soup taste good.

瞭解了吧？其實 [] 裡面不論有幾個字元，他都謹代表某『一個』字元， 所以，上面的例子說明了，我需要的字串是『tast』或『test』兩個字串而已！ 而如果想要搜尋到有 oo 的字元時，則使用：

[root@www ~]# grep -n 'oo' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

2:apple is my favorite food.

3:Football game is not use feet only.

9:Oh! The soup taste good.

18:google is the best tools for search keyword.

19:goooooogle yes!

但是，如果我不想要 oo 前面有 g 的話呢？此時，可以利用在集合字元的反向選擇 [^] 來達成：

[root@www ~]# grep -n '[^g]oo' regular_express.txt

2:apple is my favorite food.

3:Football game is not use feet only.

18:google is the best tools for search keyword.

19:goooooogle yes!

意思就是說，我需要的是 oo ，但是 oo 前面不能是 g 就是了！仔細比較上面兩個表格，妳會發現，第 1,9 行不見了，因為 oo 前面出現了 g 所致！第 2,3 行沒有疑問，因為 foo 與 Foo 均可被接受！但是第 18 行明明有 google 的 goo 啊∼別忘記了，因為該行後面出現了 tool 的 too 啊！所以該行也被列出來∼ 也就是說， 18 行裡面雖然出現了我們所不要的項目 (goo) 但是由於有需要的項目 (too) ， 因此，是符合字串搜尋的喔！

至於第 19 行，同樣的，因為 goooooogle 裡面的 oo 前面可能是 o ，例如： go(ooo)oogle ，所以，這一行也是符合需求的！

再來，假設我 oo 前面不想要有小寫字元，所以，我可以這樣寫 [^abcd....z]oo ， 但是這樣似乎不怎麼方便，由於小寫字元的 ASCII 上編碼的順序是連續的， 因此，我們可以將之簡化為底下這樣：

[root@www ~]# grep -n '[^a-z]oo' regular_express.txt

3:Football game is not use feet only.

也就是說，當我們在一組集合字元中，如果該字元組是連續的，例如大寫英文/小寫英文/數字等等， 就可以使用[a-z],[A-Z],[0-9]等方式來書寫，那麼如果我們的要求字串是數字與英文呢？ 呵呵！就將他全部寫在一起，變成：[a-zA-Z0-9]。例如，我們要取得有數字的那一行，就這樣：

[root@www ~]# grep -n '[0-9]' regular_express.txt

5:However, this dress is about $ 3183 dollars.

15:You are the best is mean you are the no. 1.

但由於考慮到語系對於編碼順序的影響，因此除了連續編碼使用減號『 - 』之外， 你也可以使用如下的方法來取得前面兩個測試的結果：

[root@www ~]# grep -n '[^[:lower:]]oo' regular_express.txt

# 那個 [:lower:] 代表的就是 a-z 的意思！請參考前兩小節的說明表格

[root@www ~]# grep -n '[[:digit:]]' regular_express.txt

這樣對於 [] 以及 [^] 以及 [] 當中的 - ，還有關於前面表格提到的特殊關鍵字有瞭解了嗎？^_^！

- 例題三、行首與行尾字元 ^ $

我們在例題一當中，可以查詢到一行字串裡面有 the 的，那如果我想要讓 the 只在行首列出呢？ 這個時候就得要使用定位字元了！我們可以這樣做：

[root@www ~]# grep -n '^the' regular_express.txt

12:the symbol '*' is represented as start.

此時，就只剩下第 12 行，因為只有第 12 行的行首是 the 開頭啊∼此外， 如果我想要開頭是小寫字元的那一行就列出呢？可以這樣：

[root@www ~]# grep -n '^[a-z]' regular_express.txt

2:apple is my favorite food.

4:this dress doesn't fit me.

10:motorcycle is cheap than car.

12:the symbol '*' is represented as start.

18:google is the best tools for search keyword.

19:goooooogle yes!

20:go! go! Let's go.

你可以發現我們可以捉到第一個字元都不是大寫的！只不過 grep 列出的關鍵字部分不只有第一個字元， grep 是列出一整個字 (word) 說！同樣的，上面的指令也可以用如下的方式來取代的：

[root@www ~]# grep -n '^[[:lower:]]' regular_express.txt

好！那如果我不想要開頭是英文字母，則可以是這樣：

[root@www ~]# grep -n '^[^a-zA-Z]' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

21:# I am VBird

# 指令也可以是： grep -n '^[^[:alpha:]]' regular_express.txt

注意到了吧？那個 ^ 符號，在字元集合符號(括號[])之內與之外是不同的！ 在 [] 內代表『反向選擇』，在 [] 之外則代表定位在行首的意義！要分清楚喔！ 反過來思考，那如果我想要找出來，行尾結束為小數點 (.) 的那一行，該如何處理：

[root@www ~]# grep -n '\.$' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

2:apple is my favorite food.

3:Football game is not use feet only.

4:this dress doesn't fit me.

10:motorcycle is cheap than car.

11:This window is clear.

12:the symbol '*' is represented as start.

15:You are the best is mean you are the no. 1.

16:The world <Happy> is the same with "glad".

17:I like dog.

18:google is the best tools for search keyword.

20:go! go! Let's go.

特別注意到，因為小數點具有其他意義(底下會介紹)，所以必須要使用跳脫字元(\)來加以解除其特殊意義！ 不過，你或許會覺得奇怪，但是第 5~9 行最後面也是 . 啊∼怎麼無法列印出來？ 這裡就牽涉到 Windows 平台的軟體對於斷行字元的判斷問題了！我們使用 cat -A 將第五行拿出來看， 你會發現：

[root@www ~]# cat -An regular_express.txt | head -n 10 | tail -n 6

5  However, this dress is about $ 3183 dollars.^M$

6  GNU is free air not free beer.^M$

7  Her hair is very beauty.^M$

8  I can't finish the test.^M$

9  Oh! The soup taste good.^M$

10  motorcycle is cheap than car.$

我們在第十章內談到過斷行字元在 Linux 與 Windows 上的差異， 在上面的表格中我們可以發現 5~9 行為 Windows 的斷行字元 (^M$) ，而正常的 Linux 應該僅有第 10 行顯示的那樣 ($) 。所以囉，那個 . 自然就不是緊接在 $ 之前喔！也就捉不到 5~9 行了！這樣可以瞭解 ^ 與 $ 的意義嗎？ 好了，先不要看底下的解答，自己想一想，那麼如果我想要找出來，哪一行是『空白行』， 也就是說，該行並沒有輸入任何資料，該如何搜尋？

[root@www ~]# grep -n '^$' regular_express.txt

22:

因為只有行首跟行尾 (^$)，所以，這樣就可以找出空白行啦！再來，假設你已經知道在一個程式腳本 (shell script) 或者是設定檔當中，空白行與開頭為 # 的那一行是註解，因此如果你要將資料列出給別人參考時， 可以將這些資料省略掉以節省保貴的紙張，那麼你可以怎麼作呢？ 我們以 /etc/syslog.conf 這個檔案來作範例，你可以自行參考一下輸出的結果：

[root@www ~]# cat -n /etc/syslog.conf

# 在 CentOS 中，結果可以發現有 33 行的輸出，很多空白行與 # 開頭

[root@www ~]# grep -v '^$' /etc/syslog.conf | grep -v '^#'

# 結果僅有 10 行，其中第一個『 -v '^$' 』代表『不要空白行』，

# 第二個『 -v '^#' 』代表『不要開頭是 # 的那行』喔！

是否節省很多版面啊？

- 例題四、任意一個字元 . 與重複字元 *

在第十一章 bash 當中，我們知道萬用字元 * 可以用來代表任意(0或多個)字元， 但是正規表示法並不是萬用字元，兩者之間是不相同的！ 至於正規表示法當中的『 . 』則代表『絕對有一個任意字元』的意思！這兩個符號在正規表示法的意義如下：

- . (小數點)：代表『一定有一個任意字元』的意思；

- * (星星號)：代表『重複前一個字元， 0 到無窮多次』的意思，為組合形態

這樣講不好懂，我們直接做個練習吧！假設我需要找出 g??d 的字串，亦即共有四個字元， 起頭是 g 而結束是 d ，我可以這樣做：

[root@www ~]# grep -n 'g..d' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

9:Oh! The soup taste good.

16:The world <Happy> is the same with "glad".

因為強調 g 與 d 之間一定要存在兩個字元，因此，第 13 行的 god 與第 14 行的 gd 就不會被列出來啦！再來，如果我想要列出有 oo, ooo, oooo 等等的資料， 也就是說，至少要有兩個(含) o 以上，該如何是好？是 o* 還是 oo* 還是 ooo* 呢？ 雖然你可以試看看結果， 不過結果太佔版面了 @_@ ，所以，我這裡就直接說明。

因為 * 代表的是『重複 0 個或多個前面的 RE 字符』的意義， 因此，『o*』代表的是：『擁有空字元或一個 o 以上的字元』， 特別注意，因為允許空字元(就是有沒有字元都可以的意思)，因此，『 grep -n 'o*' regular_express.txt 』將會把所有的資料都列印出來螢幕上！

那如果是『oo*』呢？則第一個 o 肯定必須要存在，第二個 o 則是可有可無的多個 o ， 所以，凡是含有 o, oo, ooo, oooo 等等，都可以被列出來∼

同理，當我們需要『至少兩個 o 以上的字串』時，就需要 ooo* ，亦即是：

[root@www ~]# grep -n 'ooo*' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

2:apple is my favorite food.

3:Football game is not use feet only.

9:Oh! The soup taste good.

18:google is the best tools for search keyword.

19:goooooogle yes!

這樣理解 * 的意義了嗎？好了，現在出個練習，如果我想要字串開頭與結尾都是 g，但是兩個 g 之間僅能存在至少一個 o ，亦即是 gog, goog, gooog.... 等等，那該如何？

[root@www ~]# grep -n 'goo*g' regular_express.txt

18:google is the best tools for search keyword.

19:goooooogle yes!

如此瞭解了嗎？再來一題，如果我想要找出 g 開頭與 g 結尾的字串，當中的字元可有可無，那該如何是好？是『g*g』嗎？

[root@www ~]# grep -n 'g*g' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

3:Football game is not use feet only.

9:Oh! The soup taste good.

13:Oh!  My god!

14:The gd software is a library for drafting programs.

16:The world <Happy> is the same with "glad".

17:I like dog.

18:google is the best tools for search keyword.

19:goooooogle yes!

20:go! go! Let's go.

但測試的結果竟然出現這麼多行？太詭異了吧？其實一點也不詭異，因為 g*g 裡面的 g* 代表『空字元或一個以上的 g』 在加上後面的 g ，因此，整個 RE 的內容就是 g, gg, ggg, gggg ， 因此，只要該行當中擁有一個以上的 g 就符合所需了！

那該如何得到我們的 g....g 的需求呢？呵呵！就利用任意一個字元『.』啊！ 亦即是：『g.*g』的作法，因為 * 可以是 0 或多個重複前面的字符，而 . 是任意字元，所以： 『.* 就代表零個或多個任意字元』的意思啦！

[root@www ~]# grep -n 'g.*g' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

14:The gd software is a library for drafting programs.

18:google is the best tools for search keyword.

19:goooooogle yes!

20:go! go! Let's go.

因為是代表 g 開頭與 g 結尾，中間任意字元均可接受，所以，第 1, 14, 20 行是可接受的喔！ 這個 .* 的 RE 表示任意字元是很常見的，希望大家能夠理解並且熟悉！ 再出一題，如果我想要找出『任意數字』的行列呢？因為僅有數字，所以就成為：

[root@www ~]# grep -n '[0-9][0-9]*' regular_express.txt

5:However, this dress is about $ 3183 dollars.

15:You are the best is mean you are the no. 1.

雖然使用 grep -n '[0-9]' regular_express.txt 也可以得到相同的結果， 但鳥哥希望大家能夠理解上面指令當中 RE 表示法的意義才好！

- 例題五、限定連續 RE 字符範圍 {}

在上個例題當中，我們可以利用 . 與 RE 字符及 * 來設定 0 個到無限多個重複字元， 那如果我想要限制一個範圍區間內的重複字元數呢？舉例來說，我想要找出兩個到五個 o 的連續字串，該如何作？這時候就得要使用到限定範圍的字符 {} 了。 但因為 { 與 } 的符號在 shell 是有特殊意義的，因此， 我們必須要使用跳脫字符 \ 來讓他失去特殊意義才行。 至於 {} 的語法是這樣的，假設我要找到兩個 o 的字串，可以是：

[root@www ~]# grep -n 'o\{2\}' regular_express.txt

1:"Open Source" is a good mechanism to develop programs.

2:apple is my favorite food.

3:Football game is not use feet only.

9:Oh! The soup taste good.

18:google is the best tools for search keyword.

19:goooooogle yes!

這樣看似乎與 ooo* 的字符沒有什麼差異啊？因為第 19 行有多個 o 依舊也出現了！ 好，那麼換個搜尋的字串，假設我們要找出 g 後面接 2 到 5 個 o ，然後再接一個 g 的字串，他會是這樣：

[root@www ~]# grep -n 'go\{2,5\}g' regular_express.txt

18:google is the best tools for search keyword.

嗯！很好！第 19 行終於沒有被取用了(因為 19 行有 6 個 o 啊！)。 那麼，如果我想要的是 2 個 o 以上的 goooo....g 呢？除了可以是 gooo*g ，也可以是：

[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt

18:google is the best tools for search keyword.

19:goooooogle yes!

呵呵！就可以找出來啦∼

基礎正規表示法字符彙整 (characters)

經過了上面的幾個簡單的範例，我們可以將基礎的正規表示法特殊字符彙整如下：

RE 字符

意義與範例

^word

意義：待搜尋的字串(word)在行首！

範例：搜尋行首為 # 開始的那一行，並列出行號

grep -n '^#' regular_express.txt

word$

意義：待搜尋的字串(word)在行尾！

範例：將行尾為 ! 的那一行列印出來，並列出行號

grep -n '!$' regular_express.txt

.

意義：代表『一定有一個任意字元』的字符！

範例：搜尋的字串可以是 (eve) (eae) (eee) (e e)， 但不能僅有 (ee) ！亦即 e 與 e 中間『一定』僅有一個字元，而空白字元也是字元！

grep -n 'e.e' regular_express.txt

\

意義：跳脫字符，將特殊符號的特殊意義去除！

範例：搜尋含有單引號 ' 的那一行！

grep -n \' regular_express.txt

*

意義：重複零個到無窮多個的前一個 RE 字符

範例：找出含有 (es) (ess) (esss) 等等的字串，注意，因為 * 可以是 0 個，所以 es 也是符合帶搜尋字串。另外，因為 * 為重複『前一個 RE 字符』的符號， 因此，在 * 之前必須要緊接著一個 RE 字符喔！例如任意字元則為 『.*』 ！

grep -n 'ess*' regular_express.txt

[list]

意義：字元集合的 RE 字符，裡面列出想要擷取的字元！

範例：搜尋含有 (gl) 或 (gd) 的那一行，需要特別留意的是，在 [] 當中『謹代表一個待搜尋的字元』， 例如『 a[afl]y 』代表搜尋的字串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思！

grep -n 'g[ld]' regular_express.txt

[n1-n2]

意義：字元集合的 RE 字符，裡面列出想要擷取的字元範圍！

範例：搜尋含有任意數字的那一行！需特別留意，在字元集合 [] 中的減號 - 是有特殊意義的，他代表兩個字元之間的所有連續字元！但這個連續與否與 ASCII 編碼有關，因此，你的編碼需要設定正確(在 bash 當中，需要確定 LANG 與 LANGUAGE 的變數是否正確！) 例如所有大寫字元則為 [A-Z]

grep -n '[A-Z]' regular_express.txt

[^list]

意義：字元集合的 RE 字符，裡面列出不要的字串或範圍！

範例：搜尋的字串可以是 (oog) (ood) 但不能是 (oot) ，那個 ^ 在 [] 內時，代表的意義是『反向選擇』的意思。 例如，我不要大寫字元，則為 [^A-Z]。但是，需要特別注意的是，如果以 grep -n [^A-Z] regular_express.txt 來搜尋，卻發現該檔案內的所有行都被列出，為什麼？因為這個 [^A-Z] 是『非大寫字元』的意思， 因為每一行均有非大寫字元，例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小寫字

grep -n 'oo[^t]' regular_express.txt

\{n,m\}

意義：連續 n 到 m 個的『前一個 RE 字符』

意義：若為 \{n\} 則是連續 n 個的前一個 RE 字符，

意義：若是 \{n,\} 則是連續 n 個以上的前一個 RE 字符！ 範例：在 g 與 g 之間有 2 個到 3 個的 o 存在的字串，亦即 (goog)(gooog)

grep -n 'go\{2,3\}g' regular_express.txt

再次強調：『正規表示法的特殊字元』與一般在指令列輸入指令的『萬用字元』並不相同， 例如，在萬用字元當中的 * 代表的是『 0 ~ 無限多個字元』的意思，但是在正規表示法當中， * 則是『重複 0 到無窮多個的前一個 RE 字符』的意思∼使用的意義並不相同，不要搞混了！

舉例來說，不支援正規表示法的 ls 這個工具中，若我們使用 『ls -l * 』 代表的是任意檔名的檔案，而 『ls -l a* 』代表的是以 a 為開頭的任何檔名的檔案， 但在正規表示法中，我們要找到含有以 a 為開頭的檔案，則必須要這樣：(需搭配支援正規表示法的工具)

ls | grep -n '^a.*'

例題：

以 ls -l 配合 grep 找出 /etc/ 底下檔案類型為連結檔屬性的檔名

答：

由於 ls -l 列出連結檔時標頭會是『 lrwxrwxrwx 』，因此使用如下的指令即可找出結果：

ls -l /etc | grep '^l'

若僅想要列出幾個檔案，再以『 |wc -l 』 來累加處理即可。

sed 工具

在瞭解了一些正規表示法的基礎應用之後，再來呢？呵呵∼兩個東西可以玩一玩的，那就是 sed 跟底下會介紹的 awk 了！ 這兩個傢伙可是相當的有用的啊！舉例來說，鳥哥寫的 logfile.sh 分析登錄檔的小程式 (第十九章會談到)，絕大部分分析關鍵字的取用、統計等等，就是用這兩個寶貝蛋來幫我完成的！那麼你說，要不要玩一玩啊？^_^

我們先來談一談 sed 好了， sed 本身也是一個管線命令，可以分析 standard input 的啦！ 而且 sed 還可以將資料進行取代、刪除、新增、擷取特定行等等的功能呢！很不錯吧∼ 我們先來瞭解一下 sed 的用法，再來聊他的用途好了！

[root@www ~]# sed [-nefr] [動作]

選項與參數：

-n  ：使用安靜(silent)模式。在一般 sed 的用法中，所有來自 STDIN

的資料一般都會被列出到螢幕上。但如果加上 -n 參數後，則只有經過

sed 特殊處理的那一行(或者動作)才會被列出來。

-e  ：直接在指令列模式上進行 sed 的動作編輯；

-f  ：直接將 sed 的動作寫在一個檔案內， -f filename 則可以執行 filename 內的

sed 動作；

-r  ：sed 的動作支援的是延伸型正規表示法的語法。(預設是基礎正規表示法語法)

-i  ：直接修改讀取的檔案內容，而不是由螢幕輸出。

動作說明：  [n1[,n2]]function

n1, n2 ：不見得會存在，一般代表『選擇進行動作的行數』，舉例來說，如果我的動作

是需要在 10 到 20 行之間進行的，則『 10,20[動作行為] 』

function 有底下這些咚咚：

a   ：新增， a 的後面可以接字串，而這些字串會在新的一行出現(目前的下一行)∼

c   ：取代， c 的後面可以接字串，這些字串可以取代 n1,n2 之間的行！

d   ：刪除，因為是刪除啊，所以 d 後面通常不接任何咚咚；

i   ：插入， i 的後面可以接字串，而這些字串會在新的一行出現(目前的上一行)；

p   ：列印，亦即將某個選擇的資料印出。通常 p 會與參數 sed -n 一起運作∼

s   ：取代，可以直接進行取代的工作哩！通常這個 s 的動作可以搭配

正規表示法！例如 1,20s/old/new/g 就是啦！

- 以行為單位的新增/刪除功能

sed 光是用看的是看不懂的啦！所以又要來練習了！先來玩玩刪除與新增的功能吧！

範例一：將 /etc/passwd 的內容列出並且列印行號，同時，請將第 2~5 行刪除！

[root@www ~]# nl /etc/passwd | sed '2,5d'

1  root:x:0:0:root:/root:/bin/bash

6  sync:x:5:0:sync:/sbin:/bin/sync

7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

.....(後面省略).....

看到了吧？sed 的動作為 '2,5d' ，那個 d 就是刪除！因為 2-5 行給他刪除了，所以顯示的資料就沒有 2-5 行囉∼ 另外，注意一下，原本應該是要下達 sed -e 才對，沒有 -e 也行啦！同時也要注意的是， sed 後面接的動作，請務必以 '' 兩個單引號括住喔！

如果題型變化一下，舉例來說，如果只要刪除第 2 行，可以使用『 nl /etc/passwd | sed '2d' 』來達成， 至於若是要刪除第 3 到最後一行，則是『 nl /etc/passwd | sed '3,$d' 』的啦，那個錢字號『 $ 』代表最後一行！

範例二：承上題，在第二行後(亦即是加在第三行)加上『drink tea?』字樣！

[root@www ~]# nl /etc/passwd | sed '2a drink tea'

1  root:x:0:0:root:/root:/bin/bash

2  bin:x:1:1:bin:/bin:/sbin/nologin

drink tea

3  daemon:x:2:2:daemon:/sbin:/sbin/nologin

.....(後面省略).....

嘿嘿！在 a 後面加上的字串就已將出現在第二行後面囉！那如果是要在第二行前呢？『 nl /etc/passwd | sed '2i drink tea' 』就對啦！就是將『 a 』變成『 i 』即可。 增加一行很簡單，那如果是要增將兩行以上呢？

範例三：在第二行後面加入兩行字，例如『Drink tea or .....』與『drink beer?』

[root@www ~]# nl /etc/passwd | sed '2a Drink tea or ......\

> drink beer ?'

1  root:x:0:0:root:/root:/bin/bash

2  bin:x:1:1:bin:/bin:/sbin/nologin

Drink tea or ......

drink beer ?

3  daemon:x:2:2:daemon:/sbin:/sbin/nologin

.....(後面省略).....

這個範例的重點是『我們可以新增不只一行喔！可以新增好幾行』但是每一行之間都必須要以反斜線『 \ 』來進行新行的增加喔！所以，上面的例子中，我們可以發現在第一行的最後面就有 \ 存在啦！那是一定要的喔！

- 以行為單位的取代與顯示功能

剛剛是介紹如何新增與刪除，那麼如果要整行取代呢？看看底下的範例吧：

範例四：我想將第2-5行的內容取代成為『No 2-5 number』呢？

[root@www ~]# nl /etc/passwd | sed '2,5c No 2-5 number'

1  root:x:0:0:root:/root:/bin/bash

No 2-5 number

6  sync:x:5:0:sync:/sbin:/bin/sync

.....(後面省略).....

透過這個方法我們就能夠將資料整行取代了！非常容易吧！sed 還有更好用的東東！我們以前想要列出第 11~20 行， 得要透過『head -n 20 | tail -n 10』之類的方法來處理，很麻煩啦∼ sed 則可以簡單的直接取出你想要的那幾行！是透過行號來捉的喔！看看底下的範例先：

範例五：僅列出 /etc/passwd 檔案內的第 5-7 行

[root@www ~]# nl /etc/passwd | sed -n '5,7p'

5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

6  sync:x:5:0:sync:/sbin:/bin/sync

7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

上述的指令中有個重要的選項『 -n 』，按照說明文件，這個 -n 代表的是『安靜模式』！ 那麼為什麼要使用安靜模式呢？你可以自行下達 sed '5,7p' 就知道了 (5-7 行會重複輸出)！ 有沒有加上 -n 的參數時，輸出的資料可是差很多的喔！你可以透過這個 sed 的以行為單位的顯示功能， 就能夠將某一個檔案內的某些行號捉出來查閱！很棒的功能！不是嗎？

- 部分資料的搜尋並取代的功能

除了整行的處理模式之外， sed 還可以用行為單位進行部分資料的搜尋並取代的功能喔！ 基本上 sed 的搜尋與取代的與 vi 相當的類似！他有點像這樣：

sed 's/要被取代的字串/新的字串/g'

上表中特殊字體的部分為關鍵字，請記下來！至於三個斜線分成兩欄就是新舊字串的替換啦！ 我們使用底下這個取得 IP 數據的範例，一段一段的來處理給您瞧瞧，讓你瞭解一下什麼是咱們所謂的搜尋並取代吧！

步驟一：先觀察原始訊息，利用 /sbin/ifconfig  查詢 IP 為何？

[root@www ~]# /sbin/ifconfig eth0

eth0      Link encap:Ethernet  HWaddr 00:90:CC:A6:34:84

inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0

inet6 addr: fe80::290:ccff:fea6:3484/64 Scope:Link

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

.....(以下省略).....

# 因為我們還沒有講到 IP ，這裡你先有個概念即可啊！我們的重點在第二行，

# 也就是 192.168.1.100 那一行而已！先利用關鍵字捉出那一行！

步驟二：利用關鍵字配合 grep 擷取出關鍵的一行資料

[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr'

inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0

# 當場僅剩下一行！接下來，我們要將開始到 addr: 通通刪除，就是像底下這樣：

# inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0

# 上面的刪除關鍵在於『 ^.*inet addr: 』啦！正規表示法出現！ ^_^

步驟三：將 IP 前面的部分予以刪除

[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \

>  sed 's/^.*addr://g'

192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0

# 仔細與上個步驟比較一下，前面的部分不見了！接下來則是刪除後續的部分，亦即：

# 192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0

# 此時所需的正規表示法為：『 Bcast.*$ 』就是啦！

步驟四：將 IP 後面的部分予以刪除

[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \

>  sed 's/^.*addr://g' | sed 's/Bcast.*$//g'

192.168.1.100

透過這個範例的練習也建議您依據此一步驟來研究你的指令！就是先觀察，然後再一層一層的試做， 如果有做不對的地方，就先予以修改，改完之後測試，成功後再往下繼續測試。以鳥哥上面的介紹中， 那一大串指令就做了四個步驟！對吧！ ^_^

讓我們再來繼續研究 sed 與正規表示法的配合練習！假設我只要 MAN 存在的那幾行資料， 但是含有 # 在內的註解我不想要，而且空白行我也不要！此時該如何處理呢？可以透過這幾個步驟來實作看看：

步驟一：先使用 grep 將關鍵字 MAN 所在行取出來

[root@www ~]# cat /etc/man.config | grep 'MAN'

# when MANPATH contains an empty substring), to find out where the cat

# MANBIN                pathname

# MANPATH               manpath_element [corresponding_catdir]

# MANPATH_MAP           path_element    manpath_element

# MANBIN                /usr/local/bin/man

# Every automatically generated MANPATH includes these fields

MANPATH /usr/man

....(後面省略)....

步驟二：刪除掉註解之後的資料！

[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g'

MANPATH /usr/man

....(後面省略)....

# 從上面可以看出來，原本註解的資料都變成空白行啦！所以，接下來要刪除掉空白行

[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g' | \

> sed '/^$/d'

MANPATH /usr/man

MANPATH /usr/share/man

MANPATH /usr/local/man

....(後面省略)....

- 直接修改檔案內容(危險動作)

你以為 sed 只有這樣的能耐嗎？那可不！ sed 甚至可以直接修改檔案的內容呢！而不必使用管線命令或資料流重導向！ 不過，由於這個動作會直接修改到原始的檔案，所以請你千萬不要隨便拿系統設定檔來測試喔！ 我們還是使用你下載的 regular_express.txt 檔案來測試看看吧！

範例六：利用 sed 將 regular_express.txt 內每一行結尾若為 . 則換成 !

[root@www ~]# sed -i 's/\.$/\!/g' regular_express.txt

# 上頭的 -i 選項可以讓你的 sed 直接去修改後面接的檔案內容而不是由螢幕輸出喔！

# 這個範例是用在取代！請您自行 cat 該檔案去查閱結果囉！

範例七：利用 sed 直接在 regular_express.txt 最後一行加入『# This is a test』

[root@www ~]# sed -i '$a # This is a test' regular_express.txt

# 由於 $ 代表的是最後一行，而 a 的動作是新增，因此該檔案最後新增囉！

sed 的『 -i 』選項可以直接修改檔案內容，這功能非常有幫助！舉例來說，如果你有一個 100 萬行的檔案，你要在第 100 行加某些文字，此時使用 vim 可能會瘋掉！因為檔案太大了！那怎辦？就利用 sed 啊！透過 sed 直接修改/取代的功能，你甚至不需要使用 vim 去修訂！很棒吧！

總之，這個 sed 不錯用啦！而且很多的 shell script 都會使用到這個指令的功能∼ sed 可以幫助系統管理員管理好日常的工作喔！要仔細的學習呢！

延伸正規表示法

事實上，一般讀者只要瞭解基礎型的正規表示法大概就已經相當足夠了，不過，某些時刻為了要簡化整個指令操作， 瞭解一下使用範圍更廣的延伸型正規表示法的表示式會更方便呢！舉個簡單的例子好了，在上節的例題三的最後一個例子中，我們要去除空白行與行首為 # 的行列，使用的是

grep -v '^$' regular_express.txt | grep -v '^#'

需要使用到管線命令來搜尋兩次！那麼如果使用延伸型的正規表示法，我們可以簡化為：

egrep -v '^$|^#' regular_express.txt

延伸型正規表示法可以透過群組功能『 | 』來進行一次搜尋！那個在單引號內的管線意義為『或 or』啦！ 是否變的更簡單呢？此外，grep 預設僅支援基礎正規表示法，如果要使用延伸型正規表示法，你可以使用 grep -E ， 不過更建議直接使用 egrep ！直接區分指令比較好記憶！其實 egrep 與 grep -E 是類似命令別名的關係啦！

熟悉了正規表示法之後，到這個延伸型的正規表示法，你應該也會想到，不就是多幾個重要的特殊符號嗎？ ^_^y 是的∼所以，我們就直接來說明一下，延伸型正規表示法有哪幾個特殊符號？由於底下的範例還是有使用到 regular_express.txt ，不巧的是剛剛我們可能將該檔案修改過了 @_@，所以，請重新下載該檔案來練習喔！

RE 字符

意義與範例

+

意義：重複『一個或一個以上』的前一個 RE 字符

範例：搜尋 (god) (good) (goood)... 等等的字串。 那個 o+ 代表『一個以上的 o 』所以，底下的執行成果會將第 1, 9, 13 行列出來。

egrep -n 'go+d' regular_express.txt

?

意義：『零個或一個』的前一個 RE 字符

範例：搜尋 (gd) (god) 這兩個字串。 那個 o? 代表『空的或 1 個 o 』所以，上面的執行成果會將第 13, 14 行列出來。 有沒有發現到，這兩個案例( 'go+d' 與 'go?d' )的結果集合與 'go*d' 相同？ 想想看，這是為什麼喔！ ^_^

egrep -n 'go?d' regular_express.txt

|

意義：用或( or )的方式找出數個字串

範例：搜尋 gd 或 good 這兩個字串，注意，是『或』！ 所以，第 1,9,14 這三行都可以被列印出來喔！那如果還想要找出 dog 呢？

egrep -n 'gd|good' regular_express.txt

egrep -n 'gd|good|dog' regular_express.txt

()

意義：找出『群組』字串

範例：搜尋 (glad) 或 (good) 這兩個字串，因為 g 與 d 是重複的，所以， 我就可以將 la 與 oo 列於 ( ) 當中，並以 | 來分隔開來，就可以啦！

egrep -n 'g(la|oo)d' regular_express.txt

()+

意義：多個重複群組的判別

範例：將『AxyzxyzxyzxyzC』用 echo 叫出，然後再使用如下的方法搜尋一下！

echo 'AxyzxyzxyzxyzC' | egrep 'A(xyz)+C'

上面的例子意思是說，我要找開頭是 A 結尾是 C ，中間有一個以上的 "xyz" 字串的意思∼

以上這些就是延伸型的正規表示法的特殊字元。另外，要特別強調的是，那個 ! 在正規表示法當中並不是特殊字元， 所以，如果你想要查出來檔案中含有 ! 與 > 的字行時，可以這樣：

grep -n '[!>]' regular_express.txt

這樣可以瞭解了嗎？常常看到有陷阱的題目寫：『反向選擇這樣對否？ '[!a-z]'？』， 呵呵！是錯的呦∼要 '[^a-z] 才是對的！至於更多關於正規表示法的進階文章，請參考文末的參考資料(註2)

文件的格式化與相關處理

接下來讓我們來將文件進行一些簡單的編排吧！底下這些動作可以將你的訊息進行排版的動作， 不需要重新以 vim 去編輯，透過資料流重導向配合底下介紹的 printf 功能，以及 awk 指令， 就可以讓你的訊息以你想要的模樣來輸出了！試看看吧！

格式化列印： printf

在很多時候，我們可能需要將自己的資料給他格式化輸出的！ 舉例來說，考試卷分數的輸出，姓名與科目及分數之間，總是可以稍微作個比較漂亮的版面配置吧？ 例如我想要輸出底下的樣式：

Name     Chinese   English   Math    Average

DmTsai        80        60     92      77.33

VBird         75        55     80      70.00

Ken           60        90     70      73.33

上表的資料主要分成五個欄位，各個欄位之間可使用 tab 或空白鍵進行分隔。 請將上表的資料轉存成為 printf.txt 檔名，等一下我們會利用這個檔案來進行幾個小練習的。 因為每個欄位的原始資料長度其實並非是如此固定的 (Chinese 長度就是比 Name 要多)， 而我就是想要如此表示出這些資料，此時，就得需要列印格式管理員 printf 的幫忙了！ printf 可以幫我們將資料輸出的結果格式化，而且而支援一些特殊的字符∼底下我們就來看看！

[root@www ~]# printf '列印格式' 實際內容

選項與參數：

關於格式方面的幾個特殊樣式：

\a    警告聲音輸出

\b    倒退鍵(backspace)

\f    清除螢幕 (form feed)

\n    輸出新的一行

\r    亦即 Enter 按鍵

\t    水平的 [tab] 按鍵

\v    垂直的 [tab] 按鍵

\xNN  NN 為兩位數的數字，可以轉換數字成為字元。

關於 C 程式語言內，常見的變數格式

%ns   那個 n 是數字， s 代表 string ，亦即多少個字元；

%ni   那個 n 是數字， i 代表 integer ，亦即多少整數位數；

%N.nf 那個 n 與 N 都是數字， f 代表 floating (浮點)，如果有小數位數，

假設我共要十個位數，但小數點有兩位，即為 %10.2f 囉！

接下來我們來進行幾個常見的練習。假設所有的資料都是一般文字 (這也是最常見的狀態)，因此最常用來分隔資料的符號就是 [Tab] 啦！因為 [Tab] 按鍵可以將資料作個整齊的排列！那麼如何利用 printf 呢？參考底下這個範例：

範例一：將剛剛上頭資料的檔案 (printf.txt) 內容僅列出姓名與成績：(用 [tab] 分隔)

[root@www ~]# printf '%s\t %s\t %s\t %s\t %s\t \n' $(cat printf.txt)

Name     Chinese         English         Math    Average

DmTsai   80      60      92      77.33

VBird    75      55      80      70.00

Ken      60      90      70      73.33

由於 printf 並不是管線命令，因此我們得要透過類似上面的功能，將檔案內容先提出來給 printf 作為後續的資料才行。 如上所示，我們將每個資料都以 [tab] 作為分隔，但是由於 Chinese 長度太長，導致 English 中間多了一個 [tab] 來將資料排列整齊！啊∼結果就看到資料對齊結果的差異了！

另外，在 printf 後續的那一段格式中，%s 代表一個不固定長度的字串，而字串與字串中間就以 \t 這個 [tab] 分隔符號來處理！你要記得的是，由於 \t 與 %s 中間還有空格，因此每個字串間會有一個 [tab] 與一個空白鍵的分隔喔！

既然每個欄位的長度不固定會造成上述的困擾，那我將每個欄位固定就好啦！沒錯沒錯！這樣想非常好！ 所以我們就將資料給他進行固定欄位長度的設計吧！

範例二：將上述資料關於第二行以後，分別以字串、整數、小數點來顯示：

[root@www ~]# printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt |\

> grep -v Name)

DmTsai    80    60    92    77.33

VBird    75    55    80    70.00

Ken    60    90    70    73.33

上面這一串格式想必您看得很辛苦！沒關係！一個一個來解釋！上面的格式共分為五個欄位， %10s 代表的是一個長度為 10 個字元的字串欄位，%5i 代表的是長度為 5 個字元的數字欄位，至於那個 %8.2f 則代表長度為 8 個字元的具有小數點的欄位，其中小數點有兩個字元寬度。我們可以使用底下的說明來介紹 %8.2f 的意義：

字元寬度： 12345678

%8.2f意義：00000.00

如上所述，全部的寬度僅有 8 個字元，整數部分佔有 5 個字元，小數點本身 (.) 佔一位，小數點下的位數則有兩位。 這種格式經常使用於數值程式的設計中！這樣瞭解乎？自己試看看如果要將小數點位數變成 1 位又該如何處理？

printf 除了可以格式化處理之外，他還可以依據 ASCII 的數字與圖形對應來顯示資料喔(註3)！ 舉例來說 16 進位的 45 可以得到什麼 ASCII 的顯示圖 (其實是字元啦)？

範例三：列出 16 進位數值 45 代表的字元為何？

[root@www ~]# printf '\x45\n'

E

# 這東西也很好玩∼他可以將數值轉換成為字元，如果你會寫 script 的話，

# 可以自行測試一下，由 20~80 之間的數值代表的字元是啥喔！ ^_^

printf 的使用相當的廣泛喔！包括等一下後面會提到的 awk 以及在 C 程式語言當中使用的螢幕輸出， 都是利用 printf 呢！鳥哥這裡也只是列出一些可能會用到的格式而已，有興趣的話，可以自行多作一些測試與練習喔！ ^_^

Tips:

列印格式化這個 printf 指令，乍看之下好像也沒有什麼很重要的∼ 不過，如果你需要自行撰寫一些軟體，需要將一些資料在螢幕上頭漂漂亮亮的輸出的話， 那麼 printf 可也是一個很棒的工具喔！

awk：好用的資料處理工具

awk 也是一個非常棒的資料處理工具！相較於 sed 常常作用於一整個行的處理， awk 則比較傾向於一行當中分成數個『欄位』來處理。因此，awk 相當的適合處理小型的數據資料處理呢！awk 通常運作的模式是這樣的：

[root@www ~]# awk '條件類型1{動作1} 條件類型2{動作2} ...' filename

awk 後面接兩個單引號並加上大括號 {} 來設定想要對資料進行的處理動作。 awk 可以處理後續接的檔案，也可以讀取來自前個指令的 standard output 。 但如前面說的， awk 主要是處理『每一行的欄位內的資料』，而預設的『欄位的分隔符號為 "空白鍵" 或 "[tab]鍵" 』！舉例來說，我們用 last 可以將登入者的資料取出來，結果如下所示：

[root@www ~]# last -n 5 <==僅取出前五行

root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in

root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)

root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)

dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)

root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

若我想要取出帳號與登入者的 IP ，且帳號與 IP 之間以 [tab] 隔開，則會變成這樣：

[root@www ~]# last -n 5 | awk '{print $1 "\t" $3}'

root    192.168.1.100

root    192.168.1.100

root    192.168.1.100

dmtsai  192.168.1.100

root    Fri

上表是 awk 最常使用的動作！透過 print 的功能將欄位資料列出來！欄位的分隔則以空白鍵或 [tab] 按鍵來隔開。 因為不論哪一行我都要處理，因此，就不需要有 "條件類型" 的限制！我所想要的是第一欄以及第三欄， 但是，第五行的內容怪怪的∼這是因為資料格式的問題啊！所以囉∼使用 awk 的時候，請先確認一下你的資料當中，如果是連續性的資料，請不要有空格或 [tab] 在內，否則，就會像這個例子這樣，會發生誤判喔！

另外，由上面這個例子你也會知道，在每一行的每個欄位都是有變數名稱的，那就是 $1, $2... 等變數名稱。以上面的例子來說， root 是 $1 ，因為他是第一欄嘛！至於 192.168.1.100 是第三欄， 所以他就是 $3 啦！後面以此類推∼呵呵！還有個變數喔！那就是 $0 ，$0 代表『一整列資料』的意思∼以上面的例子來說，第一行的 $0 代表的就是『root .... 』那一行啊！ 由此可知，剛剛上面五行當中，整個 awk 的處理流程是：

1. 讀入第一行，並將第一行的資料填入 $0, $1, $2.... 等變數當中；

2. 依據 "條件類型" 的限制，判斷是否需要進行後面的 "動作"；

3. 做完所有的動作與條件類型；

4. 若還有後續的『行』的資料，則重複上面 1~3 的步驟，直到所有的資料都讀完為止。

經過這樣的步驟，你會曉得， awk 是『以行為一次處理的單位』， 而『以欄位為最小的處理單位』。好了，那麼 awk 怎麼知道我到底這個資料有幾行？有幾欄呢？這就需要 awk 的內建變數的幫忙啦∼

變數名稱

代表意義

NF

每一行 ($0) 擁有的欄位總數

NR

目前 awk 所處理的是『第幾行』資料

FS

目前的分隔字元，預設是空白鍵

我們繼續以上面 last -n 5 的例子來做說明，如果我想要：

- 列出每一行的帳號(就是 $1)；

- 列出目前處理的行數(就是 awk 內的 NR 變數)

- 並且說明，該行有多少欄位(就是 awk 內的 NF 變數)

則可以這樣：

Tips:

要注意喔，awk 後續的所有動作是以單引號『 ' 』括住的，由於單引號與雙引號都必須是成對的， 所以， awk 的格式內容如果想要以 print 列印時，記得非變數的文字部分，包含上一小節 printf 提到的格式中，都需要使用雙引號來定義出來喔！因為單引號已經是 awk 的指令固定用法了！

[root@www ~]# last -n 5| awk '{print $1 "\t lines: " NR "\t columns: " NF}'

root     lines: 1        columns: 10

root     lines: 2        columns: 10

root     lines: 3        columns: 10

dmtsai   lines: 4        columns: 10

root     lines: 5        columns: 9

# 注意喔，在 awk 內的 NR, NF 等變數要用大寫，且不需要有錢字號 $ 啦！

這樣可以瞭解 NR 與 NF 的差別了吧？好了，底下來談一談所謂的 "條件類型" 了吧！

- awk 的邏輯運算字元

既然有需要用到 "條件" 的類別，自然就需要一些邏輯運算囉∼例如底下這些：

運算單元

代表意義

>

大於

<

小於

>=

大於或等於

<=

小於或等於

==

等於

!=

不等於

值得注意的是那個『 == 』的符號，因為：

- 邏輯運算上面亦即所謂的大於、小於、等於等判斷式上面，習慣上是以『 == 』來表示；

- 如果是直接給予一個值，例如變數設定時，就直接使用 = 而已。

好了，我們實際來運用一下邏輯判斷吧！舉例來說，在 /etc/passwd 當中是以冒號 ":" 來作為欄位的分隔， 該檔案中第一欄位為帳號，第三欄位則是 UID。那假設我要查閱，第三欄小於 10 以下的數據，並且僅列出帳號與第三欄， 那麼可以這樣做：

[root@www ~]# cat /etc/passwd | \

> awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'

root:x:0:0:root:/root:/bin/bash

bin      1

daemon   2

....(以下省略)....

有趣吧！不過，怎麼第一行沒有正確的顯示出來呢？這是因為我們讀入第一行的時候，那些變數 $1, $2... 預設還是以空白鍵為分隔的，所以雖然我們定義了 FS=":" 了， 但是卻僅能在第二行後才開始生效。那麼怎麼辦呢？我們可以預先設定 awk 的變數啊！ 利用 BEGIN 這個關鍵字喔！這樣做：

[root@www ~]# cat /etc/passwd | \

> awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'

root     0

bin      1

daemon   2

......(以下省略)......

很有趣吧！而除了 BEGIN 之外，我們還有 END 呢！另外，如果要用 awk 來進行『計算功能』呢？以底下的例子來看， 假設我有一個薪資資料表檔名為 pay.txt ，內容是這樣的：

Name    1st     2nd     3th

VBird   23000   24000   25000

DMTsai  21000   20000   23000

Bird2   43000   42000   41000

如何幫我計算每個人的總額呢？而且我還想要格式化輸出喔！我們可以這樣考慮：

- 第一行只是說明，所以第一行不要進行加總 (NR==1 時處理)；

- 第二行以後就會有加總的情況出現 (NR>=2 以後處理)

[root@www ~]# cat pay.txt | \

> awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total" }

NR>=2{total = $2 + $3 + $4

printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'

Name        1st        2nd        3th      Total

VBird      23000      24000      25000   72000.00

DMTsai      21000      20000      23000   64000.00

Bird2      43000      42000      41000  126000.00

上面的例子有幾個重要事項應該要先說明的：

- awk 的指令間隔：所有 awk 的動作，亦即在 {} 內的動作，如果有需要多個指令輔助時，可利用分號『;』間隔， 或者直接以 [Enter] 按鍵來隔開每個指令，例如上面的範例中，鳥哥共按了三次 [enter] 喔！

- 邏輯運算當中，如果是『等於』的情況，則務必使用兩個等號『==』！

- 格式化輸出時，在 printf 的格式設定當中，務必加上 \n ，才能進行分行！

- 與 bash shell 的變數不同，在 awk 當中，變數可以直接使用，不需加上 $ 符號。

利用 awk 這個玩意兒，就可以幫我們處理很多日常工作了呢！真是好用的很∼ 此外， awk 的輸出格式當中，常常會以 printf 來輔助，所以， 最好你對 printf 也稍微熟悉一下比較好啦！另外， awk 的動作內 {} 也是支援 if (條件) 的喔！ 舉例來說，上面的指令可以修訂成為這樣：

[root@www ~]# cat pay.txt | \

> awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}

NR>=2{total = $2 + $3 + $4

printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'

你可以仔細的比對一下上面兩個輸入有啥不同∼從中去瞭解兩種語法吧！我個人是比較傾向於使用第一種語法， 因為會比較有統一性啊！ ^_^

除此之外， awk 還可以幫我們進行迴圈計算喔！真是相當的好用！不過，那屬於比較進階的單獨課程了， 我們這裡就不再多加介紹。如果你有興趣的話，請務必參考延伸閱讀中的相關連結喔 (註4)。

檔案比對工具

什麼時候會用到檔案的比對啊？通常是『同一個套裝軟體的不同版本之間，比較設定檔與原始檔的差異』。 很多時候所謂的檔案比對，通常是用在 ASCII 純文字檔的比對上的！那麼比對檔案的指令有哪些？最常見的就是 diff 囉！ 另外，除了 diff 比對之外，我們還可以藉由 cmp 來比對非純文字檔！同時，也能夠藉由 diff 建立的分析檔， 以處理補丁 (patch) 功能的檔案呢！就來玩玩先！

- diff

diff 就是用在比對兩個檔案之間的差異的，並且是以行為單位來比對的！一般是用在 ASCII 純文字檔的比對上。 由於是以行為比對的單位，因此 diff 通常是用在同一的檔案(或軟體)的新舊版本差異上！ 舉例來說，假如我們要將 /etc/passwd 處理成為一個新的版本，處理方式為： 將第四行刪除，第六行則取代成為『no six line』，新的檔案放置到 /tmp/test 裡面，那麼應該怎麼做？

[root@www ~]# mkdir -p /tmp/test <==先建立測試用的目錄

[root@www ~]# cd /tmp/test

[root@www test]# cp /etc/passwd passwd.old

[root@www test]# cat /etc/passwd | \

> sed -e '4d' -e '6c no six line' > passwd.new

# 注意一下， sed 後面如果要接超過兩個以上的動作時，每個動作前面得加 -e 才行！

# 透過這個動作，在 /tmp/test  裡面便有新舊的 passwd 檔案存在了！

接下來討論一下關於 diff 的用法吧！

[root@www ~]# diff [-bBi] from-file to-file

選項與參數：

from-file ：一個檔名，作為原始比對檔案的檔名；

to-file   ：一個檔名，作為目的比對檔案的檔名；

注意，from-file 或 to-file 可以 - 取代，那個 - 代表『Standard input』之意。

-b  ：忽略一行當中，僅有多個空白的差異(例如 "about me" 與 "about     me" 視為相同

-B  ：忽略空白行的差異。

-i  ：忽略大小寫的不同。

範例一：比對 passwd.old 與 passwd.new 的差異：

[root@www test]# diff passwd.old passwd.new

4d3    <==左邊第四行被刪除 (d) 掉了，基準是右邊的第三行

< adm:x:3:4:adm:/var/adm:/sbin/nologin  <==這邊列出左邊(<)檔案被刪除的那一行內容

6c5    <==左邊檔案的第六行被取代 (c) 成右邊檔案的第五行

< sync:x:5:0:sync:/sbin:/bin/sync  <==左邊(<)檔案第六行內容

---

> no six line                      <==右邊(>)檔案第五行內容

# 很聰明吧！用 diff 就把我們剛剛的處理給比對完畢了！

用 diff 比對檔案真的是很簡單喔！不過，你不要用 diff 去比對兩個完全不相干的檔案，因為比不出個啥咚咚！ 另外， diff 也可以比對整個目錄下的差異喔！舉例來說，我們想要瞭解一下不同的開機執行等級 (runlevel) 內容有啥不同？假設你已經知道執行等級 3 與 5 的啟動腳本分別放置到 /etc/rc3.d 及 /etc/rc5.d ， 則我們可以將兩個目錄比對一下：

[root@www ~]# diff /etc/rc3.d/ /etc/rc5.d/

Only in /etc/rc3.d/: K99readahead_later

Only in /etc/rc5.d/: S96readahead_later

我們的 diff 很聰明吧！還可以比對不同目錄下的相同檔名的內容，這樣真的很方便喔∼

- cmp

相對於 diff 的廣泛用途， cmp 似乎就用的沒有這麼多了∼ cmp 主要也是在比對兩個檔案，他主要利用『位元組』單位去比對， 因此，當然也可以比對 binary file 囉∼(還是要再提醒喔， diff 主要是以『行』為單位比對， cmp 則是以『位元組』為單位去比對，這並不相同！)

[root@www ~]# cmp [-s] file1 file2

選項與參數：

-s  ：將所有的不同點的位元組處都列出來。因為 cmp 預設僅會輸出第一個發現的不同點。

範例一：用 cmp 比較一下 passwd.old 及 passwd.new

[root@www test]# cmp passwd.old passwd.new

passwd.old passwd.new differ: byte 106, line 4

看到了嗎？第一個發現的不同點在第四行，而且位元組數是在第 106 個位元組處！這個 cmp 也可以用來比對 binary 啦！ ^_^

- patch

patch 這個指令與 diff 可是有密不可分的關係啊！我們前面提到，diff 可以用來分辨兩個版本之間的差異， 舉例來說，剛剛我們所建立的 passwd.old 及 passwd.new 之間就是兩個不同版本的檔案。 那麼，如果要『升級』呢？就是『將舊的檔案升級成為新的檔案』時，應該要怎麼做呢？ 其實也不難啦！就是『先比較先舊版本的差異，並將差異檔製作成為補丁檔，再由補丁檔更新舊檔案』即可。 舉例來說，我們可以這樣做測試：

範例一：以 /tmp/test 內的 passwd.old 與 passwd.new  製作補丁檔案

[root@www test]# diff -Naur passwd.old passwd.new > passwd.patch

[root@www test]# cat passwd.patch

--- passwd.old  2009-02-10 14:29:09.000000000 +0800 <==新舊檔案的資訊

+++ passwd.new  2009-02-10 14:29:18.000000000 +0800

@@ -1,9 +1,8 @@   <==新舊檔案要修改資料的界定範圍，舊檔在 1-9 行，新檔在 1-8 行

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

-adm:x:3:4:adm:/var/adm:/sbin/nologin      <==左側檔案刪除

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

-sync:x:5:0:sync:/sbin:/bin/sync           <==左側檔案刪除

+no six line                               <==右側新檔加入

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

一般來說，使用 diff 製作出來的比較檔案通常使用副檔名為 .patch 囉。至於內容就如同上面介紹的樣子。 基本上就是以行為單位，看看哪邊有一樣與不一樣的，找到一樣的地方，然後將不一樣的地方取代掉！ 以上面表格為例，新檔案看到 - 會刪除，看到 + 會加入！好了，那麼如何將舊的檔案更新成為新的內容呢？ 就是將 passwd.old 改成與 passwd.new 相同！可以這樣做：

[root@www ~]# patch -pN < patch_file    <==更新

[root@www ~]# patch -R -pN < patch_file <==還原

選項與參數：

-p  ：後面可以接『取消幾層目錄』的意思。

-R  ：代表還原，將新的檔案還原成原來舊的版本。

範例二：將剛剛製作出來的 patch file 用來更新舊版資料

[root@www test]# patch -p0 < passwd.patch

patching file passwd.old

[root@www test]# ll passwd*

-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new

-rw-r--r-- 1 root root 1929 Feb 10 15:12 passwd.old <==檔案一模一樣！

範例三：恢復舊檔案的內容

[root@www test]# patch -R -p0 < passwd.patch

[root@www test]# ll passwd*

-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new

-rw-r--r-- 1 root root 1986 Feb 10 15:18 passwd.old

# 檔案就這樣恢復成為舊版本囉

為什麼這裡會使用 -p0 呢？因為我們在比對新舊版的資料時是在同一個目錄下， 因此不需要減去目錄啦！如果是使用整體目錄比對 (diff 舊目錄 新目錄) 時， 就得要依據建立 patch 檔案所在目錄來進行目錄的刪減囉！

更詳細的 patch 用法我們會在後續的第五篇的原始碼編譯 (第二十二章)再跟大家介紹， 這裡僅是介紹給你，我們可以利用 diff 來比對兩個檔案之間的差異， 更可進一步利用這個功能來製作修補檔案 (patch file) ，讓大家更容易進行比對與升級呢！很不賴吧！ ^_^

檔案列印準備： pr

如果你曾經使用過一些圖形介面的文書處理軟體的話，那麼很容易發現，當我們在列印的時候， 可以同時選擇與設定每一頁列印時的標頭吧！也可以設定頁碼呢！那麼，如果我是在 Linux 底下列印純文字檔呢 可不可以具有標題啊？可不可以加入頁碼啊？呵呵！當然可以啊！使用 pr 就能夠達到這個功能了。不過， pr 的參數實在太多了，鳥哥也說不完，一般來說，鳥哥都僅使用最簡單的方式來處理而已。舉例來說，如果想要列印 /etc/man.config 呢？

[root@www ~]# pr /etc/man.config

2007-01-06 18:24                 /etc/man.config                  Page 1

#

# Generated automatically from man.conf.in by the

# configure script.

.....以下省略......

上面特殊字體那一行呢，其實就是使用 pr 處理後所造成的標題啦！標題中會有『檔案時間』、『檔案檔名』及『頁碼』三大項目。 更多的 pr 使用，請參考 pr 的說明啊！ ^_^

重點回顧

- 正規表示法就是處理字串的方法，他是以行為單位來進行字串的處理行為；

- 正規表示法透過一些特殊符號的輔助，可以讓使用者輕易的達到『搜尋/刪除/取代』某特定字串的處理程序；

- 只要工具程式支援正規表示法，那麼該工具程式就可以用來作為正規表示法的字串處理之用；

- 正規表示法與萬用字元是完全不一樣的東西！萬用字元 (wildcard) 代表的是 bash 操作介面的一個功能， 但正規表示法則是一種字串處理的表示方式！

- 使用 grep 或其他工具進行正規表示法的字串比對時，因為編碼的問題會有不同的狀態，因此， 你最好將 LANG 等變數設定為 C 或者是 en 等英文語系！

- grep 與 egrep 在正規表示法裡面是很常見的兩支程式，其中， egrep 支援更嚴謹的正規表示法的語法；

- 由於編碼系統的不同，不同的語系 (LANG) 會造成正規表示法擷取資料的差異。因此可利用特殊符號如 [:upper:] 來替代編碼範圍較佳；

- 由於嚴謹度的不同，正規表示法之上還有更嚴謹的延伸正規表示法；

- 基礎正規表示法的特殊字符有： *, ., [], [-], [^], ^, $ 等！

- 常見的正規表示法工具有： grep , sed, vim 等等

- printf 可以透過一些特殊符號來將資料進行格式化輸出；

- awk 可以使用『欄位』為依據，進行資料的重新整理與輸出；

- 文件的比對中，可利用 diff 及 cmp 進行比對，其中 diff 主要用在純文字檔案方面的新舊版本比對

- patch 指令可以將舊版資料更新到新版 (主要亦由 diff 建立 patch 的補丁來源檔案)

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：透過 grep 搜尋特殊字串，並配合資料流重導向來處理大量的檔案搜尋問題。

- 目標：正確的使用正規表示法；

- 前提：需要瞭解資料流重導向，以及透過子指令 $(command) 來處理檔名的搜尋；

我們簡單的以搜尋星號 (*) 來處理底下的任務：

- 利用正規表示法找出系統中含有某些特殊關鍵字的檔案，舉例來說，找出在 /etc 底下含有星號 (*) 的檔案與內容：

解決的方法必須要搭配萬用字元，但是星號本身就是正規表示法的字符，因此需要如此進行：

[root@www ~]# grep '\*' /etc/*

你必須要注意的是，在單引號內的星號是正規表示法的字符，但我們要找的是星號，因此需要加上跳脫字符 (\)。但是在 /etc/* 的那個 * 則是 bash 的萬用字元！ 代表的是檔案的檔名喔！不過由上述的這個結果中，我們僅能找到 /etc 底下第一層子目錄的資料，無法找到次目錄的資料， 如果想要連同完整的 /etc 次目錄資料，就得要這樣做：

[root@www ~]# grep '\*' $(find /etc -type f)

- 但如果檔案數量太多呢？如同上述的案例，如果要找的是全系統 (/) 呢？你可以這樣做：

[root@www ~]# grep '\*' $(find / -type f)

-bash: /bin/grep: Argument list too long

真要命！由於指令列的內容長度是有限制的，因此當搜尋的對象是整個系統時，上述的指令會發生錯誤。那該如何是好？ 此時我們可以透過管線命令以及 xargs 來處理。舉例來說，讓 grep 每次僅能處理 10 個檔名，此時你可以這樣想：

1. 先用 find 去找出檔案；

2. 用 xargs 將這些檔案每次丟 10 個給 grep 來作為參數處理；

3. grep 實際開始搜尋檔案內容。

所以整個作法就會變成這樣：

[root@www ~]# find / -type f | xargs -n 10 grep '\*'

- 從輸出的結果來看，資料量實在非常龐大！那如果我只是想要知道檔名而已呢？你可以透過 grep 的功能來找到如下的參數！

[root@www ~]# find / -type f | xargs -n 10 grep -l '\*'

- 情境模擬題二：使用管線命令配合正規表示法建立新指令與新變數。我想要建立一個新的指令名為 myip ， 這個指令能夠將我系統的 IP 捉出來顯示。而我想要有個新變數，變數名為 MYIP ，這個變數可以記錄我的 IP 。

處理的方式很簡單，我們可以這樣試看看：

- 首先，我們依據本章內的 ifconfig, sed 與 awk 來取得我們的 IP ，指令為：

[root@www ~]# ifconfig eth0 | grep 'inet addr' | \

>  sed 's/^.*inet addr://g'| cut -d ' ' -f1

- 再來，我們可以將此指令利用 alias 指定為 myip 喔！如下所示：

[root@www ~]# alias myip="ifconfig eth0 | grep 'inet addr' | \

>  sed 's/^.*inet addr://g'| cut -d ' ' -f1 "

- 最終，我們可以透過變數設定來處理 MYIP 喔！

[root@www ~]# MYIP=$( myip )

- 如果每次登入都要生效，可以將 alias 與 MYIP 的設定那兩行，寫入你的 ~/.bashrc 即可！

簡答題部分：

- 我想要知道，在 /etc 底下，只要含有 XYZ 三個字元的任何一個字元的那一行就列出來，要怎樣進行？

grep [XYZ] /etc/*

- 將 /etc/termcap 內容取出後，(1)去除開頭為 # 的行 (2)去除空白行 (3)取出開頭為英文字母的那幾行 (4)最終統計總行數該如何進行？

grep -v '^#' /etc/termcap | grep -v '^$' | grep '^[[:alpha:]]' | wc -l

參考資料與延伸閱讀

- 註1：關於正規表示法與 POSIX 及特殊語法的參考網址可以查詢底下的來源：

維基百科的說明：http://en.wikipedia.org/wiki/Regular_expression

ZYTRAX 網站介紹：http://zytrax.com/tech/web/regex.htm

- 註2：其他關於正規表示法的網站介紹：

洪朝貴老師的網頁：http://www.cyut.edu.tw/~ckhung/b/re/index.php

龍門少尉的窩：http://main.rtfiber.com.tw/~changyj/

PCRE 官方網站：http://perldoc.perl.org/perlre.html

- 註3：關於 ASCII 編碼對照表可參考維基百科的介紹：

維基百科 (ASCII) 條目： http://zh.wikipedia.org/w/index.php?title=ASCII&variant=zh-tw

- 註4：關於 awk 的進階文獻，包括有底下幾個連結：

中研院計算中心 ASPAC 計畫之 awk 程式介紹：http://phi.sinica.edu.tw/aspac/reports/94/94011/

鳥哥備份：http://linux.vbird.org/linux_basic/0330regularex/awk.pdf

這份文件寫的非常棒！歡迎大家多多參考！

Study Area：http://www.study-area.org/linux/system/linux_shell.htm

2002/07/29：第一次完成；

2003/02/10：重新編排與加入 FAQ ；

2005/01/28：重新彙整基礎正規表示法的內容！重點在 regular_express.txt 的處理與練習上！

2005/03/30：修訂了 grep -n 'goo*g' regular_express.txt 這一段

2005/05/23：修訂了 grep -n '^[a-z]' regular_express.txt 所要擷取的是小寫，之前寫成大寫，錯了！

2005/08/22：加入了 awk, sed 等工具的介紹，還有 diff 與 cmp 等指令的說明！

2005/09/05：加入 printf 內，關於 \xNN 的說明！

2006/03/10：將原本的 sed 內的動作(action)中， s 由『搜尋』改成『取代』了！

2006/10/05：在 sed 當中多了一個 -i 的參數說明，也多了一個範例八可以參考。感謝討論區的thyme兄！

2008/10/08：加入 grep 內的 --color=auto 說明！

2009/02/07：將舊的基於 FC4 版本的文章移動到此處

2009/02/10：重新排版，並且加入語系的說明，以及特殊 [:資料:] 的說明！更改不少範例的說明。

2009/05/14：感謝網友 Jack 的回報， cmp 應該是使用『位元組 bytes』而非位元 bits，感謝 Jack 兄。

2009/08/26：加入情境模擬題目了！

2010/04/16：由linux_task兄提供的意見， 將原本的 * 說明訂正一些部分，可讀性較佳！感謝您！

2002/06/28 以來統計人數

第十三章、學習 Shell Scripts

切換解析度為 800x600

最近更新日期：2009/02/18

如果你真的很想要走資訊這條路，並且想要管理好屬於你的主機，那麼，別說鳥哥不告訴你， 可以自動管理系統的好工具： Shell scripts！這傢伙真的是得要好好學習學習的！ 基本上， shell script 有點像是早期的批次檔，亦即是將一些指令彙整起來一次執行，但是 Shell script 擁有更強大的功能，那就是他可以進行類似程式 (program) 的撰寫，並且不需要經過編譯 (compile) 就能夠執行， 真的很方便。加上我們可透過 shell script 來簡化我們日常的工作管理， 而且，整個 Linux 環境中，一些服務 (services) 的啟動都是透過 shell script 的， 如果你對於 script 不瞭解，嘿嘿！發生問題時，可真是會求助無門喔！所以，好好的學一學他吧！

1. 什麼是 Shell Script

1.1 幹嘛學習 shell scripts

1.2 第一支 script 的撰寫與執行

1.3 撰寫 shell script 的良好習慣建立

2. 簡單的 shell script 練習

2.1 簡單範例： 對談式腳本, 隨日期變化, 數值運算

2.2 script 的執行方式差異 (source, sh script, ./script)

3. 善用判斷式

3.1 利用 test 指令的測試功能

3.2 利用判斷符號 [ ]

3.3 Shell script 的預設變數($0, $1...)： shift

4. 條件判斷式

4.1 利用 if .... then： 單層簡單條件, 多重複雜條件, 檢驗$1內容, 網路狀態, 退伍

4.2 利用 case ..... esac 判斷

4.3 利用 function 功能

5. 迴圈 (loop)

5.1 while...do...done, until...do...done (不定迴圈)

5.2 for...do...done (固定迴圈)： 帳號檢查, 網路狀態 $(seq )

5.3 for...do...done 的數值處理

6. shell script 的追蹤與 debug

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23886

什麼是 Shell scripts

什麼是 shell script (程式化腳本) 呢？就字面上的意義，我們將他分為兩部份。 在『 shell 』部分，我們在 十一章的 BASH 當中已經提過了，那是一個文字介面底下讓我們與系統溝通的一個工具介面。那麼『 script 』是啥？ 字面上的意義， script 是『腳本、劇本』的意思。整句話是說， shell script 是針對 shell 所寫的『劇本！』

什麼東西啊？其實， shell script 是利用 shell 的功能所寫的一個『程式 (program)』，這個程式是使用純文字檔，將一些 shell 的語法與指令(含外部指令)寫在裡面， 搭配正規表示法、管線命令與資料流重導向等功能，以達到我們所想要的處理目的。

所以，簡單的說， shell script 就像是早期 DOS 年代的批次檔 (.bat) ，最簡單的功能就是將許多指令彙整寫在一起， 讓使用者很輕易的就能夠 one touch 的方法去處理複雜的動作 (執行一個檔案 "shell script" ，就能夠一次執行多個指令)。 而且 shell script 更提供陣列、迴圈、條件與邏輯判斷等重要功能，讓使用者也可以直接以 shell 來撰寫程式，而不必使用類似 C 程式語言等傳統程式撰寫的語法呢！

這麼說你可以瞭解了嗎？是的！ shell script 可以簡單的被看成是批次檔， 也可以被說成是一個程式語言，且這個程式語言由於都是利用 shell 與相關工具指令， 所以不需要編譯即可執行，且擁有不錯的除錯 (debug) 工具，所以，他可以幫助系統管理員快速的管理好主機。

幹嘛學習 shell scripts

這是個好問題：『我又幹嘛一定要學 shell script ？我又不是資訊人，沒有寫程式的概念， 那我幹嘛還要學 shell script 呢？不要學可不可以啊？』呵呵∼如果 Linux 對你而言， 你只是想要『會用』而已，那麼，不需要學 shell script 也還無所謂，這部分先給他跳過去， 等到有空的時候，再來好好的瞧一瞧。但是，如果你是真的想要玩清楚 Linux 的來龍去脈， 那麼 shell script 就不可不知，為什麼呢？因為：

- 自動化管理的重要依據：

不用鳥哥說你也知道，管理一部主機真不是件簡單的事情，每天要進行的任務就有： 查詢登錄檔、追蹤流量、監控使用者使用主機狀態、主機各項硬體設備狀態、 主機軟體更新查詢、更不要說得應付其他使用者的突然要求了。而這些工作的進行可以分為： (1)自行手動處理，或是 (2)寫個簡單的程式來幫你每日自動處理分析這兩種方式，你覺得哪種方式比較好？ 當然是讓系統自動工作比較好，對吧！呵呵∼這就得要良好的 shell script 來幫忙的啦！

- 追蹤與管理系統的重要工作：

雖然我們還沒有提到服務啟動的方法，不過，這裡可以先提一下，我們 Linux 系統的服務 (services) 啟動的介面是在 /etc/init.d/ 這個目錄下，目錄下的所有檔案都是 scripts ； 另外，包括開機 (booting) 過程也都是利用 shell script 來幫忙搜尋系統的相關設定資料， 然後再代入各個服務的設定參數啊！舉例來說，如果我們想要重新啟動系統登錄檔， 可以使用：『/etc/init.d/syslogd restart』，那個 syslogd 檔案就是 script 啦！

另外，鳥哥曾經在某一代的 Fedora 上面發現，啟動 MySQL 這個資料庫服務時，確實是可以啟動的， 但是螢幕上卻老是出現『failure』！後來才發現，原來是啟動 MySQL 那個 script 會主動的以『空的密碼』去嘗試登入 MySQL ，但為了安全性鳥哥修改過 MySQL 的密碼囉∼當然就登入失敗∼ 後來改了改 script ，就略去這個問題啦！如此說來， script 確實是需要學習的啊！

- 簡單入侵偵測功能：

當我們的系統有異狀時，大多會將這些異狀記錄在系統記錄器，也就是我們常提到的『系統登錄檔』， 那麼我們可以在固定的幾分鐘內主動的去分析系統登錄檔，若察覺有問題，就立刻通報管理員， 或者是立刻加強防火牆的設定規則，如此一來，你的主機可就能夠達到『自我保護』的聰明學習功能啦∼ 舉例來說，我們可以通過 shell script 去分析『當該封包嘗試幾次還是連線失敗之後，就予以抵擋住該 IP』之類的舉動，例如鳥哥寫過一個關於抵擋砍站軟體的 shell script ， 就是用這個想法去達成的呢！

- 連續指令單一化：

其實，對於新手而言， script 最簡單的功能就是：『彙整一些在 command line 下達的連續指令，將他寫入 scripts 當中，而由直接執行 scripts 來啟動一連串的 command line 指令輸入！』例如： 防火牆連續規則 (iptables)，開機載入程序的項目 (就是在 /etc/rc.d/rc.local 裡頭的資料) ，等等都是相似的功能啦！ 其實，說穿了，如果不考慮 program 的部分，那麼 scripts 也可以想成『僅是幫我們把一大串的指令彙整在一個檔案裡面， 而直接執行該檔案就可以執行那一串又臭又長的指令段！』就是這麼簡單啦！

- 簡易的資料處理：

由前一章正規表示法的 awk 程式說明中， 你可以發現， awk 可以用來處理簡單的數據資料呢！例如薪資單的處理啊等等的。 shell script 的功能更強大，例如鳥哥曾經用 shell script 直接處理數據資料的比對啊， 文字資料的處理啊等等的，撰寫方便，速度又快(因為在 Linux 效能較佳)，真的是很不錯用的啦！

- 跨平台支援與學習歷程較短：

幾乎所有的 Unix Like 上面都可以跑 shell script ，連 MS Windows 系列也有相關的 script 模擬器可以用， 此外， shell script 的語法是相當親和的，看都看的懂得文字 (雖然是英文)，而不是機器碼， 很容易學習∼這些都是你可以加以考量的學習點啊！

上面這些都是你考慮學習 shell script 的特點∼此外， shell script 還可以簡單的以 vim 來直接編寫，實在是很方便的好東西！所以，還是建議你學習一下啦。

不過，雖然 shell script 號稱是程式 (program) ，但實際上， shell script 處理資料的速度上是不太夠的。因為 shell script 用的是外部的指令與 bash shell 的一些預設工具，所以，他常常會去呼叫外部的函式庫，因此，運算速度上面當然比不上傳統的程式語言。 所以囉， shell script 用在系統管理上面是很好的一項工具，但是用在處理大量數值運算上， 就不夠好了，因為 Shell scripts 的速度較慢，且使用的 CPU 資源較多，造成主機資源的分配不良。還好， 我們通常利用 shell script 來處理伺服器的偵測，倒是沒有進行大量運算的需求啊！所以不必擔心的啦！

第一支 script 的撰寫與執行

如同前面講到的，shell script 其實就是純文字檔，我們可以編輯這個檔案，然後讓這個檔案來幫我們一次執行多個指令， 或者是利用一些運算與邏輯判斷來幫我們達成某些功能。所以啦，要編輯這個檔案的內容時，當然就需要具備有 bash 指令下達的相關認識。下達指令需要注意的事項在第五章的開始下達指令小節內已經提過，有疑問請自行回去翻閱。 在 shell script 的撰寫中還需要用到底下的注意事項：

1. 指令的執行是從上而下、從左而右的分析與執行；

2. 指令的下達就如同第五章內提到的： 指令、選項與參數間的多個空白都會被忽略掉；

3. 空白行也將被忽略掉，並且 [tab] 按鍵所推開的空白同樣視為空白鍵；

4. 如果讀取到一個 Enter 符號 (CR) ，就嘗試開始執行該行 (或該串) 命令；

5. 至於如果一行的內容太多，則可以使用『 \[Enter] 』來延伸至下一行；

6. 『 # 』可做為註解！任何加在 # 後面的資料將全部被視為註解文字而被忽略！

如此一來，我們在 script 內所撰寫的程式，就會被一行一行的執行。現在我們假設你寫的這個程式檔名是 /home/dmtsai/shell.sh 好了，那如何執行這個檔案？很簡單，可以有底下幾個方法：

- 直接指令下達： shell.sh 檔案必須要具備可讀與可執行 (rx) 的權限，然後：

- 絕對路徑：使用 /home/dmtsai/shell.sh 來下達指令；

- 相對路徑：假設工作目錄在 /home/dmtsai/ ，則使用 ./shell.sh 來執行

- 變數『PATH』功能：將 shell.sh 放在 PATH 指定的目錄內，例如： ~/bin/

- 以 bash 程式來執行：透過『 bash shell.sh 』或『 sh shell.sh 』來執行

反正重點就是要讓那個 shell.sh 內的指令可以被執行的意思啦！ 咦！那我為何需要使用 『./shell.sh 』來下達指令？忘記了嗎？回去第十一章內的指令搜尋順序察看一下， 你就會知道原因了！同時，由於 CentOS 預設使用者家目錄下的 ~/bin 目錄會被設定到 $PATH 內，所以你也可以將 shell.sh 建立在 /home/dmtsai/bin/ 底下 ( ~/bin 目錄需要自行設定) 。此時，若 shell.sh 在 ~/bin 內且具有 rx 的權限，那就直接輸入 shell.sh 即可執行該腳本程式！

那為何『 sh shell.sh 』也可以執行呢？這是因為 /bin/sh 其實就是 /bin/bash (連結檔)，使用 sh shell.sh 亦即告訴系統，我想要直接以 bash 的功能來執行 shell.sh 這個檔案內的相關指令的意思，所以此時你的 shell.sh 只要有 r 的權限即可被執行喔！而我們也可以利用 sh 的參數，如 -n 及 -x 來檢查與追蹤 shell.sh 的語法是否正確呢！ ^_^

- 撰寫第一支 script

在武俠世界中，不論是那個門派，要學武功要從掃地做起，那麼要學程式呢？呵呵，肯定是由『秀出 Hello World！』 這個字眼開始的！OK！那麼鳥哥就先寫一支 script 給大家瞧一瞧：

[root@www ~]# mkdir scripts; cd scripts

[root@www scripts]# vi sh01.sh

#!/bin/bash

# Program:

#       This program shows "Hello World!" in your screen.

# History:

# 2005/08/23   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

echo -e "Hello World! \a \n"

exit 0

在本章當中，請將所有撰寫的 script 放置到你家目錄的 ~/scripts 這個目錄內， 未來比較好管理啦！上面的寫法當中，鳥哥主要將整個程式的撰寫分成數段，大致是這樣：

1. 第一行 #!/bin/bash 在宣告這個 script 使用的 shell 名稱：

因為我們使用的是 bash ，所以，必須要以『 #!/bin/bash 』來宣告這個檔案內的語法使用 bash 的語法！那麼當這個程式被執行時，他就能夠載入 bash 的相關環境設定檔 (一般來說就是 non-login shell 的 ~/.bashrc)， 並且執行 bash 來使我們底下的指令能夠執行！這很重要的！(在很多狀況中，如果沒有設定好這一行， 那麼該程式很可能會無法執行，因為系統可能無法判斷該程式需要使用什麼 shell 來執行啊！)

2. 程式內容的說明：

整個 script 當中，除了第一行的『 #! 』是用來宣告 shell 的之外，其他的 # 都是『註解』用途！ 所以上面的程式當中，第二行以下就是用來說明整個程式的基本資料。一般來說， 建議你一定要養成說明該 script 的：1. 內容與功能； 2. 版本資訊； 3. 作者與聯絡方式； 4. 建檔日期；5. 歷史紀錄 等等。這將有助於未來程式的改寫與 debug 呢！

3. 主要環境變數的宣告：

建議務必要將一些重要的環境變數設定好，鳥哥個人認為， PATH 與 LANG (如果有使用到輸出相關的資訊時) 是當中最重要的！ 如此一來，則可讓我們這支程式在進行時，可以直接下達一些外部指令，而不必寫絕對路徑呢！比較好啦！

4. 主要程式部分

就將主要的程式寫好即可！在這個例子當中，就是 echo 那一行啦！

5. 執行成果告知 (定義回傳值)

是否記得我們在第十一章裡面要討論一個指令的執行成功與否，可以使用 $? 這個變數來觀察∼ 那麼我們也可以利用 exit 這個指令來讓程式中斷，並且回傳一個數值給系統。 在我們這個例子當中，鳥哥使用 exit 0 ，這代表離開 script 並且回傳一個 0 給系統， 所以我執行完這個 script 後，若接著下達 echo $? 則可得到 0 的值喔！ 更聰明的讀者應該也知道了，呵呵！利用這個 exit n (n 是數字) 的功能，我們還可以自訂錯誤訊息， 讓這支程式變得更加的 smart 呢！

接下來透過剛剛上頭介紹的執行方法來執行看看結果吧！

[root@www scripts]# sh sh01.sh

Hello World !

你會看到螢幕是這樣，而且應該還會聽到『咚』的一聲，為什麼呢？還記得前一章提到的 printf 吧？用 echo 接著那些特殊的按鍵也可以發生同樣的事情∼ 不過， echo 必須要加上 -e 的選項才行！呵呵！在你寫完這個小 script 之後，你就可以大聲的說：『我也會寫程式了』！哈哈！ 很簡單有趣吧∼ ^_^

另外，你也可以利用：『chmod a+x sh01.sh; ./sh01.sh』來執行這個 script 的呢！

撰寫 shell script 的良好習慣建立

一個良好習慣的養成是很重要的∼大家在剛開始撰寫程式的時候，最容易忽略這部分， 認為程式寫出來就好了，其他的不重要。其實，如果程式的說明能夠更清楚，那麼對你自己是有很大的幫助的。

舉例來說，鳥哥自己為了自己的需求，曾經撰寫了不少的 script 來幫我進行主機 IP 的偵測啊、 登錄檔分析與管理啊、自動上傳下載重要設定檔啊等等的，不過，早期就是因為太懶了， 管理的主機又太多了，常常同一個程式在不同的主機上面進行更改，到最後，到底哪一支才是最新的都記不起來， 而且，重點是，我到底是改了哪裡？為什麼做那樣的修改？都忘的一乾二淨∼真要命∼

所以，後來鳥哥在寫程式的時候，通常會比較仔細的將程式的設計過程給他記錄下來，而且還會記錄一些歷史紀錄， 如此一來，好多了∼至少很容易知道我修改了哪些資料，以及程式修改的理念與邏輯概念等等， 在維護上面是輕鬆很多很多的喔！

另外，在一些環境的設定上面，畢竟每個人的環境都不相同，為了取得較佳的執行環境， 我都會自行先定義好一些一定會被用到的環境變數，例如 PATH 這個玩意兒！ 這樣比較好啦∼所以說，建議你一定要養成良好的 script 撰寫習慣，在每個 script 的檔頭處記錄好：

- script 的功能；

- script 的版本資訊；

- script 的作者與聯絡方式；

- script 的版權宣告方式；

- script 的 History (歷史紀錄)；

- script 內較特殊的指令，使用『絕對路徑』的方式來下達；

- script 運作時需要的環境變數預先宣告與設定。

除了記錄這些資訊之外，在較為特殊的程式碼部分，個人建議務必要加上註解說明，可以幫助你非常非常多！ 此外，程式碼的撰寫最好使用巢狀方式，在包覆的內部程式碼最好能以 [tab] 按鍵的空格向後推， 這樣你的程式碼會顯的非常的漂亮與有條理！在查閱與 debug 上較為輕鬆愉快喔！ 另外，使用撰寫 script 的工具最好使用 vim 而不是 vi ，因為 vim 會有額外的語法檢驗機制，能夠在第一階段撰寫時就發現語法方面的問題喔！

簡單的 shell script 練習

在第一支 shell script 撰寫完畢之後，相信你應該具有基本的撰寫功力了。 接下來，在開始更深入的程式概念之前，我們先來玩一些簡單的小範例好了。 底下的範例中，達成結果的方式相當的多，建議你先自行撰寫看看，寫完之後再與鳥哥寫的內容比對， 這樣才能更加深概念喔！好！不囉唆，我們就一個一個來玩吧！

簡單範例

底下的範例在很多的腳本程式中都會用到，而底下的範例又都很簡單！值得參考看看喔！

- 對談式腳本：變數內容由使用者決定

很多時候我們需要使用者輸入一些內容，好讓程式可以順利運作。 簡單的來說，大家應該都有安裝過軟體的經驗，安裝的時候，他不是會問你『要安裝到那個目錄去』嗎？ 那個讓使用者輸入資料的動作，就是讓使用者輸入變數內容啦。

你應該還記得在十一章 bash 的時候，我們有學到一個 read 指令吧？現在，請你以 read 指令的用途，撰寫一個 script ，他可以讓使用者輸入：1. first name 與 2. last name， 最後並且在螢幕上顯示：『Your full name is: 』的內容：

[root@www scripts]# vi sh02.sh

#!/bin/bash

# Program:

#       User inputs his first name and last name.  Program shows his full name.

# History:

# 2005/08/23   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

read -p "Please input your first name: " firstname  # 提示使用者輸入

read -p "Please input your last name:  " lastname   # 提示使用者輸入

echo -e "\nYour full name is: $firstname $lastname" # 結果由螢幕輸出

將上面這個 sh02.sh 執行一下，你就能夠發現使用者自己輸入的變數可以讓程式所取用，並且將他顯示到螢幕上！ 接下來，如果想要製作一個每次執行都會依據不同的日期而變化結果的腳本呢？

- 隨日期變化：利用 date 進行檔案的建立

想像一個狀況，假設我的伺服器內有資料庫，資料庫每天的資料都不太一樣，因此當我備份時， 希望將每天的資料都備份成不同的檔名，這樣才能夠讓舊的資料也能夠保存下來不被覆蓋。 哇！不同檔名呢！這真困擾啊？難道要我每天去修改 script ？

不需要啊！考慮每天的『日期』並不相同，所以我可以將檔名取成類似： backup.2009-02-14.data ， 不就可以每天一個不同檔名了嗎？呵呵！確實如此。那個 2009-02-14 怎麼來的？那就是重點啦！接下來出個相關的例子： 假設我想要建立三個空的檔案 (透過 touch) ，檔名最開頭由使用者輸入決定，假設使用者輸入 filename 好了，那今天的日期是 2009/02/14 ， 我想要以前天、昨天、今天的日期來建立這些檔案，亦即 filename_20090212, filename_20090213, filename_20090214 ，該如何是好？

[root@www scripts]# vi sh03.sh

#!/bin/bash

# Program:

#       Program creates three files, which named by user's input

#       and date command.

# History:

# 2005/08/23   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

# 1. 讓使用者輸入檔案名稱，並取得 fileuser 這個變數；

echo -e "I will use 'touch' command to create 3 files." # 純粹顯示資訊

read -p "Please input your filename: " fileuser         # 提示使用者輸入

# 2. 為了避免使用者隨意按 Enter ，利用變數功能分析檔名是否有設定？

filename=${fileuser:-"filename"}           # 開始判斷有否設定檔名

# 3. 開始利用 date 指令來取得所需要的檔名了；

date1=$(date --date='2 days ago' +%Y%m%d)  # 前兩天的日期

date2=$(date --date='1 days ago' +%Y%m%d)  # 前一天的日期

date3=$(date +%Y%m%d)                      # 今天的日期

file1=${filename}${date1}                  # 底下三行在設定檔名

file2=${filename}${date2}

file3=${filename}${date3}

# 4. 將檔名建立吧！

touch "$file1"                             # 底下三行在建立檔案

touch "$file2"

touch "$file3"

上面的範例鳥哥使用了很多在十一章介紹過的概念： 包括小指令『 $(command) 』的取得訊息、變數的設定功能、變數的累加以及利用 touch 指令輔助！ 如果你開始執行這個 sh03.sh 之後，你可以進行兩次執行：一次直接按 [Enter] 來查閱檔名是啥？ 一次可以輸入一些字元，這樣可以判斷你的腳本是否設計正確喔！

- 數值運算：簡單的加減乘除

各位看官應該還記得，我們可以使用 declare 來定義變數的類型吧？ 當變數定義成為整數後才能夠進行加減運算啊！此外，我們也可以利用『 $((計算式)) 』來進行數值運算的。 可惜的是， bash shell 裡頭預設僅支援到整數的資料而已。OK！那我們來玩玩看，如果我們要使用者輸入兩個變數， 然後將兩個變數的內容相乘，最後輸出相乘的結果，那可以怎麼做？

[root@www scripts]# vi sh04.sh

#!/bin/bash

# Program:

#       User inputs 2 integer numbers; program will cross these two numbers.

# History:

# 2005/08/23   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

echo -e "You SHOULD input 2 numbers, I will cross them! \n"

read -p "first number:  " firstnu

read -p "second number: " secnu

total=$(($firstnu*$secnu))

echo -e "\nThe result of $firstnu x $secnu is ==> $total"

在數值的運算上，我們可以使用『 declare -i total=$firstnu*$secnu 』 也可以使用上面的方式來進行！基本上，鳥哥比較建議使用這樣的方式來進行運算：

var=$((運算內容))

不但容易記憶，而且也比較方便的多，因為兩個小括號內可以加上空白字元喔！ 未來你可以使用這種方式來計算的呀！至於數值運算上的處理，則有：『 +, -, *, /, % 』等等。 那個 % 是取餘數啦∼舉例來說， 13 對 3 取餘數，結果是 13=4*3+1，所以餘數是 1 啊！就是：

[root@www scripts]# echo $(( 13 % 3 ))

1

這樣瞭解了吧？多多學習與應用喔！ ^_^

script 的執行方式差異 (source, sh script, ./script)

不同的 script 執行方式會造成不一樣的結果喔！尤其影響 bash 的環境很大呢！腳本的執行方式除了前面小節談到的方式之外，還可以利用 source 或小數點 (.) 來執行喔！那麼這種執行方式有何不同呢？當然是不同的啦！讓我們來說說！

- 利用直接執行的方式來執行 script

當使用前一小節提到的直接指令下達 (不論是絕對路徑/相對路徑還是 $PATH 內)，或者是利用 bash (或 sh) 來下達腳本時， 該 script 都會使用一個新的 bash 環境來執行腳本內的指令！也就是說，使用者種執行方式時， 其實 script 是在子程序的 bash 內執行的！我們在第十一章 BASH 內談到 export 的功能時，曾經就父程序/子程序談過一些概念性的問題， 重點在於：『當子程序完成後，在子程序內的各項變數或動作將會結束而不會傳回到父程序中』！ 這是什麼意思呢？

我們舉剛剛提到過的 sh02.sh 這個腳本來說明好了，這個腳本可以讓使用者自行設定兩個變數，分別是 firstname 與 lastname，想一想，如果你直接執行該指令時，該指令幫你設定的 firstname 會不會生效？看一下底下的執行結果：

[root@www scripts]# echo $firstname $lastname

<==確認了，這兩個變數並不存在喔！

[root@www scripts]# sh sh02.sh

Please input your first name: VBird <==這個名字是鳥哥自己輸入的

Please input your last name:  Tsai

Your full name is: VBird Tsai      <==看吧！在 script 運作中，這兩個變數有生效

[root@www scripts]# echo $firstname $lastname

<==事實上，這兩個變數在父程序的 bash 中還是不存在的！

上面的結果你應該會覺得很奇怪，怎麼我已經利用 sh02.sh 設定好的變數竟然在 bash 環境底下無效！怎麼回事呢？ 如果將程序相關性繪製成圖的話，我們以下圖來說明。當你使用直接執行的方法來處理時，系統會給予一支新的 bash 讓我們來執行 sh02.sh 裡面的指令，因此你的 firstname, lastname 等變數其實是在下圖中的子程序 bash 內執行的。 當 sh02.sh 執行完畢後，子程序 bash 內的所有資料便被移除，因此上表的練習中，在父程序底下 echo $firstname 時， 就看不到任何東西了！這樣可以理解嗎？

圖 2.2.1、sh02.sh 在子程序中運作

- 利用 source 來執行腳本：在父程序中執行

如果你使用 source 來執行指令那就不一樣了！同樣的腳本我們來執行看看：

[root@www scripts]# source sh02.sh

Please input your first name: VBird

Please input your last name:  Tsai

Your full name is: VBird Tsai

[root@www scripts]# echo $firstname $lastname

VBird Tsai  <==嘿嘿！有資料產生喔！

竟然生效了！沒錯啊！因為 source 對 script 的執行方式可以使用底下的圖示來說明！ sh02.sh 會在父程序中執行的，因此各項動作都會在原本的 bash 內生效！這也是為啥你不登出系統而要讓某些寫入 ~/.bashrc 的設定生效時，需要使用『 source ~/.bashrc 』而不能使用『 bash ~/.bashrc 』是一樣的啊！

圖 2.2.2、sh02.sh 在父程序中運作

善用判斷式

在第十一章中，我們提到過 $? 這個變數所代表的意義， 此外，也透過 && 及 || 來作為前一個指令執行回傳值對於後一個指令是否要進行的依據。第十一章的討論中，如果想要判斷一個目錄是否存在， 當時我們使用的是 ls 這個指令搭配資料流重導向，最後配合 $? 來決定後續的指令進行與否。 但是否有更簡單的方式可以來進行『條件判斷』呢？有的∼那就是『 test 』這個指令。

利用 test 指令的測試功能

當我要檢測系統上面某些檔案或者是相關的屬性時，利用 test 這個指令來工作真是好用得不得了， 舉例來說，我要檢查 /dmtsai 是否存在時，使用：

[root@www ~]# test -e /dmtsai

執行結果並不會顯示任何訊息，但最後我們可以透過 $? 或 && 及 || 來展現整個結果呢！ 例如我們在將上面的例子改寫成這樣：

[root@www ~]# test -e /dmtsai && echo "exist" || echo "Not exist"

Not exist  <==結果顯示不存在啊！

最終的結果可以告知我們是『exist』還是『Not exist』呢！那我知道 -e 是測試一個『東西』在不在， 如果還想要測試一下該檔名是啥玩意兒時，還有哪些標誌可以來判斷的呢？呵呵！有底下這些東西喔！

測試的標誌

代表意義

1. 關於某個檔名的『檔案類型』判斷，如 test -e filename 表示存在否

-e

該『檔名』是否存在？(常用)

-f

該『檔名』是否存在且為檔案(file)？(常用)

-d

該『檔名』是否存在且為目錄(directory)？(常用)

-b

該『檔名』是否存在且為一個 block device 裝置？

-c

該『檔名』是否存在且為一個 character device 裝置？

-S

該『檔名』是否存在且為一個 Socket 檔案？

-p

該『檔名』是否存在且為一個 FIFO (pipe) 檔案？

-L

該『檔名』是否存在且為一個連結檔？

2. 關於檔案的權限偵測，如 test -r filename 表示可讀否 (但 root 權限常有例外)

-r

偵測該檔名是否存在且具有『可讀』的權限？

-w

偵測該檔名是否存在且具有『可寫』的權限？

-x

偵測該檔名是否存在且具有『可執行』的權限？

-u

偵測該檔名是否存在且具有『SUID』的屬性？

-g

偵測該檔名是否存在且具有『SGID』的屬性？

-k

偵測該檔名是否存在且具有『Sticky bit』的屬性？

-s

偵測該檔名是否存在且為『非空白檔案』？

3. 兩個檔案之間的比較，如： test file1 -nt file2

-nt

(newer than)判斷 file1 是否比 file2 新

-ot

(older than)判斷 file1 是否比 file2 舊

-ef

判斷 file1 與 file2 是否為同一檔案，可用在判斷 hard link 的判定上。 主要意義在判定，兩個檔案是否均指向同一個 inode 哩！

4. 關於兩個整數之間的判定，例如 test n1 -eq n2

-eq

兩數值相等 (equal)

-ne

兩數值不等 (not equal)

-gt

n1 大於 n2 (greater than)

-lt

n1 小於 n2 (less than)

-ge

n1 大於等於 n2 (greater than or equal)

-le

n1 小於等於 n2 (less than or equal)

5. 判定字串的資料

test -z string

判定字串是否為 0 ？若 string 為空字串，則為 true

test -n string

判定字串是否非為 0 ？若 string 為空字串，則為 false。

註： -n 亦可省略

test str1 = str2

判定 str1 是否等於 str2 ，若相等，則回傳 true

test str1 != str2

判定 str1 是否不等於 str2 ，若相等，則回傳 false

6. 多重條件判定，例如： test -r filename -a -x filename

-a

(and)兩狀況同時成立！例如 test -r file -a -x file，則 file 同時具有 r 與 x 權限時，才回傳 true。

-o

(or)兩狀況任何一個成立！例如 test -r file -o -x file，則 file 具有 r 或 x 權限時，就可回傳 true。

!

反相狀態，如 test ! -x file ，當 file 不具有 x 時，回傳 true

OK！現在我們就利用 test 來幫我們寫幾個簡單的例子。首先，判斷一下，讓使用者輸入一個檔名，我們判斷：

1. 這個檔案是否存在，若不存在則給予一個『Filename does not exist』的訊息，並中斷程式；

2. 若這個檔案存在，則判斷他是個檔案或目錄，結果輸出『Filename is regular file』或 『Filename is directory』

3. 判斷一下，執行者的身份對這個檔案或目錄所擁有的權限，並輸出權限資料！

你可以先自行創作看看，然後再跟底下的結果討論討論。注意利用 test 與 && 還有 || 等標誌！

[root@www scripts]# vi sh05.sh

#!/bin/bash

# Program:

#       User input a filename, program will check the flowing:

#       1.) exist? 2.) file/directory? 3.) file permissions

# History:

# 2005/08/25   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

# 1. 讓使用者輸入檔名，並且判斷使用者是否真的有輸入字串？

echo -e "Please input a filename, I will check the filename's type and \

permission. \n\n"

read -p "Input a filename : " filename

test -z $filename && echo "You MUST input a filename." && exit 0

# 2. 判斷檔案是否存在？若不存在則顯示訊息並結束腳本

test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0

# 3. 開始判斷檔案類型與屬性

test -f $filename && filetype="regulare file"

test -d $filename && filetype="directory"

test -r $filename && perm="readable"

test -w $filename && perm="$perm writable"

test -x $filename && perm="$perm executable"

# 4. 開始輸出資訊！

echo "The filename: $filename is a $filetype"

echo "And the permissions are : $perm"

如果你執行這個腳本後，他會依據你輸入的檔名來進行檢查喔！先看是否存在，再看為檔案或目錄類型，最後判斷權限。 但是你必須要注意的是，由於 root 在很多權限的限制上面都是無效的，所以使用 root 執行這個腳本時， 常常會發現與 ls -l 觀察到的結果並不相同！所以，建議使用一般使用者來執行這個腳本試看看。 不過你必須要使用 root 的身份先將這個腳本搬移給使用者就是了，不然一般使用者無法進入 /root 目錄的。 很有趣的例子吧！你可以自行再以其他的案例來撰寫一下可用的功能呢！

利用判斷符號 [ ]

除了我們很喜歡使用的 test 之外，其實，我們還可以利用判斷符號『 [ ] 』(就是中括號啦) 來進行資料的判斷呢！ 舉例來說，如果我想要知道 $HOME 這個變數是否為空的，可以這樣做：

[root@www ~]# [ -z "$HOME" ] ; echo $?

使用中括號必須要特別注意，因為中括號用在很多地方，包括萬用字元與正規表示法等等，所以如果要在 bash 的語法當中使用中括號作為 shell 的判斷式時，必須要注意中括號的兩端需要有空白字元來分隔喔！ 假設我空白鍵使用『□』符號來表示，那麼，在這些地方你都需要有空白鍵：

[  "$HOME"  ==  "$MAIL"  ]

[□"$HOME"□==□"$MAIL"□]

↑       ↑  ↑       ↑

Tips:

你會發現鳥哥在上面的判斷式當中使用了兩個等號『 == 』。其實在 bash 當中使用一個等號與兩個等號的結果是一樣的！ 不過在一般慣用程式的寫法中，一個等號代表『變數的設定』，兩個等號則是代表『邏輯判斷 (是否之意)』。 由於我們在中括號內重點在於『判斷』而非『設定變數』，因此鳥哥建議您還是使用兩個等號較佳！

上面的例子在說明，兩個字串 $HOME 與 $MAIL 是否相同的意思，相當於 test $HOME = $MAIL 的意思啦！ 而如果沒有空白分隔，例如 [$HOME==$MAIL] 時，我們的 bash 就會顯示錯誤訊息了！這可要很注意啊！ 所以說，你最好要注意：

- 在中括號 [] 內的每個元件都需要有空白鍵來分隔；

- 在中括號內的變數，最好都以雙引號括號起來；

- 在中括號內的常數，最好都以單或雙引號括號起來。

為什麼要這麼麻煩啊？直接舉例來說，假如我設定了 name="VBird Tsai" ，然後這樣判定：

[root@www ~]# name="VBird Tsai"

[root@www ~]# [ $name == "VBird" ]

bash: [: too many arguments

見鬼了！怎麼會發生錯誤啊？bash 還跟我說錯誤是由於『太多參數 (arguments)』所致！ 為什麼呢？因為 $name 如果沒有使用雙引號刮起來，那麼上面的判定式會變成：

[ VBird Tsai == "VBird" ]

上面肯定不對嘛！因為一個判斷式僅能有兩個資料的比對，上面 VBird 與 Tsai 還有 "VBird" 就有三個資料！ 這不是我們要的！我們要的應該是底下這個樣子：

[ "VBird Tsai" == "VBird" ]

這可是差很多的喔！另外，中括號的使用方法與 test 幾乎一模一樣啊∼ 只是中括號比較常用在條件判斷式 if ..... then ..... fi 的情況中就是了。 好，那我們也使用中括號的判斷來做一個小案例好了，案例設定如下：

1. 當執行一個程式的時候，這個程式會讓使用者選擇 Y 或 N ，

2. 如果使用者輸入 Y 或 y 時，就顯示『 OK, continue 』

3. 如果使用者輸入 n 或 N 時，就顯示『 Oh, interrupt ！』

4. 如果不是 Y/y/N/n 之內的其他字元，就顯示『 I don't know what your choice is 』

利用中括號、 && 與 || 來繼續吧！

[root@www scripts]# vi sh06.sh

#!/bin/bash

# Program:

#       This program shows the user's choice

# History:

# 2005/08/25   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

read -p "Please input (Y/N): " yn

[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0

[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0

echo "I don't know what your choice is" && exit 0

由於輸入正確 (Yes) 的方法有大小寫之分，不論輸入大寫 Y 或小寫 y 都是可以的，此時判斷式內就得要有兩個判斷才行！ 由於是任何一個成立即可 (大小或小寫的 y) ，所以這裡使用 -o (或) 連結兩個判斷喔！ 很有趣吧！利用這個字串判別的方法，我們就可以很輕鬆的將使用者想要進行的工作分門別類呢！ 接下來，我們再來談一些其他有的沒有的東西吧！

Shell script 的預設變數($0, $1...)

我們知道指令可以帶有選項與參數，例如 ls -la 可以察看包含隱藏檔的所有屬性與權限。那麼 shell script 能不能在腳本檔名後面帶有參數呢？很有趣喔！舉例來說，如果你想要重新啟動系統登錄檔的功能，可以這樣做：

[root@www ~]# file /etc/init.d/syslog

/etc/init.d/syslog: Bourne-Again shell script text executable

# 使用 file 來查詢後，系統告知這個檔案是個 bash 的可執行 script 喔！

[root@www ~]# /etc/init.d/syslog restart

restart 是重新啟動的意思，上面的指令可以『重新啟動 /etc/init.d/syslog 這支程式』的意思！ 唔！那麼如果你在 /etc/init.d/syslog 後面加上 stop 呢？沒錯！就可以直接關閉該服務了！這麼神奇啊？ 沒錯啊！如果你要依據程式的執行給予一些變數去進行不同的任務時，本章一開始是使用 read 的功能！但 read 功能的問題是你得要手動由鍵盤輸入一些判斷式。如果透過指令後面接參數， 那麼一個指令就能夠處理完畢而不需要手動再次輸入一些變數行為！這樣下達指令會比較簡單方便啦！

script 是怎麼達成這個功能的呢？其實 script 針對參數已經有設定好一些變數名稱了！對應如下：

/path/to/scriptname  opt1  opt2  opt3  opt4

$0             $1    $2    $3    $4

這樣夠清楚了吧？執行的腳本檔名為 $0 這個變數，第一個接的參數就是 $1 啊∼ 所以，只要我們在 script 裡面善用 $1 的話，就可以很簡單的立即下達某些指令功能了！除了這些數字的變數之外， 我們還有一些較為特殊的變數可以在 script 內使用來呼叫這些參數喔！

- $# ：代表後接的參數『個數』，以上表為例這裡顯示為『 4 』；

- $@ ：代表『 "$1" "$2" "$3" "$4" 』之意，每個變數是獨立的(用雙引號括起來)；

- $* ：代表『 "$1c$2c$3c$4" 』，其中 c 為分隔字元，預設為空白鍵， 所以本例中代表『 "$1 $2 $3 $4" 』之意。

那個 $@ 與 $* 基本上還是有所不同啦！不過，一般使用情況下可以直接記憶 $@ 即可！ 好了，來做個例子吧∼假設我要執行一個可以攜帶參數的 script ，執行該腳本後螢幕會顯示如下的資料：

- 程式的檔名為何？

- 共有幾個參數？

- 若參數的個數小於 2 則告知使用者參數數量太少

- 全部的參數內容為何？

- 第一個參數為何？

- 第二個參數為何

[root@www scripts]# vi sh07.sh

#!/bin/bash

# Program:

#       Program shows the script name, parameters...

# History:

# 2009/02/17   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

echo "The script name is        ==> $0"

echo "Total parameter number is ==> $#"

[ "$#" -lt 2 ] && echo "The number of parameter is less than 2.  Stop here." \

&& exit 0

echo "Your whole parameter is   ==> '$@'"

echo "The 1st parameter         ==> $1"

echo "The 2nd parameter         ==> $2"

執行結果如下：

[root@www scripts]# sh sh07.sh theone haha quot

The script name is        ==> sh07.sh            <==檔名

Total parameter number is ==> 3                  <==果然有三個參數

Your whole parameter is   ==> 'theone haha quot' <==參數的內容全部

The 1st parameter         ==> theone             <==第一個參數

The 2nd parameter         ==> haha               <==第二個參數

- shift：造成參數變數號碼偏移

除此之外，腳本後面所接的變數是否能夠進行偏移 (shift) 呢？什麼是偏移啊？我們直接以底下的範例來說明好了， 用範例說明比較好解釋！我們將 sh07.sh 的內容稍作變化一下，用來顯示每次偏移後參數的變化情況：

[root@www scripts]# vi sh08.sh

#!/bin/bash

# Program:

#       Program shows the effect of shift function.

# History:

# 2009/02/17   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

echo "Total parameter number is ==> $#"

echo "Your whole parameter is   ==> '$@'"

shift   # 進行第一次『一個變數的 shift 』

echo "Total parameter number is ==> $#"

echo "Your whole parameter is   ==> '$@'"

shift 3 # 進行第二次『三個變數的 shift 』

echo "Total parameter number is ==> $#"

echo "Your whole parameter is   ==> '$@'"

這玩意的執行成果如下：

[root@www scripts]# sh sh08.sh one two three four five six <==給予六個參數

Total parameter number is ==> 6   <==最原始的參數變數情況

Your whole parameter is   ==> 'one two three four five six'

Total parameter number is ==> 5   <==第一次偏移，看底下發現第一個 one 不見了

Your whole parameter is   ==> 'two three four five six'

Total parameter number is ==> 2   <==第二次偏移掉三個，two three four 不見了

Your whole parameter is   ==> 'five six'

光看結果你就可以知道啦，那個 shift 會移動變數，而且 shift 後面可以接數字，代表拿掉最前面的幾個參數的意思。 上面的執行結果中，第一次進行 shift 後他的顯示情況是『 one two three four five six』，所以就剩下五個啦！第二次直接拿掉三個，就變成『 two three four five six 』啦！ 這樣這個案例可以瞭解了嗎？理解了 shift 的功能了嗎？

上面這8個例子都很簡單吧？幾乎都是利用 bash 的相關功能而已∼ 不難啦∼底下我們就要使用條件判斷式來進行一些分別功能的設定了，好好瞧一瞧先∼

條件判斷式

只要講到『程式』的話，那麼條件判斷式，亦即是『 if then 』這種判別式肯定一定要學習的！ 因為很多時候，我們都必須要依據某些資料來判斷程式該如何進行。舉例來說，我們在上頭的 sh06.sh 範例中不是有練習當使用者輸入 Y/N 時，必須要執行不同的訊息輸出嗎？簡單的方式可以利用 && 與 || ，但如果我還想要執行一堆指令呢？那真的得要 if then 來幫忙囉∼底下我們就來聊一聊！

利用 if .... then

這個 if .... then 是最常見的條件判斷式了∼簡單的說，就是當符合某個條件判斷的時候， 就予以進行某項工作就是了。這個 if ... then 的判斷還有多層次的情況！我們分別介紹如下：

- 單層、簡單條件判斷式

如果你只有一個判斷式要進行，那麼我們可以簡單的這樣看：

if [ 條件判斷式 ]; then

當條件判斷式成立時，可以進行的指令工作內容；

fi   <==將 if 反過來寫，就成為 fi 啦！結束 if 之意！

至於條件判斷式的判斷方法，與前一小節的介紹相同啊！較特別的是，如果我有多個條件要判別時， 除了 sh06.sh 那個案例所寫的，也就是『將多個條件寫入一個中括號內的情況』之外， 我還可以有多個中括號來隔開喔！而括號與括號之間，則以 && 或 || 來隔開，他們的意義是：

- && 代表 AND ；

- || 代表 or ；

所以，在使用中括號的判斷式中， && 及 || 就與指令下達的狀態不同了。舉例來說， sh06.sh 裡面的判斷式可以這樣修改：

[ "$yn" == "Y" -o "$yn" == "y" ]

上式可替換為

[ "$yn" == "Y" ] || [ "$yn" == "y" ]

之所以這樣改，很多人是習慣問題！很多人則是喜歡一個中括號僅有一個判別式的原因。好了， 現在我們來將 sh06.sh 這個腳本修改成為 if ... then 的樣式來看看：

[root@www scripts]# cp sh06.sh sh06-2.sh  <==用改的比較快！

[root@www scripts]# vi sh06-2.sh

#!/bin/bash

# Program:

#       This program shows the user's choice

# History:

# 2005/08/25    VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

read -p "Please input (Y/N): " yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then

echo "OK, continue"

exit 0

fi

if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then

echo "Oh, interrupt!"

exit 0

fi

echo "I don't know what your choice is" && exit 0

不過，由這個例子看起來，似乎也沒有什麼了不起吧？ sh06.sh 還比較簡單呢∼ 但是如果以邏輯概念來看，其實上面的範例中，我們使用了兩個條件判斷呢！明明僅有一個 $yn 的變數，為何需要進行兩次比對呢？ 此時，多重條件判斷就能夠來測試測試囉！

- 多重、複雜條件判斷式

在同一個資料的判斷中，如果該資料需要進行多種不同的判斷時，應該怎麼作？舉例來說，上面的 sh06.sh 腳本中，我們只要進行一次 $yn 的判斷就好 (僅進行一次 if )，不想要作多次 if 的判斷。 此時你就得要知道底下的語法了：

# 一個條件判斷，分成功進行與失敗進行 (else)

if [ 條件判斷式 ]; then

當條件判斷式成立時，可以進行的指令工作內容；

else

當條件判斷式不成立時，可以進行的指令工作內容；

fi

如果考慮更複雜的情況，則可以使用這個語法：

# 多個條件判斷 (if ... elif ... elif ... else) 分多種不同情況執行

if [ 條件判斷式一 ]; then

當條件判斷式一成立時，可以進行的指令工作內容；

elif [ 條件判斷式二 ]; then

當條件判斷式二成立時，可以進行的指令工作內容；

else

當條件判斷式一與二均不成立時，可以進行的指令工作內容；

fi

你得要注意的是， elif 也是個判斷式，因此出現 elif 後面都要接 then 來處理！但是 else 已經是最後的沒有成立的結果了， 所以 else 後面並沒有 then 喔！好！我們來將 sh06-2.sh 改寫成這樣：

[root@www scripts]# cp sh06-2.sh sh06-3.sh

[root@www scripts]# vi sh06-3.sh

#!/bin/bash

# Program:

#       This program shows the user's choice

# History:

# 2005/08/25    VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

read -p "Please input (Y/N): " yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then

echo "OK, continue"

elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then

echo "Oh, interrupt!"

else

echo "I don't know what your choice is"

fi

是否程式變得很簡單，而且依序判斷，可以避免掉重複判斷的狀況，這樣真的很容易設計程式的啦！ ^_^！ 好了，讓我們再來進行另外一個案例的設計。一般來說，如果你不希望使用者由鍵盤輸入額外的資料時， 可以使用上一節提到的參數功能 ($1)！讓使用者在下達指令時就將參數帶進去！ 現在我們想讓使用者輸入『 hello 』這個關鍵字時，利用參數的方法可以這樣依序設計：

1. 判斷 $1 是否為 hello，如果是的話，就顯示 "Hello, how are you ?"；

2. 如果沒有加任何參數，就提示使用者必須要使用的參數下達法；

3. 而如果加入的參數不是 hello ，就提醒使用者僅能使用 hello 為參數。

整個程式的撰寫可以是這樣的：

[root@www scripts]# vi sh09.sh

#!/bin/bash

# Program:

#       Check $1 is equal to "hello"

# History:

# 2005/08/28   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

if [ "$1" == "hello" ]; then

echo "Hello, how are you ?"

elif [ "$1" == "" ]; then

echo "You MUST input parameters, ex> {$0 someword}"

else

echo "The only parameter is 'hello', ex> {$0 hello}"

fi

然後你可以執行這支程式，分別在 $1 的位置輸入 hello, 沒有輸入與隨意輸入， 就可以看到不同的輸出囉∼是否還覺得挺簡單的啊！ ^_^。事實上， 學到這裡，也真的很厲害了∼好了，底下我們繼續來玩一些比較大一點的計畫囉∼

我們在第十一章已經學會了 grep 這個好用的玩意兒，那麼多學一個叫做 netstat 的指令，這個指令可以查詢到目前主機有開啟的網路服務埠口 (service ports)， 相關的功能我們會在伺服器架設篇繼續介紹，這裡你只要知道，我可以利用『 netstat -tuln 』來取得目前主機有啟動的服務， 而且取得的資訊有點像這樣：

[root@www ~]# netstat -tuln

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address     Foreign Address   State

tcp        0      0 0.0.0.0:111       0.0.0.0:*         LISTEN

tcp        0      0 127.0.0.1:631     0.0.0.0:*         LISTEN

tcp        0      0 127.0.0.1:25      0.0.0.0:*         LISTEN

tcp        0      0 :::22             :::*              LISTEN

udp        0      0 0.0.0.0:111       0.0.0.0:*

udp        0      0 0.0.0.0:631       0.0.0.0:*

#封包格式           本地IP:埠口       遠端IP:埠口       是否監聽

上面的重點是『Local Address (本地主機的IP與埠口對應)』那個欄位，他代表的是本機所啟動的網路服務！ IP的部分說明的是該服務位於那個介面上，若為 127.0.0.1 則是僅針對本機開放，若是 0.0.0.0 或 ::: 則代表對整個 Internet 開放 (更多資訊請參考伺服器架設篇的介紹)。 每個埠口 (port) 都有其特定的網路服務，幾個常見的 port 與相關網路服務的關係是：

- 80: WWW

- 22: ssh

- 21: ftp

- 25: mail

- 111: RPC(遠端程序呼叫)

- 631: CUPS(列印服務功能)

假設我的主機有興趣要偵測的是比較常見的 port 21, 22, 25及 80 時，那我如何透過 netstat 去偵測我的主機是否有開啟這四個主要的網路服務埠口呢？由於每個服務的關鍵字都是接在冒號『 : 』後面， 所以可以藉由擷取類似『 :80 』來偵測的！那我就可以簡單的這樣去寫這個程式喔：

[root@www scripts]# vi sh10.sh

#!/bin/bash

# Program:

#       Using netstat and grep to detect WWW,SSH,FTP and Mail services.

# History:

# 2005/08/28   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

# 1. 先作一些告知的動作而已∼

echo "Now, I will detect your Linux server's services!"

echo -e "The www, ftp, ssh, and mail will be detect! \n"

# 2. 開始進行一些測試的工作，並且也輸出一些資訊囉！

testing=$(netstat -tuln | grep ":80 ")   # 偵測看 port 80 在否？

if [ "$testing" != "" ]; then

echo "WWW is running in your system."

fi

testing=$(netstat -tuln | grep ":22 ")   # 偵測看 port 22 在否？

if [ "$testing" != "" ]; then

echo "SSH is running in your system."

fi

testing=$(netstat -tuln | grep ":21 ")   # 偵測看 port 21 在否？

if [ "$testing" != "" ]; then

echo "FTP is running in your system."

fi

testing=$(netstat -tuln | grep ":25 ")   # 偵測看 port 25 在否？

if [ "$testing" != "" ]; then

echo "Mail is running in your system."

fi

實際執行這支程式你就可以看到你的主機有沒有啟動這些服務啦！是否很有趣呢？ 條件判斷式還可以搞的更複雜！舉例來說，在台灣當兵是國民應盡的義務，不過，在當兵的時候總是很想要退伍的！ 那你能不能寫個腳本程式來跑，讓使用者輸入他的退伍日期，讓你去幫他計算還有幾天才退伍？

由於日期是要用相減的方式來處置，所以我們可以透過使用 date 顯示日期與時間，將他轉為由 1970-01-01 累積而來的秒數， 透過秒數相減來取得剩餘的秒數後，再換算為日數即可。整個腳本的製作流程有點像這樣：

1. 先讓使用者輸入他們的退伍日期；

2. 再由現在日期比對退伍日期；

3. 由兩個日期的比較來顯示『還需要幾天』才能夠退伍的字樣。

似乎挺難的樣子？其實也不會啦，利用『 date --date="YYYYMMDD" +%s 』轉成秒數後，接下來的動作就容易的多了！如果你已經寫完了程式，對照底下的寫法試看看：

[root@www scripts]# vi sh11.sh

#!/bin/bash

# Program:

#       You input your demobilization date, I calculate how many days

#       before you demobilize.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

# 1. 告知使用者這支程式的用途，並且告知應該如何輸入日期格式？

echo "This program will try to calculate :"

echo "How many days before your demobilization date..."

read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2

# 2. 測試一下，這個輸入的內容是否正確？利用正規表示法囉∼

date_d=$(echo $date2 |grep '[0-9]\{8\}')   # 看看是否有八個數字

if [ "$date_d" == "" ]; then

echo "You input the wrong date format...."

exit 1

fi

# 3. 開始計算日期囉∼

declare -i date_dem=`date --date="$date2" +%s`    # 退伍日期秒數

declare -i date_now=`date +%s`                    # 現在日期秒數

declare -i date_total_s=$(($date_dem-$date_now))  # 剩餘秒數統計

declare -i date_d=$(($date_total_s/60/60/24))     # 轉為日數

if [ "$date_total_s" -lt "0" ]; then              # 判斷是否已退伍

echo "You had been demobilization before: " $((-1*$date_d)) " ago"

else

declare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60))

echo "You will demobilize after $date_d days and $date_h hours."

fi

瞧一瞧，這支程式可以幫你計算退伍日期呢∼如果是已經退伍的朋友， 還可以知道已經退伍多久了∼哈哈！很可愛吧∼腳本中的 date_d 變數宣告那個 /60/60/24 是來自於一天的總秒數 (24小時*60分*60秒) 。瞧∼全部的動作都沒有超出我們所學的範圍吧∼ ^_^ 還能夠避免使用者輸入錯誤的數字，所以多了一個正規表示法的判斷式呢∼ 這個例子比較難，有興趣想要一探究竟的朋友，可以作一下課後練習題 關於計算生日的那一題喔！∼加油！

利用 case ..... esac 判斷

上個小節提到的『 if .... then .... fi 』對於變數的判斷是以『比對』的方式來分辨的， 如果符合狀態就進行某些行為，並且透過較多層次 (就是 elif ...) 的方式來進行多個變數的程式碼撰寫，譬如 sh09.sh 那個小程式，就是用這樣的方式來撰寫的囉。 好，那麼萬一我有多個既定的變數內容，例如 sh09.sh 當中，我所需要的變數就是 "hello" 及空字串兩個， 那麼我只要針對這兩個變數來設定狀況就好了，對吧？那麼可以使用什麼方式來設計呢？呵呵∼就用 case ... in .... esac 吧∼，他的語法如下：

case  $變數名稱 in   <==關鍵字為 case ，還有變數前有錢字號

"第一個變數內容")   <==每個變數內容建議用雙引號括起來，關鍵字則為小括號 )

程式段

;;            <==每個類別結尾使用兩個連續的分號來處理！

"第二個變數內容")

程式段

;;

*)                  <==最後一個變數內容都會用 * 來代表所有其他值

不包含第一個變數內容與第二個變數內容的其他程式執行段

exit 1

;;

esac                  <==最終的 case 結尾！『反過來寫』思考一下！

要注意的是，這個語法以 case (實際案例之意) 為開頭，結尾自然就是將 case 的英文反過來寫！就成為 esac 囉！ 不會很難背啦！另外，每一個變數內容的程式段最後都需要兩個分號 (;;) 來代表該程式段落的結束，這挺重要的喔！ 至於為何需要有 * 這個變數內容在最後呢？這是因為，如果使用者不是輸入變數內容一或二時， 我們可以告知使用者相關的資訊啊！廢話少說，我們拿 sh09.sh 的案例來修改一下，他應該會變成這樣喔：

[root@www scripts]# vi sh09-2.sh

#!/bin/bash

# Program:

#       Show "Hello" from $1.... by using case .... esac

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

case $1 in

"hello")

echo "Hello, how are you ?"

;;

"")

echo "You MUST input parameters, ex> {$0 someword}"

;;

*)   # 其實就相當於萬用字元，0~無窮多個任意字元之意！

echo "Usage $0 {hello}"

;;

esac

在上面這個 sh09-2.sh 的案例當中，如果你輸入『 sh sh09-2.sh test 』來執行， 那麼螢幕上就會出現『Usage sh09-2.sh {hello}』的字樣，告知執行者僅能夠使用 hello 喔∼ 這樣的方式對於需要某些固定字串來執行的變數內容就顯的更加的方便呢！ 這種方式你真的要熟悉喔！這是因為系統的很多服務的啟動 scripts 都是使用這種寫法的， 舉例來說，我們 Linux 的服務啟動放置目錄是在 /etc/init.d/ 當中，我已經知道裡頭有個 syslog 的服務，我想要重新啟動這個服務，可以這樣做：

/etc/init.d/syslog restart

重點是那個 restart 啦！如果你使用『 less /etc/init.d/syslog 』去查閱一下，就會看到他使用的是 case 語法， 並且會規定某些既定的變數內容，你可以直接下達 /etc/init.d/syslog ， 該 script 就會告知你有哪些後續接的變數可以使用囉∼方便吧！ ^_^

一般來說，使用『 case $變數 in 』這個語法中，當中的那個『 $變數 』大致有兩種取得的方式：

- 直接下達式：例如上面提到的，利用『 script.sh variable 』 的方式來直接給予 $1 這個變數的內容，這也是在 /etc/init.d 目錄下大多數程式的設計方式。

- 互動式：透過 read 這個指令來讓使用者輸入變數的內容。

這麼說或許你的感受性還不高，好，我們直接寫個程式來玩玩：讓使用者能夠輸入 one, two, three ， 並且將使用者的變數顯示到螢幕上，如果不是 one, two, three 時，就告知使用者僅有這三種選擇。

[root@www scripts]# vi sh12.sh

#!/bin/bash

# Program:

#       This script only accepts the flowing parameter: one, two or three.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

echo "This program will print your selection !"

# read -p "Input your choice: " choice # 暫時取消，可以替換！

# case $choice in                      # 暫時取消，可以替換！

case $1 in                             # 現在使用，可以用上面兩行替換！

"one")

echo "Your choice is ONE"

;;

"two")

echo "Your choice is TWO"

;;

"three")

echo "Your choice is THREE"

;;

*)

echo "Usage $0 {one|two|three}"

;;

esac

此時，你可以使用『 sh sh12.sh two 』的方式來下達指令，就可以收到相對應的回應了。 上面使用的是直接下達的方式，而如果使用的是互動式時，那麼將上面第 10, 11 行的 "#" 拿掉， 並將 12 行加上註解 (#)，就可以讓使用者輸入參數囉∼這樣是否很有趣啊？

利用 function 功能

什麼是『函數 (function)』功能啊？簡單的說，其實， 函數可以在 shell script 當中做出一個類似自訂執行指令的東西，最大的功能是， 可以簡化我們很多的程式碼∼舉例來說，上面的 sh12.sh 當中，每個輸入結果 one, two, three 其實輸出的內容都一樣啊∼那麼我就可以使用 function 來簡化了！ function 的語法是這樣的：

function fname() {

程式段

}

那個 fname 就是我們的自訂的執行指令名稱∼而程式段就是我們要他執行的內容了。 要注意的是，因為 shell script 的執行方式是由上而下，由左而右， 因此在 shell script 當中的 function 的設定一定要在程式的最前面， 這樣才能夠在執行時被找到可用的程式段喔！好∼我們將 sh12.sh 改寫一下，自訂一個名為 printit 的函數來使用喔：

[root@www scripts]# vi sh12-2.sh

#!/bin/bash

# Program:

#       Use function to repeat information.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

function printit(){

echo -n "Your choice is "     # 加上 -n 可以不斷行繼續在同一行顯示

}

echo "This program will print your selection !"

case $1 in

"one")

printit; echo $1 | tr 'a-z' 'A-Z'  # 將參數做大小寫轉換！

;;

"two")

printit; echo $1 | tr 'a-z' 'A-Z'

;;

"three")

printit; echo $1 | tr 'a-z' 'A-Z'

;;

*)

echo "Usage $0 {one|two|three}"

;;

esac

以上面的例子來說，鳥哥做了一個函數名稱為 printit ，所以，當我在後續的程式段裡面， 只要執行 printit 的話，就表示我的 shell script 要去執行『 function printit .... 』 裡面的那幾個程式段落囉！當然囉，上面這個例子舉得太簡單了，所以你不會覺得 function 有什麼好厲害的， 不過，如果某些程式碼一再地在 script 當中重複時，這個 function 可就重要的多囉∼ 不但可以簡化程式碼，而且可以做成類似『模組』的玩意兒，真的很棒啦！

Tips:

建議讀者可以使用類似 vim 的編輯器到 /etc/init.d/ 目錄下去查閱一下你所看到的檔案， 並且自行追蹤一下每個檔案的執行情況，相信會更有心得！

另外， function 也是擁有內建變數的∼他的內建變數與 shell script 很類似， 函數名稱代表示 $0 ，而後續接的變數也是以 $1, $2... 來取代的∼ 這裡很容易搞錯喔∼因為『 function fname() { 程式段 } 』內的 $0, $1... 等等與 shell script 的 $0 是不同的。以上面 sh12-2.sh 來說，假如我下達：『 sh sh12-2.sh one 』 這表示在 shell script 內的 $1 為 "one" 這個字串。但是在 printit() 內的 $1 則與這個 one 無關。 我們將上面的例子再次的改寫一下，讓你更清楚！

[root@www scripts]# vi sh12-3.sh

#!/bin/bash

# Program:

#       Use function to repeat information.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

function printit(){

echo "Your choice is $1"   # 這個 $1 必須要參考底下指令的下達

}

echo "This program will print your selection !"

case $1 in

"one")

printit 1  # 請注意， printit 指令後面還有接參數！

;;

"two")

printit 2

;;

"three")

printit 3

;;

*)

echo "Usage $0 {one|two|three}"

;;

esac

在上面的例子當中，如果你輸入『 sh sh12-3.sh one 』就會出現『 Your choice is 1 』的字樣∼ 為什麼是 1 呢？因為在程式段落當中，我們是寫了『 printit 1 』那個 1 就會成為 function 當中的 $1 喔∼ 這樣是否理解呢？ function 本身其實比較困難一點，如果你還想要進行其他的撰寫的話。 不過，我們僅是想要更加瞭解 shell script 而已，所以，這裡看看即可∼瞭解原理就好囉∼ ^_^

迴圈 (loop)

除了 if...then...fi 這種條件判斷式之外，迴圈可能是程式當中最重要的一環了∼ 迴圈可以不斷的執行某個程式段落，直到使用者設定的條件達成為止。 所以，重點是那個『條件的達成』是什麼。除了這種依據判斷式達成與否的不定迴圈之外， 還有另外一種已經固定要跑多少次的迴圈形態，可稱為固定迴圈的形態呢！底下我們就來談一談：

while do done, until do done (不定迴圈)

一般來說，不定迴圈最常見的就是底下這兩種狀態了：

while [ condition ]  <==中括號內的狀態就是判斷式

do            <==do 是迴圈的開始！

程式段落

done          <==done 是迴圈的結束

while 的中文是『當....時』，所以，這種方式說的是『當 condition 條件成立時，就進行迴圈，直到 condition 的條件不成立才停止』的意思。還有另外一種不定迴圈的方式：

until [ condition ]

do

程式段落

done

這種方式恰恰與 while 相反，它說的是『當 condition 條件成立時，就終止迴圈， 否則就持續進行迴圈的程式段。』是否剛好相反啊∼我們以 while 來做個簡單的練習好了。 假設我要讓使用者輸入 yes 或者是 YES 才結束程式的執行，否則就一直進行告知使用者輸入字串。

[root@www scripts]# vi sh13.sh

#!/bin/bash

# Program:

#       Repeat question until user input correct answer.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

while [ "$yn" != "yes" -a "$yn" != "YES" ]

do

read -p "Please input yes/YES to stop this program: " yn

done

echo "OK! you input the correct answer."

上面這個例題的說明是『當 $yn 這個變數不是 "yes" 且 $yn 也不是 "YES" 時，才進行迴圈內的程式。』 而如果 $yn 是 "yes" 或 "YES" 時，就會離開迴圈囉∼那如果使用 until 呢？呵呵有趣囉∼ 他的條件會變成這樣：

[root@www scripts]# vi sh13-2.sh

#!/bin/bash

# Program:

#       Repeat question until user input correct answer.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

until [ "$yn" == "yes" -o "$yn" == "YES" ]

do

read -p "Please input yes/YES to stop this program: " yn

done

echo "OK! you input the correct answer."

仔細比對一下這兩個東西有啥不同喔！ ^_^再來，如果我想要計算 1+2+3+....+100 這個數據呢？ 利用迴圈啊∼他是這樣的：

[root@www scripts]# vi sh14.sh

#!/bin/bash

# Program:

#       Use loop to calculate "1+2+3+...+100" result.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

s=0  # 這是加總的數值變數

i=0  # 這是累計的數值，亦即是 1, 2, 3....

while [ "$i" != "100" ]

do

i=$(($i+1))   # 每次 i 都會增加 1

s=$(($s+$i))  # 每次都會加總一次！

done

echo "The result of '1+2+3+...+100' is ==> $s"

嘿嘿！當你執行了『 sh sh14.sh 』之後，就可以得到 5050 這個數據才對啊！這樣瞭呼∼ 那麼讓你自行做一下，如果想要讓使用者自行輸入一個數字，讓程式由 1+2+... 直到你輸入的數字為止， 該如何撰寫呢？應該很簡單吧？答案可以參考一下習題練習裡面的一題喔！

for...do...done (固定迴圈)

相對於 while, until 的迴圈方式是必須要『符合某個條件』的狀態， for 這種語法，則是『 已經知道要進行幾次迴圈』的狀態！他的語法是：

for var in con1 con2 con3 ...

do

程式段

done

以上面的例子來說，這個 $var 的變數內容在迴圈工作時：

1. 第一次迴圈時， $var 的內容為 con1 ；

2. 第二次迴圈時， $var 的內容為 con2 ；

3. 第三次迴圈時， $var 的內容為 con3 ；

4. ....

我們可以做個簡單的練習。假設我有三種動物，分別是 dog, cat, elephant 三種， 我想每一行都輸出這樣：『There are dogs...』之類的字樣，則可以：

[root@www scripts]# vi sh15.sh

#!/bin/bash

# Program:

#       Using for .... loop to print 3 animals

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

for animal in dog cat elephant

do

echo "There are ${animal}s.... "

done

等你執行之後就能夠發現這個程式運作的情況啦！讓我們想像另外一種狀況，由於系統上面的各種帳號都是寫在 /etc/passwd 內的第一個欄位，你能不能透過管線命令的 cut 捉出單純的帳號名稱後，以 id 及 finger 分別檢查使用者的識別碼與特殊參數呢？由於不同的 Linux 系統上面的帳號都不一樣！此時實際去捉 /etc/passwd 並使用迴圈處理，就是一個可行的方案了！程式可以如下：

[root@www scripts]# vi sh16.sh

#!/bin/bash

# Program

#       Use id, finger command to check system account's information.

# History

# 2009/02/18    VBird   first release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

users=$(cut -d ':' -f1 /etc/passwd)  # 擷取帳號名稱

for username in $users               # 開始迴圈進行！

do

id $username

finger $username

done

執行上面的腳本後，你的系統帳號就會被捉出來檢查啦！這個動作還可以用在每個帳號的刪除、重整上面呢！ 換個角度來看，如果我現在需要一連串的數字來進行迴圈呢？舉例來說，我想要利用 ping 這個可以判斷網路狀態的指令， 來進行網路狀態的實際偵測時，我想要偵測的網域是本機所在的 192.168.1.1~192.168.1.100，由於有 100 台主機， 總不會要我在 for 後面輸入 1 到 100 吧？此時你可以這樣做喔！

[root@www scripts]# vi sh17.sh

#!/bin/bash

# Program

#       Use ping command to check the network's PC state.

# History

# 2009/02/18    VBird   first release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

network="192.168.1"              # 先定義一個網域的前面部分！

for sitenu in $(seq 1 100)       # seq 為 sequence(連續) 的縮寫之意

do

# 底下的程式在取得 ping 的回傳值是正確的還是失敗的！

ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1

# 開始顯示結果是正確的啟動 (UP) 還是錯誤的沒有連通 (DOWN)

if [ "$result" == 0 ]; then

echo "Server ${network}.${sitenu} is UP."

else

echo "Server ${network}.${sitenu} is DOWN."

fi

done

上面這一串指令執行之後就可以顯示出 192.168.1.1~192.168.1.100 共 100 部主機目前是否能與你的機器連通！ 如果你的網域與鳥哥所在的位置不同，則直接修改上頭那個 network 的變數內容即可！其實這個範例的重點在 $(seq ..) 那個位置！那個 seq 是連續 (sequence) 的縮寫之意！代表後面接的兩個數值是一直連續的！ 如此一來，就能夠輕鬆的將連續數字帶入程式中囉！

最後，讓我們來玩判斷式加上迴圈的功能！我想要讓使用者輸入某個目錄檔名， 然後我找出某目錄內的檔名的權限，該如何是好？呵呵！可以這樣做啦∼

[root@www scripts]# vi sh18.sh

#!/bin/bash

# Program:

#       User input dir name, I find the permission of files.

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

# 1. 先看看這個目錄是否存在啊？

read -p "Please input a directory: " dir

if [ "$dir" == "" -o ! -d "$dir" ]; then

echo "The $dir is NOT exist in your system."

exit 1

fi

# 2. 開始測試檔案囉∼

filelist=$(ls $dir)        # 列出所有在該目錄下的檔案名稱

for filename in $filelist

do

perm=""

test -r "$dir/$filename" && perm="$perm readable"

test -w "$dir/$filename" && perm="$perm writable"

test -x "$dir/$filename" && perm="$perm executable"

echo "The file $dir/$filename's permission is $perm "

done

呵呵！很有趣的例子吧∼利用這種方式，你可以很輕易的來處理一些檔案的特性呢。接下來，讓我們來玩玩另一種 for 迴圈的功能吧！主要用在數值方面的處理喔！

for...do...done 的數值處理

除了上述的方法之外，for 迴圈還有另外一種寫法！語法如下：

for (( 初始值; 限制值; 執行步階 ))

do

程式段

done

這種語法適合於數值方式的運算當中，在 for 後面的括號內的三串內容意義為：

- 初始值：某個變數在迴圈當中的起始值，直接以類似 i=1 設定好；

- 限制值：當變數的值在這個限制值的範圍內，就繼續進行迴圈。例如 i<=100；

- 執行步階：每作一次迴圈時，變數的變化量。例如 i=i+1。

值得注意的是，在『執行步階』的設定上，如果每次增加 1 ，則可以使用類似『i++』的方式，亦即是 i 每次迴圈都會增加一的意思。好，我們以這種方式來進行 1 累加到使用者輸入的迴圈吧！

[root@www scripts]# vi sh19.sh

#!/bin/bash

# Program:

#       Try do calculate 1+2+....+${your_input}

# History:

# 2005/08/29   VBird   First release

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin

export PATH

read -p "Please input a number, I will count for 1+2+...+your_input: " nu

s=0

for (( i=1; i<=$nu; i=i+1 ))

do

s=$(($s+$i))

done

echo "The result of '1+2+3+...+$nu' is ==> $s"

一樣也是很簡單吧！利用這個 for 則可以直接限制迴圈要進行幾次呢！

shell script 的追蹤與 debug

scripts 在執行之前，最怕的就是出現語法錯誤的問題了！那麼我們如何 debug 呢？有沒有辦法不需要透過直接執行該 scripts 就可以來判斷是否有問題呢？呵呵！當然是有的！我們就直接以 bash 的相關參數來進行判斷吧！

[root@www ~]# sh [-nvx] scripts.sh

選項與參數：

-n  ：不要執行 script，僅查詢語法的問題；

-v  ：再執行 sccript 前，先將 scripts 的內容輸出到螢幕上；

-x  ：將使用到的 script 內容顯示到螢幕上，這是很有用的參數！

範例一：測試 sh16.sh 有無語法的問題？

[root@www ~]# sh -n sh16.sh

# 若語法沒有問題，則不會顯示任何資訊！

範例二：將 sh15.sh 的執行過程全部列出來∼

[root@www ~]# sh -x sh15.sh

+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin

+ export PATH

+ for animal in dog cat elephant

+ echo 'There are dogs.... '

There are dogs....

+ for animal in dog cat elephant

+ echo 'There are cats.... '

There are cats....

+ for animal in dog cat elephant

+ echo 'There are elephants.... '

There are elephants....

請注意，上面範例二中執行的結果並不會有顏色的顯示！鳥哥為了方便說明所以在 + 號之後的資料都加上顏色了！ 在輸出的訊息中，在加號後面的資料其實都是指令串，由於 sh -x 的方式來將指令執行過程也顯示出來， 如此使用者可以判斷程式碼執行到哪一段時會出現相關的資訊！這個功能非常的棒！透過顯示完整的指令串， 你就能夠依據輸出的錯誤資訊來訂正你的腳本了！

熟悉 sh 的用法，將可以使你在管理 Linux 的過程中得心應手！至於在 Shell scripts 的學習方法上面，需要『多看、多模仿、並加以修改成自己的樣式！』 是最快的學習手段了！網路上有相當多的朋友在開發一些相當有用的 scripts ，若是你可以將對方的 scripts 拿來，並且改成適合自己主機的樣子！那麼學習的效果會是最快的呢！

另外，我們 Linux 系統本來就有很多的服務啟動腳本，如果你想要知道每個 script 所代表的功能是什麼？ 可以直接以 vim 進入該 script 去查閱一下，通常立刻就知道該 script 的目的了。 舉例來說，我們之前一直提到的 /etc/init.d/syslog ，這個 script 是幹嘛用的？ 利用 vi 去查閱最前面的幾行字，他出現如下資訊：

# description: Syslog is the facility by which many daemons use to log \

# messages to various system log files.  It is a good idea to always \

# run syslog.

### BEGIN INIT INFO

# Provides: $syslog

### END INIT INFO

簡單的說，這個腳本在啟動一個名為 syslog 的常駐程式 (daemon)，這個常駐程式可以幫助很多系統服務記載她們的登錄檔 (log file)， 我們的 Linux 建議你一直啟動 syslog 是個好主意！嘿嘿！簡單的看看您就知道啥是啥啦！

另外，本章所有的範例都可以在 http://linux.vbird.org/linux_basic/0340bashshell-scripts/scripts-v3.tar.bz2 裡頭找到喔！加油∼

重點回顧

- shell script 是利用 shell 的功能所寫的一個『程式 (program)』，這個程式是使用純文字檔，將一些 shell 的語法與指令(含外部指令)寫在裡面， 搭配正規表示法、管線命令與資料流重導向等功能，以達到我們所想要的處理目的

- shell script 用在系統管理上面是很好的一項工具，但是用在處理大量數值運算上， 就不夠好了，因為 Shell scripts 的速度較慢，且使用的 CPU 資源較多，造成主機資源的分配不良。

- 在 Shell script 的檔案中，指令的執行是從上而下、從左而右的分析與執行；

- shell script 的執行，至少需要有 r 的權限，若需要直接指令下達，則需要擁有 r 與 x 的權限；

- 良好的程式撰寫習慣中，第一行要宣告 shell (#!/bin/bash) ，第二行以後則宣告程式用途、版本、作者等

- 對談式腳本可用 read 指令達成；

- 要建立每次執行腳本都有不同結果的資料，可使用 date 指令利用日期達成；

- script 的執行若以 source 來執行時，代表在父程序的 bash 內執行之意！

- 若需要進行判斷式，可使用 test 或中括號 ( [] ) 來處理；

- 在 script 內，$0, $1, $2..., $@ 是有特殊意義的！

- 條件判斷式可使用 if...then 來判斷，若是固定變數內容的情況下，可使用 case $var in ... esac 來處理

- 迴圈主要分為不定迴圈 (while, until) 以及固定迴圈 (for) ，配合 do, done 來達成所需任務！

- 我們可使用 sh -x script.sh 來進行程式的 debug

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

底下皆為實作題，請自行撰寫出程式喔！

- 請建立一支 script ，當你執行該 script 的時候，該 script 可以顯示： 1. 你目前的身份 (用 whoami ) 2. 你目前所在的目錄 (用 pwd)

#!/bin/bash

echo -e "Your name is ==> $(whoami)"

echo -e "The current directory is ==> $(pwd)"

- 請自行建立一支程式，該程式可以用來計算『你還有幾天可以過生日』啊？

#!/bin/bash

read -p "Pleas input your birthday (MMDD, ex> 0709): " bir

now=`date +%m%d`

if [ "$bir" == "$now" ]; then

echo "Happy Birthday to you!!!"

elif [ "$bir" -gt "$now" ]; then

year=`date +%Y`

total_d=$(($((`date --date="$year$bir" +%s`-`date +%s`))/60/60/24))

echo "Your birthday will be $total_d later"

else

year=$((`date +%Y`+1))

total_d=$(($((`date --date="$year$bir" +%s`-`date +%s`))/60/60/24))

echo "Your birthday will be $total_d later"

fi

- 讓使用者輸入一個數字，程式可以由 1+2+3... 一直累加到使用者輸入的數字為止。

#!/bin/bash

read -p "Please input an integer number: " number

i=0

s=0

while [ "$i" != "$number" ]

do

i=$(($i+1))

s=$(($s+$i))

done

echo "the result of '1+2+3+...$number' is ==> $s"

- 撰寫一支程式，他的作用是: 1.) 先查看一下 /root/test/logical 這個名稱是否存在； 2.) 若不存在，則建立一個檔案，使用 touch 來建立，建立完成後離開； 3.) 如果存在的話，判斷該名稱是否為檔案，若為檔案則將之刪除後建立一個目錄，檔名為 logical ，之後離開； 4.) 如果存在的話，而且該名稱為目錄，則移除此目錄！

#!/bin/bash

if [ ! -e logical ]; then

touch logical

echo "Just make a file logical"

exit 1

elif [ -e logical ] && [ -f logical ]; then

rm logical

mkdir logical

echo "remove file ==> logical"

echo "and make directory logical"

exit 1

elif [ -e logical ] && [ -d logical ]; then

rm -rf logical

echo "remove directory ==> logical"

exit 1

else

echo "Does here have anything?"

fi

- 我們知道 /etc/passwd 裡面以 : 來分隔，第一欄為帳號名稱。請寫一隻程式，可以將 /etc/passwd 的第一欄取出，而且每一欄都以一行字串『The 1 account is "root" 』來顯示，那個 1 表示行數。

#!/bin/bash

accounts=`cat /etc/passwd | cut -d':' -f1`

for account in $accounts

do

declare -i i=$i+1

echo "The $i account is \"$account\" "

done

參考資料與延伸閱讀

- 臥龍小三大師的文件：http://linux.tnc.edu.tw/techdoc/shell/book1.html

2002/06/27：第一次完成

2003/02/10：重新編排與加入 FAQ

2005/08/29：將舊的文章移動到 這裡 了。

2005/08/29：呼呼∼加入了一些比較有趣的練習題∼比第一版要難的多∼大家多多玩一玩喔∼

2009/02/10：將舊的基於 FC4 版本的文章移動到此處

2009/02/17：加入 shift 的介紹

2009/02/18：加入了一些額外的練習，包括 for 的 ping 處理！

2002/06/27以來統計人數

第八章、Linux 磁碟與檔案系統管理

切換解析度為 800x600

最近更新日期：2009/08/30

系統管理員很重要的任務之一就是管理好自己的磁碟檔案系統，每個分割槽不可太大也不能太小， 太大會造成磁碟容量的浪費，太小則會產生檔案無法儲存的困擾。此外，我們在前面幾章談到的檔案權限與屬性中， 這些權限與屬性分別記錄在檔案系統的哪個區塊內？這就得要談到 filesystem 中的 inode 與 block 了。 在本章我們的重點在於如何製作檔案系統，包括分割、格式化與掛載等，是很重要的一個章節喔！

1. 認識 EXT2 檔案系統

1.1 硬碟組成與分割的複習

1.2 檔案系統特性： 索引式檔案系統

1.3 Linux 的 EXT2 檔案系統(inode): data block, inode table, superblock, dumpe2fs

1.4 與目錄樹的關係

1.5 EXT2/EXT3 檔案的存取與日誌式檔案系統的功能

1.6 Linux 檔案系統的運作

1.7 掛載點的意義 (mount point)

1.8 其他 Linux 支援的檔案系統與 VFS

2. 檔案系統的簡單操作

2.1 磁碟與目錄的容量： df, du

2.2 實體連結與符號連結： ln

3. 磁碟的分割、格式化、檢驗與掛載

3.1 磁碟分割： fdisk, partprobe

3.2 磁碟格式化： mkfs, mke2fs

3.3 磁碟檢驗： fsck, badblocks

3.4 磁碟掛載與卸載： mount, umount

3.5 磁碟參數修訂： mknod, e2label, tune2fs, hdparm

4. 設定開機掛載：

4.1 開機掛載 /etc/fstab 及 /etc/mtab

4.2 特殊裝置 loop 掛載(映象檔不燒錄就掛載使用)

5. 記憶體置換空間(swap)之建置：

5.1 使用實體分割槽建置swap

5.2 使用檔案建置swap

5.3 swap使用上的限制

6. 檔案系統的特殊觀察與操作

6.1 boot sector 與 superblock 的關係

6.2 磁碟空間之浪費問題

6.3 利用 GNU 的 parted 進行分割行為

7. 重點回顧

8. 本章習題

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23881

認識 EXT2 檔案系統

Linux最傳統的磁碟檔案系統(filesystem)使用的是EXT2這個啦！所以要瞭解檔案系統就得要由認識EXT2開始！ 而檔案系統是建立在硬碟上面的，因此我們得瞭解硬碟的物理組成才行。磁碟物理組成的部分我們在第零章談過了，至於磁碟分割則在第三章談過了，所以底下只會很快的複習這兩部份。 重點在於inode, block還有superblock等檔案系統的基本部分喔！

硬碟組成與分割的複習

由於各項磁碟的物理組成我們在第零章裡面就介紹過， 同時第三章也談過分割的概念了， 所以這個小節我們就拿之前的重點出來介紹就好了！詳細的資訊請您回去那兩章自行複習喔！^_^。 好了，首先說明一下磁碟的物理組成，整顆磁碟的組成主要有：

- 圓形的磁碟盤(主要記錄資料的部分)；

- 機械手臂，與在機械手臂上的磁碟讀取頭(可讀寫磁碟盤上的資料)；

- 主軸馬達，可以轉動磁碟盤，讓機械手臂的讀取頭在磁碟盤上讀寫資料。

從上面我們知道資料儲存與讀取的重點在於磁碟盤，而磁碟盤上的物理組成則為(假設此磁碟為單碟片， 磁碟盤圖示請參考第三章圖2.2.1的示意)：

- 磁區(Sector)為最小的物理儲存單位，每個磁區為 512 bytes；

- 將磁區組成一個圓，那就是磁柱(Cylinder)，磁柱是分割槽(partition)的最小單位；

- 第一個磁區最重要，裡面有：(1)主要開機區(Master boot record, MBR)及分割表(partition table)， 其中 MBR 佔有 446 bytes，而 partition table 則佔有 64 bytes。

各種介面的磁碟在Linux中的檔案名稱分別為：

- /dev/sd[a-p][1-15]：為SCSI, SATA, USB, Flash隨身碟等介面的磁碟檔名；

- /dev/hd[a-d][1-63]：為 IDE 介面的磁碟檔名；

複習完物理組成後，來複習一下磁碟分割吧！所謂的磁碟分割指的是告訴作業系統『我這顆磁碟在此分割槽可以存取的區域是由 A 磁柱到 B 磁柱之間的區塊』， 如此一來作業系統就能夠知道他可以在所指定的區塊內進行檔案資料的讀/寫/搜尋等動作了。 也就是說，磁碟分割意即指定分割槽的啟始與結束磁柱就是了。

那麼指定分割槽的磁柱範圍是記錄在哪裡？就是第一個磁區的分割表中啦！但是因為分割表僅有64bytes而已， 因此最多只能記錄四筆分割槽的記錄，這四筆記錄我們稱為主要 (primary) 或延伸 (extended) 分割槽，其中延伸分割槽還可以再分割出邏輯分割槽 (logical) ， 而能被格式化的則僅有主要分割與邏輯分割而已。

最後，我們再將第三章關於分割的定義拿出來說明一下囉：

- 主要分割與延伸分割最多可以有四筆(硬碟的限制)

- 延伸分割最多只能有一個(作業系統的限制)

- 邏輯分割是由延伸分割持續切割出來的分割槽；

- 能夠被格式化後，作為資料存取的分割槽為主要分割與邏輯分割。延伸分割無法格式化；

- 邏輯分割的數量依作業系統而不同，在Linux系統中，IDE硬碟最多有59個邏輯分割(5號到63號)， SATA硬碟則有11個邏輯分割(5號到15號)。

檔案系統特性

我們都知道磁碟分割完畢後還需要進行格式化(format)，之後作業系統才能夠使用這個分割槽。 為什麼需要進行『格式化』呢？這是因為每種作業系統所設定的檔案屬性/權限並不相同， 為了存放這些檔案所需的資料，因此就需要將分割槽進行格式化，以成為作業系統能夠利用的『檔案系統格式(filesystem)』。

由此我們也能夠知道，每種作業系統能夠使用的檔案系統並不相同。 舉例來說，windows 98 以前的微軟作業系統主要利用的檔案系統是 FAT (或 FAT16)，windows 2000 以後的版本有所謂的 NTFS 檔案系統，至於 Linux 的正統檔案系統則為 Ext2 (Linux second extended file system, ext2fs)這一個。此外，在預設的情況下，windows 作業系統是不會認識 Linux 的 Ext2 的。

傳統的磁碟與檔案系統之應用中，一個分割槽就是只能夠被格式化成為一個檔案系統，所以我們可以說一個 filesystem 就是一個 partition。但是由於新技術的利用，例如我們常聽到的LVM與軟體磁碟陣列(software raid)， 這些技術可以將一個分割槽格式化為多個檔案系統(例如LVM)，也能夠將多個分割槽合成一個檔案系統(LVM, RAID)！ 所以說，目前我們在格式化時已經不再說成針對 partition 來格式化了， 通常我們可以稱呼一個可被掛載的資料為一個檔案系統而不是一個分割槽喔！

那麼檔案系統是如何運作的呢？這與作業系統的檔案資料有關。較新的作業系統的檔案資料除了檔案實際內容外， 通常含有非常多的屬性，例如 Linux 作業系統的檔案權限(rwx)與檔案屬性(擁有者、群組、時間參數等)。 檔案系統通常會將這兩部份的資料分別存放在不同的區塊，權限與屬性放置到 inode 中，至於實際資料則放置到 data block 區塊中。 另外，還有一個超級區塊 (superblock) 會記錄整個檔案系統的整體資訊，包括 inode 與 block 的總量、使用量、剩餘量等。

每個 inode 與 block 都有編號，至於這三個資料的意義可以簡略說明如下：

- superblock：記錄此 filesystem 的整體資訊，包括inode/block的總量、使用量、剩餘量， 以及檔案系統的格式與相關資訊等；

- inode：記錄檔案的屬性，一個檔案佔用一個inode，同時記錄此檔案的資料所在的 block 號碼；

- block：實際記錄檔案的內容，若檔案太大時，會佔用多個 block 。

由於每個 inode 與 block 都有編號，而每個檔案都會佔用一個 inode ，inode 內則有檔案資料放置的 block 號碼。 因此，我們可以知道的是，如果能夠找到檔案的 inode 的話，那麼自然就會知道這個檔案所放置資料的 block 號碼， 當然也就能夠讀出該檔案的實際資料了。這是個比較有效率的作法，因為如此一來我們的磁碟就能夠在短時間內讀取出全部的資料， 讀寫的效能比較好囉。

我們將 inode 與 block 區塊用圖解來說明一下，如下圖所示，檔案系統先格式化出 inode 與 block 的區塊，假設某一個檔案的屬性與權限資料是放置到 inode 4 號(下圖較小方格內)，而這個 inode 記錄了檔案資料的實際放置點為 2, 7, 13, 15 這四個 block 號碼，此時我們的作業系統就能夠據此來排列磁碟的讀取順序，可以一口氣將四個 block 內容讀出來！ 那麼資料的讀取就如同下圖中的箭頭所指定的模樣了。

圖1.2.1、inode/block 資料存取示意圖

這種資料存取的方法我們稱為索引式檔案系統(indexed allocation)。那有沒有其他的慣用檔案系統可以比較一下啊？ 有的，那就是我們慣用的隨身碟(快閃記憶體)，隨身碟使用的檔案系統一般為 FAT 格式。FAT 這種格式的檔案系統並沒有 inode 存在，所以 FAT 沒有辦法將這個檔案的所有 block 在一開始就讀取出來。每個 block 號碼都記錄在前一個 block 當中， 他的讀取方式有點像底下這樣：

圖1.2.2、FAT檔案系統資料存取示意圖

上圖中我們假設檔案的資料依序寫入1->7->4->15號這四個 block 號碼中， 但這個檔案系統沒有辦法一口氣就知道四個 block 的號碼，他得要一個一個的將 block 讀出後，才會知道下一個 block 在何處。 如果同一個檔案資料寫入的 block 分散的太過厲害時，則我們的磁碟讀取頭將無法在磁碟轉一圈就讀到所有的資料， 因此磁碟就會多轉好幾圈才能完整的讀取到這個檔案的內容！

常常會聽到所謂的『磁碟重組』吧？ 需要磁碟重組的原因就是檔案寫入的 block 太過於離散了，此時檔案讀取的效能將會變的很差所致。 這個時候可以透過磁碟重組將同一個檔案所屬的 blocks 彙整在一起，這樣資料的讀取會比較容易啊！ 想當然爾，FAT 的檔案系統需要三不五時的磁碟重組一下，那麼 Ext2 是否需要磁碟重整呢？

由於 Ext2 是索引式檔案系統，基本上不太需要常常進行磁碟重組的。但是如果檔案系統使用太久， 常常刪除/編輯/新增檔案時，那麼還是可能會造成檔案資料太過於離散的問題，此時或許會需要進行重整一下的。 不過，老實說，鳥哥倒是沒有在 Linux 作業系統上面進行過 Ext2/Ext3 檔案系統的磁碟重組說！似乎不太需要啦！^_^

Linux 的 EXT2 檔案系統(inode)：

在第六章當中我們介紹過 Linux 的檔案除了原有的資料內容外，還含有非常多的權限與屬性，這些權限與屬性是為了保護每個使用者所擁有資料的隱密性。 而前一小節我們知道 filesystem 裡面可能含有的 inode/block/superblock 等。為什麼要談這個呢？因為標準的 Linux 檔案系統 Ext2 就是使用這種 inode 為基礎的檔案系統啦！

而如同前一小節所說的，inode 的內容在記錄檔案的權限與相關屬性，至於 block 區塊則是在記錄檔案的實際內容。 而且檔案系統一開始就將 inode 與 block 規劃好了，除非重新格式化(或者利用 resize2fs 等指令變更檔案系統大小)，否則 inode 與 block 固定後就不再變動。但是如果仔細考慮一下，如果我的檔案系統高達數百GB時， 那麼將所有的 inode 與 block 通通放置在一起將是很不智的決定，因為 inode 與 block 的數量太龐大，不容易管理。

為此之故，因此 Ext2 檔案系統在格式化的時候基本上是區分為多個區塊群組 (block group) 的，每個區塊群組都有獨立的 inode/block/superblock 系統。感覺上就好像我們在當兵時，一個營裡面有分成數個連，每個連有自己的聯絡系統， 但最終都向營部回報連上最正確的資訊一般！這樣分成一群群的比較好管理啦！整個來說，Ext2 格式化後有點像底下這樣：

圖1.3.1、ext2檔案系統示意圖(註1)

在整體的規劃當中，檔案系統最前面有一個開機磁區(boot sector)，這個開機磁區可以安裝開機管理程式， 這是個非常重要的設計，因為如此一來我們就能夠將不同的開機管理程式安裝到個別的檔案系統最前端，而不用覆蓋整顆硬碟唯一的 MBR， 這樣也才能夠製作出多重開機的環境啊！至於每一個區塊群組(block group)的六個主要內容說明如後：

- data block (資料區塊)

data block 是用來放置檔案內容資料地方，在 Ext2 檔案系統中所支援的 block 大小有 1K, 2K 及 4K 三種而已。在格式化時 block 的大小就固定了，且每個 block 都有編號，以方便 inode 的記錄啦。 不過要注意的是，由於 block 大小的差異，會導致該檔案系統能夠支援的最大磁碟容量與最大單一檔案容量並不相同。 因為 block 大小而產生的 Ext2 檔案系統限制如下：(註2)

Block 大小

1KB

2KB

4KB

最大單一檔案限制

16GB

256GB

2TB

最大檔案系統總容量

2TB

8TB

16TB

你需要注意的是，雖然 Ext2 已經能夠支援大於 2GB 以上的單一檔案容量，不過某些應用程式依然使用舊的限制， 也就是說，某些程式只能夠捉到小於 2GB 以下的檔案而已，這就跟檔案系統無關了！ 舉例來說，鳥哥在環工方面的應用中有一套秀圖軟體稱為PAVE(註3)， 這套軟體就無法捉到鳥哥在數值模式模擬後產生的大於 2GB 以上的檔案！害的鳥哥常常還要重跑數值模式...

除此之外 Ext2 檔案系統的 block 還有什麼限制呢？有的！基本限制如下：

- 原則上，block 的大小與數量在格式化完就不能夠再改變了(除非重新格式化)；

- 每個 block 內最多只能夠放置一個檔案的資料；

- 承上，如果檔案大於 block 的大小，則一個檔案會佔用多個 block 數量；

- 承上，若檔案小於 block ，則該 block 的剩餘容量就不能夠再被使用了(磁碟空間會浪費)。

如上第四點所說，由於每個 block 僅能容納一個檔案的資料而已，因此如果你的檔案都非常小，但是你的 block 在格式化時卻選用最大的 4K 時，可能會產生一些容量的浪費喔！我們以底下的一個簡單例題來算一下空間的浪費吧！

例題：

假設你的Ext2檔案系統使用 4K block ，而該檔案系統中有 10000 個小檔案，每個檔案大小均為 50bytes， 請問此時你的磁碟浪費多少容量？

答：

由於 Ext2 檔案系統中一個 block 僅能容納一個檔案，因此每個 block 會浪費『 4096 - 50 = 4046 (byte)』， 系統中總共有一萬個小檔案，所有檔案容量為：50 (bytes) x 10000 = 488.3Kbytes，但此時浪費的容量為：『 4046 (bytes) x 10000 = 38.6MBytes 』。想一想，不到 1MB 的總檔案容量卻浪費將近 40MB 的容量，且檔案越多將造成越多的磁碟容量浪費。

什麼情況會產生上述的狀況呢？例如 BBS 網站的資料啦！如果 BBS 上面的資料使用的是純文字檔案來記載每篇留言， 而留言內容如果都寫上『如題』時，想一想，是否就會產生很多小檔案了呢？

好，既然大的 block 可能會產生較嚴重的磁碟容量浪費，那麼我們是否就將 block 大小訂為 1K 即可？ 這也不妥，因為如果 block 較小的話，那麼大型檔案將會佔用數量更多的 block ，而 inode 也要記錄更多的 block 號碼，此時將可能導致檔案系統不良的讀寫效能。

所以我們可以說，在您進行檔案系統的格式化之前，請先想好該檔案系統預計使用的情況。 以鳥哥來說，我的數值模式模擬平台隨便一個檔案都好幾百 MB，那麼 block 容量當然選擇較大的！至少檔案系統就不必記錄太多的 block 號碼，讀寫起來也比較方便啊！

- inode table (inode 表格)

再來討論一下 inode 這個玩意兒吧！如前所述 inode 的內容在記錄檔案的屬性以及該檔案實際資料是放置在哪幾號 block 內！ 基本上，inode 記錄的檔案資料至少有底下這些：(註4)

- 該檔案的存取模式(read/write/excute)；

- 該檔案的擁有者與群組(owner/group)；

- 該檔案的容量；

- 該檔案建立或狀態改變的時間(ctime)；

- 最近一次的讀取時間(atime)；

- 最近修改的時間(mtime)；

- 定義檔案特性的旗標(flag)，如 SetUID...；

- 該檔案真正內容的指向 (pointer)；

inode 的數量與大小也是在格式化時就已經固定了，除此之外 inode 還有些什麼特色呢？

- 每個 inode 大小均固定為 128 bytes；

- 每個檔案都僅會佔用一個 inode 而已；

- 承上，因此檔案系統能夠建立的檔案數量與 inode 的數量有關；

- 系統讀取檔案時需要先找到 inode，並分析 inode 所記錄的權限與使用者是否符合，若符合才能夠開始實際讀取 block 的內容。

我們約略來分析一下 inode / block 與檔案大小的關係好了。inode 要記錄的資料非常多，但偏偏又只有 128bytes 而已， 而 inode 記錄一個 block 號碼要花掉 4byte ，假設我一個檔案有 400MB 且每個 block 為 4K 時， 那麼至少也要十萬筆 block 號碼的記錄呢！inode 哪有這麼多可記錄的資訊？為此我們的系統很聰明的將 inode 記錄 block 號碼的區域定義為12個直接，一個間接, 一個雙間接與一個三間接記錄區。這是啥？我們將 inode 的結構畫一下好了。

圖1.3.2、inode 結構示意圖(註5)

上圖最左邊為 inode 本身 (128 bytes)，裡面有 12 個直接指向 block 號碼的對照，這 12 筆記錄就能夠直接取得 block 號碼啦！ 至於所謂的間接就是再拿一個 block 來當作記錄 block 號碼的記錄區，如果檔案太大時， 就會使用間接的 block 來記錄號碼。如上圖 1.3.2 當中間接只是拿一個 block 來記錄額外的號碼而已。 同理，如果檔案持續長大，那麼就會利用所謂的雙間接，第一個 block 僅再指出下一個記錄號碼的 block 在哪裡， 實際記錄的在第二個 block 當中。依此類推，三間接就是利用第三層 block 來記錄號碼啦！

這樣子 inode 能夠指定多少個 block 呢？我們以較小的 1K block 來說明好了，可以指定的情況如下：

- 12 個直接指向： 12*1K=12K

由於是直接指向，所以總共可記錄 12 筆記錄，因此總額大小為如上所示；

- 間接： 256*1K=256K

每筆 block 號碼的記錄會花去 4bytes，因此 1K 的大小能夠記錄 256 筆記錄，因此一個間接可以記錄的檔案大小如上；

- 雙間接： 256*256*1K=256^2K

第一層 block 會指定 256 個第二層，每個第二層可以指定 256 個號碼，因此總額大小如上；

- 三間接： 256*256*256*1K=256^3K

第一層 block 會指定 256 個第二層，每個第二層可以指定 256 個第三層，每個第三層可以指定 256 個號碼，因此總額大小如上；

- 總額：將直接、間接、雙間接、三間接加總，得到 12 + 256 + 256*256 + 256*256*256 (K) = 16GB

此時我們知道當檔案系統將 block 格式化為 1K 大小時，能夠容納的最大檔案為 16GB，比較一下檔案系統限制表的結果可發現是一致的！但這個方法不能用在 2K 及 4K block 大小的計算中， 因為大於 2K 的 block 將會受到 Ext2 檔案系統本身的限制，所以計算的結果會不太符合之故。

- Superblock (超級區塊)

Superblock 是記錄整個 filesystem 相關資訊的地方， 沒有 Superblock ，就沒有這個 filesystem 了。他記錄的資訊主要有：

- block 與 inode 的總量；

- 未使用與已使用的 inode / block 數量；

- block 與 inode 的大小 (block 為 1, 2, 4K，inode 為 128 bytes)；

- filesystem 的掛載時間、最近一次寫入資料的時間、最近一次檢驗磁碟 (fsck) 的時間等檔案系統的相關資訊；

- 一個 valid bit 數值，若此檔案系統已被掛載，則 valid bit 為 0 ，若未被掛載，則 valid bit 為 1 。

Superblock 是非常重要的，因為我們這個檔案系統的基本資訊都寫在這裡，因此，如果 superblock 死掉了， 你的檔案系統可能就需要花費很多時間去挽救啦！一般來說， superblock 的大小為 1024bytes。相關的 superblock 訊息我們等一下會以 dumpe2fs 指令來呼叫出來觀察喔！

此外，每個 block group 都可能含有 superblock 喔！但是我們也說一個檔案系統應該僅有一個 superblock 而已，那是怎麼回事啊？ 事實上除了第一個 block group 內會含有 superblock 之外，後續的 block group 不一定含有 superblock ， 而若含有 superblock 則該 superblock 主要是做為第一個 block group 內 superblock 的備份咯，這樣可以進行 superblock 的救援呢！

- Filesystem Description (檔案系統描述說明)

這個區段可以描述每個 block group 的開始與結束的 block 號碼，以及說明每個區段 (superblock, bitmap, inodemap, data block) 分別介於哪一個 block 號碼之間。這部份也能夠用 dumpe2fs 來觀察的。

- block bitmap (區塊對照表)

如果你想要新增檔案時總會用到 block 吧！那你要使用哪個 block 來記錄呢？當然是選擇『空的 block 』來記錄新檔案的資料囉。 那你怎麼知道哪個 block 是空的？這就得要透過 block bitmap 的輔助了。從 block bitmap 當中可以知道哪些 block 是空的，因此我們的系統就能夠很快速的找到可使用的空間來處置檔案囉。

同樣的，如果你刪除某些檔案時，那麼那些檔案原本佔用的 block 號碼就得要釋放出來， 此時在 block bitmap 當中相對應到該 block 號碼的標誌就得要修改成為『未使用中』囉！這就是 bitmap 的功能。

- inode bitmap (inode 對照表)

這個其實與 block bitmap 是類似的功能，只是 block bitmap 記錄的是使用與未使用的 block 號碼， 至於 inode bitmap 則是記錄使用與未使用的 inode 號碼囉！

瞭解了檔案系統的概念之後，再來當然是觀察這個檔案系統囉！剛剛談到的各部分資料都與 block 號碼有關！ 每個區段與 superblock 的資訊都可以使用 dumpe2fs 這個指令來查詢的！查詢的方法與實際的觀察如下：

[root@www ~]# dumpe2fs [-bh] 裝置檔名

選項與參數：

-b ：列出保留為壞軌的部分(一般用不到吧！？)

-h ：僅列出 superblock 的資料，不會列出其他的區段內容！

範例：找出我的根目錄磁碟檔名，並觀察檔案系統的相關資訊

[root@www ~]# df   <==這個指令可以叫出目前掛載的裝置

Filesystem    1K-blocks      Used Available Use% Mounted on

/dev/hdc2       9920624   3822848   5585708  41% /        <==就是這個光！

/dev/hdc3       4956316    141376   4559108   4% /home

/dev/hdc1        101086     11126     84741  12% /boot

tmpfs            371332         0    371332   0% /dev/shm

[root@www ~]# dumpe2fs /dev/hdc2

dumpe2fs 1.39 (29-May-2006)

Filesystem volume name:   /1             <==這個是檔案系統的名稱(Label)

Filesystem features:      has_journal ext_attr resize_inode dir_index

filetype needs_recovery sparse_super large_file

Default mount options:    user_xattr acl <==預設掛載的參數

Filesystem state:         clean          <==這個檔案系統是沒問題的(clean)

Errors behavior:          Continue

Filesystem OS type:       Linux

Inode count:              2560864        <==inode的總數

Block count:              2560359        <==block的總數

Free blocks:              1524760        <==還有多少個 block 可用

Free inodes:              2411225        <==還有多少個 inode 可用

First block:              0

Block size:               4096           <==每個 block 的大小啦！

Filesystem created:       Fri Sep  5 01:49:20 2008

Last mount time:          Mon Sep 22 12:09:30 2008

Last write time:          Mon Sep 22 12:09:30 2008

Last checked:             Fri Sep  5 01:49:20 2008

First inode:              11

Inode size:               128            <==每個 inode 的大小

Journal inode:            8              <==底下這三個與下一小節有關

Journal backup:           inode blocks

Journal size:             128M

Group 0: (Blocks 0-32767) <==第一個 data group 內容, 包含 block 的啟始/結束號碼

Primary superblock at 0, Group descriptors at 1-1  <==超級區塊在 0 號 block

Reserved GDT blocks at 2-626

Block bitmap at 627 (+627), Inode bitmap at 628 (+628)

Inode table at 629-1641 (+629)                     <==inode table 所在的 block

0 free blocks, 32405 free inodes, 2 directories    <==所有 block 都用完了！

Free blocks:

Free inodes: 12-32416                              <==剩餘未使用的 inode 號碼

Group 1: (Blocks 32768-65535)

....(底下省略)....

# 由於資料量非常的龐大，因此鳥哥將一些資訊省略輸出了！上表與你的螢幕會有點差異。

# 前半部在秀出 supberblock 的內容，包括標頭名稱(Label)以及inode/block的相關資訊

# 後面則是每個 block group 的個別資訊了！您可以看到各區段資料所在的號碼！

# 也就是說，基本上所有的資料還是與 block 的號碼有關就是了！很重要！

如上所示，利用 dumpe2fs 可以查詢到非常多的資訊，不過依內容主要可以區分為上半部是 superblock 內容， 下半部則是每個 block group 的資訊了。從上面的表格中我們可以觀察到這個 /dev/hdc2 規劃的 block 為 4K， 第一個 block 號碼為 0 號，且 block group 內的所有資訊都以 block 的號碼來表示的。 然後在 superblock 中還有談到目前這個檔案系統的可用 block 與 inode 數量喔！

至於 block group 的內容我們單純看 Group0 資訊好了。從上表中我們可以發現：

- Group0 所佔用的 block 號碼由 0 到 32767 號，superblock 則在第 0 號的 block 區塊內！

- 檔案系統描述說明在第 1 號 block 中；

- block bitmap 與 inode bitmap 則在 627 及 628 的 block 號碼上。

- 至於 inode table 分佈於 629-1641 的 block 號碼中！

- 由於 (1)一個 inode 佔用 128 bytes ，(2)總共有 1641 - 629 + 1(629本身) = 1013 個 block 花在 inode table 上， (3)每個 block 的大小為 4096 bytes(4K)。由這些數據可以算出 inode 的數量共有 1013 * 4096 / 128 = 32416 個 inode 啦！

- 這個 Group0 目前沒有可用的 block 了，但是有剩餘 32405 個 inode 未被使用；

- 剩餘的 inode 號碼為 12 號到 32416 號。

如果你對檔案系統的詳細資訊還有更多想要瞭解的話，那麼請參考本章最後一小節的介紹喔！ 否則檔案系統看到這裡對於基礎認知您應該是已經相當足夠啦！底下則是要探討一下， 那麼這個檔案系統概念與實際的目錄樹應用有啥關連啊？

與目錄樹的關係

由前一小節的介紹我們知道在 Linux 系統下，每個檔案(不管是一般檔案還是目錄檔案)都會佔用一個 inode ， 且可依據檔案內容的大小來分配多個 block 給該檔案使用。而由第六章的權限說明中我們知道目錄的內容在記錄檔名， 一般檔案才是實際記錄資料內容的地方。那麼目錄與檔案在 Ext2 檔案系統當中是如何記錄資料的呢？ 基本上可以這樣說：

- 目錄

當我們在 Linux 下的 ext2 檔案系統建立一個目錄時， ext2 會分配一個 inode 與至少一塊 block 給該目錄。其中，inode 記錄該目錄的相關權限與屬性，並可記錄分配到的那塊 block 號碼； 而 block 則是記錄在這個目錄下的檔名與該檔名佔用的 inode 號碼資料。也就是說目錄所佔用的 block 內容在記錄如下的資訊：

圖1.4.1、目錄佔用的 block 記錄的資料示意圖

如果想要實際觀察 root 家目錄內的檔案所佔用的 inode 號碼時，可以使用 ls -i 這個選項來處理：

[root@www ~]# ls -li

total 92

654683 -rw------- 1 root root  1474 Sep  4 18:27 anaconda-ks.cfg

648322 -rw-r--r-- 1 root root 42304 Sep  4 18:26 install.log

648323 -rw-r--r-- 1 root root  5661 Sep  4 18:25 install.log.syslog

由於每個人所使用的電腦並不相同，系統安裝時選擇的項目與 partition 都不一樣，因此你的環境不可能與我的 inode 號碼一模一樣！上表的左邊所列出的 inode 僅是鳥哥的系統所顯示的結果而已！而由這個目錄的 block 結果我們現在就能夠知道， 當你使用『 ll / 』時，出現的目錄幾乎都是 1024 的倍數，為什麼呢？因為每個 block 的數量都是 1K, 2K, 4K 嘛！ 看一下鳥哥的環境：

[root@www ~]# ll -d / /bin /boot /proc /lost+found /sbin

drwxr-xr-x 23 root root  4096 Sep 22 12:09 /           <==一個 4K block

drwxr-xr-x  2 root root  4096 Sep 24 00:07 /bin        <==一個 4K block

drwxr-xr-x  4 root root  1024 Sep  4 18:06 /boot       <==一個 1K block

drwx------  2 root root 16384 Sep  5 01:49 /lost+found <==四個 4K block

dr-xr-xr-x 96 root root     0 Sep 22 20:07 /proc       <==此目錄不佔硬碟空間

drwxr-xr-x  2 root root 12288 Sep  5 12:33 /sbin       <==三個 4K block

由於鳥哥的根目錄 /dev/hdc2 使用的 block 大小為 4K ，因此每個目錄幾乎都是 4K 的倍數。 其中由於 /sbin 的內容比較複雜因此佔用了 3 個 block ，此外，鳥哥的系統中 /boot 為獨立的 partition ， 該 partition 的 block 為 1K 而已，因此該目錄就僅佔用 1024 bytes 的大小囉！至於奇怪的 /proc 我們在第六章就講過該目錄不佔硬碟容量， 所以當然耗用的 block 就是 0 囉！

Tips:

由上面的結果我們知道目錄並不只會佔用一個 block 而已，也就是說： 在目錄底下的檔案數如果太多而導致一個 block 無法容納的下所有的檔名與 inode 對照表時，Linux 會給予該目錄多一個 block 來繼續記錄相關的資料；

- 檔案：

當我們在 Linux 下的 ext2 建立一個一般檔案時， ext2 會分配一個 inode 與相對於該檔案大小的 block 數量給該檔案。例如：假設我的一個 block 為 4 Kbytes ，而我要建立一個 100 KBytes 的檔案，那麼 linux 將分配一個 inode 與 25 個 block 來儲存該檔案！ 但同時請注意，由於 inode 僅有 12 個直接指向，因此還要多一個 block 來作為區塊號碼的記錄喔！

- 目錄樹讀取：

好了，經過上面的說明你也應該要很清楚的知道 inode 本身並不記錄檔名，檔名的記錄是在目錄的 block 當中。 因此在第六章檔案與目錄的權限說明中， 我們才會提到『新增/刪除/更名檔名與目錄的 w 權限有關』的特色！那麼因為檔名是記錄在目錄的 block 當中， 因此當我們要讀取某個檔案時，就務必會經過目錄的 inode 與 block ，然後才能夠找到那個待讀取檔案的 inode 號碼， 最終才會讀到正確的檔案的 block 內的資料。

由於目錄樹是由根目錄開始讀起，因此系統透過掛載的資訊可以找到掛載點的 inode 號碼(通常一個 filesystem 的最頂層 inode 號碼會由 2 號開始喔！)，此時就能夠得到根目錄的 inode 內容，並依據該 inode 讀取根目錄的 block 內的檔名資料，再一層一層的往下讀到正確的檔名。

舉例來說，如果我想要讀取 /etc/passwd 這個檔案時，系統是如何讀取的呢？

[root@www ~]# ll -di / /etc /etc/passwd

2 drwxr-xr-x  23 root root  4096 Sep 22 12:09 /

1912545 drwxr-xr-x 105 root root 12288 Oct 14 04:02 /etc

1914888 -rw-r--r--   1 root root  1945 Sep 29 02:21 /etc/passwd

在鳥哥的系統上面與 /etc/passwd 有關的目錄與檔案資料如上表所示，該檔案的讀取流程為(假設讀取者身份為 vbird 這個一般身份使用者)：

1. / 的 inode：

透過掛載點的資訊找到 /dev/hdc2 的 inode 號碼為 2 的根目錄 inode，且 inode 規範的權限讓我們可以讀取該 block 的內容(有 r 與 x) ；

2. / 的 block：

經過上個步驟取得 block 的號碼，並找到該內容有 etc/ 目錄的 inode 號碼 (1912545)；

3. etc/ 的 inode：

讀取 1912545 號 inode 得知 vbird 具有 r 與 x 的權限，因此可以讀取 etc/ 的 block 內容；

4. etc/ 的 block：

經過上個步驟取得 block 號碼，並找到該內容有 passwd 檔案的 inode 號碼 (1914888)；

5. passwd 的 inode：

讀取 1914888 號 inode 得知 vbird 具有 r 的權限，因此可以讀取 passwd 的 block 內容；

6. passwd 的 block：

最後將該 block 內容的資料讀出來。

- filesystem 大小與磁碟讀取效能：

另外，關於檔案系統的使用效率上，當你的一個檔案系統規劃的很大時，例如 100GB 這麼大時， 由於硬碟上面的資料總是來來去去的，所以，整個檔案系統上面的檔案通常無法連續寫在一起(block 號碼不會連續的意思)， 而是填入式的將資料填入沒有被使用的 block 當中。如果檔案寫入的 block 真的分的很散， 此時就會有所謂的檔案資料離散的問題發生了。

如前所述，雖然我們的 ext2 在 inode 處已經將該檔案所記錄的 block 號碼都記上了， 所以資料可以一次性讀取，但是如果檔案真的太過離散，確實還是會發生讀取效率低落的問題。 因為磁碟讀取頭還是得要在整個檔案系統中來來去去的頻繁讀取！ 果真如此，那麼可以將整個 filesystme 內的資料全部複製出來，將該 filesystem 重新格式化， 再將資料給他複製回去即可解決這個問題。

此外，如果 filesystem 真的太大了，那麼當一個檔案分別記錄在這個檔案系統的最前面與最後面的 block 號碼中， 此時會造成硬碟的機械手臂移動幅度過大，也會造成資料讀取效能的低落。而且讀取頭在搜尋整個 filesystem 時， 也會花費比較多的時間去搜尋！因此， partition 的規劃並不是越大越好， 而是真的要針對您的主機用途來進行規劃才行！^_^

EXT2/EXT3 檔案的存取與日誌式檔案系統的功能

上一小節談到的僅是讀取而已，那麼如果是新建一個檔案或目錄時，我們的 Ext2 是如何處理的呢？ 這個時候就得要 block bitmap 及 inode bitmap 的幫忙了！假設我們想要新增一個檔案，此時檔案系統的行為是：

1. 先確定使用者對於欲新增檔案的目錄是否具有 w 與 x 的權限，若有的話才能新增；

2. 根據 inode bitmap 找到沒有使用的 inode 號碼，並將新檔案的權限/屬性寫入；

3. 根據 block bitmap 找到沒有使用中的 block 號碼，並將實際的資料寫入 block 中，且更新 inode 的 block 指向資料；

4. 將剛剛寫入的 inode 與 block 資料同步更新 inode bitmap 與 block bitmap，並更新 superblock 的內容。

一般來說，我們將 inode table 與 data block 稱為資料存放區域，至於其他例如 superblock、 block bitmap 與 inode bitmap 等區段就被稱為 metadata (中介資料) 囉，因為 superblock, inode bitmap 及 block bitmap 的資料是經常變動的，每次新增、移除、編輯時都可能會影響到這三個部分的資料，因此才被稱為中介資料的啦。

- 資料的不一致 (Inconsistent) 狀態

在一般正常的情況下，上述的新增動作當然可以順利的完成。但是如果有個萬一怎麼辦？ 例如你的檔案在寫入檔案系統時，因為不知名原因導致系統中斷(例如突然的停電啊、 系統核心發生錯誤啊∼等等的怪事發生時)，所以寫入的資料僅有 inode table 及 data block 而已， 最後一個同步更新中介資料的步驟並沒有做完，此時就會發生 metadata 的內容與實際資料存放區產生不一致 (Inconsistent) 的情況了。

既然有不一致當然就得要克服！在早期的 Ext2 檔案系統中，如果發生這個問題， 那麼系統在重新開機的時候，就會藉由 Superblock 當中記錄的 valid bit (是否有掛載) 與 filesystem state (clean 與否) 等狀態來判斷是否強制進行資料一致性的檢查！若有需要檢查時則以 e2fsck 這支程式來進行的。

不過，這樣的檢查真的是很費時∼因為要針對 metadata 區域與實際資料存放區來進行比對， 呵呵∼得要搜尋整個 filesystem 呢∼如果你的檔案系統有 100GB 以上，而且裡面的檔案數量又多時， 哇！系統真忙碌∼而且在對 Internet 提供服務的伺服器主機上面， 這樣的檢查真的會造成主機復原時間的拉長∼真是麻煩∼這也就造成後來所謂日誌式檔案系統的興起了。

- 日誌式檔案系統 (Journaling filesystem)

為了避免上述提到的檔案系統不一致的情況發生，因此我們的前輩們想到一個方式， 如果在我們的 filesystem 當中規劃出一個區塊，該區塊專門在記錄寫入或修訂檔案時的步驟， 那不就可以簡化一致性檢查的步驟了？也就是說：

1. 預備：當系統要寫入一個檔案時，會先在日誌記錄區塊中紀錄某個檔案準備要寫入的資訊；

2. 實際寫入：開始寫入檔案的權限與資料；開始更新 metadata 的資料；

3. 結束：完成資料與 metadata 的更新後，在日誌記錄區塊當中完成該檔案的紀錄。

在這樣的程序當中，萬一資料的紀錄過程當中發生了問題，那麼我們的系統只要去檢查日誌記錄區塊， 就可以知道哪個檔案發生了問題，針對該問題來做一致性的檢查即可，而不必針對整塊 filesystem 去檢查， 這樣就可以達到快速修復 filesystem 的能力了！這就是日誌式檔案最基礎的功能囉∼

那麼我們的 ext2 可達到這樣的功能嗎？當然可以啊！ 就透過 ext3 即可！ ext3 是 ext2 的升級版本，並且可向下相容 ext2 版本呢！ 所以囉，目前我們才建議大家，可以直接使用 ext3 這個 filesystem 啊！ 如果你還記得 dumpe2fs 輸出的訊息，可以發現 superblock 裡面含有底下這樣的資訊：

Journal inode:            8

Journal backup:           inode blocks

Journal size:             128M

看到了吧！透過 inode 8 號記錄 journal 區塊的 block 指向，而且具有 128MB 的容量在處理日誌呢！ 這樣對於所謂的日誌式檔案系統有沒有比較有概念一點呢？^_^。如果想要知道為什麼 Ext3 檔案系統會更適用於目前的 Linux 系統， 我們可以參考 Red Hat 公司中，首席核心開發者 Michael K. Johnson 的話：(註6)

『為什麼你想要從ext2轉換到ext3呢？有四個主要的理由：可利用性、資料完整性、速度及易於轉換』 『可利用性』，他指出，這意味著從系統中止到快速重新復原而不是持續的讓e2fsck執行長時間的修復。ext3 的日誌式條件可以避免資料毀損的可能。他也指出： 『除了寫入若干資料超過一次時，ext3往往會較快於ext2，因為ext3的日誌使硬碟讀取頭的移動能更有效的進行』 然而或許決定的因素還是在Johnson先生的第四個理由中。

『它是可以輕易的從ext2變更到ext3來獲得一個強而有力的日誌式檔案系統而不需要重新做格式化』。『那是正確的，為了體驗一下 ext3 的好處是不需要去做一種長時間的，冗長乏味的且易於產生錯誤的備份工作及重新格式化的動作』。

Linux 檔案系統的運作：

我們現在知道了目錄樹與檔案系統的關係了，但是由第零章的內容我們也知道， 所有的資料都得要載入到記憶體後 CPU 才能夠對該資料進行處理。想一想，如果你常常編輯一個好大的檔案， 在編輯的過程中又頻繁的要系統來寫入到磁碟中，由於磁碟寫入的速度要比記憶體慢很多， 因此你會常常耗在等待硬碟的寫入/讀取上。真沒效率！

為了解決這個效率的問題，因此我們的 Linux 使用的方式是透過一個稱為非同步處理 (asynchronously) 的方式。所謂的非同步處理是這樣的：

當系統載入一個檔案到記憶體後，如果該檔案沒有被更動過，則在記憶體區段的檔案資料會被設定為乾淨(clean)的。 但如果記憶體中的檔案資料被更改過了(例如你用 nano 去編輯過這個檔案)，此時該記憶體中的資料會被設定為髒的 (Dirty)。此時所有的動作都還在記憶體中執行，並沒有寫入到磁碟中！ 系統會不定時的將記憶體中設定為『Dirty』的資料寫回磁碟，以保持磁碟與記憶體資料的一致性。 你也可以利用第五章談到的 sync指令來手動強迫寫入磁碟。

我們知道記憶體的速度要比硬碟快的多，因此如果能夠將常用的檔案放置到記憶體當中，這不就會增加系統性能嗎？ 沒錯！是有這樣的想法！因此我們 Linux 系統上面檔案系統與記憶體有非常大的關係喔：

- 系統會將常用的檔案資料放置到主記憶體的緩衝區，以加速檔案系統的讀/寫；

- 承上，因此 Linux 的實體記憶體最後都會被用光！這是正常的情況！可加速系統效能；

- 你可以手動使用 sync 來強迫記憶體中設定為 Dirty 的檔案回寫到磁碟中；

- 若正常關機時，關機指令會主動呼叫 sync 來將記憶體的資料回寫入磁碟內；

- 但若不正常關機(如跳電、當機或其他不明原因)，由於資料尚未回寫到磁碟內， 因此重新開機後可能會花很多時間在進行磁碟檢驗，甚至可能導致檔案系統的損毀(非磁碟損毀)。

掛載點的意義 (mount point)：

每個 filesystem 都有獨立的 inode / block / superblock 等資訊，這個檔案系統要能夠連結到目錄樹才能被我們使用。 將檔案系統與目錄樹結合的動作我們稱為『掛載』。 關於掛載的一些特性我們在第三章稍微提過， 重點是：掛載點一定是目錄，該目錄為進入該檔案系統的入口。 因此並不是你有任何檔案系統都能使用，必須要『掛載』到目錄樹的某個目錄後，才能夠使用該檔案系統的。

舉例來說，如果你是依據鳥哥的方法安裝你的 CentOS 5.x 的話， 那麼應該會有三個掛載點才是，分別是 /, /boot, /home 三個 (鳥哥的系統上對應的裝置檔名為 /dev/hdc2, /dev/hdc1, /dev/hdc3)。 那如果觀察這三個目錄的 inode 號碼時，我們可以發現如下的情況：

[root@www ~]# ls -lid / /boot /home

2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /

2 drwxr-xr-x  4 root root 1024 Sep  4 18:06 /boot

2 drwxr-xr-x  6 root root 4096 Sep 29 02:21 /home

看到了吧！由於 filesystem 最頂層的目錄之 inode 一般為 2 號，因此可以發現 /, /boot, /home 為三個不同的 filesystem 囉！ (因為每一行的檔案屬性並不相同，且三個目錄的掛載點也均不相同之故。) 我們在第七章一開始的路徑中曾經提到根目錄下的 . 與 .. 是相同的東西， 因為權限是一模一樣嘛！如果使用檔案系統的觀點來看，同一個 filesystem 的某個 inode 只會對應到一個檔案內容而已(因為一個檔案佔用一個 inode 之故)， 因此我們可以透過判斷 inode 號碼來確認不同檔名是否為相同的檔案喔！所以可以這樣看：

[root@www ~]# ls -ild /  /.  /..

2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /

2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /.

2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /..

上面的資訊中由於掛載點均為 / ，因此三個檔案 (/, /., /..) 均在同一個 filesystem 內，而這三個檔案的 inode 號碼均為 2 號，因此這三個檔名都指向同一個 inode 號碼，當然這三個檔案的內容也就完全一模一樣了！ 也就是說，根目錄的上層 (/..) 就是他自己！這麼說，看的懂了嗎？ ^_^

其他 Linux 支援的檔案系統與 VFS

雖然 Linux 的標準檔案系統是 ext2 ，且還有增加了日誌功能的 ext3 ，事實上，Linux 還有支援很多檔案系統格式的， 尤其是最近這幾年推出了好幾種速度很快的日誌式檔案系統，包括 SGI 的 XFS 檔案系統， 可以適用更小型檔案的 Reiserfs 檔案系統，以及 Windows 的 FAT 檔案系統等等， 都能夠被 Linux 所支援喔！常見的支援檔案系統有：

- 傳統檔案系統：ext2 / minix / MS-DOS / FAT (用 vfat 模組) / iso9660 (光碟)等等；

- 日誌式檔案系統： ext3 / ReiserFS / Windows' NTFS / IBM's JFS / SGI's XFS

- 網路檔案系統： NFS / SMBFS

想要知道你的 Linux 支援的檔案系統有哪些，可以察看底下這個目錄：

[root@www ~]# ls -l /lib/modules/$(uname -r)/kernel/fs

系統目前已載入到記憶體中支援的檔案系統則有：

[root@www ~]# cat /proc/filesystems

- Linux VFS (Virtual Filesystem Switch)

瞭解了我們使用的檔案系統之後，再來則是要提到，那麼 Linux 的核心又是如何管理這些認識的檔案系統呢？ 其實，整個 Linux 的系統都是透過一個名為 Virtual Filesystem Switch 的核心功能去讀取 filesystem 的。 也就是說，整個 Linux 認識的 filesystem 其實都是 VFS 在進行管理，我們使用者並不需要知道每個 partition 上頭的 filesystem 是什麼∼ VFS 會主動的幫我們做好讀取的動作呢∼

假設你的 / 使用的是 /dev/hda1 ，用 ext3 ，而 /home 使用 /dev/hda2 ，用 reiserfs ， 那麼你取用 /home/dmtsai/.bashrc 時，有特別指定要用的什麼檔案系統的模組來讀取嗎？ 應該是沒有吧！這個就是 VFS 的功能啦！透過這個 VFS 的功能來管理所有的 filesystem， 省去我們需要自行設定讀取檔案系統的定義啊∼方便很多！整個 VFS 可以約略用下圖來說明：

圖 1.8.1、VFS 檔案系統的示意圖

老實說，檔案系統真的不好懂！ 如果你想要對檔案系統有更深入的瞭解，文末的相關連結(註7)務必要參考參考才好喔！ 鳥哥有找了一些資料放置於這裡：

- Ext2/Ext3 檔案系統：appendix_B.htm

有興趣的朋友務必要前往參考參考才好！

檔案系統的簡單操作

稍微瞭解了檔案系統後，再來我們得要知道如何查詢整體檔案系統的總容量與每個目錄所佔用的容量囉！ 此外，前兩章談到的檔案類型中尚未講的很清楚的連結檔 (Link file) 也會在這一小節當中介紹的。

磁碟與目錄的容量：

現在我們知道磁碟的整體資料是在 superblock 區塊中，但是每個各別檔案的容量則在 inode 當中記載的。 那在文字介面底下該如何叫出這幾個資料呢？底下就讓我們來談一談這兩個指令：

- df：列出檔案系統的整體磁碟使用量；

- du：評估檔案系統的磁碟使用量(常用在推估目錄所佔容量)

- df

[root@www ~]# df [-ahikHTm] [目錄或檔名]

選項與參數：

-a  ：列出所有的檔案系統，包括系統特有的 /proc 等檔案系統；

-k  ：以 KBytes 的容量顯示各檔案系統；

-m  ：以 MBytes 的容量顯示各檔案系統；

-h  ：以人們較易閱讀的 GBytes, MBytes, KBytes 等格式自行顯示；

-H  ：以 M=1000K 取代 M=1024K 的進位方式；

-T  ：連同該 partition 的 filesystem 名稱 (例如 ext3) 也列出；

-i  ：不用硬碟容量，而以 inode 的數量來顯示

範例一：將系統內所有的 filesystem 列出來！

[root@www ~]# df

Filesystem      1K-blocks      Used Available Use% Mounted on

/dev/hdc2         9920624   3823112   5585444  41% /

/dev/hdc3         4956316    141376   4559108   4% /home

/dev/hdc1          101086     11126     84741  12% /boot

tmpfs              371332         0    371332   0% /dev/shm

# 在 Linux 底下如果 df 沒有加任何選項，那麼預設會將系統內所有的

# (不含特殊記憶體內的檔案系統與 swap) 都以 1 Kbytes 的容量來列出來！

# 至於那個 /dev/shm 是與記憶體有關的掛載，先不要理他！

範例二：將容量結果以易讀的容量格式顯示出來

[root@www ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdc2             9.5G  3.7G  5.4G  41% /

/dev/hdc3             4.8G  139M  4.4G   4% /home

/dev/hdc1              99M   11M   83M  12% /boot

tmpfs                 363M     0  363M   0% /dev/shm

# 不同於範例一，這裡會以 G/M 等容量格式顯示出來，比較容易看啦！

範例三：將系統內的所有特殊檔案格式及名稱都列出來

[root@www ~]# df -aT

Filesystem    Type 1K-blocks    Used Available Use% Mounted on

/dev/hdc2     ext3   9920624 3823112   5585444  41% /

proc          proc         0       0         0   -  /proc

sysfs        sysfs         0       0         0   -  /sys

devpts      devpts         0       0         0   -  /dev/pts

/dev/hdc3     ext3   4956316  141376   4559108   4% /home

/dev/hdc1     ext3    101086   11126     84741  12% /boot

tmpfs        tmpfs    371332       0    371332   0% /dev/shm

none   binfmt_misc         0       0         0   -  /proc/sys/fs/binfmt_misc

sunrpc  rpc_pipefs         0       0         0   -  /var/lib/nfs/rpc_pipefs

# 系統裡面其實還有很多特殊的檔案系統存在的。那些比較特殊的檔案系統幾乎

# 都是在記憶體當中，例如 /proc 這個掛載點。因此，這些特殊的檔案系統

# 都不會佔據硬碟空間喔！ ^_^

範例四：將 /etc 底下的可用的磁碟容量以易讀的容量格式顯示

[root@www ~]# df -h /etc

Filesystem            Size  Used Avail Use% Mounted on

/dev/hdc2             9.5G  3.7G  5.4G  41% /

# 這個範例比較有趣一點啦，在 df 後面加上目錄或者是檔案時， df

# 會自動的分析該目錄或檔案所在的 partition ，並將該 partition 的容量顯示出來，

# 所以，您就可以知道某個目錄底下還有多少容量可以使用了！ ^_^

範例五：將目前各個 partition 當中可用的 inode 數量列出

[root@www ~]# df -ih

Filesystem            Inodes   IUsed   IFree IUse% Mounted on

/dev/hdc2               2.5M    147K    2.3M    6% /

/dev/hdc3               1.3M      46    1.3M    1% /home

/dev/hdc1                26K      34     26K    1% /boot

tmpfs                    91K       1     91K    1% /dev/shm

# 這個範例則主要列出可用的 inode 剩餘量與總容量。分析一下與範例一的關係，

# 你可以清楚的發現到，通常 inode 的數量剩餘都比 block 還要多呢

先來說明一下範例一所輸出的結果訊息為：

- Filesystem：代表該檔案系統是在哪個 partition ，所以列出裝置名稱；

- 1k-blocks：說明底下的數字單位是 1KB 呦！可利用 -h 或 -m 來改變容量；

- Used：顧名思義，就是使用掉的硬碟空間啦！

- Available：也就是剩下的磁碟空間大小；

- Use%：就是磁碟的使用率啦！如果使用率高達 90% 以上時， 最好需要注意一下了，免得容量不足造成系統問題喔！(例如最容易被灌爆的 /var/spool/mail 這個放置郵件的磁碟)

- Mounted on：就是磁碟掛載的目錄所在啦！(掛載點啦！)

由於 df 主要讀取的資料幾乎都是針對一整個檔案系統，因此讀取的範圍主要是在 Superblock 內的資訊， 所以這個指令顯示結果的速度非常的快速！在顯示的結果中你需要特別留意的是那個根目錄的剩餘容量！ 因為我們所有的資料都是由根目錄衍生出來的，因此當根目錄的剩餘容量剩下 0 時，那你的 Linux 可能就問題很大了。

Tips:

說個陳年老笑話！鳥哥還在唸書時，別的研究室有個管理 Sun 工作站的研究生發現， 他的硬碟明明還有好幾 GB ，但是就是沒有辦法將光碟內幾 MB 的資料 copy 進去， 他就去跟老闆講說機器壞了！嘿！明明才來維護過幾天而已為何會壞了！ 結果他老闆就將維護商叫來罵了 2 小時左右吧！

後來，維護商發現原來硬碟的『總空間』還有很多， 只是某個分割槽填滿了，偏偏該研究生就是要將資料 copy 去那個分割槽！呵呵！ 後來那個研究生就被命令『再也不許碰 Sun 主機』了∼∼

另外需要注意的是，如果使用 -a 這個參數時，系統會出現 /proc 這個掛載點，但是裡面的東西都是 0 ，不要緊張！ /proc 的東西都是 Linux 系統所需要載入的系統資料，而且是掛載在『記憶體當中』的， 所以當然沒有佔任何的硬碟空間囉！

至於那個 /dev/shm/ 目錄，其實是利用記憶體虛擬出來的磁碟空間！ 由於是透過記憶體模擬出來的磁碟，因此你在這個目錄底下建立任何資料檔案時，存取速度是非常快速的！(在記憶體內工作) 不過，也由於他是記憶體模擬出來的，因此這個檔案系統的大小在每部主機上都不一樣，而且建立的東西在下次開機時就消失了！ 因為是在記憶體中嘛！

- du

[root@www ~]# du [-ahskm] 檔案或目錄名稱

選項與參數：

-a  ：列出所有的檔案與目錄容量，因為預設僅統計目錄底下的檔案量而已。

-h  ：以人們較易讀的容量格式 (G/M) 顯示；

-s  ：列出總量而已，而不列出每個各別的目錄佔用容量；

-S  ：不包括子目錄下的總計，與 -s 有點差別。

-k  ：以 KBytes 列出容量顯示；

-m  ：以 MBytes 列出容量顯示；

範例一：列出目前目錄下的所有檔案容量

[root@www ~]# du

8       ./test4     <==每個目錄都會列出來

8       ./test2

....中間省略....

12      ./.gconfd   <==包括隱藏檔的目錄

220     .           <==這個目錄(.)所佔用的總量

# 直接輸入 du 沒有加任何選項時，則 du 會分析『目前所在目錄』

# 的檔案與目錄所佔用的硬碟空間。但是，實際顯示時，僅會顯示目錄容量(不含檔案)，

# 因此 . 目錄有很多檔案沒有被列出來，所以全部的目錄相加不會等於 . 的容量喔！

# 此外，輸出的數值資料為 1K 大小的容量單位。

範例二：同範例一，但是將檔案的容量也列出來

[root@www ~]# du -a

12      ./install.log.syslog   <==有檔案的列表了

8       ./.bash_logout

8       ./test4

8       ./test2

....中間省略....

12      ./.gconfd

220     .

範例三：檢查根目錄底下每個目錄所佔用的容量

[root@www ~]# du -sm /*

7       /bin

6       /boot

.....中間省略....

0       /proc

.....中間省略....

1       /tmp

3859    /usr     <==系統初期最大就是他了啦！

77      /var

# 這是個很常被使用的功能∼利用萬用字元 * 來代表每個目錄，

# 如果想要檢查某個目錄下，哪個次目錄佔用最大的容量，可以用這個方法找出來

# 值得注意的是，如果剛剛安裝好 Linux 時，那麼整個系統容量最大的應該是 /usr

# 而 /proc 雖然有列出容量，但是那個容量是在記憶體中，不佔硬碟空間。

與 df 不一樣的是，du 這個指令其實會直接到檔案系統內去搜尋所有的檔案資料， 所以上述第三個範例指令的運作會執行一小段時間！此外，在預設的情況下，容量的輸出是以 KB 來設計的， 如果你想要知道目錄佔了多少 MB ，那麼就使用 -m 這個參數即可囉！而， 如果你只想要知道該目錄佔了多少容量的話，使用 -s 就可以啦！

至於 -S 這個選項部分，由於 du 預設會將所有檔案的大小均列出，因此假設你在 /etc 底下使用 du 時， 所有的檔案大小，包括 /etc 底下的次目錄容量也會被計算一次。然後最終的容量 (/etc) 也會加總一次， 因此很多朋友都會誤會 du 分析的結果不太對勁。所以囉，如果想要列出某目錄下的全部資料， 或許也可以加上 -S 的選項，減少次目錄的加總喔！

實體連結與符號連結： ln

關於連結(link)資料我們第六章的Linux檔案屬性及Linux檔案種類與副檔名當中提過一些資訊， 不過當時由於尚未講到檔案系統，因此無法較完整的介紹連結檔啦。不過在上一小節談完了檔案系統後， 我們可以來瞭解一下連結檔這玩意兒了。

在 Linux 底下的連結檔有兩種，一種是類似 Windows 的捷徑功能的檔案，可以讓你快速的連結到目標檔案(或目錄)； 另一種則是透過檔案系統的 inode 連結來產生新檔名，而不是產生新檔案！這種稱為實體連結 (hard link)。 這兩種玩意兒是完全不一樣的東西呢！現在就分別來談談。

- Hard Link (實體連結, 硬式連結或實際連結)

在前一小節當中，我們知道幾件重要的資訊，包括：

- 每個檔案都會佔用一個 inode ，檔案內容由 inode 的記錄來指向；

- 想要讀取該檔案，必須要經過目錄記錄的檔名來指向到正確的 inode 號碼才能讀取。

也就是說，其實檔名只與目錄有關，但是檔案內容則與 inode 有關。那麼想一想， 有沒有可能有多個檔名對應到同一個 inode 號碼呢？有的！那就是 hard link 的由來。 所以簡單的說：hard link 只是在某個目錄下新增一筆檔名連結到某 inode 號碼的關連記錄而已。

舉個例子來說，假設我系統有個 /root/crontab 他是 /etc/crontab 的實體連結，也就是說這兩個檔名連結到同一個 inode ， 自然這兩個檔名的所有相關資訊都會一模一樣(除了檔名之外)。實際的情況可以如下所示：

[root@www ~]# ln /etc/crontab .   <==建立實體連結的指令

[root@www ~]# ll -i /etc/crontab /root/crontab

1912701 -rw-r--r-- 2 root root 255 Jan  6  2007 /etc/crontab

1912701 -rw-r--r-- 2 root root 255 Jan  6  2007 /root/crontab

你可以發現兩個檔名都連結到 1912701 這個 inode 號碼，所以您瞧瞧，是否檔案的權限/屬性完全一樣呢？ 因為這兩個『檔名』其實是一模一樣的『檔案』啦！而且你也會發現第二個欄位由原本的 1 變成 2 了！ 那個欄位稱為『連結』，這個欄位的意義為：『有多少個檔名連結到這個 inode 號碼』的意思。 如果將讀取到正確資料的方式畫成示意圖，就類似如下畫面：

圖 2.2.1、實體連結的檔案讀取示意圖

上圖的意思是，你可以透過 1 或 2 的目錄之 inode 指定的 block 找到兩個不同的檔名，而不管使用哪個檔名均可以指到 real 那個 inode 去讀取到最終資料！那這樣有什麼好處呢？最大的好處就是『安全』！如同上圖中， 如果你將任何一個『檔名』刪除，其實 inode 與 block 都還是存在的！ 此時你可以透過另一個『檔名』來讀取到正確的檔案資料喔！此外，不論你使用哪個『檔名』來編輯， 最終的結果都會寫入到相同的 inode 與 block 中，因此均能進行資料的修改哩！

一般來說，使用 hard link 設定連結檔時，磁碟的空間與 inode 的數目都不會改變！ 我們還是由圖 2.2.1 來看，由圖中可以知道， hard link 只是在某個目錄下的 block 多寫入一個關連資料而已，既不會增加 inode 也不會耗用 block 數量哩！

Tips:

hard link 的製作中，其實還是可能會改變系統的 block 的，那就是當你新增這筆資料卻剛好將目錄的 block 填滿時，就可能會新加一個 block 來記錄檔名關連性，而導致磁碟空間的變化！不過，一般 hard link 所用掉的關連資料量很小，所以通常不會改變 inode 與磁碟空間的大小喔！

由圖 2.2.1 其實我們也能夠知道，事實上 hard link 應該僅能在單一檔案系統中進行的，應該是不能夠跨檔案系統才對！ 因為圖 2.2.1 就是在同一個 filesystem 上嘛！所以 hard link 是有限制的：

- 不能跨 Filesystem；

- 不能 link 目錄。

不能跨 Filesystem 還好理解，那不能 hard link 到目錄又是怎麼回事呢？這是因為如果使用 hard link 連結到目錄時， 連結的資料需要連同被連結目錄底下的所有資料都建立連結，舉例來說，如果你要將 /etc 使用實體連結建立一個 /etc_hd 的目錄時，那麼在 /etc_hd 底下的所有檔名同時都與 /etc 底下的檔名要建立 hard link 的，而不是僅連結到 /etc_hd 與 /etc 而已。 並且，未來如果需要在 /etc_hd 底下建立新檔案時，連帶的， /etc 底下的資料又得要建立一次 hard link ，因此造成環境相當大的複雜度。 所以囉，目前 hard link 對於目錄暫時還是不支援的啊！

- Symbolic Link (符號連結，亦即是捷徑)

相對於 hard link ， Symbolic link 可就好理解多了，基本上， Symbolic link 就是在建立一個獨立的檔案，而這個檔案會讓資料的讀取指向他 link 的那個檔案的檔名！由於只是利用檔案來做為指向的動作， 所以，當來源檔被刪除之後，symbolic link 的檔案會『開不了』， 會一直說『無法開啟某檔案！』。實際上就是找不到原始『檔名』而已啦！

舉例來說，我們先建立一個符號連結檔連結到 /etc/crontab 去看看：

[root@www ~]# ln -s /etc/crontab crontab2

[root@www ~]# ll -i /etc/crontab /root/crontab2

1912701 -rw-r--r-- 2 root root 255 Jan  6  2007 /etc/crontab

654687 lrwxrwxrwx 1 root root  12 Oct 22 13:58 /root/crontab2 -> /etc/crontab

由上表的結果我們可以知道兩個檔案指向不同的 inode 號碼，當然就是兩個獨立的檔案存在！ 而且連結檔的重要內容就是他會寫上目標檔案的『檔名』， 你可以發現為什麼上表中連結檔的大小為 12 bytes 呢？ 因為箭頭(-->)右邊的檔名『/etc/crontab』總共有 12 個英文，每個英文佔用 1 個 byes ，所以檔案大小就是 12bytes了！

關於上述的說明，我們以如下圖示來解釋：

圖 2.2.2、符號連結的檔案讀取示意圖

由 1 號 inode 讀取到連結檔的內容僅有檔名，根據檔名連結到正確的目錄去取得目標檔案的 inode ， 最終就能夠讀取到正確的資料了。你可以發現的是，如果目標檔案(/etc/crontab)被刪除了，那麼整個環節就會無法繼續進行下去， 所以就會發生無法透過連結檔讀取的問題了！

這裡還是得特別留意，這個 Symbolic Link 與 Windows 的捷徑可以給他劃上等號，由 Symbolic link 所建立的檔案為一個獨立的新的檔案，所以會佔用掉 inode 與 block 喔！

由上面的說明來看，似乎 hard link 比較安全，因為即使某一個目錄下的關連資料被殺掉了， 也沒有關係，只要有任何一個目錄下存在著關連資料，那麼該檔案就不會不見！舉上面的例子來說，我的 /etc/crontab 與 /root/crontab 指向同一個檔案，如果我刪除了 /etc/crontab 這個檔案，該刪除的動作其實只是將 /etc 目錄下關於 crontab 的關連資料拿掉而已， crontab 所在的 inode 與 block 其實都沒有被變動喔！

不過由於 Hard Link 的限制太多了，包括無法做『目錄』的 link ， 所以在用途上面是比較受限的！反而是 Symbolic Link 的使用方面較廣喔！好了， 說的天花亂墜，看你也差不多快要昏倒了！沒關係，實作一下就知道怎麼回事了！要製作連結檔就必須要使用 ln 這個指令呢！

[root@www ~]# ln [-sf] 來源檔 目標檔

選項與參數：

-s  ：如果不加任何參數就進行連結，那就是hard link，至於 -s 就是symbolic link

-f  ：如果 目標檔 存在時，就主動的將目標檔直接移除後再建立！

範例一：將 /etc/passwd 複製到 /tmp 底下，並且觀察 inode 與 block

[root@www ~]# cd /tmp

[root@www tmp]# cp -a /etc/passwd .

[root@www tmp]# du -sb ; df -i .

18340   .  <==先注意一下這裡的容量是多少！

Filesystem            Inodes   IUsed   IFree IUse% Mounted on

/dev/hdc2            2560864  149738 2411126    6% /

# 利用 du 與 df 來檢查一下目前的參數∼那個 du -sb

# 是計算整個 /tmp 底下有多少 bytes 的容量啦！

範例二：將 /tmp/passwd 製作 hard link 成為 passwd-hd 檔案，並觀察檔案與容量

[root@www tmp]# ln passwd passwd-hd

[root@www tmp]# du -sb ; df -i .

18340   .

Filesystem            Inodes   IUsed   IFree IUse% Mounted on

/dev/hdc2            2560864  149738 2411126    6% /

# 仔細看，即使多了一個檔案在 /tmp 底下，整個 inode 與 block 的容量並沒有改變！

[root@www tmp]# ls -il passwd*

586361 -rw-r--r-- 2 root root 1945 Sep 29 02:21 passwd

586361 -rw-r--r-- 2 root root 1945 Sep 29 02:21 passwd-hd

# 原來是指向同一個 inode 啊！這是個重點啊！另外，那個第二欄的連結數也會增加！

範例三：將 /tmp/passwd 建立一個符號連結

[root@www tmp]# ln -s passwd passwd-so

[root@www tmp]# ls -li passwd*

586361 -rw-r--r-- 2 root root 1945 Sep 29 02:21 passwd

586361 -rw-r--r-- 2 root root 1945 Sep 29 02:21 passwd-hd

586401 lrwxrwxrwx 1 root root    6 Oct 22 14:18 passwd-so -> passwd

# passwd-so 指向的 inode number 不同了！這是一個新的檔案∼這個檔案的內容是指向

# passwd 的。passwd-so 的大小是 6bytes ，因為 passwd 共有六個字元之故

[root@www tmp]# du -sb ; df -i .

18346   .

Filesystem            Inodes   IUsed   IFree IUse% Mounted on

/dev/hdc2            2560864  149739 2411125    6% /

# 呼呼！整個容量與 inode 使用數都改變囉∼確實如此啊！

範例四：刪除原始檔案 passwd ，其他兩個檔案是否能夠開啟？

[root@www tmp]# rm passwd

[root@www tmp]# cat passwd-hd

......正常顯示完畢！

[root@www tmp]# cat passwd-so

cat: passwd-so: No such file or directory

[root@www tmp]# ll passwd*

-rw-r--r-- 1 root root 1945 Sep 29 02:21 passwd-hd

lrwxrwxrwx 1 root root    6 Oct 22 14:18 passwd-so -> passwd

# 怕了吧！符號連結果然無法開啟！另外，如果符號連結的目標檔案不存在，

# 其實檔名的部分就會有特殊的顏色顯示喔！

Tips:

還記得第六章當中，我們提到的 /tmp 這個目錄是幹嘛用的嗎？是給大家作為暫存檔用的啊！ 所以，您會發現，過去我們在進行測試時，都會將資料移動到 /tmp 底下去練習∼ 嘿嘿！因此，有事沒事，記得將 /tmp 底下的一些怪異的資料清一清先！

要注意囉！使用 ln 如果不加任何參數的話，那麼就是 Hard Link 囉！如同範例二的情況，增加了 hard link 之後，可以發現使用 ls -l 時，顯示的 link 那一欄屬性增加了！而如果這個時候砍掉 passwd 會發生什麼事情呢？passwd-hd 的內容還是會跟原來 passwd 相同，但是 passwd-so 就會找不到該檔案啦！

而如果 ln 使用 -s 的參數時，就做成差不多是 Windows 底下的『捷徑』的意思。當你修改 Linux 下的 symbolic link 檔案時，則更動的其實是『原始檔』， 所以不論你的這個原始檔被連結到哪裡去，只要你修改了連結檔，原始檔就跟著變囉！ 以上面為例，由於你使用 -s 的參數建立一個名為 passwd-so 的檔案，則你修改 passwd-so 時，其內容與 passwd 完全相同，並且，當你按下儲存之後，被改變的將是 passwd 這個檔案！

此外，如果你做了底下這樣的連結：

ln -s /bin /root/bin

那麼如果你進入 /root/bin 這個目錄下，『請注意呦！該目錄其實是 /bin 這個目錄，因為你做了連結檔了！』所以，如果你進入 /root/bin 這個剛剛建立的連結目錄， 並且將其中的資料殺掉時，嗯！ /bin 裡面的資料就通通不見了！這點請千萬注意！所以趕緊利用『rm /root/bin 』 將這個連結檔刪除吧！

基本上， Symbolic link 的用途比較廣，所以您要特別留意 symbolic link 的用法呢！未來一定還會常常用到的啦！

- 關於目錄的 link 數量：

或許您已經發現了，那就是，當我們以 hard link 進行『檔案的連結』時，可以發現，在 ls -l 所顯示的第二欄位會增加一才對，那麼請教，如果建立目錄時，他預設的 link 數量會是多少？ 讓我們來想一想，一個『空目錄』裡面至少會存在些什麼？呵呵！就是存在 . 與 .. 這兩個目錄啊！ 那麼，當我們建立一個新目錄名稱為 /tmp/testing 時，基本上會有三個東西，那就是：

- /tmp/testing

- /tmp/testing/.

- /tmp/testing/..

而其中 /tmp/testing 與 /tmp/testing/. 其實是一樣的！都代表該目錄啊∼而 /tmp/testing/.. 則代表 /tmp 這個目錄，所以說，當我們建立一個新的目錄時， 『新的目錄的 link 數為 2 ，而上層目錄的 link 數則會增加 1 』 不信的話，我們來作個測試看看：

[root@www ~]# ls -ld /tmp

drwxrwxrwt 5 root root 4096 Oct 22 14:22 /tmp

[root@www ~]# mkdir /tmp/testing1

[root@www ~]# ls -ld /tmp

drwxrwxrwt 6 root root 4096 Oct 22 14:37 /tmp

[root@www ~]# ls -ld /tmp/testing1

drwxr-xr-x 2 root root 4096 Oct 22 14:37 /tmp/testing1

瞧！原本的所謂上層目錄 /tmp 的 link 數量由 5 增加為 6 ，至於新目錄 /tmp/testing 則為 2 ，這樣可以理解目錄的 link 數量的意義了嗎？ ^_^

磁碟的分割、格式化、檢驗與掛載：

對於一個系統管理者( root )而言，磁碟的的管理是相當重要的一環，尤其近來硬碟已經漸漸的被當成是消耗品了 ..... 如果我們想要在系統裡面新增一顆硬碟時，應該有哪些動作需要做的呢：

1. 對磁碟進行分割，以建立可用的 partition ；

2. 對該 partition 進行格式化( format )，以建立系統可用的 filesystem；

3. 若想要仔細一點，則可對剛剛建立好的 filesystem 進行檢驗；

4. 在 Linux 系統上，需要建立掛載點 ( 亦即是目錄 )，並將他掛載上來；

當然囉，在上述的過程當中，還有很多需要考慮的，例如磁碟分割槽 (partition) 需要定多大？ 是否需要加入 journal 的功能？inode 與 block 的數量應該如何規劃等等的問題。但是這些問題的決定， 都需要與你的主機用途來加以考量的∼所以，在這個小節裡面，鳥哥僅會介紹幾個動作而已， 更詳細的設定值，則需要以你未來的經驗來參考囉！

磁碟分割： fdisk

[root@www ~]# fdisk [-l] 裝置名稱

選項與參數：

-l  ：輸出後面接的裝置所有的 partition 內容。若僅有 fdisk -l 時，

則系統將會把整個系統內能夠搜尋到的裝置的 partition 均列出來。

範例：找出你系統中的根目錄所在磁碟，並查閱該硬碟內的相關資訊

[root@www ~]# df /            <==注意：重點在找出磁碟檔名而已

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hdc2              9920624   3823168   5585388  41% /

[root@www ~]# fdisk /dev/hdc  <==仔細看，不要加上數字喔！

The number of cylinders for this disk is set to 5005.

There is nothing wrong with that, but this is larger than 1024,

and could in certain setups cause problems with:

1) software that runs at boot time (e.g., old versions of LILO)

2) booting and partitioning software from other OSs

(e.g., DOS FDISK, OS/2 FDISK)

Command (m for help):     <==等待你的輸入！

由於每個人的環境都不一樣，因此每部主機的磁碟數量也不相同。所以你可以先使用 df 這個指令找出可用磁碟檔名， 然後再用 fdisk 來查閱。在你進入 fdisk 這支程式的工作畫面後，如果您的硬碟太大的話(通常指磁柱數量多於 1024 以上)，就會出現如上訊息。這個訊息僅是在告知你，因為某些舊版的軟體與作業系統並無法支援大於 1024 磁柱 (cylinter) 後的磁區使用，不過我們新版的 Linux 是沒問題啦！底下繼續來看看 fdisk 內如何操作相關動作吧！

Command (m for help): m   <== 輸入 m 後，就會看到底下這些指令介紹

Command action

a   toggle a bootable flag

b   edit bsd disklabel

c   toggle the dos compatibility flag

d   delete a partition            <==刪除一個partition

l   list known partition types

m   print this menu

n   add a new partition           <==新增一個partition

o   create a new empty DOS partition table

p   print the partition table     <==在螢幕上顯示分割表

q   quit without saving changes   <==不儲存離開fdisk程式

s   create a new empty Sun disklabel

t   change a partition's system id

u   change display/entry units

v   verify the partition table

w   write table to disk and exit  <==將剛剛的動作寫入分割表

x   extra functionality (experts only)

老實說，使用 fdisk 這支程式是完全不需要背指令的！如同上面的表格中，你只要按下 m 就能夠看到所有的動作！ 比較重要的動作在上面已經用底線畫出來了，你可以參考看看。其中比較不一樣的是『q 與 w』這兩個玩意兒！ 不管你進行了什麼動作，只要離開 fdisk 時按下『q』，那麼所有的動作『都不會生效！』相反的， 按下『w』就是動作生效的意思。所以，你可以隨便玩 fdisk ，只要離開時按下的是『q』即可。 ^_^！ 好了，先來看看分割表資訊吧！

Command (m for help): p  <== 這裡可以輸出目前磁碟的狀態

Disk /dev/hdc: 41.1 GB, 41174138880 bytes        <==這個磁碟的檔名與容量

255 heads, 63 sectors/track, 5005 cylinders      <==磁頭、磁區與磁柱大小

Units = cylinders of 16065 * 512 = 8225280 bytes <==每個磁柱的大小

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1   *           1          13      104391   83  Linux

/dev/hdc2              14        1288    10241437+  83  Linux

/dev/hdc3            1289        1925     5116702+  83  Linux

/dev/hdc4            1926        5005    24740100    5  Extended

/dev/hdc5            1926        2052     1020096   82  Linux swap / Solaris

# 裝置檔名 開機區否 開始磁柱    結束磁柱  1K大小容量 磁碟分割槽內的系統

Command (m for help): q

# 想要不儲存離開嗎？按下 q 就對了！不要隨便按 w 啊！

使用『 p 』可以列出目前這顆磁碟的分割表資訊，這個資訊的上半部在顯示整體磁碟的狀態。 以鳥哥這顆磁碟為例，這個磁碟共有 41.1GB 左右的容量，共有 5005 個磁柱，每個磁柱透過 255 個磁頭在管理讀寫， 每個磁頭管理 63 個磁區，而每個磁區的大小均為 512bytes ，因此每個磁柱為『 255*63*512 = 16065*512 = 8225280bytes 』。

下半部的分割表資訊主要在列出每個分割槽的個別資訊項目。每個項目的意義為：

- Device：裝置檔名，依據不同的磁碟介面/分割槽位置而變。

- Boot：是否為開機啟動區塊？通常 Windows 系統的 C 需要這塊！

- Start, End：這個分割槽在哪個磁柱號碼之間，可以決定此分割槽的大小；

- Blocks：就是以 1K 為單位的容量。如上所示，/dev/hdc1 大小為104391K = 102MB

- ID, System：代表這個分割槽內的檔案系統應該是啥！不過這個項目只是一個提示而已， 不見得真的代表此分割槽內的檔案系統喔！

從上表我們可以發現幾件事情：

- 整部磁碟還可以進行額外的分割，因為最大磁柱為 5005 ，但只使用到 2052 號而已；

- /dev/hdc5 是由 /dev/hdc4 分割出來的，因為 /dev/hdc4 為 Extended，且 /dev/hdc5 磁柱號碼在 /dev/hdc4 之內；

fdisk 還可以直接秀出系統內的所有 partition 喔！舉例來說，鳥哥剛剛插入一個 USB 磁碟到這部 Linux 系統中， 那該如何觀察 (1)這個磁碟的代號與 (2)這個磁碟的分割槽呢？

範例：查閱目前系統內的所有 partition 有哪些？

[root@www ~]# fdisk -l

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1   *           1          13      104391   83  Linux

/dev/hdc2              14        1288    10241437+  83  Linux

/dev/hdc3            1289        1925     5116702+  83  Linux

/dev/hdc4            1926        5005    24740100    5  Extended

/dev/hdc5            1926        2052     1020096   82  Linux swap / Solaris

Disk /dev/sda: 8313 MB, 8313110528 bytes

59 heads, 58 sectors/track, 4744 cylinders

Units = cylinders of 3422 * 512 = 1752064 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/sda1               1        4745     8118260    b  W95 FAT32

由上表的資訊我們可以看到我有兩顆磁碟，磁碟檔名為『/dev/hdc 與 /dev/sda』，/dev/hdc 已經在上面談過了， 至於 /dev/sda 則有 8GB 左右的容量，且全部的磁柱都已經分割給 /dev/sda1 ，該檔案系統應該為 Windows 的 FAT 檔案系統。這樣很容易查閱到分割方面的資訊吧！

這個 fdisk 只有 root 才能執行，此外，請注意， 使用的『裝置檔名』請不要加上數字，因為 partition 是針對『整個硬碟裝置』而不是某個 partition 呢！所以執行『 fdisk /dev/hdc1 』 就會發生錯誤啦！要使用 fdisk /dev/hdc 才對！那麼我們知道可以利用 fdisk 來查閱硬碟的 partition 資訊外，底下再來說一說進入 fdisk 之後的幾個常做的工作！

Tips:

再次強調，你可以使用 fdisk 在您的硬碟上面胡搞瞎搞的進行實際操作，都不打緊， 但是請『千萬記住，不要按下 w 即可！』離開的時候按下 q 就萬事無妨囉！

- 刪除磁碟分割槽

如果你是按照鳥哥建議的方式去安裝你的 CentOS ，那麼你的磁碟應該會預留一塊容量來做練習的。 實際練習新增硬碟之前，我們先來玩一玩恐怖的刪除好了∼如果想要測試一下如何將你的 /dev/hdc 全部的分割槽刪除，應該怎麼做？

1. fdisk /dev/hdc ：先進入 fdisk 畫面；

2. p ：先看一下分割槽的資訊，假設要殺掉 /dev/hdc1；

3. d ：這個時候會要你選擇一個 partition ，就選 1 囉！

4. w (or) q ：按 w 可儲存到磁碟資料表中，並離開 fdisk ；當然囉， 如果你反悔了，呵呵，直接按下 q 就可以取消剛剛的刪除動作了！

# 練習一： 先進入 fdisk 的畫面當中去！

[root@www ~]# fdisk /dev/hdc

# 練習二： 先看看整個分割表的情況是如何

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1   *           1          13      104391   83  Linux

/dev/hdc2              14        1288    10241437+  83  Linux

/dev/hdc3            1289        1925     5116702+  83  Linux

/dev/hdc4            1926        5005    24740100    5  Extended

/dev/hdc5            1926        2052     1020096   82  Linux swap / Solaris

# 練習三： 按下 d 給他刪除吧！

Command (m for help): d

Partition number (1-5): 4

Command (m for help): d

Partition number (1-4): 3

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1   *           1          13      104391   83  Linux

/dev/hdc2              14        1288    10241437+  83  Linux

# 因為 /dev/hdc5 是由 /dev/hdc4 所衍生出來的邏輯分割槽，因此 /dev/hdc4 被刪除，

# /dev/hdc5 就自動不見了！最終就會剩下兩個分割槽而已喔！

Command (m for help): q

# 鳥哥這裡僅是做一個練習而已，所以，按下 q 就能夠離開囉∼

- 練習新增磁碟分割槽

新增磁碟分割槽有好多種情況，因為新增 Primary / Extended / Logical 的顯示結果都不太相同。 底下我們先將 /dev/hdc 全部刪除成為乾淨未分割的磁碟，然後依序新增給大家瞧瞧！

# 練習一： 進入 fdisk 的分割軟體畫面中，並刪除所有分割槽：

[root@www ~]# fdisk /dev/hdc

Command (m for help): d

Partition number (1-5): 4

Command (m for help): d

Partition number (1-4): 3

Command (m for help): d

Partition number (1-4): 2

Command (m for help): d

Selected partition 1

# 由於最後僅剩下一個 partition ，因此系統主動選取這個 partition 刪除去！

# 練習二： 開始新增，我們先新增一個 Primary  的分割槽，且指定為 4 號看看！

Command (m for help): n

Command action            <==因為是全新磁碟，因此只會問extended/primary而已

e   extended

p   primary partition (1-4)

p                         <==選擇 Primary 分割槽

Partition number (1-4): 4 <==設定為 4 號！

First cylinder (1-5005, default 1): <==直接按下[enter]按鍵決定！

Using default value 1               <==啟始磁柱就選用預設值！

Last cylinder or +size or +sizeM or +sizeK (1-5005, default 5005): +512M

# 這個地方有趣了！我們知道 partition 是由 n1 到 n2 的磁柱號碼 (cylinder)，

# 但磁柱的大小每顆磁碟都不相同，這個時候可以填入 +512M 來讓系統自動幫我們找出

# 『最接近 512M 的那個 cylinder 號碼』！因為不可能剛好等於 512MBytes 啦！

# 如上所示：這個地方輸入的方式有兩種：

# 1) 直接輸入磁柱的號碼，你得要自己計算磁柱/分割槽的大小才行；

# 2) 用 +XXM 來輸入分割槽的大小，讓系統自己捉磁柱的號碼。

#    +與M是必須要有的，XX為數字

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc4               1          63      506016   83  Linux

# 注意！只有 4 號！ 1 ~ 3 保留下來了！

# 練習三： 繼續新增一個，這次我們新增 Extended 的分割槽好了！

Command (m for help): n

Command action

e   extended

p   primary partition (1-4)

e    <==選擇的是 Extended 喔！

Partition number (1-4): 1

First cylinder (64-5005, default 64): <=[enter]

Using default value 64

Last cylinder or +size or +sizeM or +sizeK (64-5005, default 5005): <=[enter]

Using default value 5005

# 還記得我們在第三章的磁碟分割表曾經談到過的，延伸分割最好能夠包含所有

# 未分割的區間；所以在這個練習中，我們將所有未配置的磁柱都給了這個分割槽喔！

# 所以在開始/結束磁柱的位置上，按下兩個[enter]用預設值即可！

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1              64        5005    39696615    5  Extended

/dev/hdc4               1          63      506016   83  Linux

# 如上所示，所有的磁柱都在 /dev/hdc1 裡面囉！

# 練習四： 這次我們隨便新增一個 2GB 的分割槽看看！

Command (m for help): n

Command action

l   logical (5 or over)     <==因為已有 extended ，所以出現 logical 分割槽

p   primary partition (1-4)

p   <==偷偷玩一下，能否新增主要分割槽

Partition number (1-4): 2

No free sectors available   <==肯定不行！因為沒有多餘的磁柱可供配置

Command (m for help): n

Command action

l   logical (5 or over)

p   primary partition (1-4)

l   <==乖乖使用邏輯分割槽吧！

First cylinder (64-5005, default 64): <=[enter]

Using default value 64

Last cylinder or +size or +sizeM or +sizeK (64-5005, default 5005): +2048M

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1              64        5005    39696615    5  Extended

/dev/hdc4               1          63      506016   83  Linux

/dev/hdc5              64         313     2008093+  83  Linux

# 這樣就新增了 2GB 的分割槽，且由於是 logical ，所以由 5 號開始！

Command (m for help): q

# 鳥哥這裡僅是做一個練習而已，所以，按下 q 就能夠離開囉∼

上面的練習非常重要！您得要自行練習一下比較好！注意，不要按下 w 喔！會讓你的系統損毀的！ 由上面的一連串練習中，最重要的地方其實就在於建立分割槽的形式( primary/extended/logical )以及分割槽的大小了！一般來說建立分割槽的形式會有底下的數種狀況：

- 1-4 號尚有剩餘，且系統未有 extended：

此時會出現讓你挑選 Primary / Extended 的項目，且你可以指定 1~4 號間的號碼；

- 1-4 號尚有剩餘，且系統有 extended：

此時會出現讓你挑選 Primary / Logical 的項目；若選擇 p 則你還需要指定 1~4 號間的號碼； 若選擇 l(L的小寫) 則不需要設定號碼，因為系統會自動指定邏輯分割槽的檔名號碼；

- 1-4 沒有剩餘，且系統有 extended：

此時不會讓你挑選分割槽類型，直接會進入 logical 的分割槽形式。

例題：

請依照你的系統情況，建立一個大約 1GB 左右的分割槽，並顯示該分割槽的相關資訊：

答：

鳥哥的磁碟為 /dev/hdc ，尚有剩餘磁柱號碼，因此可以這樣做：

[root@www ~]# fdisk /dev/hdc

Command (m for help): n

First cylinder (2053-5005, default 2053): <==[enter]

Using default value 2053

Last cylinder or +size or +sizeM or +sizeK (2053-5005, default 5005): +2048M

Command (m for help): p

Disk /dev/hdc: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hdc1   *           1          13      104391   83  Linux

/dev/hdc2              14        1288    10241437+  83  Linux

/dev/hdc3            1289        1925     5116702+  83  Linux

/dev/hdc4            1926        5005    24740100    5  Extended

/dev/hdc5            1926        2052     1020096   82  Linux swap / Solaris

/dev/hdc6            2053        2302     2008093+  83  Linux

Command (m for help): w

The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or

resource busy.

The kernel still uses the old table.

The new table will be used at the next reboot.

Syncing disks. <==見鬼了！竟然需要 reboot 才能夠生效！我可不要重新開機！

[root@www ~]# partprobe  <==強制讓核心重新捉一次 partition table

在這個實作題中，請務必要按下『 w 』這個動作！因為我們實際上確實要建立這個分割槽嘛！ 但請仔細看一下最後的警告訊息，因為我們的磁碟無法卸載(因為含有根目錄)，所以核心無法重新取得分割表資訊， 因此此時系統會要求我們重新開機(reboot)以更新核心的分割表資訊才行。

如上的練習中，最終寫入分割表後竟然會讓核心無法捉到分割表資訊！此時你可以直接使用 reboot 來處理， 也可以使用 GNU 推出的工具程式來處置，那就是 partprobe 這個指令。這個指令的執行很簡單， 他僅是告知核心必須要讀取新的分割表而已，因此並不會在螢幕上出現任何資訊才是！ 這樣一來，我們就不需要 reboot 囉！

- 操作環境的說明

以 root 的身份進行硬碟的 partition 時，最好是在單人維護模式底下比較安全一些， 此外，在進行 fdisk 的時候，如果該硬碟某個 partition 還在使用當中， 那麼很有可能系統核心會無法重新載入硬碟的 partition table ，解決的方法就是將該使用中的 partition 給他卸載，然後再重新進入 fdisk 一遍，重新寫入 partition table ，那麼就可以成功囉！

- 注意事項：

另外在實作過程中請特別注意，因為 SATA 硬碟最多能夠支援到 15 號的分割槽， IDE 則可以支援到 63 號。 但目前大家常見的系統都是 SATA 磁碟，因此在練習的時候千萬不要讓你的分割槽超過 15 號！ 否則即使你還有剩餘的磁柱容量，但還是會無法繼續進行分割的喔！

另外需要特別留意的是，fdisk 沒有辦法處理大於 2TB 以上的磁碟分割槽！ 這個問題比較嚴重！因為雖然 Ext3 檔案系統已經支援達到 16TB 以上的磁碟，但是分割指令卻無法支援。 時至今日(2009)所有的硬體價格大跌，硬碟也已經出到單顆 1TB 之譜，若加上磁碟陣列 (RAID) ， 高於 2TB 的磁碟系統應該會很常見！此時你就得使用 parted 這個指令了！我們會在本章最後談一談這個指令的用法。

磁碟格式化

分割完畢後自然就是要進行檔案系統的格式化囉！格式化的指令非常的簡單，那就是『make filesystem, mkfs』 這個指令啦！這個指令其實是個綜合的指令，他會去呼叫正確的檔案系統格式化工具軟體！ 不囉唆，讓我們來瞧瞧吧！

- mkfs

[root@www ~]# mkfs [-t 檔案系統格式] 裝置檔名

選項與參數：

-t  ：可以接檔案系統格式，例如 ext3, ext2, vfat 等(系統有支援才會生效)

範例一：請將上個小節當中所製作出來的 /dev/hdc6 格式化為 ext3 檔案系統

[root@www ~]# mkfs -t ext3 /dev/hdc6

mke2fs 1.39 (29-May-2006)

Filesystem label=                <==這裡指的是分割槽的名稱(label)

OS type: Linux

Block size=4096 (log=2)          <==block 的大小設定為 4K

Fragment size=4096 (log=2)

251392 inodes, 502023 blocks     <==由此設定決定的inode/block數量

25101 blocks (5.00%) reserved for the super user

First data block=0

Maximum filesystem blocks=515899392

16 block groups

32768 blocks per group, 32768 fragments per group

15712 inodes per group

Superblock backups stored on blocks:

32768, 98304, 163840, 229376, 294912

Writing inode tables: done

Creating journal (8192 blocks): done <==有日誌記錄

Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 34 mounts or

180 days, whichever comes first.  Use tune2fs -c or -i to override.

# 這樣就建立起來我們所需要的 Ext3 檔案系統了！簡單明瞭！

[root@www ~]# mkfs[tab][tab]

mkfs         mkfs.cramfs  mkfs.ext2    mkfs.ext3    mkfs.msdos   mkfs.vfat

# 按下兩個[tab]，會發現 mkfs 支援的檔案格式如上所示！可以格式化 vfat 喔！

mkfs 其實是個綜合指令而已，事實上如同上表所示，當我們使用『 mkfs -t ext3 ...』時， 系統會去呼叫 mkfs.ext3 這個指令來進行格式化的動作啦！若如同上表所展現的結果， 那麼鳥哥這個系統支援的檔案系統格式化工具有『cramfs, ext2, ext3, msdoc, vfat』等， 而最常用的應該是 ext3, vfat 兩種啦！ vfat 可以用在 Windows/Linux 共用的 USB 隨身碟囉。

例題：

將剛剛的 /dev/hdc6 格式化為 Windows 可讀的 vfat 格式吧！

答：

mkfs -t vfat /dev/hdc6

在格式化為 Ext3 的範例中，我們可以發現結果裡面含有非常多的資訊，由於我們沒有詳細指定檔案系統的細部項目， 因此系統會使用預設值來進行格式化。其中比較重要的部分為：檔案系統的標頭(Label)、Block的大小以及 inode 的數量。 如果你要指定這些東西，就得要瞭解一下 Ext2/Ext3 的公用程式，亦即 mke2fs 這個指令囉！

- mke2fs

[root@www ~]# mke2fs [-b block大小] [-i block大小] [-L 標頭] [-cj] 裝置

選項與參數：

-b  ：可以設定每個 block 的大小，目前支援 1024, 2048, 4096 bytes 三種；

-i  ：多少容量給予一個 inode 呢？

-c  ：檢查磁碟錯誤，僅下達一次 -c 時，會進行快速讀取測試；

如果下達兩次 -c -c 的話，會測試讀寫(read-write)，會很慢∼

-L  ：後面可以接標頭名稱 (Label)，這個 label 是有用的喔！e2label指令介紹會談到∼

-j  ：本來 mke2fs 是 EXT2 ，加上 -j 後，會主動加入 journal 而成為 EXT3。

mke2fs 是一個很詳細但是很麻煩的指令！因為裡面的細部設定太多了！現在我們進行如下的假設：

- 這個檔案系統的標頭設定為：vbird_logical

- 我的 block 指定為 2048 大小；

- 每 8192 bytes 分配一個 inode ；

- 建置為 journal 的 Ext3 檔案系統。

開始格式化 /dev/hdc6 結果會變成如下所示：

[root@www ~]# mke2fs -j -L "vbird_logical" -b 2048 -i 8192 /dev/hdc6

mke2fs 1.39 (29-May-2006)

Filesystem label=vbird_logical

OS type: Linux

Block size=2048 (log=1)

Fragment size=2048 (log=1)

251968 inodes, 1004046 blocks

50202 blocks (5.00%) reserved for the super user

First data block=0

Maximum filesystem blocks=537919488

62 block groups

16384 blocks per group, 16384 fragments per group

4064 inodes per group

Superblock backups stored on blocks:

16384, 49152, 81920, 114688, 147456, 409600, 442368, 802816

Writing inode tables: done

Creating journal (16384 blocks): done

Writing superblocks and filesystem accounting information: done

# 比較看看，跟上面的範例用預設值的結果，有什麼不一樣的啊？

其實 mke2fs 所使用的各項選項/參數也可以用在『 mkfs -t ext3 ... 』後面，因為最終使用的公用程式是相同的啦！ 特別要注意的是 -b, -i 及 -j 這幾個選項，尤其是 -j 這個選項，當沒有指定 -j 的時候， mke2fs 使用 ext2 為格式化檔案格式，若加入 -j 時，則格式化為 ext3 這個 Journaling 的 filesystem 呦！

老實說，如果沒有特殊需求的話，使用『 mkfs -t ext3....』不但容易記憶，而且就非常好用囉！

磁碟檢驗： fsck, badblocks

由於系統在運作時誰也說不準啥時硬體或者是電源會有問題，所以『當機』可能是難免的情況(不管是硬體還是軟體)。 現在我們知道檔案系統運作時會有硬碟與記憶體資料非同步的狀況發生，因此莫名其妙的當機非常可能導致檔案系統的錯亂。 問題來啦，如果檔案系統真的發生錯亂的話，那該如何是好？就...挽救啊！此時那個好用的 filesystem check, fsck 就得拿來仔細瞧瞧囉。

- fsck

[root@www ~]# fsck [-t 檔案系統] [-ACay] 裝置名稱

選項與參數：

-t  ：如同 mkfs 一樣，fsck 也是個綜合軟體而已！因此我們同樣需要指定檔案系統。

不過由於現今的 Linux 太聰明了，他會自動的透過 superblock 去分辨檔案系統，

因此通常可以不需要這個選項的囉！請看後續的範例說明。

-A  ：依據 /etc/fstab 的內容，將需要的裝置掃瞄一次。/etc/fstab 於下一小節說明，

通常開機過程中就會執行此一指令了。

-a  ：自動修復檢查到的有問題的磁區，所以你不用一直按 y 囉！

-y  ：與 -a 類似，但是某些 filesystem 僅支援 -y 這個參數！

-C  ：可以在檢驗的過程當中，使用一個長條圖來顯示目前的進度！

EXT2/EXT3 的額外選項功能：(e2fsck 這支指令所提供)

-f  ：強制檢查！一般來說，如果 fsck 沒有發現任何 unclean 的旗標，不會主動進入

細部檢查的，如果您想要強制 fsck 進入細部檢查，就得加上 -f 旗標囉！

-D  ：針對檔案系統下的目錄進行最佳化配置。

範例一：強制的將前面我們建立的 /dev/hdc6 這個裝置給他檢驗一下！

[root@www ~]# fsck -C -f -t ext3 /dev/hdc6

fsck 1.39 (29-May-2006)

e2fsck 1.39 (29-May-2006)

Pass 1: Checking inodes, blocks, and sizes

Pass 2: Checking directory structure

Pass 3: Checking directory connectivity

Pass 4: Checking reference counts

Pass 5: Checking group summary information

vbird_logical: 11/251968 files (9.1% non-contiguous), 36926/1004046 blocks

# 如果沒有加上 -f 的選項，則由於這個檔案系統不曾出現問題，

# 檢查的經過非常快速！若加上 -f 強制檢查，才會一項一項的顯示過程。

範例二：系統有多少檔案系統支援的 fsck 軟體？

[root@www ~]# fsck[tab][tab]

fsck         fsck.cramfs  fsck.ext2    fsck.ext3    fsck.msdos   fsck.vfat

這是用來檢查與修正檔案系統錯誤的指令。注意：通常只有身為 root 且你的檔案系統有問題的時候才使用這個指令，否則在正常狀況下使用此一指令， 可能會造成對系統的危害！通常使用這個指令的場合都是在系統出現極大的問題，導致你在 Linux 開機的時候得進入單人單機模式下進行維護的行為時，才必須使用此一指令！

另外，如果你懷疑剛剛格式化成功的硬碟有問題的時後，也可以使用 fsck 來檢查一硬碟呦！其實就有點像是 Windows 的 scandisk 啦！此外，由於 fsck 在掃瞄硬碟的時候，可能會造成部分 filesystem 的損壞，所以『執行 fsck 時， 被檢查的 partition 務必不可掛載到系統上！亦即是需要在卸載的狀態喔！』

不知道你還記不記得第六章的目錄配置中我們提過， ext2/ext3 檔案系統的最頂層(就是掛載點那個目錄底下)會存在一個『lost+found』的目錄吧！ 該目錄就是在當你使用 fsck 檢查檔案系統後，若出現問題時，有問題的資料會被放置到這個目錄中喔！ 所以理論上這個目錄不應該會有任何資料，若系統自動產生資料在裡面，那...你就得特別注意你的檔案系統囉！

另外，我們的系統實際執行的 fsck 指令，其實是呼叫 e2fsck 這個軟體啦！可以 man e2fsck 找到更多的選項輔助喔！

- badblocks

[root@www ~]# badblocks -[svw] 裝置名稱

選項與參數：

-s  ：在螢幕上列出進度

-v  ：可以在螢幕上看到進度

-w  ：使用寫入的方式來測試，建議不要使用此一參數，尤其是待檢查的裝置已有檔案時！

[root@www ~]# badblocks -sv /dev/hdc6

Checking blocks 0 to 2008093

Checking for bad blocks (read-only test): done

Pass completed, 0 bad blocks found.

剛剛談到的 fsck 是用來檢驗檔案系統是否出錯，至於 badblocks 則是用來檢查硬碟或軟碟磁區有沒有壞軌的指令！ 由於這個指令其實可以透過『 mke2fs -c 裝置檔名 』在進行格式化的時候處理磁碟表面的讀取測試， 因此目前大多不使用這個指令囉！

磁碟掛載與卸載

我們在本章一開始時的掛載點的意義當中提過掛載點是目錄， 而這個目錄是進入磁碟分割槽(其實是檔案系統啦！)的入口就是了。不過要進行掛載前，你最好先確定幾件事：

- 單一檔案系統不應該被重複掛載在不同的掛載點(目錄)中；

- 單一目錄不應該重複掛載多個檔案系統；

- 要作為掛載點的目錄，理論上應該都是空目錄才是。

尤其是上述的後兩點！如果你要用來掛載的目錄裡面並不是空的，那麼掛載了檔案系統之後，原目錄下的東西就會暫時的消失。 舉個例子來說，假設你的 /home 原本與根目錄 (/) 在同一個檔案系統中，底下原本就有 /home/test 與 /home/vbird 兩個目錄。然後你想要加入新的硬碟，並且直接掛載 /home 底下，那麼當你掛載上新的分割槽時，則 /home 目錄顯示的是新分割槽內的資料，至於原先的 test 與 vbird 這兩個目錄就會暫時的被隱藏掉了！注意喔！並不是被覆蓋掉， 而是暫時的隱藏了起來，等到新分割槽被卸載之後，則 /home 原本的內容就會再次的跑出來啦！

而要將檔案系統掛載到我們的 Linux 系統上，就要使用 mount 這個指令啦！ 不過，這個指令真的是博大精深∼粉難啦！我們學簡單一點啊∼ ^_^

[root@www ~]# mount -a

[root@www ~]# mount [-l]

[root@www ~]# mount [-t 檔案系統] [-L Label名] [-o 額外選項] \

[-n]  裝置檔名  掛載點

選項與參數：

-a  ：依照設定檔 /etc/fstab 的資料將所有未掛載的磁碟都掛載上來

-l  ：單純的輸入 mount 會顯示目前掛載的資訊。加上 -l 可增列 Label 名稱！

-t  ：與 mkfs 的選項非常類似的，可以加上檔案系統種類來指定欲掛載的類型。

常見的 Linux 支援類型有：ext2, ext3, vfat, reiserfs, iso9660(光碟格式),

nfs, cifs, smbfs(此三種為網路檔案系統類型)

-n  ：在預設的情況下，系統會將實際掛載的情況即時寫入 /etc/mtab 中，以利其他程式

的運作。但在某些情況下(例如單人維護模式)為了避免問題，會刻意不寫入。

此時就得要使用這個 -n 的選項了。

-L  ：系統除了利用裝置檔名 (例如 /dev/hdc6) 之外，還可以利用檔案系統的標頭名稱

(Label)來進行掛載。最好為你的檔案系統取一個獨一無二的名稱吧！

-o  ：後面可以接一些掛載時額外加上的參數！比方說帳號、密碼、讀寫權限等：

ro, rw:       掛載檔案系統成為唯讀(ro) 或可讀寫(rw)

async, sync:  此檔案系統是否使用同步寫入 (sync) 或非同步 (async) 的

記憶體機制，請參考檔案系統運作方式。預設為 async。

auto, noauto: 允許此 partition 被以 mount -a 自動掛載(auto)

dev, nodev:   是否允許此 partition 上，可建立裝置檔案？ dev 為可允許

suid, nosuid: 是否允許此 partition 含有 suid/sgid 的檔案格式？

exec, noexec: 是否允許此 partition 上擁有可執行 binary 檔案？

user, nouser: 是否允許此 partition 讓任何使用者執行 mount ？一般來說，

mount 僅有 root 可以進行，但下達 user 參數，則可讓

一般 user 也能夠對此 partition 進行 mount 。

defaults:     預設值為：rw, suid, dev, exec, auto, nouser, and async

remount:      重新掛載，這在系統出錯，或重新更新參數時，很有用！

會不會覺得光是看這個指令的細部選項就快要昏倒了？如果有興趣的話看一下 man mount ，那才會真的昏倒的。 事實上 mount 是個很萬用的指令，他可以掛載 ext3/vfat/nfs 等檔案系統，由於每種檔案系統的資料並不相同， 想當然爾，詳細的參數與選項自然也就不相同啦！不過實際應用時卻簡單的會讓你想笑呢！ 看看底下的幾個簡單範例先！

第十五章、磁碟配額(Quota)與進階檔案系統管理

切換解析度為 800x600

最近更新日期：2009/09/10

如果您的 Linux 伺服器有多個用戶經常存取資料時，為了維護所有使用者在硬碟容量的公平使用，磁碟配額 (Quota) 就是一項非常有用的工具！另外，如果你的用戶常常抱怨磁碟容量不夠用，那麼更進階的檔案系統就得要學習學習。 本章我們會介紹磁碟陣列 (RAID) 及邏輯捲軸檔案系統 (LVM)，這些工具都可以幫助你管理與維護使用者可用的磁碟容量喔！

1. 磁碟配額 (Quota) 的應用與實作

1.1 什麼是 Quota：一般用途, 限制, 規範 (inode/block, soft/hard, grace time)

1.2 一個 Quota 的實作範例

1.3 實作 Quota 流程-1：檔案系統支援 (/etc/fstab, /etc/mtab)

1.4 實作 Quota 流程-2：建立 quota 記錄檔 (quotacheck)

1.5 實作 Quota 流程-3：啟動、關閉與限制值設定 (quotaon, quotaoff, edquota)

1.6 實作 Quota 流程-4：Quota 限制值的報表 (quota, repquota)

1.7 實作 Quota 流程-5：測試與管理 (測試, warnquota, setquota)

1.8 不更動既有系統的 Quota 實例

2. 軟體磁碟陣列 (Software RAID)

2.1 什麼是 RAID： RAID-0, RAID-1, RAID0+1, RAID-5, Spare disk

2.2 software, hardware RAID

2.3 軟體磁碟陣列的設定： mdadm --create

2.4 模擬 RAID 錯誤的救援模式： mdadm --manage

2.5 開機自動啟動 RAID 並自動掛載

2.6 關閉軟體 RAID(重要！)

3. 邏輯捲軸管理員 (Logical Volume Manager)

3.1 什麼是 LVM： PV, PE, VG, LV 的意義

3.2 LVM 實作流程： PV 階段, VG 階段, LV 階段, 檔案系統階段

3.3 放大 LV 容量： resize2fs

3.4 縮小 LV 容量

3.5 LVM 的系統快照： 建立, 還原, 用於測試環境

3.6 LVM 相關指令彙整與 LVM 的關閉

4. 重點回顧

5. 本章習題

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23888

磁碟配額 (Quota) 的應用與實作

Quota 這個玩意兒就字面上的意思來看，就是有多少『限額』的意思啦！如果是用在零用錢上面， 就是類似『有多少零用錢一個月』的意思之類的。如果是在電腦主機的磁碟使用量上呢？以 Linux 來說，就是有多少容量限制的意思囉。我們可以使用 quota 來讓磁碟的容量使用較為公平， 底下我們會介紹什麼是 quota ，然後以一個完整的範例來介紹 quota 的實作喔！

什麼是 Quota

在 Linux 系統中，由於是多人多工的環境，所以會有多人共同使用一個硬碟空間的情況發生， 如果其中有少數幾個使用者大量的佔掉了硬碟空間的話，那勢必壓縮其他使用者的使用權力！ 因此管理員應該適當的限制硬碟的容量給使用者，以妥善的分配系統資源！避免有人抗議呀！

舉例來說，我們使用者的預設家目錄都是在 /home 底下，如果 /home 是個獨立的 partition ， 假設這個分割槽有 10G 好了，而 /home 底下共有 30 個帳號，也就是說，每個使用者平均應該會有 333MB 的空間才對。 偏偏有個使用者在他的家目錄底下塞了好多隻影片，佔掉了 8GB 的空間，想想看，是否造成其他正常使用者的不便呢？ 如果想要讓磁碟的容量公平的分配，這個時候就得要靠 quota 的幫忙囉！

- Quota 的一般用途

quota 比較常使用的幾個情況是：

- 針對 WWW server ，例如：每個人的網頁空間的容量限制！

- 針對 mail server，例如：每個人的郵件空間限制。

- 針對 file server，例如：每個人最大的可用網路硬碟空間 (教學環境中最常見！)

上頭講的是針對網路服務的設計，如果是針對 Linux 系統主機上面的設定那麼使用的方向有底下這一些：

- 限制某一群組所能使用的最大磁碟配額 (使用群組限制)：

你可以將你的主機上的使用者分門別類，有點像是目前很流行的付費與免付費會員制的情況， 你比較喜好的那一群的使用配額就可以給高一些！呵呵！ ^_^...

- 限制某一使用者的最大磁碟配額 (使用使用者限制)：

在限制了群組之後，你也可以再繼續針對個人來進行限制，使得同一群組之下還可以有更公平的分配！

- 以 Link 的方式，來使郵件可以作為限制的配額 (更改 /var/spool/mail 這個路徑)：

如果是分為付費與免付費會員的『郵件主機系統』，是否需要重新再規劃一個硬碟呢？ 也不需要啦！直接使用 Link 的方式指向 /home (或者其他已經做好的 quota 磁碟) 就可以啦！ 這通常是用在原本磁碟分割的規劃不好，但是卻又不想要更動原有主機架構的情況中啊！

大概有這些實際的用途啦！

- Quota 的使用限制

雖然 quota 很好用，但是使用上還是有些限制要先瞭解的：

- 僅能針對整個 filesystem：

quota 實際在運作的時候，是針對『整個 filesystem』進行限制的， 例如：如果你的 /dev/sda5 是掛載在 /home 底下，那麼在 /home 底下的所有目錄都會受到限制！

- 核心必須支援 quota ：

Linux 核心必須有支援 quota 這個功能才行：如果你是使用 CentOS 5.x 的預設核心， 嘿嘿！那恭喜你了，你的系統已經預設有支援 quota 這個功能囉！如果你是自行編譯核心的， 那麼請特別留意你是否已經『真的』開啟了 quota 這個功能？否則底下的功夫將全部都視為『白工』。

- Quota 的記錄檔：

目前新版的 Linux distributions 使用的是 Kernel 2.6.xx 的核心版本，這個核心版本支援新的 quota 模組，使用的預設檔案 (aquota.user, aquota.group )將不同於舊版本的 quota.user, quota.group ！ (多了一個 a 呦！) 而由舊版本的 quota 可以藉由 convertquota 這個程式來轉換呢！

- 只對一般身份使用者有效：

這就有趣了！並不是所有在 Linux 上面的帳號都可以設定 quota 呢，例如 root 就不能設定 quota ， 因為整個系統所有的資料幾乎都是他的啊！ ^_^

所以囉，你不能針對『某個目錄』來進行 Quota 的設計，但你可以針對『某個檔案系統 (filesystem) 』來設定。 如果不明白目錄與掛載點還有檔案系統的關係，請回到第八章去瞧瞧再回來！

- Quota 的規範設定項目：

quota 這玩意兒針對整個 filesystem 的限制項目主要分為底下幾個部分：

- 容量限制或檔案數量限制 (block 或 inode)：

我們在第八章談到檔案系統中，說到檔案系統主要規劃為存放屬性的 inode 與實際檔案資料的 block 區塊，Quota 既然是管理檔案系統，所以當然也可以管理 inode 或 block 囉！ 這兩個管理的功能為：

- 限制 inode 用量：可以管理使用者可以建立的『檔案數量』；

- 限制 block 用量：管理使用者磁碟容量的限制，較常見為這種方式。

- 柔性勸導與硬性規定 (soft/hard)：

既然是規範，當然就有限制值。不管是 inode/block ，限制值都有兩個，分別是 soft 與 hard。 通常 hard 限制值要比 soft 還要高。舉例來說，若限制項目為 block ，可以限制 hard 為 500MBytes 而 soft 為 400MBytes。這兩個限值的意義為：

- hard：表示使用者的用量絕對不會超過這個限制值，以上面的設定為例， 使用者所能使用的磁碟容量絕對不會超過 500Mbytes ，若超過這個值則系統會鎖住該用戶的磁碟使用權；

- soft：表示使用者在低於 soft 限值時 (此例中為 400Mbytes)，可以正常使用磁碟，但若超過 soft 且低於 hard 的限值 (介於 400~500Mbytes 之間時)，每次使用者登入系統時，系統會主動發出磁碟即將爆滿的警告訊息， 且會給予一個寬限時間 (grace time)。不過，若使用者在寬限時間倒數期間就將容量再次降低於 soft 限值之下， 則寬限時間會停止。

- 會倒數計時的寬限時間 (grace time)：

剛剛上面就談到寬限時間了！這個寬限時間只有在使用者的磁碟用量介於 soft 到 hard 之間時，才會出現且會倒數的一個咚咚！ 由於達到 hard 限值時，使用者的磁碟使用權可能會被鎖住。為了擔心使用者沒有注意到這個磁碟配額的問題， 因此設計了 soft 。當你的磁碟用量即將到達 hard 且超過 soft 時，系統會給予警告，但也會給一段時間讓使用者自行管理磁碟。 一般預設的寬限時間為七天，如果七天內你都不進行任何磁碟管理，那麼 soft 限制值會即刻取代 hard 限值來作為 quota 的限制。

以上面設定的例子來說，假設你的容量高達 450MBytes 了，那七天的寬限時間就會開始倒數， 若七天內你都不進行任何刪除檔案的動作來替你的磁碟用量瘦身， 那麼七天後你的磁碟最大用量將變成 400MBytes (那個 soft 的限制值)，此時你的磁碟使用權就會被鎖住而無法新增檔案了。

整個 soft, hard, grace time 的相關性我們可以用底下的圖示來說明：

圖 1.1.1、soft, hard, grace time 的相關性

圖中的長條圖為使用者的磁碟容量，soft/hard 分別是限制值。只要小於 400M 就一切 OK ， 若高於 soft 就出現 grace time 並倒數且等待使用者自行處理，若到達 hard 的限制值， 那我們就搬張小板凳等著看好戲啦！嘿嘿！^_^！這樣圖示有清楚一點了嗎？

一個 Quota 實作範例

坐而言不如起而行啊，所以這裡我們使用一個範例來設計一下如何處理 Quota 的設定流程。

- 目的與帳號：現在我想要讓我的專題生五個為一組，這五個人的帳號分別是 myquota1, myquota2, myquota3, myquota4, myquota5，這五個用戶的密碼都是 password ，且這五個用戶所屬的初始群組都是 myquotagrp 。 其他的帳號屬性則使用預設值。

- 帳號的磁碟容量限制值：我想讓這五個用戶都能夠取得 300MBytes 的磁碟使用量(hard)，檔案數量則不予限制。 此外，只要容量使用率超過 250MBytes ，就予以警告 (soft)。

- 群組的限額：由於我的系統裡面還有其他用戶存在，因此我僅承認 myquotagrp 這個群組最多僅能使用 1GBytes 的容量。 這也就是說，如果 myquota1, myquota2, myquota3 都用了 280MBytes 的容量了，那麼其他兩人最多只能使用 (1000MB - 280x3 = 160MB) 的磁碟容量囉！這就是使用者與群組同時設定時會產生的後果。

- 寬限時間的限制：最後，我希望每個使用者在超過 soft 限制值之後，都還能夠有 14 天的寬限時間。

好了，那你怎麼規範帳號以及相關的 Quota 設定呢？首先，在這個小節我們先來將帳號相關的屬性與參數搞定再說吧！

# 製作帳號環境時，由於有五個帳號，因此鳥哥使用 script 來建立環境！

[root@www ~]# vi addaccount.sh

#!/bin/bash

# 使用 script 來建立實驗 quota 所需的環境

groupadd myquotagrp

for username in myquota1 myquota2 myquota3 myquota4 myquota5

do

useradd -g myquotagrp $username

echo "password" | passwd --stdin $username

done

[root@www ~]# sh addaccount.sh

接下來，就讓我們來實作 Quota 的練習吧！

實作 Quota 流程-1：檔案系統支援

前面我們就談到，要使用 Quota 必須要核心與檔案系統支援才行！假設你已經使用了預設支援 Quota 的核心， 那麼接下來就是要啟動檔案系統的支援啦！不過，由於 Quota 僅針對整個檔案系統來進行規劃，所以我們得先查一下， /home 是否是個獨立的 filesystem 呢？

[root@www ~]# df -h /home

Filesystem     Size  Used Avail Use% Mounted on

/dev/hda3      4.8G  740M  3.8G  17% /home  <==鳥哥主機的 /home 確實是獨立的！

[root@www ~]# mount | grep home

/dev/hda3 on /home type ext3 (rw)

從上面的資料來看，鳥哥這部主機的 /home 確實是獨立的 filesystem，因此可以直接限制 /dev/hda3 。 如果你的系統的 /home 並非獨立的檔案系統，那麼可能就得要針對根目錄 (/) 來規範了！不過，不太建議在根目錄設定 Quota。 此外，由於 VFAT 檔案系統並不支援 Linux Quota 功能，所以我們得要使用 mount 查詢一下 /home 的檔案系統為何？ 看起來是 Linux 傳統的 ext2/ext3 ，這種檔案系統肯定有支援 Quota 啦！沒問題！

如果只是想要在這次開機中實驗 Quota ，那麼可以使用如下的方式來手動加入 quota 的支援：

[root@www ~]# mount -o remount,usrquota,grpquota /home

[root@www ~]# mount | grep home

/dev/hda3 on /home type ext3 (rw,usrquota,grpquota)

# 重點就在於 usrquota, grpquota ！注意寫法！

事實上，當你重新掛載時，系統會同步更新 /etc/mtab 這個檔案， 所以你必須要確定 /etc/mtab 已經加入 usrquota, grpquota 的支援到你所想要設定的檔案系統中。 另外也要特別強調，使用者與群組的 quota 檔案系統支援參數分別是：usrquota, grpquota ！千萬不要寫錯了！這一點非常多初接觸 Quota 的朋友常常搞錯。

不過手動掛載的資料在下次重新掛載就會消失，因此最好寫入設定檔中啊！在鳥哥這部主機的案例中， 我可以直接修改 /etc/fstab 成為底下這個樣子：

[root@www ~]# vi /etc/fstab

LABEL=/home   /home  ext3   defaults,usrquota,grpquota  1 2

# 其他項目鳥哥並沒有列出來！重點在於第四欄位！於 default 後面加上兩個參數！

[root@www ~]# umount /home

[root@www ~]# mount -a

[root@www ~]# mount | grep home

/dev/hda3 on /home type ext3 (rw,usrquota,grpquota)

還是要再次的強調，修改完 /etc/fstab 後，務必要測試一下！若有發生錯誤得要趕緊處理！ 因為這個檔案如果修改錯誤，是會造成無法開機完全的情況啊！切記切記！最好使用 vim 來修改啦！ 因為會有語法的檢驗，就不會讓你寫錯字了！啟動檔案系統的支援後，接下來讓我們建立起 quota 的記錄檔吧！

實作 Quota 流程-2：建立 quota 記錄檔

其實 Quota 是透過分析整個檔案系統中，每個使用者(群組)擁有的檔案總數與總容量， 再將這些資料記錄在該檔案系統的最頂層目錄，然後在該記錄檔中再使用每個帳號(或群組)的限制值去規範磁碟使用量的。 所以啦，建置這個 Quota 記錄檔就顯的非常的重要。掃瞄有支援 Quota 參數 (usrquota, grpquota) 的檔案系統， 就使用 quotacheck 這個指令！這個指令的語法如下：

- quotacheck ：掃瞄檔案系統並建立 Quota 的記錄檔

[root@www ~]# quotacheck [-avugfM] [/mount_point]

選項與參數：

-a  ：掃瞄所有在 /etc/mtab 內，含有 quota 支援的 filesystem，加上此參數後，

/mount_point 可不必寫，因為掃瞄所有的 filesystem 了嘛！

-u  ：針對使用者掃瞄檔案與目錄的使用情況，會建立 aquota.user

-g  ：針對群組掃瞄檔案與目錄的使用情況，會建立 aquota.group

-v  ：顯示掃瞄過程的資訊；

-f  ：強制掃瞄檔案系統，並寫入新的 quota 設定檔 (危險)

-M  ：強制以讀寫的方式掃瞄檔案系統，只有在特殊情況下才會使用。

quotacheck 的選項你只要記得『 -avug 』一起下達即可！那個 -f 與 -M 是在檔案系統可能已經啟動 quota 了， 但是你還想要重新掃瞄檔案系統時，系統會要求你加入那兩個選項啦 (擔心有其他人已經使用 quota 中)！平時沒必要不要加上那兩個項目。好了，那就讓我們來處理我們的任務吧！

# 針對整個系統含有 usrquota, grpquota 參數的檔案系統進行 quotacheck 掃瞄

[root@www ~]# quotacheck -avug

quotacheck: Scanning /dev/hda3 [/home] quotacheck: Cannot stat old user quota

file: No such file or directory <==有找到檔案系統，但尚未製作記錄檔！

quotacheck: Cannot stat old group quota file: No such file or directory

quotacheck: Cannot stat old user quota file: No such file or directory

quotacheck: Cannot stat old group quota file: No such file or directory

done  <==上面三個錯誤只是說明記錄檔尚未建立而已，可以忽略不理！

quotacheck: Checked 130 directories and 107 files <==實際搜尋結果

quotacheck: Old file not found.

quotacheck: Old file not found.

# 若執行這個指令卻出現如下的錯誤訊息，表示你沒有任何檔案系統有啟動 quota 支援！

# quotacheck: Can't find filesystem to check or filesystem not mounted with

# quota option.

[root@www ~]# ll -d /home/a*

-rw------- 1 root root 8192 Mar  6 11:58 /home/aquota.group

-rw------- 1 root root 9216 Mar  6 11:58 /home/aquota.user

# 在鳥哥的案例中，/home 獨立的檔案系統，因此搜尋結果會將兩個記錄檔放在

# /home 底下。這兩個檔案就是 Quota 最重要的資訊了！

這個指令只要進行到這裡就夠了，不要反覆的進行！因為等一下我們會啟動 quota 功能，若啟動後你還要進行 quotacheck ， 系統會擔心破壞原有的記錄檔，所以會產生一些錯誤訊息警告你。如果你確定沒有任何人在使用 quota 時， 可以強制重新進行 quotacheck 的動作。強制執行的情況可以使用如下的選項功能：

# 如果因為特殊需求需要強制掃瞄已掛載的檔案系統時

[root@www ~]# quotacheck -avug -mf

quotacheck: Scanning /dev/hda3 [/home] done

quotacheck: Checked 130 directories and 109 files

# 資料要簡潔很多！因為有記錄檔存在嘛！所以警告訊息不會出現！

這樣記錄檔就建立起來了！你不用手動去編輯那兩個檔案∼因為那兩個檔案是 quota 自己的資料檔，並不是純文字檔啦！ 且該檔案會一直變動，這是因為當你對 /home 這個檔案系統進行操作時，你操作的結果會影響磁碟吧！ 所以當然會同步記載到那兩個檔案中啦！所以要建立 aquota.user, aquota.group，記得使用的是 quotacheck 指令！ 不是手動編輯的喔！

實作 Quota 流程-3：Quota 啟動、 關閉與限制值設定

製作好 Quota 設定檔之後，接下來就是要啟動 quota 了！啟動的方式很簡單！使用 quotaon ，至於關閉就用 quotaoff 即可

- quotaon ：啟動 quota 的服務

[root@www ~]# quotaon [-avug]

[root@www ~]# quotaon [-vug] [/mount_point]

選項與參數：

-u  ：針對使用者啟動 quota (aquota.user)

-g  ：針對群組啟動 quota (aquota.group)

-v  ：顯示啟動過程的相關訊息；

-a  ：根據 /etc/mtab 內的 filesystem 設定啟動有關的 quota ，若不加 -a 的話，

則後面就需要加上特定的那個 filesystem 喔！

# 由於我們要啟動 user/group 的 quota ，所以使用底下的語法即可

[root@www ~]# quotaon -auvg

/dev/hda3 [/home]: group quotas turned on

/dev/hda3 [/home]: user quotas turned on

# 特殊用法，假如你的啟動 /var 的 quota 支援，那麼僅啟動 user quota 時

[root@www ~]# quotaon -uv /var

這個『 quotaon -auvg 』的指令幾乎只在第一次啟動 quota 時才需要進行！因為下次等你重新啟動系統時， 系統的 /etc/rc.d/rc.sysinit 這個初始化腳本就會自動的下達這個指令了！因此你只要在這次實例中進行一次即可， 未來都不需要自行啟動 quota ，因為 CentOS 5.x 系統會自動幫你搞定他！

- quotaoff ：關閉 quota 的服務

[root@www ~]# quotaoff [-a]

[root@www ~]# quotaoff [-ug] [/mount_point]

選項與參數：

-a  ：全部的 filesystem 的 quota 都關閉 (根據 /etc/mtab)

-u  ：僅針對後面接的那個 /mount_point 關閉 user quota

-g  ：僅針對後面接的那個 /mount_point 關閉 group quota

這個指令就是關閉了 quota 的支援！我們這裡需要練習 quota 實作，所以這裡請不要關閉他喔！ 接下來讓我們開始來設定使用者與群組的 quota 限額吧！

- edquota ：編輯帳號/群組的限值與寬限時間

edquota 是 edit quota 的縮寫，所以就是用來編輯使用者或者是群組限額的指令囉。我們先來看看 edquota 的語法吧， 看完後再來實際操作一下。

[root@www ~]# edquota [-u username] [-g groupname]

[root@www ~]# edquota -t  <==修改寬限時間

[root@www ~]# edquota -p 範本帳號 -u 新帳號

選項與參數：

-u  ：後面接帳號名稱。可以進入 quota 的編輯畫面 (vi) 去設定 username 的限制值；

-g  ：後面接群組名稱。可以進入 quota 的編輯畫面 (vi) 去設定 groupname 的限制值；

-t  ：可以修改寬限時間。

-p  ：複製範本。那個 範本帳號 為已經存在並且已設定好 quota 的使用者，

意義為『將 範本帳號 這個人的 quota 限制值複製給 新帳號 』！

好了，先讓我們來看看當進入 myquota1 的限額設定時，會出現什麼畫面：

範例一：設定 dmtsai 這個使用者的 quota 限制值

[root@www ~]# edquota -u myquota1

Disk quotas for user myquota1 (uid 710):

Filesystem    blocks  soft   hard  inodes  soft  hard

/dev/hda3         80     0      0      10     0     0

上頭第一行在說明針對哪個帳號 (myquota1) 進行 quota 的限額設定，第二行則是標頭行，裡面共分為七個欄位， 七個欄位分別的意義為：

1. 檔案系統 (filesystem)：說明該限制值是針對哪個檔案系統 (或 partition)；

2. 磁碟容量 (blocks)：這個數值是 quota 自己算出來的，單位為 Kbytes，請不要更動他；

3. soft：磁碟容量 (block) 的 soft 限制值，單位亦為 KB

4. hard：block 的 hard 限制值，單位 KB；

5. 檔案數量 (inodes)：這是 quota 自己算出來的，單位為個數，請不要更動他；

6. soft：inode 的 soft 限制值；

7. hard：inode 的 hard 限制值；

當 soft/hard 為 0 時，表示沒有限制的意思。好，依據我們的範例說明，我們需要設定的是 blocks 的 soft/hard ，至於 inode 則不要去更動他！因此上述的畫面我們將他改成如下的模樣：

Tips:

在 edquota 的畫面中，每一行只要保持七個欄位就可以了，並不需要排列整齊的！

Disk quotas for user myquota1 (uid 710):

Filesystem    blocks    soft    hard  inodes  soft  hard

/dev/hda3         80  250000  300000      10     0     0

# 鳥哥使用 1000 去近似 1024 的倍數！比較好算啦！然後就可以儲存後離開囉！

設定完成之後，我們還有其他 5 個用戶要設定，由於設定值都一樣，此時可以使用 quota 複製喔！

# 將 myquota1 的限制值複製給其他四個帳號

[root@www ~]# edquota -p myquota1 -u myquota2

[root@www ~]# edquota -p myquota1 -u myquota3

[root@www ~]# edquota -p myquota1 -u myquota4

[root@www ~]# edquota -p myquota1 -u myquota5

這樣就方便多了！然後，趕緊更改一下群組的 quota 限額吧！

[root@www ~]# edquota -g myquotagrp

Disk quotas for group myquotagrp (gid 713):

Filesystem    blocks    soft     hard  inodes  soft  hard

/dev/hda3        400  900000  1000000      50     0     0

# 記得，單位為 KB 喔！

最後，將寬限時間給他改成 14 天吧！

# 寬限時間原本為 7 天，將他改成 14 天吧！

[root@www ~]# edquota -t

Grace period before enforcing soft limits for users:

Time units may be: days, hours, minutes, or seconds

Filesystem         Block grace period     Inode grace period

/dev/hda3                14days                  7days

# 原本是 7days ，我們將他給改為 14days 喔！

透過這個簡單的小步驟，我們已經將使用者/群組/寬限時間都設定妥當！接下來就是觀察到底設定有沒有生效啦！

實作 Quota 流程-4：Quota 限制值的報表

quota 的報表主要有兩種模式，一種是針對每個個人或群組的 quota 指令，一個是針對整個檔案系統的 repquota 指令。 我們先從較簡單的 quota 來介紹！你也可以順道看看你的設定值對不對啊！

- quota ：單一用戶的 quota 報表

[root@www ~]# quota [-uvs] [username]

[root@www ~]# quota [-gvs] [groupname]

選項與參數：

-u  ：後面可以接 username ，表示顯示出該使用者的 quota 限制值。若不接 username

，表示顯示出執行者的 quota 限制值。

-g  ：後面可接 groupname ，表示顯示出該群組的 quota 限制值。

-v  ：顯示每個用戶在 filesystem 的 quota 值；

-s  ：使用 1024 為倍數來指定單位，會顯示如 M 之類的單位！

# 直接使用 quota 去顯示出 myquota1 與 myquota2 的限額

[root@www ~]# quota -uvs myquota1 myquota2

Disk quotas for user myquota1 (uid 710):

Filesystem  blocks  quota  limit   grace   files   quota   limit   grace

/dev/hda3      80   245M   293M              10       0       0

Disk quotas for user myquota2 (uid 711):

Filesystem  blocks  quota  limit   grace   files   quota   limit   grace

/dev/hda3      80   245M   293M              10       0       0

# 這個指令顯示出來的資料跟 edquota 幾乎是一模一樣的！只是多了個 grace 項目。

# 你會發現 grace 底下沒有任何資料，這是因為我們的使用量 (80) 尚未超過 soft

# 顯示出 myquotagrp 的群組限額

[root@www ~]# quota -gvs myquotagrp

Disk quotas for group myquotagrp (gid 713):

Filesystem  blocks  quota  limit   grace   files   quota   limit   grace

/dev/hda3     400   879M   977M              50       0       0

由於使用常見的 K, M, G 等單位比較好算，因此上頭我們使用了『 -s 』的選項，就能夠以 M 為單位顯示了。 不過由於我們使用 edquota 設定限額時，使用的是近似值 (1000) 而不是實際的 1024 倍數， 所以看起來會有點不太一樣喔！由於 quota 僅能針對某些用戶顯示報表，如果要針對整個 filesystem 列出報表時， 那個可愛的 repquota 就派上用場啦！

- repquota ：針對檔案系統的限額做報表

[root@www ~]# repquota -a [-vugs]

選項與參數：

-a  ：直接到 /etc/mtab 搜尋具有 quota 標誌的 filesystem ，並報告 quota 的結果；

-v  ：輸出的資料將含有 filesystem 相關的細部資訊；

-u  ：顯示出使用者的 quota 限值 (這是預設值)；

-g  ：顯示出個別群組的 quota 限值。

-s  ：使用 M, G 為單位顯示結果

# 查詢本案例中所有使用者的 quota 限制情況：

[root@www ~]# repquota -auvs

*** Report for user quotas on device /dev/hda3    <==針對 /dev/hda3

Block grace time: 14days; Inode grace time: 7days <==block 寬限時間為 14 天

Block limits                File limits

User            used    soft    hard  grace    used  soft  hard  grace

----------------------------------------------------------------------

root      --    651M       0       0              5     0     0

myquota1  --      80    245M    293M             10     0     0

myquota2  --      80    245M    293M             10     0     0

myquota3  --      80    245M    293M             10     0     0

myquota4  --      80    245M    293M             10     0     0

myquota5  --      80    245M    293M             10     0     0

Statistics:  <==這是所謂的系統相關資訊，用 -v 才會顯示

Total blocks: 9

Data blocks: 2

Entries: 22

Used average: 11.000000

根據這些資訊，您就可以知道目前的限制情況囉！ ^_^！怎樣， Quota 很簡單吧！你可以趕緊針對你的系統設定一下磁碟使用的規則，讓你的用戶不會抱怨磁碟怎麼老是被耗光！

實作 Quota 流程-5：測試與管理

Quota 到底有沒有效果？測試看看不就知道了？讓我們使用 myquota1 去測試看看，如果建立一個大檔案時， 整個系統會便怎樣呢？

# 測試一：利用 myquota1 的身份，建置一個 270MB 的大檔案，並觀察 quota 結果！

[myquota1@www ~]$ dd if=/dev/zero of=bigfile bs=1M count=270

hda3: warning, user block quota exceeded.

270+0 records in

270+0 records out

283115520 bytes (283 MB) copied, 3.20282 seconds, 88.4 MB/s

# 注意看，我是使用 myquota1 的帳號去進行 dd 指令的喔！不要惡搞啊！

# 然後你可以發現出現一個 warning 的訊息喔！接下來看看報表。

[root@www ~]# repquota -auv

*** Report for user quotas on device /dev/hda3

Block grace time: 14days; Inode grace time: 7days

Block limits                File limits

User            used    soft    hard  grace    used  soft  hard  grace

----------------------------------------------------------------------

myquota1  +-  276840  250000  300000 13days      11     0     0

# 這個指令則是利用 root 去查閱的！

# 你可以發現 myquota1 的 grace 出現！並且開始倒數了！

# 測試二：再建立另外一個大檔案，讓總容量超過 300M ！

[myquota1@www ~]$ dd if=/dev/zero of=bigfile2 bs=1M count=300

hda3: write failed, user block limit reached.

dd: writing `bigfile2': Disk quota exceeded <==看！錯誤訊息不一樣了！

23+0 records in  <==沒辦法寫入了！所以只記錄 23 筆

22+0 records out

23683072 bytes (24 MB) copied, 0.260081 seconds, 91.1 MB/s

[myquota1@www ~]$ du -sk

300000  .  <==果然是到極限了！

此時 myquota1 可以開始處理他的檔案系統了！如果不處理的話，最後寬限時間會歸零，然後出現如下的畫面：

[root@www ~]# repquota -au

*** Report for user quotas on device /dev/hda3

Block grace time: 00:01; Inode grace time: 7days

Block limits                File limits

User            used    soft    hard  grace    used  soft  hard  grace

----------------------------------------------------------------------

myquota1  +-  300000  250000  300000   none      11     0     0

# 倒數整個歸零，所以 grace 的部分就會變成 none 啦！不繼續倒數

其實倒數歸零也不會有什麼特殊的意外啦！別擔心！只是如果你的磁碟使用量介於 soft/hard 之間時， 當倒數歸零那麼 soft 的值會變成嚴格限制，此時你就沒有多餘的容量可以使用了。如何解決？ 就登入系統去刪除檔案即可啦！沒有想像中那麼可怕啦！問題是，使用者通常傻傻分不清楚到底系統出了什麼問題， 所以我們可能需要寄送一些警告信 (email) 給用戶比較妥當。那麼如何處理呢？透過 warnquota 來處置即可。

- warnquota ：對超過限額者發出警告信

warnquota字面上的意義就是 quota 的警告 (warn) 嘛！那麼這東西有什麼用呢？他可以依據 /etc/warnquota.conf 的設定，然後找出目前系統上面 quota 用量超過 soft (就是有 grace time 出現的那些傢伙) 的帳號，透過 email 的功能將警告信件發送到使用者的電子郵件信箱。 warnquota 並不會自動執行，所以我們需要手動去執行他。單純執行『 warnquota 』之後，他會發送兩封信出去， 一封給 myquota1 一封給 root ！

[root@www ~]# warnquota

# 完全不會出現任何訊息！沒有訊息就是『好訊息』！ ^_^

[root@www ~]# mail

N329 root@www.vbird.tsai   Fri Mar  6 16:10  27/1007  "NOTE: ....

& 329   <==因為新信件在第 329 封之故

From root@www.vbird.tsai  Fri Mar  6 16:10:18 2009

Date: Fri, 6 Mar 2009 16:10:17 +0800

From: root <root@www.vbird.tsai>

Reply-To: root@myhost.com

Subject: NOTE: You are exceeding your allocated disk space limits

To: myquota1@www.vbird.tsai

Cc: root@www.vbird.tsai   <==注意這三行，分別是標題、收件者與副本 (CC)。

Your disk usage has exceeded the agreed limits on this server <==問題說明

Please delete any unnecessary files on following filesystems:

/dev/hda3  <==底下這幾行為發生磁碟『爆表』的資訊啦！

Block limits               File limits

Filesystem           used    soft    hard  grace    used  soft  hard  grace

/dev/hda3      +-  300000  250000  300000 13days      12     0     0

root@localhost  <==這個是警告訊息發送者的『簽名資料』啦！

& exit  <==離開 mail 程式！

執行 warnquota 可能也不會產生任何訊息以及信件，因為只有當使用者的 quota 有超過 soft 時， warnquota 才會發送警告信啦！那麼上表的內容中，包括標題、資訊內容說明、簽名檔等資料放在哪裡呢？ 剛剛不是講過嗎？ /etc/warnquota 啦！因為上述的資料是英文，不好理解嗎？沒關係，你可以自己轉成中文喔！ 所以你可以這樣處理的：

[root@www ~]# vi /etc/warnquota.conf

# 先找到底下這幾行的設定值：

SUBJECT   = NOTE: You are exceeding your allocated disk space limits <==第10行

CC_TO     = "root@localhost"                                         <==第11行

MESSAGE   = Your disk usage has exceeded the agreed limits\          <==第21行

on this server|Please delete any unnecessary files on following filesystems:|

SIGNATURE = root@localhost                                           <==第25行

# 可以將他改成如下的模樣啊！

SUBJECT   = 注意：你在本系統上擁有的檔案容量已經超過最大容許限額

CC_TO     = "root@localhost"  <==除非你要寄給其他人，否則這個項目可以不改

MESSAGE   = 你的磁碟容量已經超過本機的容許限額，|\

請在如下的檔案系統中，刪除不必要的檔案：|

SIGNATURE = 你的系統管理員 (root@localhost)

# 在 MESSAGE 內的 | 代表斷行的意思，反斜線則代表連接下一行；

如果你重複執行 warnquota ，那麼 myquota1 就會收到類似如下的信件內容：

Subject: 注意：你在本系統上擁有的檔案容量已經超過最大容許限額

To: myquota1@www.vbird.tsai

Cc: root@www.vbird.tsai

你的磁碟容量已經超過本機的容許限額，

請在如下的檔案系統中，刪除不必要的檔案：

/dev/hda3

Filesystem           used    soft    hard  grace    used  soft  hard  grace

/dev/hda3      +-  300000  250000  300000   none      11     0     0

你的系統管理員 (root@localhost)

不過這個方法並不適用在 /var/spool/mail 也爆表的 quota 控管中，因為如果使用者在這個 filesystem 的容量已經爆表，那麼新的信件當然就收不下來啦！此時就只能等待使用者自己發現並跑來這裡刪除資料， 或者是請求 root 幫忙處理囉！知道了這玩意兒這麼好用，那麼我們怎麼讓系統自動的執行 warnquota 呢？ 你可以這樣做：

[root@www ~]# vi /etc/cron.daily/warnquota

/usr/sbin/warnquota

# 你沒有看錯！只要這一行，且將執行檔以絕對路徑的方式寫入即可！

[root@www ~]# chmod 755 /etc/cron.daily/warnquota

那麼未來每天早上 4:02am 時，這個檔案就會主動被執行，那麼系統就能夠主動的通知磁碟配額爆表的用戶囉！ 您瞧瞧！這玩意兒是否很好用啊！至於為何要寫入上述的檔案呢？留待下一章工作排程時我們再來加強介紹囉！

- setquota ：直接於指令中設定 quota 限額

如果你想要使用 script 的方法來建立大量的帳號，並且所有的帳號都在建立時就給予 quota ，那該如何是好？ 其實有兩個方法可以考慮：

- 先建立一個原始 quota 帳號，再以『 edquota -p old -u new 』寫入 script 中；

- 直接以 setquota 建立用戶的 quota 設定值。

不同於 edquota 是呼叫 vi 來進行設定，setquota 直接由指令輸入所必須要的各項限制值。 他的語法有點像這樣：

[root@www ~]# setquota [-u|-g] 名稱 block(soft) block(hard) \

>  inode(soft) inode(hard) 檔案系統

# 觀察原始的 myquota5 限值，並給予 soft/hard 分別為 100000/200000

[root@www ~]# quota -uv myquota5

Disk quotas for user myquota5 (uid 714):

Filesystem blocks  quota  limit  grace files  quota  limit  grace

/dev/hda3     80 250000 300000           10      0      0

[root@www ~]# setquota -u myquota5 100000 200000 0 0 /home

[root@www ~]# quota -uv myquota5

Disk quotas for user myquota5 (uid 714):

Filesystem blocks  quota  limit  grace files  quota  limit  grace

/dev/hda3     80 100000 200000           10      0      0

# 看吧！真的有改變過來！這就是 quota 的簡單腳本設定語法！

不更動既有系統的 quota 實例

想一想，如果你的主機原先沒有想到要設定成為郵件主機，所以並沒有規劃將郵件信箱所在的 /var/spool/mail/ 目錄獨立成為一個 partition ，然後目前你的主機已經沒有辦法新增或分割出任何新的分割槽了。那我們知道 quota 是針對整個 filesystem 進行設計的，因此，你是否就無法針對 mail 的使用量給予 quota 的限制呢？

此外，如果你想要讓使用者的郵件信箱與家目錄的總體磁碟使用量為固定，那又該如何是好？ 由於 /home 及 /var/spool/mail 根本不可能是同一個 filesystem (除非是都不分割，使用根目錄，才有可能整合在一起)， 所以，該如何進行這樣的 quota 限制呢？

其實沒有那麼難啦！既然 quota 是針對整個 filesystem 來進行限制，假設你又已經有 /home 這個獨立的分割槽了， 那麼你只要：

1. 將 /var/spool/mail 這個目錄完整的移動到 /home 底下；

2. 利用 ln -s /home/mail /var/spool/mail 來建立連結資料；

3. 將 /home 進行 quota 限額設定

只要這樣的一個小步驟，嘿嘿！您家主機的郵件就有一定的限額囉！當然囉！您也可以依據不同的使用者與群組來設定 quota 然後同樣的以上面的方式來進行 link 的動作！嘿嘿嘿！就有不同的限額針對不同的使用者提出囉！很方便吧！ ^_^

Tips:

朋友們需要注意的是，由於目前新的 distributions 大多有使用 SELinux 的機制， 因此你要進行如同上面的目錄搬移時，在許多情況下可能會有使用上的限制喔！或許你得要先暫時關閉 SELinux 才能測試， 也或許你得要自行修改 SELinux 的規則才行喔！

軟體磁碟陣列 (Software RAID)

在過去鳥哥還年輕的時代，我們能使用的硬碟容量都不大，幾十 GB 的容量就是大硬碟了！但是某些情況下，我們需要很大容量的儲存空間， 例如鳥哥在跑的空氣品質模式所輸出的資料檔案一個案例通常需要好幾 GB ，連續跑個幾個案例，磁碟容量就不夠用了。 此時我該如何是好？其實可以透過一種儲存機制，稱為磁碟陣列 (RAID) 的就是了。這種機制的功能是什麼？他有哪些等級？什麼是硬體、軟體磁碟陣列？Linux 支援什麼樣的軟體磁碟陣列？ 底下就讓我們來談談！

什麼是 RAID

磁碟陣列全名是『 Redundant Arrays of Inexpensive Disks, RAID 』，英翻中的意思是：容錯式廉價磁碟陣列。 RAID 可以透過一個技術(軟體或硬體)，將多個較小的磁碟整合成為一個較大的磁碟裝置； 而這個較大的磁碟功能可不止是儲存而已，他還具有資料保護的功能呢。整個 RAID 由於選擇的等級 (level) 不同，而使得整合後的磁碟具有不同的功能， 基本常見的 level 有這幾種(註1)：

- RAID-0 (等量模式, stripe)：效能最佳

這種模式如果使用相同型號與容量的磁碟來組成時，效果較佳。這種模式的 RAID 會將磁碟先切出等量的區塊 (舉例來說， 4KB)， 然後當一個檔案要寫入 RAID 時，該檔案會依據區塊的大小切割好，之後再依序放到各個磁碟裡面去。由於每個磁碟會交錯的存放資料， 因此當你的資料要寫入 RAID 時，資料會被等量的放置在各個磁碟上面。舉例來說，你有兩顆磁碟組成 RAID-0 ， 當你有 100MB 的資料要寫入時，每個磁碟會各被分配到 50MB 的儲存量。RAID-0 的示意圖如下所示：

圖 2.1.1、 RAID-0 的磁碟寫入示意圖

上圖的意思是，在組成 RAID-0 時，每顆磁碟 (Disk A 與 Disk B) 都會先被區隔成為小區塊 (chunk)。 當有資料要寫入 RAID 時，資料會先被切割成符合小區塊的大小，然後再依序一個一個的放置到不同的磁碟去。 由於資料已經先被切割並且依序放置到不同的磁碟上面，因此每顆磁碟所負責的資料量都降低了！照這樣的情況來看， 越多顆磁碟組成的 RAID-0 效能會越好，因為每顆負責的資料量就更低了！ 這表示我的資料可以分散讓多顆磁碟來儲存，當然效能會變的更好啊！此外，磁碟總容量也變大了！ 因為每顆磁碟的容量最終會加總成為 RAID-0 的總容量喔！

只是使用此等級你必須要自行負擔資料損毀的風險，由上圖我們知道檔案是被切割成為適合每顆磁碟分割區塊的大小， 然後再依序放置到各個磁碟中。想一想，如果某一顆磁碟損毀了，那麼檔案資料將缺一塊，此時這個檔案就損毀了。 由於每個檔案都是這樣存放的，因此 RAID-0 只要有任何一顆磁碟損毀，在 RAID 上面的所有資料都會遺失而無法讀取。

另外，如果使用不同容量的磁碟來組成 RAID-0 時，由於資料是一直等量的依序放置到不同磁碟中，當小容量磁碟的區塊被用完了， 那麼所有的資料都將被寫入到最大的那顆磁碟去。舉例來說，我用 200G 與 500G 組成 RAID-0 ， 那麼最初的 400GB 資料可同時寫入兩顆磁碟 (各消耗 200G 的容量)，後來再加入的資料就只能寫入 500G 的那顆磁碟中了。 此時的效能就變差了，因為只剩下一顆可以存放資料嘛！

- RAID-1 (映射模式, mirror)：完整備份

這種模式也是需要相同的磁碟容量的，最好是一模一樣的磁碟啦！如果是不同容量的磁碟組成 RAID-1 時，那麼總容量將以最小的那一顆磁碟為主！這種模式主要是『讓同一份資料，完整的保存在兩顆磁碟上頭』。舉例來說，如果我有一個 100MB 的檔案，且我僅有兩顆磁碟組成 RAID-1 時， 那麼這兩顆磁碟將會同步寫入 100MB 到他們的儲存空間去。 因此，整體 RAID 的容量幾乎少了 50%。由於兩顆硬碟內容一模一樣，好像鏡子映照出來一樣， 所以我們也稱他為 mirror 模式囉∼

圖 2.1.2、 RAID-1 的磁碟寫入示意圖

如上圖所示，一份資料傳送到 RAID-1 之後會被分為兩股，並分別寫入到各個磁碟裡頭去。 由於同一份資料會被分別寫入到其他不同磁碟，因此如果要寫入 100MB 時，資料傳送到 I/O 匯流排後會被複製多份到各個磁碟， 結果就是資料量感覺變大了！因此在大量寫入 RAID-1 的情況下，寫入的效能可能會變的非常差 (因為我們只有一個南橋啊！)。 好在如果你使用的是硬體 RAID (磁碟陣列卡) 時，磁碟陣列卡會主動的複製一份而不使用系統的 I/O 匯流排，效能方面則還可以。 如果使用軟體磁碟陣列，可能效能就不好了。

由於兩顆磁碟內的資料一模一樣，所以任何一顆硬碟損毀時，你的資料還是可以完整的保留下來的！ 所以我們可以說， RAID-1 最大的優點大概就在於資料的備份吧！不過由於磁碟容量有一半用在備份， 因此總容量會是全部磁碟容量的一半而已。雖然 RAID-1 的寫入效能不佳，不過讀取的效能則還可以啦！這是因為資料有兩份在不同的磁碟上面，如果多個 processes 在讀取同一筆資料時， RAID 會自行取得最佳的讀取平衡。

- RAID 0+1，RAID 1+0

RAID-0 的效能佳但是資料不安全，RAID-1 的資料安全但是效能不佳，那麼能不能將這兩者整合起來設定 RAID 呢？ 可以啊！那就是 RAID 0+1 或 RAID 1+0。所謂的 RAID 0+1 就是： (1)先讓兩顆磁碟組成 RAID 0，並且這樣的設定共有兩組； (2)將這兩組 RAID 0 再組成一組 RAID 1。這就是 RAID 0+1 囉！反過來說，RAID 1+0 就是先組成 RAID-1 再組成 RAID-0 的意思。

圖 2.1.3、 RAID-0+1 的磁碟寫入示意圖

如上圖所示，Disk A + Disk B 組成第一組 RAID 0，Disk C + Disk D 組成第二組 RAID 0， 然後這兩組再整合成為一組 RAID 1。如果我有 100MB 的資料要寫入，則由於 RAID 1 的關係， 兩組 RAID 0 都會寫入 100MB，但由於 RAID 0 的關係，因此每顆磁碟僅會寫入 50MB 而已。 如此一來不論哪一組 RAID 0 的磁碟損毀，只要另外一組 RAID 0 還存在，那麼就能夠透過 RAID 1 的機制來回復資料。

由於具有 RAID 0 的優點，所以效能得以提升，由於具有 RAID 1 的優點，所以資料得以備份。 但是也由於 RAID 1 的缺點，所以總容量會少一半用來做為備份喔！

- RAID 5：效能與資料備份的均衡考量

RAID-5 至少需要三顆以上的磁碟才能夠組成這種類型的磁碟陣列。這種磁碟陣列的資料寫入有點類似 RAID-0 ， 不過每個循環的寫入過程中，在每顆磁碟還加入一個同位檢查資料 (Parity) ，這個資料會記錄其他磁碟的備份資料， 用於當有磁碟損毀時的救援。RAID-5 讀寫的情況有點像底下這樣：

圖 2.1.4、 RAID-5 的磁碟寫入示意圖

如上圖所示，每個循環寫入時，都會有部分的同位檢查碼 (parity) 被記錄起來，並且記錄的同位檢查碼每次都記錄在不同的磁碟， 因此，任何一個磁碟損毀時都能夠藉由其他磁碟的檢查碼來重建原本磁碟內的資料喔！不過需要注意的是， 由於有同位檢查碼，因此 RAID 5 的總容量會是整體磁碟數量減一顆。以上圖為例， 原本的 3 顆磁碟只會剩下 (3-1)=2 顆磁碟的容量。而且當損毀的磁碟數量大於等於兩顆時，這整組 RAID 5 的資料就損毀了。 因為 RAID 5 預設僅能支援一顆磁碟的損毀情況。

在讀寫效能的比較上，讀取的效能還不賴！與 RAID-0 有的比！不過寫的效能就不見得能夠增加很多！ 這是因為要寫入 RAID 5 的資料還得要經過計算同位檢查碼 (parity) 的關係。由於加上這個計算的動作， 所以寫入的效能與系統的硬體關係較大！尤其當使用軟體磁碟陣列時，同位檢查碼是透過 CPU 去計算而非專職的磁碟陣列卡， 因此效能方面還需要評估。

另外，由於 RAID 5 僅能支援一顆磁碟的損毀，因此近來還有發展出另外一種等級，就是 RAID 6 ，這個 RAID 6 則使用兩顆磁碟的容量作為 parity 的儲存，因此整體的磁碟容量就會少兩顆，但是允許出錯的磁碟數量就可以達到兩顆了！ 也就是在 RAID 6 的情況下，同時兩顆磁碟損毀時，資料還是可以救回來！

- Spare Disk：預備磁碟的功能：

當磁碟陣列的磁碟損毀時，就得要將壞掉的磁碟拔除，然後換一顆新的磁碟。換成新磁碟並且順利啟動磁碟陣列後， 磁碟陣列就會開始主動的重建 (rebuild) 原本壞掉的那顆磁碟資料到新的磁碟上！然後你磁碟陣列上面的資料就復原了！ 這就是磁碟陣列的優點。不過，我們還是得要動手拔插硬碟，此時通常得要關機才能這麼做。

為了讓系統可以即時的在壞掉硬碟時主動的重建，因此就需要預備磁碟 (spare disk) 的輔助。 所謂的 spare disk 就是一顆或多顆沒有包含在原本磁碟陣列等級中的磁碟，這顆磁碟平時並不會被磁碟陣列所使用， 當磁碟陣列有任何磁碟損毀時，則這顆 spare disk 會被主動的拉進磁碟陣列中，並將壞掉的那顆硬碟移出磁碟陣列！ 然後立即重建資料系統。如此你的系統則可以永保安康啊！若你的磁碟陣列有支援熱拔插那就更完美了！ 直接將壞掉的那顆磁碟拔除換一顆新的，再將那顆新的設定成為 spare disk ，就完成了！

舉例來說，鳥哥之前所待的研究室有一個磁碟陣列可允許 16 顆磁碟的數量，不過我們只安裝了 10 顆磁碟作為 RAID 5。 每顆磁碟的容量為 250GB，我們用了一顆磁碟作為 spare disk ，並將其他的 9 顆設定為一個 RAID 5， 因此這個磁碟陣列的總容量為： (9-1)*250G=2000G。運作了一兩年後真的有一顆磁碟壞掉了，我們後來看燈號才發現！ 不過對系統沒有影響呢！因為 spare disk 主動的加入支援，壞掉的那顆拔掉換顆新的，並重新設定成為 spare 後， 系統內的資料還是完整無缺的！嘿嘿！真不錯！

- 磁碟陣列的優點

說的口沫橫飛，重點在哪裡呢？其實你的系統如果需要磁碟陣列的話，其實重點在於：

- 資料安全與可靠性：指的並非資訊安全，而是當硬體 (指磁碟) 損毀時，資料是否還能夠安全的救援或使用之意；

- 讀寫效能：例如 RAID 0 可以加強讀寫效能，讓你的系統 I/O 部分得以改善；

- 容量：可以讓多顆磁碟組合起來，故單一檔案系統可以有相當大的容量。

尤其資料的可靠性與完整性更是使用 RAID 的考量重點！畢竟硬體壞掉換掉就好了，軟體資料損毀那可不是鬧著玩的！ 所以企業界為何需要大量的 RAID 來做為檔案系統的硬體基準，現在您有點瞭解了吧？

software, hardware RAID

為何磁碟陣列又分為硬體與軟體呢？所謂的硬體磁碟陣列 (hardware RAID) 是透過磁碟陣列卡來達成陣列的目的。 磁碟陣列卡上面有一塊專門的晶片在處理 RAID 的任務，因此在效能方面會比較好。在很多任務 (例如 RAID 5 的同位檢查碼計算) 磁碟陣列並不會重複消耗原本系統的 I/O 匯流排，理論上效能會較佳。此外目前一般的中高階磁碟陣列卡都支援熱拔插， 亦即在不關機的情況下抽換損壞的磁碟，對於系統的復原與資料的可靠性方面非常的好用。

不過一塊好的磁碟陣列卡動不動就上萬元台幣，便宜的在主機板上面『附贈』的磁碟陣列功能可能又不支援某些高階功能， 例如低階主機板若有磁碟陣列晶片，通常僅支援到 RAID0 與 RAID1 ，鳥哥喜歡的 RAID 5 並沒有支援。 此外，作業系統也必須要擁有磁碟陣列卡的驅動程式，才能夠正確的捉到磁碟陣列所產生的磁碟機！

由於磁碟陣列有很多優秀的功能，然而硬體磁碟陣列卡偏偏又貴的很∼因此就有發展出利用軟體來模擬磁碟陣列的功能， 這就是所謂的軟體磁碟陣列 (software RAID)。軟體磁碟陣列主要是透過軟體來模擬陣列的任務， 因此會損耗較多的系統資源，比如說 CPU 的運算與 I/O 匯流排的資源等。不過目前我們的個人電腦實在已經非常快速了， 因此以前的速度限制現在已經不存在！所以我們可以來玩一玩軟體磁碟陣列！

我們的 CentOS 提供的軟體磁碟陣列為 mdadm 這套軟體，這套軟體會以 partition 或 disk 為磁碟的單位，也就是說，你不需要兩顆以上的磁碟，只要有兩個以上的分割槽 (partition) 就能夠設計你的磁碟陣列了。此外， mdadm 支援剛剛我們前面提到的 RAID0/RAID1/RAID5/spare disk 等！ 而且提供的管理機制還可以達到類似熱拔插的功能，可以線上 (檔案系統正常使用) 進行分割槽的抽換！ 使用上也非常的方便呢！

另外你必須要知道的是，硬體磁碟陣列在 Linux 底下看起來就是一顆實際的大磁碟，因此硬體磁碟陣列的裝置檔名為 /dev/sd[a-p] ，因為使用到 SCSI 的模組之故。至於軟體磁碟陣列則是系統模擬的，因此使用的裝置檔名是系統的裝置檔， 檔名為 /dev/md0, /dev/md1...，兩者的裝置檔名並不相同！不要搞混了喔！因為很多朋友常常覺得奇怪， 怎麼他的 RAID 檔名跟我們這裡測試的軟體 RAID 檔名不同，所以這裡特別強調說明喔！

軟體磁碟陣列的設定

軟體磁碟陣列的設定很簡單呢！簡單到讓你很想笑喔！因為你只要使用一個指令即可！那就是 mdadm 這個指令。 這個指令在建立 RAID 的語法有點像這樣：

[root@www ~]# mdadm --detail /dev/md0

[root@www ~]# mdadm --create --auto=yes /dev/md[0-9] --raid-devices=N \

> --level=[015] --spare-devices=N /dev/sdx /dev/hdx...

選項與參數：

--create ：為建立 RAID 的選項；

--auto=yes ：決定建立後面接的軟體磁碟陣列裝置，亦即 /dev/md0, /dev/md1...

--raid-devices=N ：使用幾個磁碟 (partition) 作為磁碟陣列的裝置

--spare-devices=N ：使用幾個磁碟作為備用 (spare) 裝置

--level=[015] ：設定這組磁碟陣列的等級。支援很多，不過建議只要用 0, 1, 5 即可

--detail ：後面所接的那個磁碟陣列裝置的詳細資訊

上面的語法中，最後面會接許多的裝置檔名，這些裝置檔名可以是整顆磁碟，例如 /dev/sdb ， 也可以是分割槽，例如 /dev/sdb1 之類。不過，這些裝置檔名的總數必須要等於 --raid-devices 與 --spare-devices 的個數總和才行！鳥哥利用我的測試機來建置一個 RAID 5 的軟體磁碟陣列給您瞧瞧！ 首先，將系統裡面過去練習過而目前用不到的分割槽通通刪除掉：

[root@www ~]# fdisk -l

Disk /dev/hda: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hda1   *           1          13      104391   83  Linux

/dev/hda2              14        1288    10241437+  83  Linux

/dev/hda3            1289        1925     5116702+  83  Linux

/dev/hda4            1926        5005    24740100    5  Extended

/dev/hda5            1926        2052     1020096   82  Linux swap / Solaris

/dev/hda6            2053        2302     2008093+  83  Linux

/dev/hda7            2303        2334      257008+  82  Linux swap / Solaris

/dev/hda8            2335        2353      152586   83  Linux

/dev/hda9            2354        2366      104391   83  Linux

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hda2              9920624   3858800   5549756  42% /

/dev/hda1               101086     21408     74459  23% /boot

tmpfs                   371332         0    371332   0% /dev/shm

/dev/hda3              4956316   1056996   3643488  23% /home

# 從上面可以發現，我的 /dev/hda6~/dev/hda9 沒有用到！將他刪除看看！

[root@www ~]# fdisk /dev/hda

Command (m for help): d

Partition number (1-9): 9

Command (m for help): d

Partition number (1-8): 8

Command (m for help): d

Partition number (1-7): 7

Command (m for help): d

Partition number (1-6): 6

Command (m for help): p

Disk /dev/hda: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hda1   *           1          13      104391   83  Linux

/dev/hda2              14        1288    10241437+  83  Linux

/dev/hda3            1289        1925     5116702+  83  Linux

/dev/hda4            1926        5005    24740100    5  Extended

/dev/hda5            1926        2052     1020096   82  Linux swap / Solaris

Command (m for help): w

[root@www ~]# partprobe

# 這個動作很重要！還記得吧！將核心的 partition table 更新！

底下是鳥哥希望做成的 RAID 5 環境：

- 利用 4 個 partition 組成 RAID 5；

- 每個 partition 約為 1GB 大小，需確定每個 partition 一樣大較佳；

- 利用 1 個 partition 設定為 spare disk

- 這個 spare disk 的大小與其他 RAID 所需 partition 一樣大！

- 將此 RAID 5 裝置掛載到 /mnt/raid 目錄下

最終我需要 5 個 1GB 的 partition 。由於鳥哥的系統僅有一顆磁碟，這顆磁碟剩餘容量約 20GB 是夠用的， 分割槽代號僅使用到 5 號，所以要製作成 RAID 5 應該是不成問題！接下來就是連續的建置流程囉！

- 建置所需的磁碟裝置

如前所述，我需要 5 個 1GB 的分割槽，請利用 fdisk 來建置吧！

[root@www ~]# fdisk /dev/hda

Command (m for help): n

First cylinder (2053-5005, default 2053): <==直接按下 [enter]

Using default value 2053

Last cylinder or +size or +sizeM or +sizeK (2053-5005, default 5005): +1000M

# 上述的動作請作五次！

Command (m for help): p

Disk /dev/hda: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hda1   *           1          13      104391   83  Linux

/dev/hda2              14        1288    10241437+  83  Linux

/dev/hda3            1289        1925     5116702+  83  Linux

/dev/hda4            1926        5005    24740100    5  Extended

/dev/hda5            1926        2052     1020096   82  Linux swap / Solaris

/dev/hda6            2053        2175      987966   83  Linux

/dev/hda7            2176        2298      987966   83  Linux

/dev/hda8            2299        2421      987966   83  Linux

/dev/hda9            2422        2544      987966   83  Linux

/dev/hda10           2545        2667      987966   83  Linux

# 上面的 6~10 號，就是我們需要的 partition 囉！

Command (m for help): w

[root@www ~]# partprobe

- 以 mdadm 建置 RAID

接下來就簡單啦！透過 mdadm 來建立磁碟陣列先！

[root@www ~]# mdadm --create --auto=yes /dev/md0 --level=5 \

> --raid-devices=4 --spare-devices=1 /dev/hda{6,7,8,9,10}

# 詳細的參數說明請回去前面看看囉！這裡我透過 {} 將重複的項目簡化！

[root@www ~]# mdadm --detail /dev/md0

/dev/md0:                                        <==RAID 裝置檔名

Version : 00.90.03

Creation Time : Tue Mar 10 17:47:51 2009       <==RAID 被建立的時間

Raid Level : raid5                          <==RAID 等級為 RAID 5

Array Size : 2963520 (2.83 GiB 3.03 GB)     <==此 RAID 的可用磁碟容量

Used Dev Size : 987840 (964.85 MiB 1011.55 MB) <==每個裝置的可用容量

Raid Devices : 4                              <==用作 RAID 的裝置數量

Total Devices : 5                              <==全部的裝置數量

Preferred Minor : 0

Persistence : Superblock is persistent

Update Time : Tue Mar 10 17:52:23 2009

State : clean

Active Devices : 4                              <==啟動的(active)裝置數量

Working Devices : 5                              <==可動作的裝置數量

Failed Devices : 0                              <==出現錯誤的裝置數量

Spare Devices : 1                              <==預備磁碟的數量

Layout : left-symmetric

Chunk Size : 64K      <==就是圖2.1.4內的小區塊

UUID : 7c60c049:57d60814:bd9a77f1:57e49c5b <==此裝置(RAID)識別碼

Events : 0.2

Number   Major   Minor   RaidDevice State

0       3        6        0      active sync   /dev/hda6

1       3        7        1      active sync   /dev/hda7

2       3        8        2      active sync   /dev/hda8

3       3        9        3      active sync   /dev/hda9

4       3       10        -      spare   /dev/hda10

# 最後五行就是這五個裝置目前的情況，包括四個 active sync 一個 spare ！

# 至於 RaidDevice  指的則是此 RAID 內的磁碟順序

由於磁碟陣列的建置需要一些時間，所以你最好等待數分鐘後再使用『 mdadm --detail /dev/md0 』去查閱你的磁碟陣列詳細資訊！ 否則有可能看到某些磁碟正在『spare rebuilding』之類的建置字樣！透過上面的指令， 你就能夠建立一個 RAID5 且含有一顆 spare disk 的磁碟陣列囉！非常簡單吧！ 除了指令之外，你也可以查閱如下的檔案來看看系統軟體磁碟陣列的情況：

[root@www ~]# cat /proc/mdstat

Personalities : [raid6] [raid5] [raid4]

md0 : active raid5 hda9[3] hda10[4](S) hda8[2] hda7[1] hda6[0]    <==第一行

2963520 blocks level 5, 64k chunk, algorithm 2 [4/4] [UUUU] <==第二行

unused devices: <none>

上述的資料比較重要的在特別指出的第一行與第二行部分(註2)：

- 第一行部分：指出 md0 為 raid5 ，且使用了 hda9, hda8, hda7, hda6 等四顆磁碟裝置。每個裝置後面的中括號 [] 內的數字為此磁碟在 RAID 中的順序 (RaidDevice)；至於 hda10 後面的 [S] 則代表 hda10 為 spare 之意。

- 第二行：此磁碟陣列擁有 2963520 個block(每個 block 單位為 1K)，所以總容量約為 3GB， 使用 RAID 5 等級，寫入磁碟的小區塊 (chunk) 大小為 64K，使用 algorithm 2 磁碟陣列演算法。 [m/n] 代表此陣列需要 m 個裝置，且 n 個裝置正常運作。因此本 md0 需要 4 個裝置且這 4 個裝置均正常運作。 後面的 [UUUU] 代表的是四個所需的裝置 (就是 [m/n] 裡面的 m) 的啟動情況，U 代表正常運作，若為 _ 則代表不正常。

這兩種方法都可以知道目前的磁碟陣列狀態啦！

- 格式化與掛載使用 RAID

接下來就是開始使用格式化工具啦！這部分就簡單到爆！不多說了，直接進行吧！

[root@www ~]# mkfs -t ext3 /dev/md0

# 有趣吧！是 /dev/md0 做為裝置被格式化呢！

[root@www ~]# mkdir /mnt/raid

[root@www ~]# mount /dev/md0 /mnt/raid

[root@www ~]# df

Filesystem     1K-blocks      Used Available Use% Mounted on

/dev/hda2        9920624   3858820   5549736  42% /

/dev/hda1         101086     21408     74459  23% /boot

tmpfs             371332         0    371332   0% /dev/shm

/dev/hda3        4956316   1056996   3643488  23% /home

/dev/md0         2916920     69952   2698792   3% /mnt/raid

# 看吧！多了一個 /dev/md0 的裝置，而且真的可以讓你使用呢！還不賴！

模擬 RAID 錯誤的救援模式

俗話說『天有不測風雲、人有旦夕禍福』，誰也不知道你的磁碟陣列內的裝置啥時會出差錯，因此， 瞭解一下軟體磁碟陣列的救援還是必須的！底下我們就來玩一玩救援的機制吧！首先來瞭解一下 mdadm 這方面的語法：

[root@www ~]# mdadm --manage /dev/md[0-9] [--add 裝置] [--remove 裝置] \

> [--fail 裝置]

選項與參數：

--add ：會將後面的裝置加入到這個 md 中！

--remove ：會將後面的裝置由這個 md 中移除

--fail ：會將後面的裝置設定成為出錯的狀態

- 設定磁碟為錯誤 (fault)

首先，我們來處理一下，該如何讓一個磁碟變成錯誤，然後讓 spare disk 自動的開始重建系統呢？

# 0. 先複製一些東西到 /mnt/raid 去，假設這個 RAID 已經在使用了

[root@www ~]# cp -a /etc /var/log /mnt/raid

[root@www ~]# df /mnt/raid ; du -sm /mnt/raid/*

Filesystem   1K-blocks      Used Available Use% Mounted on

/dev/md0       2916920    188464   2580280   7% /mnt/raid

118     /mnt/raid/etc <==看吧！確實有資料在裡面喔！

8       /mnt/raid/log

1       /mnt/raid/lost+found

# 1. 假設 /dev/hda8 這個裝置出錯了！實際模擬的方式：

[root@www ~]# mdadm --manage /dev/md0 --fail /dev/hda8

mdadm: set /dev/hda8 faulty in /dev/md0

[root@www ~]# mdadm --detail /dev/md0

....(前面省略)....

State : clean, degraded, recovering

Active Devices : 3

Working Devices : 4

Failed Devices : 1  <==出錯的磁碟有一個！

Spare Devices : 1

....(中間省略)....

Number   Major   Minor   RaidDevice State

0       3        6        0      active sync   /dev/hda6

1       3        7        1      active sync   /dev/hda7

4       3       10        2      spare rebuilding   /dev/hda10

3       3        9        3      active sync   /dev/hda9

5       3        8        -      faulty spare   /dev/hda8

# 看到沒！這的動作要快做才會看到！ /dev/hda10 啟動了而 /dev/hda8 死掉了

[root@www ~]# cat /proc/mdstat

Personalities : [raid6] [raid5] [raid4]

md0 : active raid5 hda9[3] hda10[4] hda8[5](F) hda7[1] hda6[0]

2963520 blocks level 5, 64k chunk, algorithm 2 [4/3] [UU_U]

[>.......]  recovery =  0.8% (9088/987840) finish=14.3min speed=1136K/sec

上面的畫面你得要快速的連續輸入那些 mdadm 的指令才看的到！因為你的 RAID 5 正在重建系統！ 若你等待一段時間再輸入後面的觀察指令，則會看到如下的畫面了：

# 2. 已經藉由 spare disk 重建完畢的 RAID 5 情況

[root@www ~]# mdadm --detail /dev/md0

....(前面省略)....

Number   Major   Minor   RaidDevice State

0       3        6        0      active sync   /dev/hda6

1       3        7        1      active sync   /dev/hda7

2       3       10        2      active sync   /dev/hda10

3       3        9        3      active sync   /dev/hda9

4       3        8        -      faulty spare   /dev/hda8

[root@www ~]# cat /proc/mdstat

Personalities : [raid6] [raid5] [raid4]

md0 : active raid5 hda9[3] hda10[2] hda8[4](F) hda7[1] hda6[0]

2963520 blocks level 5, 64k chunk, algorithm 2 [4/4] [UUUU]

看吧！又恢復正常了！真好！我們的 /mnt/raid 檔案系統是完整的！並不需要卸載！很棒吧！

- 將出錯的磁碟移除並加入新磁碟

首先，我們再建立一個新的分割槽，這個分割槽要與其他分割槽一樣大才好！然後再利用 mdadm 移除錯誤的並加入新的！

# 3. 建立新的分割槽

[root@www ~]# fdisk /dev/hda

Command (m for help): n

First cylinder (2668-5005, default 2668): <==這裡按 [enter]

Using default value 2668

Last cylinder or +size or +sizeM or +sizeK (2668-5005, default 5005): +1000M

Command (m for help): w

[root@www ~]# partprobe

# 此時系統會多一個 /dev/hda11 的分割槽喔！

# 4. 加入新的拔除有問題的磁碟

[root@www ~]# mdadm --manage /dev/md0 --add /dev/hda11 --remove /dev/hda8

mdadm: added /dev/hda11

mdadm: hot removed /dev/hda8

[root@www ~]# mdadm --detail /dev/md0

....(前面省略)....

0       3        6        0      active sync   /dev/hda6

1       3        7        1      active sync   /dev/hda7

2       3       10        2      active sync   /dev/hda10

3       3        9        3      active sync   /dev/hda9

4       3       11        -      spare   /dev/hda11

嘿嘿！你的磁碟陣列內的資料不但一直存在，而且你可以一直順利的運作 /mnt/raid 內的資料，即使 /dev/hda8 損毀了！然後透過管理的功能就能夠加入新磁碟且拔除壞掉的磁碟！注意，這一切都是在上線 (on-line) 的情況下進行！ 所以，您說這樣的咚咚好不好用啊！ ^_^

開機自動啟動 RAID 並自動掛載

新的 distribution 大多會自己搜尋 /dev/md[0-9] 然後在開機的時候給予設定好所需要的功能。不過鳥哥還是建議你， 修改一下設定檔吧！ ^_^。software RAID 也是有設定檔的，這個設定檔在 /etc/mdadm.conf ！這個設定檔內容很簡單， 你只要知道 /dev/md0 的 UUID 就能夠設定這個檔案啦！這裡鳥哥僅介紹他最簡單的語法：

[root@www ~]# mdadm --detail /dev/md0 | grep -i uuid

UUID : 7c60c049:57d60814:bd9a77f1:57e49c5b

# 後面那一串資料，就是這個裝置向系統註冊的 UUID 識別碼！

# 開始設定 mdadm.conf

[root@www ~]# vi /etc/mdadm.conf

ARRAY /dev/md0 UUID=7c60c049:57d60814:bd9a77f1:57e49c5b

#     RAID裝置      識別碼內容

# 開始設定開機自動掛載並測試

[root@www ~]# vi /etc/fstab

/dev/md0    /mnt/raid    ext3    defaults     1 2

[root@www ~]# umount /dev/md0; mount -a

[root@www ~]# df /mnt/raid

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/md0               2916920    188464   2580280   7% /mnt/raid

# 你得確定可以順利掛載，並且沒有發生任何錯誤！

如果到這裡都沒有出現任何問題！接下來就請 reboot 你的系統並等待看看能否順利的啟動吧！ ^_^

關閉軟體 RAID(重要！)

除非你未來就是要使用這顆 software RAID (/dev/md0)，否則你勢必要跟鳥哥一樣，將這個 /dev/md0 關閉！ 因為他畢竟是我們在這個測試機上面的練習裝置啊！為什麼要關掉他呢？因為這個 /dev/md0 其實還是使用到我們系統的磁碟分割槽， 在鳥哥的例子裡面就是 /dev/hda{6,7,8,9,10,11}，如果你只是將 /dev/md0 卸載，然後忘記將 RAID 關閉， 結果就是....未來你在重新分割 /dev/hdaX 時可能會出現一些莫名的錯誤狀況啦！所以才需要關閉 software RAID 的步驟！ 那如何關閉呢？也是簡單到爆炸！(請注意，確認你的 /dev/md0 確實不要用且要關閉了才進行底下的玩意兒)

# 1. 先卸載且刪除設定檔內與這個 /dev/md0 有關的設定：

[root@www ~]# umount /dev/md0

[root@www ~]# vi /etc/fstab

/dev/md0    /mnt/raid     ext3    defaults      1 2

# 將這一行刪除掉！或者是註解掉也可以！

# 2. 直接關閉 /dev/md0 的方法！

[root@www ~]# mdadm --stop /dev/md0

mdadm: stopped /dev/md0  <==不囉唆！這樣就關閉了！

[root@www ~]# cat /proc/mdstat

Personalities : [raid6] [raid5] [raid4]

unused devices: <none>  <==看吧！確實不存在任何陣列裝置！

[root@www ~]# vi /etc/mdadm.conf

ARRAY /dev/md0 UUID=7c60c049:57d60814:bd9a77f1:57e49c5b

# 一樣啦！刪除他或是註解他！

Tips:

在這個練習中，鳥哥使用同一顆磁碟進行軟體 RAID 的實驗。不過朋友們要注意的是，如果真的要實作軟體磁碟陣列， 最好是由多顆不同的磁碟來組成較佳！因為這樣才能夠使用到不同磁碟的讀寫，效能才會好！ 而資料分配在不同的磁碟，當某顆磁碟損毀時資料才能夠藉由其他磁碟挽救回來！這點得特別留意呢！

邏輯捲軸管理員 (Logical Volume Manager)

想像一個情況，你在當初規劃主機的時候將 /home 只給他 50G ，等到使用者眾多之後導致這個 filesystem 不夠大， 此時你能怎麼作？多數的朋友都是這樣：再加一顆新硬碟，然後重新分割、格式化，將 /home 的資料完整的複製過來， 然後將原本的 partition 卸載重新掛載新的 partition 。啊！好忙碌啊！若是第二次分割卻給的容量太多！導致很多磁碟容量被浪費了！ 你想要將這個 partition 縮小時，又該如何作？將上述的流程再搞一遍！唉∼煩死了，尤其複製很花時間ㄟ∼有沒有更簡單的方法呢？ 有的！那就是我們這個小節要介紹的 LVM 這玩意兒！

LVM 的重點在於『可以彈性的調整 filesystem 的容量！』而並非在於效能與資料保全上面。 需要檔案的讀寫效能或者是資料的可靠性，請參考前面的 RAID 小節。 LVM 可以整合多個實體 partition 在一起， 讓這些 partitions 看起來就像是一個磁碟一樣！而且，還可以在未來新增或移除其他的實體 partition 到這個 LVM 管理的磁碟當中。 如此一來，整個磁碟空間的使用上，實在是相當的具有彈性啊！ 既然 LVM 這麼好用，那就讓我們來瞧瞧這玩意吧！

什麼是 LVM： PV, PE, VG, LV 的意義

LVM 的全名是 Logical Volume Manager，中文可以翻譯作邏輯捲軸管理員。之所以稱為『捲軸』可能是因為可以將 filesystem 像捲軸一樣伸長或縮短之故吧！LVM 的作法是將幾個實體的 partitions (或 disk) 透過軟體組合成為一塊看起來是獨立的大磁碟 (VG) ，然後將這塊大磁碟再經過分割成為可使用分割槽 (LV)， 最終就能夠掛載使用了。但是為什麼這樣的系統可以進行 filesystem 的擴充或縮小呢？其實與一個稱為 PE 的項目有關！ 底下我們就得要針對這幾個項目來好好聊聊！

- Physical Volume, PV, 實體捲軸

我們實際的 partition 需要調整系統識別碼 (system ID) 成為 8e (LVM 的識別碼)，然後再經過 pvcreate 的指令將他轉成 LVM 最底層的實體捲軸 (PV) ，之後才能夠將這些 PV 加以利用！ 調整 system ID 的方是就是透過 fdisk 啦！

- Volume Group, VG, 捲軸群組

所謂的 LVM 大磁碟就是將許多 PV 整合成這個 VG 的東西就是啦！所以 VG 就是 LVM 組合起來的大磁碟！這麼想就好了。 那麼這個大磁碟最大可以到多少容量呢？這與底下要說明的 PE 以及 LVM 的格式版本有關喔∼在預設的情況下， lvm2 可能會使用 lvm1 的儲存格式，該格式的 LV 最大僅能支援到 65534 PE 而已。 所以，如果使用 LVM 預設的參數 (CentOS 5.x 32 位元使用 lvm2 軟體、lvm1 格式)，則一個 VG 最大可達 256GB 的容量啊！(參考底下的 PE 說明)

- Physical Extend, PE, 實體延伸區塊

LVM 預設使用 4MB 的 PE 區塊，而 LVM 的 LV 最多僅能含有 65534 個 PE (lvm1 的格式)，因此預設的 LVM 的 LV 會有 4M*65534/(1024M/G)=256G。這個 PE 很有趣喔！他是整個 LVM 最小的儲存區塊，也就是說，其實我們的檔案資料都是藉由寫入 PE 來處理的。簡單的說，這個 PE 就有點像檔案系統裡面的 block 大小啦。 這樣說應該就比較好理解了吧？所以調整 PE 會影響到 LVM 的最大容量喔！不過，在 CentOS 6.x 以後，由於直接使用 lvm2 的各項格式功能，因此這個限制已經不存在了。

- Logical Volume, LV, 邏輯捲軸

最終的 VG 還會被切成 LV，這個 LV 就是最後可以被格式化使用的類似分割槽的咚咚了！那麼 LV 是否可以隨意指定大小呢？ 當然不可以！既然 PE 是整個 LVM 的最小儲存單位，那麼 LV 的大小就與在此 LV 內的 PE 總數有關。 為了方便使用者利用 LVM 來管理其系統，因此 LV 的裝置檔名通常指定為『 /dev/vgname/lvname 』的樣式！

此外，我們剛剛有談到 LVM 可彈性的變更 filesystem 的容量，那是如何辦到的？其實他就是透過『交換 PE 』來進行資料轉換， 將原本 LV 內的 PE 移轉到其他裝置中以降低 LV 容量，或將其他裝置的 PE 加到此 LV 中以加大容量！ VG、LV 與 PE 的關係有點像下圖：

圖 3.1.1、PE 與 VG 的相關性圖示

如上圖所示，VG 內的 PE 會分給虛線部分的 LV，如果未來這個 VG 要擴充的話，加上其他的 PV 即可。 而最重要的 LV 如果要擴充的話，也是透過加入 VG 內沒有使用到的 PE 來擴充的！

- 實作流程

透過 PV, VG, LV 的規劃之後，再利用 mkfs 就可以將你的 LV 格式化成為可以利用的檔案系統了！而且這個檔案系統的容量在未來還能夠進行擴充或減少， 而且裡面的資料還不會被影響！實在是很『福氣啦！』那實作方面要如何進行呢？很簡單呢！ 整個流程由基礎到最終的結果可以這樣看：

圖 3.1.2、 LVM 各元件的實現流程圖示

如此一來，我們就可以利用 LV 這個玩意兒來進行系統的掛載了。不過，你應該要覺得奇怪的是， 那麼我的資料寫入這個 LV 時，到底他是怎麼寫入硬碟當中的？ 呵呵！好問題∼其實，依據寫入機制的不同，而有兩種方式：

- 線性模式 (linear)：假如我將 /dev/hda1, /dev/hdb1 這兩個 partition 加入到 VG 當中，並且整個 VG 只有一個 LV 時，那麼所謂的線性模式就是：當 /dev/hda1 的容量用完之後，/dev/hdb1 的硬碟才會被使用到， 這也是我們所建議的模式。

- 交錯模式 (triped)：那什麼是交錯模式？很簡單啊，就是我將一筆資料拆成兩部分，分別寫入 /dev/hda1 與 /dev/hdb1 的意思，感覺上有點像 RAID 0 啦！如此一來，一份資料用兩顆硬碟來寫入，理論上，讀寫的效能會比較好。

基本上，LVM 最主要的用處是在實現一個可以彈性調整容量的檔案系統上， 而不是在建立一個效能為主的磁碟上，所以，我們應該利用的是 LVM 可以彈性管理整個 partition 大小的用途上，而不是著眼在效能上的。因此， LVM 預設的讀寫模式是線性模式啦！ 如果你使用 triped 模式，要注意，當任何一個 partition 『歸天』時，所有的資料都會『損毀』的！ 所以啦，不是很適合使用這種模式啦！如果要強調效能與備份，那麼就直接使用 RAID 即可， 不需要用到 LVM 啊！

LVM 實作流程

LVM 必需要核心有支援且需要安裝 lvm2 這個軟體，好佳在的是， CentOS 與其他較新的 distributions 已經預設將 lvm 的支援與軟體都安裝妥當了！所以你不需要擔心這方面的問題！用就對了！

鳥哥使用的測試機又要出動了喔！剛剛我們才練習過 RAID，必須要將一堆目前沒有用到的分割槽先殺掉， 然後再重建新的分割槽。並且由於鳥哥僅有一個 40GB 的磁碟，所以底下的練習都僅針對同一顆磁碟來作的。 我的要求有點像這樣：

- 先分割出 4 個 partition ，每個 partition 的容量均為 1.5GB 左右，且 system ID 需要為 8e；

- 全部的 partition 整合成為一個 VG，VG 名稱設定為 vbirdvg；且 PE 的大小為 16MB；

- 全部的 VG 容量都丟給 LV ，LV 的名稱設定為 vbirdlv；

- 最終這個 LV 格式化為 ext3 的檔案系統，且掛載在 /mnt/lvm 中

鳥哥就不仔細的介紹實體分割了，請您自行參考第八章的 fdisk 來達成底下的範例：(注意：修改系統識別碼請使用 t 這個 fdisk 內的指令來處理即可)

[root@www ~]# fdisk /dev/hda  <==其他流程請自行參考第八章處理

[root@www ~]# partprobe       <==別忘記這個動作了！粉重要！

[root@www ~]# fdisk -l

Disk /dev/hda: 41.1 GB, 41174138880 bytes

255 heads, 63 sectors/track, 5005 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/hda1   *           1          13      104391   83  Linux

/dev/hda2              14        1288    10241437+  83  Linux

/dev/hda3            1289        1925     5116702+  83  Linux

/dev/hda4            1926        5005    24740100    5  Extended

/dev/hda5            1926        2052     1020096   82  Linux swap / Solaris

/dev/hda6            2053        2235     1469916   8e  Linux LVM

/dev/hda7            2236        2418     1469916   8e  Linux LVM

/dev/hda8            2419        2601     1469916   8e  Linux LVM

/dev/hda9            2602        2784     1469916   8e  Linux LVM

上面的 /dev/hda{6,7,8,9} 這四個分割槽就是我們的實體分割槽！也就是底下會實際用到的資訊！ 注意看，那個 8e 的出現會導致 system 變成『 Linux LVM 』哩！其實沒有設定成為 8e 也沒關係， 不過某些 LVM 的偵測指令可能會偵測不到該 partition 就是了！接下來，就一個一個的處理各流程吧！

- PV 階段

要建立 PV 其實很簡單，只要直接使用 pvcreate 即可！我們來談一談與 PV 有關的指令吧！

- pvcreate ：將實體 partition 建立成為 PV ；

- pvscan ：搜尋目前系統裡面任何具有 PV 的磁碟；

- pvdisplay ：顯示出目前系統上面的 PV 狀態；

- pvremove ：將 PV 屬性移除，讓該 partition 不具有 PV 屬性。

那就直接來瞧一瞧吧！

# 1. 檢查有無 PV 在系統上，然後將 /dev/hda6~/dev/hda9 建立成為 PV 格式

[root@www ~]# pvscan

No matching physical volumes found <==找不到任何的 PV 存在喔！

[root@www ~]# pvcreate /dev/hda{6,7,8,9}

Physical volume "/dev/hda6" successfully created

Physical volume "/dev/hda7" successfully created

Physical volume "/dev/hda8" successfully created

Physical volume "/dev/hda9" successfully created

# 這個指令可以一口氣建立這四個 partition 成為 PV 啦！注意大括號的用途

[root@www ~]# pvscan

PV /dev/hda6         lvm2 [1.40 GB]

PV /dev/hda7         lvm2 [1.40 GB]

PV /dev/hda8         lvm2 [1.40 GB]

PV /dev/hda9         lvm2 [1.40 GB]

Total: 4 [5.61 GB] / in use: 0 [0   ] / in no VG: 4 [5.61 GB]

# 這就分別顯示每個 PV 的資訊與系統所有 PV 的資訊。尤其最後一行，顯示的是：

# 整體 PV 的量 / 已經被使用到 VG 的 PV 量 / 剩餘的 PV 量

# 2. 更詳細的列示出系統上面每個 PV 的個別資訊：

[root@www ~]# pvdisplay

"/dev/hda6" is a new physical volume of "1.40 GB"

--- NEW Physical volume ---

PV Name               /dev/hda6  <==實際的 partition 裝置名稱

VG Name                          <==因為尚未分配出去，所以空白！

PV Size               1.40 GB    <==就是容量說明

Allocatable           NO         <==是否已被分配，結果是 NO

PE Size (KByte)       0          <==在此 PV 內的 PE 大小

Total PE              0          <==共分割出幾個 PE

Free PE               0          <==沒被 LV 用掉的 PE

Allocated PE          0          <==尚可分配出去的 PE 數量

PV UUID               Z13Jk5-RCls-UJ8B-HzDa-Gesn-atku-rf2biN

....(底下省略)....

# 由於 PE 是在建立 VG 時才給予的參數，因此在這裡看到的 PV 裡頭的 PE 都會是 0

# 而且也沒有多餘的 PE 可供分配 (allocatable)。

講是很難，作是很簡單！這樣就將 PV 建立了兩個囉！簡單到不行吧！ ^_^！繼續來玩 VG 去！

- VG 階段

建立 VG 及 VG 相關的指令也不少，我們來看看：

- vgcreate ：就是主要建立 VG 的指令啦！他的參數比較多，等一下介紹。

- vgscan ：搜尋系統上面是否有 VG 存在？

- vgdisplay ：顯示目前系統上面的 VG 狀態；

- vgextend ：在 VG 內增加額外的 PV ；

- vgreduce ：在 VG 內移除 PV；

- vgchange ：設定 VG 是否啟動 (active)；

- vgremove ：刪除一個 VG 啊！

與 PV 不同的是， VG 的名稱是自訂的！我們知道 PV 的名稱其實就是 partition 的裝置檔名， 但是這個 VG 名稱則可以隨便你自己取啊！在底下的例子當中，我將 VG 名稱取名為 vbirdvg 。建立這個 VG 的流程是這樣的：

[root@www ~]# vgcreate [-s N[mgt]] VG名稱 PV名稱

選項與參數：

-s ：後面接 PE 的大小 (size) ，單位可以是 m, g, t (大小寫均可)

# 1. 將 /dev/hda6-8 建立成為一個 VG，且指定 PE 為 16MB 喔！

[root@www ~]# vgcreate -s 16M vbirdvg /dev/hda{6,7,8}

Volume group "vbirdvg" successfully created

[root@www ~]# vgscan

Reading all physical volumes.  This may take a while...

Found volume group "vbirdvg" using metadata type lvm2

# 確實存在這個 vbirdvg 的 VG 啦！

[root@www ~]# pvscan

PV /dev/hda6   VG vbirdvg   lvm2 [1.39 GB / 1.39 GB free]

PV /dev/hda7   VG vbirdvg   lvm2 [1.39 GB / 1.39 GB free]

PV /dev/hda8   VG vbirdvg   lvm2 [1.39 GB / 1.39 GB free]

PV /dev/hda9                lvm2 [1.40 GB]

Total: 4 [5.57 GB] / in use: 3 [4.17 GB] / in no VG: 1 [1.40 GB]

# 嘿嘿！發現沒！有三個 PV 被用去，剩下一個 /dev/hda9 的 PV 沒被用掉！

[root@www ~]# vgdisplay

--- Volume group ---

VG Name               vbirdvg

System ID

Format                lvm2

Metadata Areas        3

Metadata Sequence No  1

VG Access             read/write

VG Status             resizable

MAX LV                0

Cur LV                0

Open LV               0

Max PV                0

Cur PV                3

Act PV                3

VG Size               4.17 GB   <==整體的 VG 容量有這麼大

PE Size               16.00 MB  <==內部每個 PE 的大小

Total PE              267       <==總共的 PE 數量共有這麼多！

Alloc PE / Size       0 / 0

Free  PE / Size       267 / 4.17 GB

VG UUID               4VU5Jr-gwOq-jkga-sUPx-vWPu-PmYm-dZH9EO

# 最後那三行指的就是 PE 能夠使用的情況！由於尚未切出 LV，因此所有的 PE

# 均可自由使用。

這樣就建立一個 VG 了！假設我們要增加這個 VG 的容量，因為我們還有 /dev/hda9 嘛！此時你可以這樣做：

# 2. 將剩餘的 PV (/dev/hda9) 丟給 vbirdvg 吧！

[root@www ~]# vgextend vbirdvg /dev/hda9

Volume group "vbirdvg" successfully extended

[root@www ~]# vgdisplay

....(前面省略)....

VG Size               5.56 GB

PE Size               16.00 MB

Total PE              356

Alloc PE / Size       0 / 0

Free  PE / Size       356 / 5.56 GB

VG UUID               4VU5Jr-gwOq-jkga-sUPx-vWPu-PmYm-dZH9EO

# 基本上，不難吧！這樣就可以抽換整個 VG 的大小啊！

我們多了一個裝置喔！接下來為這個 vbirdvg 進行分割吧！透過 LV 功能來處理！

- LV 階段

創造出 VG 這個大磁碟之後，再來就是要建立分割區啦！這個分割區就是所謂的 LV 囉！假設我要將剛剛那個 vbirdvg 磁碟，分割成為 vbirdlv ，整個 VG 的容量都被分配到 vbirdlv 裡面去！先來看看能使用的指令後，就直接工作了先！

- lvcreate ：建立 LV 啦！

- lvscan ：查詢系統上面的 LV ；

- lvdisplay ：顯示系統上面的 LV 狀態啊！

- lvextend ：在 LV 裡面增加容量！

- lvreduce ：在 LV 裡面減少容量；

- lvremove ：刪除一個 LV ！

- lvresize ：對 LV 進行容量大小的調整！

[root@www ~]# lvcreate [-L N[mgt]] [-n LV名稱] VG名稱

[root@www ~]# lvcreate [-l N] [-n LV名稱] VG名稱

選項與參數：

-L  ：後面接容量，容量的單位可以是 M,G,T 等，要注意的是，最小單位為 PE，

因此這個數量必須要是 PE 的倍數，若不相符，系統會自行計算最相近的容量。

-l  ：後面可以接 PE 的『個數』，而不是數量。若要這麼做，得要自行計算 PE 數。

-n  ：後面接的就是 LV 的名稱啦！

更多的說明應該可以自行查閱吧！ man lvcreate

# 1. 將整個 vbirdvg 通通分配給 vbirdlv 啊，要注意， PE 共有 356 個。

[root@www ~]# lvcreate -l 356 -n vbirdlv vbirdvg

Logical volume "vbirdlv" created

# 由於本案例中每個 PE 為 16M ，因此上述的指令也可以使用如下的方式來建立：

# lvcreate -L 5.56G -n vbirdlv vbirdvg

[root@www ~]# ll /dev/vbirdvg/vbirdlv

lrwxrwxrwx 1 root root 27 Mar 11 16:49 /dev/vbirdvg/vbirdlv ->

/dev/mapper/vbirdvg-vbirdlv

# 看見了沒有啊！這就是我們最重要的一個玩意兒了！

[root@www ~]# lvdisplay

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdlv  <==這個才是 LV 的全名！

VG Name                vbirdvg

LV UUID                8vFOPG-Jrw0-Runh-ug24-t2j7-i3nA-rPEyq0

LV Write Access        read/write

LV Status              available

# open                 0

LV Size                5.56 GB               <==這個 LV 的容量這麼大！

Current LE             356

Segments               4

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:0

如此一來，整個 partition 也準備好啦！接下來，就是針對這個 LV 來處理啦！要特別注意的是， VG 的名稱為 vbirdvg ， 但是 LV 的名稱必須使用全名！亦即是 /dev/vbirdvg/vbirdlv 才對喔！ 後續的處理都是這樣的！這點初次接觸 LVM 的朋友很容易搞錯！

- 檔案系統階段

這個部分鳥哥我就不再多加解釋了！直接來進行吧！

# 1. 格式化、掛載與觀察我們的 LV 吧！

[root@www ~]# mkfs -t ext3 /dev/vbirdvg/vbirdlv <==注意 LV 全名！

[root@www ~]# mkdir /mnt/lvm

[root@www ~]# mount /dev/vbirdvg/vbirdlv /mnt/lvm

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hda2              9920624   3858984   5549572  42% /

/dev/hda3              4956316   1056996   3643488  23% /home

/dev/hda1               101086     21408     74459  23% /boot

tmpfs                   371332         0    371332   0% /dev/shm

/dev/mapper/vbirdvg-vbirdlv

5741020    142592   5306796   3% /mnt/lvm

[root@www ~]# cp -a /etc /var/log /mnt/lvm

其實 LV 的名稱建置成為 /dev/vbirdvg/vbirdlv 是為了讓使用者直覺式的找到我們所需要的資料， 實際上 LVM 使用的裝置是放置到 /dev/mapper/ 目錄下的！所以你才會看到上表當中的特殊字體部分。 透過這樣的功能，我們現在已經建置好一個 LV 了！你可以自由的應用 /mnt/lvm 內的所有資源！

放大 LV 容量

我們不是說 LVM 最大的特色就是彈性調整磁碟容量嗎？好！那我們就來處理一下，如果要放大 LV 的容量時， 該如何進行完整的步驟呢？其實一點都不難喔！你只要這樣做即可：

1. 用 fdisk 設定新的具有 8e system ID 的 partition

2. 利用 pvcreate 建置 PV

3. 利用 vgextend 將 PV 加入我們的 vbirdvg

4. 利用 lvresize 將新加入的 PV 內的 PE 加入 vbirdlv 中

5. 透過 resize2fs 將檔案系統的容量確實增加！

其中最後一個步驟最重要！我們在第八章當中知道， 整個檔案系統在最初格式化的時候就建立了 inode/block/superblock 等資訊，要改變這些資訊是很難的！ 不過因為檔案系統格式化的時候建置的是多個 block group ，因此我們可以透過在檔案系統當中增加 block group 的方式來增減檔案系統的量！而增減 block group 就是利用 resize2fs 啦！所以最後一步是針對檔案系統來處理的， 前面幾步則是針對 LVM 的實際容量大小！

# 1. 處理出一個 3GB 的新的 partition ，在鳥哥的系統中應該是 /dev/hda10

[root@www ~]# fdisk /dev/hda <==其他的動作請自行處理

[root@www ~]# partprobe

[root@www ~]# fdisk -l

Device Boot      Start         End      Blocks   Id  System

....(中間省略)....

/dev/hda10           2785        3150     2939863+  8e  Linux LVM

# 這個就是我們要的新的 partition 囉！

# 2. 建立新的 PV：

[root@www ~]# pvcreate /dev/hda10

Physical volume "/dev/hda10" successfully created

[root@www ~]# pvscan

PV /dev/hda6    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda7    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda8    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda9    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda10                lvm2 [2.80 GB]

Total: 5 [8.37 GB] / in use: 4 [5.56 GB] / in no VG: 1 [2.80 GB]

# 可以看到 /dev/hda10 是新加入並且尚未被使用的喔！

# 3. 加大 VG ，利用 vgextend 功能！

[root@www ~]# vgextend vbirdvg /dev/hda10

Volume group "vbirdvg" successfully extended

[root@www ~]# vgdisplay

--- Volume group ---

VG Name               vbirdvg

System ID

Format                lvm2

Metadata Areas        5

Metadata Sequence No  4

VG Access             read/write

VG Status             resizable

MAX LV                0

Cur LV                1

Open LV               1

Max PV                0

Cur PV                5

Act PV                5

VG Size               8.36 GB

PE Size               16.00 MB

Total PE              535

Alloc PE / Size       356 / 5.56 GB

Free  PE / Size       179 / 2.80 GB

VG UUID               4VU5Jr-gwOq-jkga-sUPx-vWPu-PmYm-dZH9EO

# 不但整體 VG 變大了！而且剩餘的 PE 共有 179 個，容量則為 2.80G

# 4. 放大 LV 吧！利用 lvresize 的功能來增加！

[root@www ~]# lvresize -l +179 /dev/vbirdvg/vbirdlv

Extending logical volume vbirdlv to 8.36 GB

Logical volume vbirdlv successfully resized

# 這樣就增加了 LV 了喔！lvresize 的語法很簡單，基本上同樣透過 -l 或 -L 來增加！

# 若要增加則使用 + ，若要減少則使用 - ！詳細的選項請參考 man lvresize 囉！

[root@www ~]# lvdisplay

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdlv

VG Name                vbirdvg

LV UUID                8vFOPG-Jrw0-Runh-ug24-t2j7-i3nA-rPEyq0

LV Write Access        read/write

LV Status              available

# open                 1

LV Size                8.36 GB

Current LE             535

Segments               5

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:0

[root@www ~]# df /mnt/lvm

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdlv

5741020    261212   5188176   5% /mnt/lvm

看到了吧？最終的結果中 LV 真的有放大到 8.36GB 喔！但是檔案系統卻沒有相對增加！ 而且，我們的 LVM 可以線上直接處理，並不需要特別給他 umount 哩！真是人性化！ 但是還是得要處理一下檔案系統的容量啦！開始觀察一下檔案系統，然後使用 resize2fs 來處理一下吧！

# 5.1 先看一下原本的檔案系統內的 superblock 記錄情況吧！

[root@www ~]# dumpe2fs /dev/vbirdvg/vbirdlv

dumpe2fs 1.39 (29-May-2006)

....(中間省略)....

Block count:              1458176    <==這個filesystem的 block 總數

....(中間省略)....

Blocks per group:         32768      <==多少個 block 設定成為一個 block group

Group 0: (Blocks 0-32767)            <==括號內為 block 的號碼

....(中間省略)....

Group 44: (Blocks 1441792-1458175)   <==這是本系統中最後一個 group

....(後面省略)....

# 5.2 resize2fs 的語法

[root@www ~]# resize2fs [-f] [device] [size]

選項與參數：

-f      ：強制進行 resize 的動作！

[device]：裝置的檔案名稱；

[size]  ：可以加也可以不加。如果加上 size 的話，那麼就必須要給予一個單位，

譬如 M, G 等等。如果沒有 size 的話，那麼預設使用『整個 partition』

的容量來處理！

# 5.3 完整的將 LV 的容量擴充到整個 filesystem 吧！

[root@www ~]# resize2fs /dev/vbirdvg/vbirdlv

resize2fs 1.39 (29-May-2006)

Filesystem at /dev/vbirdvg/vbirdlv is mounted on /mnt/lvm; on-line resizing

Performing an on-line resize of /dev/vbirdvg/vbirdlv to 2191360 (4k) blocks.

The filesystem on /dev/vbirdvg/vbirdlv is now 2191360 blocks long.

# 可怕吧！這一版的 lvm 竟然還可以線上進行 resize 的功能哩！真好！

[root@www ~]# df /mnt/lvm

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdlv

8628956    262632   7931368   4% /mnt/lvm

[root@www ~]# ll /mnt/lvm

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  17 root root  4096 Mar 11 14:17 log

drwx------   2 root root 16384 Mar 11 16:59 lost+found

# 剛剛複製進去的資料可還是存在的喔！並沒有消失不見！

嘿嘿！真的放大了吧！而且如果你已經有填資料在 LVM 磁區當中的話！這個資料是不會死掉的喔！還是繼續存在原本的磁區當中啦！ 整個動作竟然這麼簡單就完成了！原本的資料還是一直存在而不會消失∼您說， LVM 好不好用啊！

此外，如果你再以 dumpe2fs 來檢查 /dev/vbirdvg/vbirdlv 時，就會發現後續的 Group 增加了！ 如果還是搞不清楚什麼是 block group 時，請回到第八章看一下該章內圖1.3.1的介紹吧！

縮小 LV 容量

上一小節我們談到的是放大容量，現在來談到的是縮小容量喔！假設我們想將 /dev/hda6 抽離出來！ 那該如何處理啊？就讓上一小節的流程倒轉過來即可啊！我們就直接來玩吧！

# 1. 先找出 /dev/hda6 的容量大小，並嘗試計算檔案系統需縮小到多少

[root@www ~]# pvdisplay

--- Physical volume ---

PV Name               /dev/hda6

VG Name               vbirdvg

PV Size               1.40 GB / not usable 11.46 MB

Allocatable           yes (but full)

PE Size (KByte)       16384

Total PE              89

Free PE               0

Allocated PE          89

PV UUID               Z13Jk5-RCls-UJ8B-HzDa-Gesn-atku-rf2biN

# 從這裡可以看出 /dev/hda6 有多大，而且含有 89 個 PE 的量喔！

# 那如果要使用 resize2fs 時，則總量減去 1.40GB 就對了！

[root@www ~]# pvscan

PV /dev/hda6    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda7    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda8    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda9    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda10   VG vbirdvg   lvm2 [2.80 GB / 0    free]

Total: 5 [8.36 GB] / in use: 5 [8.36 GB] / in no VG: 0 [0   ]

# 從上面可以發現如果扣除 /dev/hda6 則剩餘容量有：1.39*3+2.8=6.97

# 2. 就直接降低檔案系統的容量吧！

[root@www ~]# resize2fs /dev/vbirdvg/vbirdlv 6900M

resize2fs 1.39 (29-May-2006)

Filesystem at /dev/vbirdvg/vbirdlv is mounted on /mnt/lvm; on-line resizing

On-line shrinking from 2191360 to 1766400 not supported.

# 容量好像不能夠寫小數點位數，因此 6.9G 是錯誤的，鳥哥就使用 6900M 了。

# 此外，放大可以線上直接進行，縮小檔案系統似乎無法支援！所以要這樣做：

[root@www ~]# umount /mnt/lvm

[root@www ~]# resize2fs /dev/vbirdvg/vbirdlv 6900M

resize2fs 1.39 (29-May-2006)

Please run 'e2fsck -f /dev/vbirdvg/vbirdlv' first.

# 他要我們先進行磁碟檢查！不囉唆！那就直接進行吧！

[root@www ~]# e2fsck -f /dev/vbirdvg/vbirdlv

e2fsck 1.39 (29-May-2006)

Pass 1: Checking inodes, blocks, and sizes

Pass 2: Checking directory structure

Pass 3: Checking directory connectivity

Pass 4: Checking reference counts

Pass 5: Checking group summary information

/dev/vbirdvg/vbirdlv: 2438/1087008 files (0.1% non-contiguous),

[root@www ~]# resize2fs /dev/vbirdvg/vbirdlv 6900M

resize2fs 1.39 (29-May-2006)

Resizing the filesystem on /dev/vbirdvg/vbirdlv to 1766400 (4k) blocks.

The filesystem on /dev/vbirdvg/vbirdlv is now 1766400 blocks long.

# 再來 resize2fs 一次就能夠成功了！如上所示啊！

[root@www ~]# mount /dev/vbirdvg/vbirdlv /mnt/lvm

[root@www ~]# df /mnt/lvm

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdlv

6955584    262632   6410328   4% /mnt/lvm

然後再來就是將 LV 的容量降低！要注意的是，我們想要抽離的是 /dev/hda6，這個 PV 有 89 個 PE (上面的 pvdisplay 查詢到的結果)。所以要這樣進行：

# 3. 降低 LV 的容量，同時我們知道 /dev/hda6 有 89 個 PE

[root@www ~]# lvresize -l -89 /dev/vbirdvg/vbirdlv

WARNING: Reducing active and open logical volume to 6.97 GB

THIS MAY DESTROY YOUR DATA (filesystem etc.)

Do you really want to reduce vbirdlv? [y/n]: y

Reducing logical volume vbirdlv to 6.97 GB

Logical volume vbirdlv successfully resized

# 會有警告訊息！但是我們的實際資料量還是比 6.97G 小，所以就 y 下去吧！

[root@www ~]# lvdisplay

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdlv

VG Name                vbirdvg

LV UUID                8vFOPG-Jrw0-Runh-ug24-t2j7-i3nA-rPEyq0

LV Write Access        read/write

LV Status              available

# open                 1

LV Size                6.97 GB

Current LE             446

Segments               5

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:0

很簡單吧！這樣就將 LV 縮小了！接下來就要將 /dev/hda6 移出 vbirdvg 這個 VG 之外囉！ 我們得要先確定 /dev/hda6 裡面的 PE 完全不被使用後，才能夠將 /dev/hda6 抽離！ 所以得要這樣進行：

# 4.1 先確認 /dev/hda6 是否將 PE 都移除了！

[root@www ~]# pvdisplay

--- Physical volume ---

PV Name               /dev/hda6

VG Name               vbirdvg

PV Size               1.40 GB / not usable 11.46 MB

Allocatable           yes (but full)

PE Size (KByte)       16384

Total PE              89

Free PE               0

Allocated PE          89

PV UUID               Z13Jk5-RCls-UJ8B-HzDa-Gesn-atku-rf2biN

....(中間省略)....

--- Physical volume ---

PV Name               /dev/hda10

VG Name               vbirdvg

PV Size               2.80 GB / not usable 6.96 MB

Allocatable           yes

PE Size (KByte)       16384

Total PE              179

Free PE               89

Allocated PE          90

PV UUID               7MfcG7-y9or-0Jmb-H7RO-5Pa5-D3qB-G426Vq

# 搞了老半天，沒有被使用的 PE 竟然在 /dev/hda10 ！此時得要搬移 PE 囉！

[root@www ~]# pvmove /dev/hda6 /dev/hda10

# pvmove 來源PV 目標PV ，可以將 /dev/hda6 內的 PE 通通移動到 /dev/hda10

# 尚未被使用的 PE 去 (Free PE)。

# 4.2 將 /dev/hda6 移出 vbirdvg 中！

[root@www ~]# vgreduce vbirdvg /dev/hda6

Removed "/dev/hda6" from volume group "vbirdvg"

[root@www ~]# pvscan

PV /dev/hda7    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda8    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda9    VG vbirdvg   lvm2 [1.39 GB / 0    free]

PV /dev/hda10   VG vbirdvg   lvm2 [2.80 GB / 0    free]

PV /dev/hda6                 lvm2 [1.40 GB]

Total: 5 [8.37 GB] / in use: 4 [6.97 GB] / in no VG: 1 [1.40 GB]

[root@www ~]# pvremove /dev/hda6

Labels on physical volume "/dev/hda6" successfully wiped

很有趣吧！這樣你的檔案系統以及實際的 LV 與 VG 通通變小了，而且那個 /dev/hda6 還真的可以拿出來！ 可以進行其他的用途啦！非常簡單吧！

LVM 的系統快照

現在你知道 LVM 的好處咯，未來如果你有想要增加某個 LVM 的容量時，就可以透過這個放大、縮小的功能來處理。 那麼 LVM 除了這些功能之外，還有什麼能力呢？其實他還有一個重要的能力，那就是系統快照 (snapshot)。 什麼是系統快照啊？快照就是將當時的系統資訊記錄下來，就好像照相記錄一般！ 未來若有任何資料更動了，則原始資料會被搬移到快照區，沒有被更動的區域則由快照區與檔案系統共享。 用講的好像很難懂，我們用圖解說明一下好了：

圖 3.5.1、LVM 系統快照區域的備份示意圖(虛線為檔案系統，長虛線為快照區)

左圖為最初建置系統快照區的狀況，LVM 會預留一個區域 (左圖的左側三個 PE 區塊) 作為資料存放處。 此時快照區內並沒有任何資料，而快照區與系統區共享所有的 PE 資料， 因此你會看到快照區的內容與檔案系統是一模一樣的。 等到系統運作一陣子後，假設 A 區域的資料被更動了 (上面右圖所示)，則更動前系統會將該區域的資料移動到快照區， 所以在右圖的快照區被佔用了一塊 PE 成為 A，而其他 B 到 I 的區塊則還是與檔案系統共用！

照這樣的情況來看，LVM 的系統快照是非常棒的『備份工具』，因為他只有備份有被更動到的資料， 檔案系統內沒有被變更的資料依舊保持在原本的區塊內，但是 LVM 快照功能會知道那些資料放置在哪裡， 因此『快照』當時的檔案系統就得以『備份』下來，且快照所佔用的容量又非常小！所以您說，這不是很棒的工具又是什麼？

那麼快照區要如何建立與使用呢？首先，由於快照區與原本的 LV 共用很多 PE 區塊，因此快照區與被快照的 LV 必須要在同一個 VG 上頭。但是我們剛剛將 /dev/hda6 移除 vbirdvg 了，目前 vbirdvg 剩下的容量為 0 ！因此，在這個小節裡面我們得要再加入 /dev/hda6 到我們的 VG 後， 才能繼續建立快照區囉！底下的動作趕緊再來玩玩看！

- 快照區的建立

底下的動作主要在增加需要的 VG 容量，然後再透過 lvcreate -s 的功能建立快照區

# 1. 先觀察 VG 還剩下多少剩餘容量

[root@www ~]# vgdisplay

--- Volume group ---

VG Name               vbirdvg

....(其他省略)....

VG Size               6.97 GB

PE Size               16.00 MB

Total PE              446

Alloc PE / Size       446 / 6.97 GB

Free  PE / Size       0 / 0  <==沒有多餘的 PE 可用！

# 2. 將剛剛移除的 /dev/hda6 加入這個 VG 吧！

[root@www ~]# pvcreate /dev/hda6

Physical volume "/dev/hda6" successfully created

[root@www ~]# vgextend vbirdvg /dev/hda6

Volume group "vbirdvg" successfully extended

[root@www ~]# vgdisplay

--- Volume group ---

VG Name               vbirdvg

....(其他省略)....

VG Size               8.36 GB

PE Size               16.00 MB

Total PE              535

Alloc PE / Size       446 / 6.97 GB

Free  PE / Size       89 / 1.39 GB  <==多出了 89 個 PE 可用囉！

# 3. 利用 lvcreate 建立系統快照區，我們取名為 vbirdss，且給予 60 個 PE

[root@www ~]# lvcreate -l 60 -s -n vbirdss /dev/vbirdvg/vbirdlv

Logical volume "vbirdss" created

# 上述的指令中最重要的是那個 -s 的選項！代表是 snapshot 快照功能之意！

# -n 後面接快照區的裝置名稱， /dev/.... 則是要被快照的 LV 完整檔名。

# -l 後面則是接使用多少個 PE 來作為這個快照區使用。

[root@www ~]# lvdisplay

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdss

VG Name                vbirdvg

LV UUID                K2tJ5E-e9mI-89Gw-hKFd-4tRU-tRKF-oeB03a

LV Write Access        read/write

LV snapshot status     active destination for /dev/vbirdvg/vbirdlv

LV Status              available

# open                 0

LV Size                6.97 GB    <==被快照的原 LV 磁碟容量

Current LE             446

COW-table size         960.00 MB  <==快照區的實際容量

COW-table LE           60         <==快照區佔用的 PE 數量

Allocated to snapshot  0.00%

Snapshot chunk size    4.00 KB

Segments               1

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:1

您看看！這個 /dev/vbirdvg/vbirdss 快照區就被建立起來了！而且他的 VG 量竟然與原本的 /dev/vbirdvg/vbirdlv 相同！也就是說，如果你真的掛載這個裝置時，看到的資料會跟原本的 vbirdlv 相同喔！我們就來測試看看：

[root@www ~]# mkdir /mnt/snapshot

[root@www ~]# mount /dev/vbirdvg/vbirdss /mnt/snapshot

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hda2              9920624   3859032   5549524  42% /

/dev/hda3              4956316   1056996   3643488  23% /home

/dev/hda1               101086     21408     74459  23% /boot

tmpfs                   371332         0    371332   0% /dev/shm

/dev/mapper/vbirdvg-vbirdlv

6955584    262632   6410328   4% /mnt/lvm

/dev/mapper/vbirdvg-vbirdss

6955584    262632   6410328   4% /mnt/snapshot

# 有沒有看到！這兩個咚咚竟然是一模一樣喔！我們根本沒有動過

# /dev/vbirdvg/vbirdss 對吧！不過這裡面會主動記錄原 vbirdlv 的內容！

[root@www ~]# umount /mnt/snapshot

# 最後將他卸載！我們準備來玩玩有趣的東西！

- 利用快照區復原系統

首先，我們來玩一下，如何利用快照區復原系統吧！不過你要注意的是，你要復原的資料量不能夠高於快照區所能負載的實際容量。由於原始資料會被搬移到快照區， 如果你的快照區不夠大，若原始資料被更動的實際資料量比快照區大，那麼快照區當然容納不了，這時候快照功能會失效喔！ 所以上面的案例中鳥哥才給予 60 個 PE (共 900MB) 作為快照區存放資料用。

我們的 /mnt/lvm 已經有 /mnt/lvm/etc, /mnt/lvm/log 等目錄了，接下來我們將這個檔案系統的內容作個變更， 然後再以快照區資料還原看看：

# 1. 先將原本的 /dev/vbirdvg/vbirdlv 內容作些變更，增增減減一些目錄吧！

[root@www ~]# df /mnt/lvm

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdlv

6955584    262632   6410328   4% /mnt/lvm

[root@www ~]# ll /mnt/lvm

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  17 root root  4096 Mar 11 14:17 log

drwx------   2 root root 16384 Mar 11 16:59 lost+found

[root@www ~]# rm -r /mnt/lvm/log

[root@www ~]# cp -a /boot /lib /sbin /mnt/lvm

[root@www ~]# ll /mnt/lvm

drwxr-xr-x   4 root root  4096 Dec 15 16:28 boot

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  14 root root  4096 Sep  5  2008 lib

drwx------   2 root root 16384 Mar 11 16:59 lost+found

drwxr-xr-x   2 root root 12288 Sep  5  2008 sbin

# 看起來資料已經不一樣了！

[root@www ~]# lvdisplay /dev/vbirdvg/vbirdss

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdss

VG Name                vbirdvg

....(中間省略)....

Allocated to snapshot  12.22%

....(底下省略)....

# 從這裡也看得出來，快照區已經被使用了 12.22% ！因為原始的檔案系統有異動過！

# 2. 利用快照區將原本的 filesystem 備份

[root@www ~]# mount /dev/vbirdvg/vbirdss /mnt/snapshot

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdlv

6955584    370472   6302488   6% /mnt/lvm

/dev/mapper/vbirdvg-vbirdss

6955584    262632   6410328   4% /mnt/snapshot

# 看吧！兩者確實不一樣了！開始將快照區內容複製出來吧！

[root@www ~]# mkdir -p /backups <==確認真的有這個目錄！

[root@www ~]# cd /mnt/snapshot

[root@www snapshot]# tar -jcv -f /backups/lvm.tar.bz2 *

# 此時你就會有一個備份資料，亦即是 /backups/lvm.tar.bz2 了！

為什麼要備份呢？為什麼不可以直接格式化 /dev/vbirdvg/vbirdlv 然後將 /dev/vbirdvg/vbirdss 直接複製給 vbirdlv 呢？ 要知道 vbirdss 其實是 vbirdlv 的快照，因此如果你格式化整個 vbirdlv 時，原本的檔案系統所有資料都會被搬移到 vbirdss。 那如果 vbirdss 的容量不夠大 (通常也真的不夠大)，那麼部分資料將無法複製到 vbirdss 內，資料當然無法全部還原啊！ 所以才要在上面表格中製作出一個備份檔案的！瞭解乎？

而快照還有另外一個功能，就是你可以比對 /mnt/lvm 與 /mnt/snapshot 的內容，就能夠發現到最近你到底改了啥咚咚！ 這樣也是很不賴啊！您說是吧！ ^_^！接下來讓我們準備還原 vbirdlv 的內容吧！

# 3. 將 vbirdss 卸載並移除 (因為裡面的內容已經備份起來了)

[root@www ~]# umount /mnt/snapshot

[root@www ~]# lvremove /dev/vbirdvg/vbirdss

Do you really want to remove active logical volume "vbirdss"? [y/n]: y

Logical volume "vbirdss" successfully removed

[root@www ~]# umount /mnt/lvm

[root@www ~]# mkfs -t ext3 /dev/vbirdvg/vbirdlv

[root@www ~]# mount /dev/vbirdvg/vbirdlv /mnt/lvm

[root@www ~]# tar -jxv -f /backups/lvm.tar.bz2 -C /mnt/lvm

[root@www ~]# ll /mnt/lvm

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  17 root root  4096 Mar 11 14:17 log

drwx------   2 root root 16384 Mar 11 16:59 lost+found

# 是否與最初的內容相同啊！這就是透過快照來還原的一個簡單的方法囉！

- 利用快照區進行各項練習與測試的任務，再以原系統還原快照

換個角度來想想，我們將原本的 vbirdlv 當作備份資料，然後將 vbirdss 當作實際在運作中的資料， 任何測試的動作都在 vbirdss 這個快照區當中測試，那麼當測試完畢要將測試的資料刪除時，只要將快照區刪去即可！ 而要複製一個 vbirdlv 的系統，再作另外一個快照區即可！這樣是否非常方便啊？ 這對於教學環境中每年都要幫學生製作一個練習環境主機的測試，非常有幫助呢！

Tips:

以前鳥哥老是覺得使用 LVM 的快照來進行備份不太合理，因為還要製作一個備份檔！後來仔細研究並參考徐秉義老師的教材(註3)後，才發現 LVM 的快照實在是一個棒到不行的工具！尤其是在虛擬機器當中建置多份給同學使用的測試環境， 你只要有一個基礎的環境保持住，其他的環境使用快照來提供即可。即時同學將系統搞爛了，你只要將快照區刪除， 再重建一個快照區！這樣環境就恢復了！天吶！實在是太棒了！ ^_^

# 1. 建立一個大一些的快照區，讓我們將 /dev/hda6 的 PE 全部給快照區！

[root@www ~]# lvcreate -s -l 89 -n vbirdss /dev/vbirdvg/vbirdlv

Logical volume "vbirdss" created

[root@www ~]# lvdisplay /dev/vbirdvg/vbirdss

--- Logical volume ---

LV Name                /dev/vbirdvg/vbirdss

VG Name                vbirdvg

LV UUID                as0ocQ-KjRS-Bu7y-fYoD-1CHC-0V3Y-JYsjj1

LV Write Access        read/write

LV snapshot status     active destination for /dev/vbirdvg/vbirdlv

LV Status              available

# open                 0

LV Size                6.97 GB

Current LE             446

COW-table size         1.39 GB

COW-table LE           89

Allocated to snapshot  0.00%

Snapshot chunk size    4.00 KB

Segments               1

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:1

# 如何！這個快照區不小吧！

# 2. 隱藏 vbirdlv 掛載 vbirdss

[root@www ~]# umount /mnt/lvm

[root@www ~]# mount /dev/vbirdvg/vbirdss /mnt/snapshot

[root@www ~]# df /mnt/snapshot

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/mapper/vbirdvg-vbirdss

7192504    265804   6561340   4% /mnt/snapshot

# 3. 開始惡搞！

[root@www ~]# rm -r /mnt/snapshot/etc /mnt/snapshot/log

[root@www ~]# cp -a /boot /lib /sbin /mnt/snapshot/

[root@www ~]# ll /mnt/snapshot

drwxr-xr-x  4 root root  4096 Dec 15 16:28 boot

drwxr-xr-x 14 root root  4096 Sep  5  2008 lib

drwx------  2 root root 16384 Mar 11 16:59 lost+found

drwxr-xr-x  2 root root 12288 Sep  5  2008 sbin  <==與原本資料有差異了

[root@www ~]# mount /dev/vbirdvg/vbirdlv /mnt/lvm

[root@www ~]# ll /mnt/lvm

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  17 root root  4096 Mar 11 14:17 log

drwx------   2 root root 16384 Mar 11 16:59 lost+found

# 不論你在快照區惡搞啥咚咚，原本的 vbirdlv 裡面的資料安好如初啊！

# 假設你將 vbirdss 搞爛了！裡面的資料不再需要！那該如何是好？

# 4. 還原原本快照區的資料，回到與原檔案系統相同的資訊

[root@www ~]# umount /mnt/snapshot

[root@www ~]# lvremove /dev/vbirdvg/vbirdss

Do you really want to remove active logical volume "vbirdss"? [y/n]: y

Logical volume "vbirdss" successfully removed

[root@www ~]# lvcreate -s -l 89 -n vbirdss /dev/vbirdvg/vbirdlv

[root@www ~]# mount /dev/vbirdvg/vbirdss /mnt/snapshot

[root@www ~]# ll /mnt/snapshot

drwxr-xr-x 105 root root 12288 Mar 11 16:59 etc

drwxr-xr-x  17 root root  4096 Mar 11 14:17 log

drwx------   2 root root 16384 Mar 11 16:59 lost+found

# 資料這樣就復原了！

老實說，上面的測試有點無厘頭∼因為快照區損毀了就刪除再建一個就好啦！何必還要測試呢？ 不過，為了讓您瞭解到快照區也能夠這樣使用，上面的測試還是需要存在的啦！未來如果你有接觸到虛擬機器， 再回到這裡來溫習一下肯定會有收穫的！

LVM 相關指令彙整與 LVM 的關閉

好了，我們將上述用過的一些指令給他彙整一下，提供給您參考參考：

任務

PV 階段

VG 階段

LV 階段

搜尋(scan)

pvscan

vgscan

lvscan

建立(create)

pvcreate

vgcreate

lvcreate

列出(display)

pvdisplay

vgdisplay

lvdisplay

增加(extend)

vgextend

lvextend (lvresize)

減少(reduce)

vgreduce

lvreduce (lvresize)

刪除(remove)

pvremove

vgremove

lvremove

改變容量(resize)

lvresize

改變屬性(attribute)

pvchange

vgchange

lvchange

至於檔案系統階段 (filesystem 的格式化處理) 部分，還需要以 resize2fs 來修訂檔案系統實際的大小才行啊！ ^_^ 。至於雖然 LVM 可以彈性的管理你的磁碟容量，但是要注意，如果你想要使用 LVM 管理您的硬碟時，那麼在安裝的時候就得要做好 LVM 的規劃了， 否則未來還是需要先以傳統的磁碟增加方式來增加後，移動資料後，才能夠進行 LVM 的使用啊！

會玩 LVM 還不行！你必須要會移除系統內的 LVM 喔！因為你的實體 partition 已經被使用到 LVM 去， 如果你還沒有將 LVM 關閉就直接將那些 partition 刪除或轉為其他用途的話，系統是會發生很大的問題的！ 所以囉，你必須要知道如何將 LVM 的裝置關閉並移除才行！會不會很難呢？其實不會啦！ 依據以下的流程來處理即可：

1. 先卸載系統上面的 LVM 檔案系統 (包括快照與所有 LV)；

2. 使用 lvremove 移除 LV ；

3. 使用 vgchange -a n VGname 讓 VGname 這個 VG 不具有 Active 的標誌；

4. 使用 vgremove 移除 VG：

5. 使用 pvremove 移除 PV；

6. 最後，使用 fdisk 修改 ID 回來啊！

好吧！那就實際的將我們之前建立的所有 LVM 資料給刪除吧！

[root@www ~]# umount /mnt/lvm

[root@www ~]# umount /mnt/snapshot

[root@www ~]# lvremove /dev/vbirdvg/vbirdss  <==先處理快照

Do you really want to remove active logical volume "vbirdss"? [y/n]: y

Logical volume "vbirdss" successfully removed

[root@www ~]# lvremove /dev/vbirdvg/vbirdlv  <==再處理原系統

Do you really want to remove active logical volume "vbirdlv"? [y/n]: y

Logical volume "vbirdlv" successfully removed

[root@www ~]# vgchange -a n vbirdvg

0 logical volume(s) in volume group "vbirdvg" now active

[root@www ~]# vgremove vbirdvg

Volume group "vbirdvg" successfully removed

[root@www ~]# pvremove /dev/hda{6,7,8,9,10}

Labels on physical volume "/dev/hda6" successfully wiped

Labels on physical volume "/dev/hda7" successfully wiped

Labels on physical volume "/dev/hda8" successfully wiped

Labels on physical volume "/dev/hda9" successfully wiped

Labels on physical volume "/dev/hda10" successfully wiped

最後再用 fdisk 將磁碟的 ID 給他改回來 83 就好啦！整個過程就這樣的啦！ ^_^

重點回顧

- Quota 可公平的分配系統上面的磁碟容量給使用者；分配的資源可以是磁碟容量(block)或可建立檔案數量(inode)；

- Quota 的限制可以有 soft/hard/grace time 等重要項目；

- Quota 僅能針對整個 filesystem 進行限制，不是針對目錄喔！

- Quota 的使用必須要核心與檔案系統均支援。檔案系統的參數必須含有 usrquota, grpquota

- Quota 實作的指令有 quotacheck, quotaon, edquota, repquota 等指令；

- 磁碟陣列 (RAID) 有硬體與軟體之分，Linux 作業系統可支援軟體磁碟陣列，透過 mdadm 套件來達成；

- 磁碟陣列建置的考量依據為『容量』、『效能』、『資料可靠性』等；

- 磁碟陣列所建置的等級常見有的 raid0, raid1, raid0+1, raid5 及 raid6

- 硬體磁碟陣列的裝置檔名與 SCSI 相同，至於 software RAID 則為 /dev/md[0-9]

- 軟體磁碟陣列的狀態可藉由 /proc/mdstat 檔案來瞭解；

- LVM 強調的是『彈性的變化檔案系統的容量』；

- 與 LVM 有關的元件有： PV/VG/PE/LV 等元件，可以被格式化者為 LV

- LVM 擁有快照功能，快照可以記錄 LV 的資料內容，並與原有的 LV 共享未更動的資料，備份與還原就變的很簡單；

- Ext3 透過 resize2fs 指令，可以彈性的調整檔案系統的大小

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：由於 LVM 可以彈性調整 filesystem 的大小，但是缺點是可能沒有加速與硬體備份(與快照不同)的功能。 而磁碟陣列則具有效能與備份的功能，但是無法提供類似 LVM 的優點。在此情境中，我們想利用『在 RAID 上面建置 LVM』的功能，以達到兩者兼顧的能力。

- 目標：測試在 RAID 磁碟上面架構 LVM 系統；

- 需求：需要具有磁碟管理的能力，包括 RAID 與 LVM；

- 前提：將本章與之前章節練習所製作的分割槽全部刪除，剩下預設的分割槽即可。

那要如何處理呢？如下的流程一個步驟一個步驟的實施看看吧：

- 復原系統時，你必須要：

- 利用 umount 先卸載之前掛載的檔案系統；

- 修改 /etc/fstab 裡面的資料，讓開機不會自動掛載；

- 利用 fdisk 將該分割槽刪除。

最終你的系統應該會只剩下如下的模樣：

[root@www ~]# fdisk -l

Device Boot      Start         End      Blocks   Id  System

/dev/hda1   *           1          13      104391   83  Linux

/dev/hda2              14        1288    10241437+  83  Linux

/dev/hda3            1289        1925     5116702+  83  Linux

/dev/hda4            1926        9382    59898352+   5  Extended

/dev/hda5            1926        2052     1020096   82  Linux swap / Solaris

- 建立 RAID ，假設我們利用五個 1GB 的分割槽建立 RAID-5 ，且具有一個 spare disk ， 那麼你應該要如何進行？首先，請自行使用 fdisk 建置好如下的分割槽狀態：

[root@www ~]# fdisk -l

....(前面省略)....

/dev/hda6            2053        2175      987966   83  Linux

/dev/hda7            2176        2298      987966   83  Linux

/dev/hda8            2299        2421      987966   83  Linux

/dev/hda9            2422        2544      987966   83  Linux

/dev/hda10           2545        2667      987966   83  Linux

接下來開始建立 RAID 吧！建立的方法可以如下簡單處理即可：

[root@www ~]# mdadm --create --auto=yes /dev/md0 --level=5  \

> --raid-devices=4 --spare-devices=1 /dev/hda{6,7,8,9,10}

若無出現任何錯誤訊息，此時你已經具有 /dev/md0 這個磁碟陣列裝置了！接下來讓我們處理 LVM 吧！

- 開始處理 LVM ，現在我們假設所有的參數都使用預設值，包括 PE ，然後 VG 名為 raidvg ，LV 名為 raidlv ，底下為基本的流程：

[root@www ~]# pvcreate /dev/md0                  <==建立 PV

[root@www ~]# vgcreate raidvg /dev/md0           <==建立 VG

[root@www ~]# lvcreate -L 2.82G -n raidlv raidvg <==建立 LM

[root@www ~]# lvdisplay

--- Logical volume ---

LV Name                /dev/raidvg/raidlv

VG Name                raidvg

LV UUID                zQsKqW-8Bt2-kpJF-8rCI-Cql1-XQYT-jw1mfH

LV Write Access        read/write

LV Status              available

# open                 0

LV Size                2.82 GB

Current LE             722

Segments               1

Allocation             inherit

Read ahead sectors     auto

- currently set to     256

Block device           253:0

這樣就搞定了 LVM 了！而且這個 LVM 是架構在 /dev/md0 上面的喔！然後就是檔案系統的建立與掛載了！

- 嘗試建立成為 Ext3 檔案系統，且掛載到 /mnt/raidlvm 目錄下：

[root@www ~]# mkfs -t ext3 /dev/raidvg/raidlv

[root@www ~]# mkdir /mnt/raidlvm

[root@www ~]# mount /dev/raidvg/raidlv /mnt/raidlvm

- 上述就是 LVM 架構在 RAID 上面的技巧，之後的動作都能夠使用本章的其他管理方式來管理， 包括 RAID 熱拔插機制、LVM 放大縮小機制等等。測試完畢之後請務必要關閉本題所建立的各項資訊。

[root@www ~]# umount /mnt/raidlvm         <==卸載檔案系統

[root@www ~]# lvremove /dev/raidvg/raidlv <==移除 LV

[root@www ~]# vgchange -a n raidvg        <==讓 VG 不活動

[root@www ~]# vgremove raidvg             <==移除 VG

[root@www ~]# pvremove /dev/md0           <==移除 PV

[root@www ~]# mdadm --stop /dev/md0       <==關閉 /dev/md0 RAID

[root@www ~]# fdisk /dev/hda              <==還原原本的分割槽

簡答題部分：

- 在前一章的第一個大量新增帳號範例中， 如果我想要讓每個用戶均具有 soft/hard 各為 40MB/50MB 的容量時，應該如何修改這個 script ？

你得先要依據本章的作法，先將 /home 製作好 quota 的環境然後， 你可以在 do...done 內的最後一行，新增一行內容為：

setquota -u $username 40000 50000 0 0 /home

這樣就可以在製作用戶時，指定更新密碼且給予 quota 的限制！

- 如果我想要讓 RAID 具有保護資料的功能，防止因為硬體損毀而導致資料的遺失，那我應該要選擇的 RAID 等級可能有哪些？ (請以本章談到的等級來思考即可)

具有備份資料的有： RAID-1, RAID-5, RAID-6

- 在預設的 LVM 設定中，請問 LVM 能否具有『備份』的功能？

是有的，就是那個快照 (snopshot) 的功能，此功能即可進行資料的備份！

- LVM 內的 LV 據說僅能達到 256 GB 的容量，請問如何克服此一容量問題？

LV 的容量與 PE 這個資料有關，由於預設 PE 為 4MB ，所以才會有此限制。 若要修改這個限制值，則需要在建置 VG 時就給予 -s 的選項來進行 PE 數值的設定。 若給到 PE = 16MB 時，則 LV 的最大總量就能夠達到 1TB 的容量了。

- 如果你的電腦主機有提供 RAID 0 的功能，你將你的三顆硬碟全部在 BIOS 階段使用 RAID 晶片整合成為一顆大磁碟， 則此磁碟在 Linux 系統當中的檔名為何？

由於硬體磁碟陣列是在 BIOS 階段完成的，因此 Linux 系統會捉到一個完整的大的 RAID 磁碟， 此磁碟的檔名就會是『 /dev/sda 』！

參考資料與延伸閱讀

- 註1：若想對 RAID 有更深入的認識，可以參考底下的連結與書目：

http://www.tldp.org/HOWTO/Software-RAID-HOWTO.html

楊振和、『作業系統導論：第十一章』、學貫出版社，2006

- 註2：詳細的 mdstat 說明也可以參考如下網頁：

http://linux-raid.osdl.org/index.php/Mdstat

- 註3：徐秉義老師在網管人雜誌 (http://www.babyface.idv.tw/NetAdmin/) 的投稿文章：

磁碟管理：SoftRAID 與 LVM 綜合實做應用 (上)

http://www.babyface.idv.tw/NetAdmin/16200705SoftRAIDLVM01/

磁碟管理：SoftRAID 與 LVM 綜合實做應用 (下)

http://www.babyface.idv.tw/NetAdmin/18200707SoftRAIDLVM02/

2002/07/14：第一次完成

2003/02/10：重新編排與加入 FAQ

2003/09/02：加入 quotacheck 發生錯誤時的解決方法。

2005/09/06：將舊的文章移動到 此處 。

2005/09/06：進行版面風格的轉換，並且進行資料的查詢，加入 repquota 的簡單說明而已！

2009/03/04：將原本舊的基於 FC4 的文件移動到 此處 。

2009/03/06：加入 warnquota 這玩意兒！挺有趣的哩！

2009/03/12：加入了 software RAID 與 LVM 的加強說明，尤其是 LVM 的快照 (snapshot) 的說明！

2009/09/10：修改一些字樣之外，增加情境模擬，以及後續的簡答題部分題目。

2002/05/06以來統計人數

第十六章、例行性工作排程 (crontab)

切換解析度為 800x600

最近更新日期：2009/09/11

學習了基礎篇也一陣子了，你會發現到為什麼系統常常會主動的進行一些任務？這些任務到底是誰在設定工作的？ 如果你想要讓自己設計的備份程式可以自動的在系統底下執行，而不需要手動來啟動他，又該如何處置？ 這些例行的工作可能又分為『單一』工作與『循環』工作，在系統內又是哪些服務在負責？ 還有還有，如果你想要每年在老婆的生日前一天就發出一封信件提醒自己不要忘記，可以辦的到嗎？ 嘿嘿！這些種種要如何處理，就看看這一章先！

1. 什麼是例行性工作排程

1.1 Linux 工作排程的種類： at, crontab

1.2 Linux 上常見的例行性工作

2. 僅執行一次的工作排程

2.1 atd 的啟動與 at 運作的方式： /etc/at.deny

2.2 實際運作單一工作排程： at, atq & atrm, batch

3. 循環執行的例行性工作排程

3.1 使用者的設定： /etc/cron.deny, crontab

3.2 系統的設定檔： /etc/crontab

3.3 一些注意事項

4. 可喚醒停機期間的工作任務

4.1 什麼是 anacron

4.2 anacron 與 /etc/anacrontab

5. 重點回顧

6. 本章習題

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23889

什麼是例行性工作排程

每個人或多或少都有一些約會或者是工作，有的工作是例行性的， 例如每年一次的加薪、每個月一次的工作報告、每週一次的午餐會報、每天需要的打卡等等； 有的工作則是臨時發生的，例如剛好總公司有高官來訪，需要你準備演講器材等等！ 用在生活上面，例如每年的愛人的生日、每天的起床時間等等、還有突發性的電腦大降價 (啊！真希望天天都有！) 等等囉。

像上面這些例行性工作，通常你得要記錄在行事曆上面才能避免忘記！不過，由於我們常常在電腦前面的緣故， 如果電腦系統能夠主動的通知我們的話，那麼不就輕鬆多了！嘿嘿！這個時候 Linux 的例行性工作排程就可以派上場了！ 在不考慮硬體與我們伺服器的連結狀態下，我們的 Linux 可以幫你提醒很多任務，例如：每一天早上 8:00 鐘要伺服器連接上音響，並啟動音樂來喚你起床；而中午 12:00 希望 Linux 可以發一封信到你的郵件信箱，提醒你可以去吃午餐了； 另外，在每年的你愛人生日的前一天，先發封信提醒你，以免忘記這麼重要的一天。

那麼 Linux 的例行性工作是如何進行排程的呢？所謂的排程就是將這些工作安排執行的流程之意！ 咱們的 Linux 排程就是透過 crontab 與 at 這兩個東西！這兩個玩意兒有啥異同？就讓我們來瞧瞧先！

Linux 工作排程的種類： at, cron

從上面的說明當中，我們可以很清楚的發現兩種工作排程的方式：

- 一種是例行性的，就是每隔一定的週期要來辦的事項；

- 一種是突發性的，就是這次做完以後就沒有的那一種 (電腦大降價...)

那麼在 Linux 底下如何達到這兩個功能呢？那就得使用 at 與 crontab 這兩個好東西囉！

- at ：at 是個可以處理僅執行一次就結束排程的指令，不過要執行 at 時， 必須要有 atd 這個服務 (第十八章) 的支援才行。在某些新版的 distributions 中，atd 可能預設並沒有啟動，那麼 at 這個指令就會失效呢！不過我們的 CentOS 預設是啟動的！

- crontab ：crontab 這個指令所設定的工作將會循環的一直進行下去！ 可循環的時間為分鐘、小時、每週、每月或每年等。crontab 除了可以使用指令執行外，亦可編輯 /etc/crontab 來支援。 至於讓 crontab 可以生效的服務則是 crond 這個服務喔！

底下我們先來談一談 Linux 的系統到底在做什麼事情，怎麼有若干多的工作排程在進行呢？然後再回來談一談 at 與 crontab 這兩個好東西！

Linux 上常見的例行性工作

如果你曾經使用過 Linux 一陣子了，那麼你大概會發現到 Linux 會主動的幫我們進行一些工作呢！ 比方說自動的進行線上更新 (on-line update)、自動的進行 updatedb (第七章談到的 locate 指令) 更新檔名資料庫、自動的作登錄檔分析 (所以 root 常常會收到標題為 logwatch 的信件) 等等。這是由於系統要正常運作的話， 某些在背景底下的工作必須要定時進行的緣故。基本上 Linux 系統常見的例行性任務有：

- 進行登錄檔的輪替 (log rotate)：

Linux 會主動的將系統所發生的各種資訊都記錄下來，這就是登錄檔 (第十九章)。 由於系統會一直記錄登錄資訊，所以登錄檔將會越來越大！我們知道大型檔案不但佔容量還會造成讀寫效能的困擾， 因此適時的將登錄檔資料挪一挪，讓舊的資料與新的資料分別存放，則比較可以有效的記錄登錄資訊。這就是 log rotate 的任務！這也是系統必要的例行任務；

- 登錄檔分析 logwatch 的任務：

如果系統發生了軟體問題、硬體錯誤、資安問題等，絕大部分的錯誤資訊都會被記錄到登錄檔中， 因此系統管理員的重要任務之一就是分析登錄檔。但你不可能手動透過 vim 等軟體去檢視登錄檔，因為資料太複雜了！ 我們的 CentOS 提供了一隻程式『 logwatch 』來主動分析登錄資訊，所以你會發現，你的 root 老是會收到標題為 logwatch 的信件，那是正常的！你最好也能夠看看該信件的內容喔！

- 建立 locate 的資料庫：

在第七章我們談到的 locate 指令時， 我們知道該指令是透過已經存在的檔名資料庫來進行系統上檔名的查詢。我們的檔名資料庫是放置到 /var/lib/mlocate/ 中。 問題是，這個資料庫怎麼會自動更新啊？嘿嘿！這就是系統的例行性工作所產生的效果啦！系統會主動的進行 updatedb 喔！

- whatis 資料庫的建立：

與 locate 資料庫類似的，whatis 也是個資料庫，這個 whatis 是與 man page 有關的一個查詢指令，不過要使用 whatis 指令時， 必須要擁有 whatis 資料庫，而這個資料庫也是透過系統的例行性工作排程來自動執行的哩！

- RPM 軟體登錄檔的建立：

RPM (第二十三章) 是一種軟體管理的機制。由於系統可能會常常變更軟體， 包括軟體的新安裝、非經常性更新等，都會造成軟體檔名的差異。為了方便未來追蹤，系統也幫我們將檔名作個排序的記錄呢！ 有時候系統也會透過排程來幫忙 RPM 資料庫的重新建置喔！

- 移除暫存檔：

某些軟體在運作中會產生一些暫存檔，但是當這個軟體關閉時，這些暫存檔可能並不會主動的被移除。 有些暫存檔則有時間性，如果超過一段時間後，這個暫存檔就沒有效用了，此時移除這些暫存檔就是一件重要的工作！ 否則磁碟容量會被耗光。系統透過例行性工作排程執行名為 tmpwatch 的指令來刪除這些暫存檔呢！

- 與網路服務有關的分析行為：

如果你有安裝類似 WWW 伺服器軟體 (一個名為 apache 的軟體)，那麼你的 Linux 系統通常就會主動的分析該軟體的登錄檔。 同時某些憑證與認證的網路資訊是否過期的問題，我們的 Linux 系統也會很親和的幫你進行自動檢查！

其實你的系統會進行的例行性工作與你安裝的軟體多寡有關，如果你安裝過多的軟體，某些服務功能的軟體都會附上分析工具， 那麼你的系統就會多出一些例行性工作囉！像鳥哥的主機還多加了很多自己撰寫的分析工具，以及其他第三方協力軟體的分析軟體， 嘿嘿！俺的 Linux 工作量可是非常大的哩！因為有這麼多的工作需要進行，所以我們當然得要瞭解例行性工作的處理方式囉！

僅執行一次的工作排程

首先，我們先來談談單一工作排程的運作，那就是 at 這個指令的運作！

atd 的啟動與 at 運作的方式

要使用單一工作排程時，我們的 Linux 系統上面必須要有負責這個排程的服務，那就是 atd 這個玩意兒。 不過並非所有的 Linux distributions 都預設會把他打開的，所以呢，某些時刻我們必須要手動將他啟用才行。 啟用的方法很簡單，就是這樣：

[root@www ~]# /etc/init.d/atd restart

正在停止 atd:                          [  確定  ]

正在啟動 atd:                          [  確定  ]

# 再設定一下開機時就啟動這個服務，免得每次重新開機都得再來一次！

[root@www ~]# chkconfig atd on

重點是那個『正在啟動(或 starting)』項目的 OK 啦！那表示啟動是正常的！這部份我們在第十八章會談及。 如果您真的有興趣，那麼可以自行到 /etc/init.d/atd 這個 shell script 內去瞧一瞧先！ ^_^。 至於那個 chkconfig ，你也可以使用 man 先查閱一下啊！我們第十八章再介紹啦！

- at 的運作方式

既然是工作排程，那麼應該會有產生工作的方式，並且將這些工作排進行程表中囉！OK！那麼產生工作的方式是怎麼進行的？ 事實上，我們使用 at 這個指令來產生所要運作的工作，並將這個工作以文字檔的方式寫入 /var/spool/at/ 目錄內，該工作便能等待 atd 這個服務的取用與執行了。就這麼簡單。

不過，並不是所有的人都可以進行 at 工作排程喔！為什麼？因為安全的理由啊∼ 很多主機被所謂的『綁架』後，最常發現的就是他們的系統當中多了很多的怪客程式 (cracker program)， 這些程式非常可能運用工作排程來執行或蒐集系統資訊，並定時的回報給怪客團體！ 所以囉，除非是你認可的帳號，否則先不要讓他們使用 at 吧！那怎麼達到使用 at 的列管呢？

我們可以利用 /etc/at.allow 與 /etc/at.deny 這兩個檔案來進行 at 的使用限制呢！ 加上這兩個檔案後， at 的工作情況其實是這樣的：

1. 先找尋 /etc/at.allow 這個檔案，寫在這個檔案中的使用者才能使用 at ，沒有在這個檔案中的使用者則不能使用 at (即使沒有寫在 at.deny 當中)；

2. 如果 /etc/at.allow 不存在，就尋找 /etc/at.deny 這個檔案，若寫在這個 at.deny 的使用者則不能使用 at ，而沒有在這個 at.deny 檔案中的使用者，就可以使用 at 咯；

3. 如果兩個檔案都不存在，那麼只有 root 可以使用 at 這個指令。

透過這個說明，我們知道 /etc/at.allow 是管理較為嚴格的方式，而 /etc/at.deny 則較為鬆散 (因為帳號沒有在該檔案中，就能夠執行 at 了)。在一般的 distributions 當中，由於假設系統上的所有用戶都是可信任的， 因此系統通常會保留一個空的 /etc/at.deny 檔案，意思是允許所有人使用 at 指令的意思 (您可以自行檢查一下該檔案)。 不過，萬一你不希望有某些使用者使用 at 的話，將那個使用者的帳號寫入 /etc/at.deny 即可！ 一個帳號寫一行。

實際運作單一工作排程

單一工作排程的進行就使用 at 這個指令囉！這個指令的運作非常簡單！將 at 加上一個時間即可！基本的語法如下：

[root@www ~]# at [-mldv] TIME

[root@www ~]# at -c 工作號碼

選項與參數：

-m  ：當 at 的工作完成後，即使沒有輸出訊息，亦以 email 通知使用者該工作已完成。

-l  ：at -l 相當於 atq，列出目前系統上面的所有該使用者的 at 排程；

-d  ：at -d 相當於 atrm ，可以取消一個在 at 排程中的工作；

-v  ：可以使用較明顯的時間格式列出 at 排程中的工作列表；

-c  ：可以列出後面接的該項工作的實際指令內容。

TIME：時間格式，這裡可以定義出『什麼時候要進行 at 這項工作』的時間，格式有：

HH:MM                        ex> 04:00

在今日的 HH:MM 時刻進行，若該時刻已超過，則明天的 HH:MM 進行此工作。

HH:MM YYYY-MM-DD             ex> 04:00 2009-03-17

強制規定在某年某月的某一天的特殊時刻進行該工作！

HH:MM[am|pm] [Month] [Date]  ex> 04pm March 17

也是一樣，強制在某年某月某日的某時刻進行！

HH:MM[am|pm] + number [minutes|hours|days|weeks]

ex> now + 5 minutes    ex> 04pm + 3 days

就是說，在某個時間點『再加幾個時間後』才進行。

老實說，這個 at 指令的下達最重要的地方在於『時間』的指定了！鳥哥喜歡使用『 now + ... 』 的方式來定義現在過多少時間再進行工作，但有時也需要定義特定的時間點來進行！底下的範例先看看囉！

範例一：再過五分鐘後，將 /root/.bashrc 寄給 root 自己

[root@www ~]# at now + 5 minutes  <==記得單位要加 s 喔！

at> /bin/mail root -s "testing at job" < /root/.bashrc

at> <EOT>   <==這裡輸入 [ctrl] + d 就會出現 <EOF> 的字樣！代表結束！

job 4 at 2009-03-14 15:38

# 上面這行資訊在說明，第 4 個 at 工作將在 2009/03/14 的 15:38 進行！

# 而執行 at 會進入所謂的 at shell 環境，讓你下達多重指令等待運作！

範例二：將上述的第 4 項工作內容列出來查閱

[root@www ~]# at -c 4

#!/bin/sh               <==就是透過 bash shell 的啦！

# atrun uid=0 gid=0

# mail     root 0

umask 22

....(中間省略許多的環境變數項目)....

cd /root || {           <==可以看出，會到下達 at 時的工作目錄去執行指令

echo 'Execution directory inaccessible' >&2

exit 1

}

/bin/mail root -s "testing at job" < /root/.bashrc

# 你可以看到指令執行的目錄 (/root)，還有多個環境變數與實際的指令內容啦！

範例三：由於機房預計於 2009/03/18 停電，我想要在 2009/03/17 23:00 關機？

[root@www ~]# at 23:00 2009-03-17

at> /bin/sync

at> /bin/sync

at> /sbin/shutdown -h now

at> <EOT>

job 5 at 2009-03-17 23:00

# 您瞧瞧！ at 還可以在一個工作內輸入多個指令呢！不錯吧！

事實上，當我們使用 at 時會進入一個 at shell 的環境來讓使用者下達工作指令，此時，建議你最好使用絕對路徑來下達你的指令，比較不會有問題喔！由於指令的下達與 PATH 變數有關， 同時與當時的工作目錄也有關連 (如果有牽涉到檔案的話)，因此使用絕對路徑來下達指令，會是比較一勞永逸的方法。 為什麼呢？舉例來說，你在 /tmp 下達『 at now 』然後輸入『 mail root -s "test" < .bashrc 』， 問一下，那個 .bashrc 的檔案會是在哪裡？答案是『 /tmp/.bashrc 』！因為 at 在運作時，會跑到當時下達 at 指令的那個工作目錄的緣故啊！

有些朋友會希望『我要在某某時刻，在我的終端機顯示出 Hello 的字樣』，然後就在 at 裡面下達這樣的資訊『 echo "Hello" 』。等到時間到了，卻發現沒有任何訊息在螢幕上顯示，這是啥原因啊？這是因為 at 的執行與終端機環境無關，而所有 standard output/standard error output 都會傳送到執行者的 mailbox 去啦！所以在終端機當然看不到任何資訊。那怎辦？沒關係， 可以透過終端機的裝置來處理！假如你在 tty1 登入，則可以使用『 echo "Hello" > /dev/tty1 』來取代。

Tips:

要注意的是，如果在 at shell 內的指令並沒有任何的訊息輸出，那麼 at 預設不會發 email 給執行者的。 如果你想要讓 at 無論如何都發一封 email 告知你是否執行了指令，那麼可以使用『 at -m 時間格式 』來下達指令喔！ at 就會傳送一個訊息給執行者，而不論該指令執行有無訊息輸出了！

at 有另外一個很棒的優點，那就是『背景執行』的功能了！什麼是背景執行啊？很難瞭解嗎？其實與 bash 的 nohup (第十七章) 類似啦！ 鳥哥提我自己的幾個例子來給您聽聽，您就瞭了！

- 離線繼續工作的任務：鳥哥初次接觸 Unix 為的是要跑空氣品質模式， 那是一種大型的程式，這個程式在當時的硬體底下跑，一個案例要跑 3 天！由於鳥哥也要進行其他研究工作，因此常常使用 Windows 98 來連線到 Unix 工作站跑那個 3 天的案例！結果你也該知道， Windows 98 連開三天而不當機的機率是很低的∼@_@∼ 而當機時，所有在 Windows 上的連線都會中斷！包括鳥哥在跑的那個程式也中斷了∼嗚嗚∼明明再三個鐘頭就跑完的程式， 由於當機害我又得跑 3 天！

- 另一個常用的時刻則是例如上面的範例三，由於某個突發狀況導致你必須要進行某項工作時，這個 at 就很好用啦！

由於 at 工作排程的使用上，系統會將該項 at 工作獨立出你的 bash 環境中， 直接交給系統的 atd 程式來接管，因此，當你下達了 at 的工作之後就可以立刻離線了， 剩下的工作就完全交給 Linux 管理即可！所以囉，如果有長時間的網路工作時，嘿嘿！ 使用 at 可以讓你免除網路斷線後的困擾喔！ ^_^

- at 工作的管理

那麼萬一我下達了 at 之後，才發現指令輸入錯誤，該如何是好？就將他移除啊！利用 atq 與 atrm 吧！

[root@www ~]# atq

[root@www ~]# atrm (jobnumber)

範例一：查詢目前主機上面有多少的 at 工作排程？

[root@www ~]# atq

5       2009-03-17 23:00 a root

# 上面說的是：『在 2009/03/17 的 23:00 有一項工作，該項工作指令下達者為

# root』而且，該項工作的工作號碼 (jobnumber) 為 5 號喔！

範例二：將上述的第 5 個工作移除！

[root@www ~]# atrm 5

[root@www ~]# atq

# 沒有任何資訊，表示該工作被移除了！

如此一來，你可以利用 atq 來查詢，利用 atrm 來刪除錯誤的指令，利用 at 來直接下達單一工作排程！很簡單吧！ 不過，有個問題需要處理一下。如果你是在一個非常忙碌的系統下運作 at ， 能不能指定你的工作在系統較閒的時候才進行呢？可以的，那就使用 batch 指令吧！

- batch：系統有空時才進行背景任務

其實 batch 是利用 at 來進行指令的下達啦！只是加入一些控制參數而已。這個 batch 神奇的地方在於：他會在 CPU 工作負載小於 0.8 的時候，才進行你所下達的工作任務啦！ 那什麼是負載 0.8 呢？這個負載的意思是： CPU 在單一時間點所負責的工作數量。不是 CPU 的使用率喔！ 舉例來說，如果我有一隻程式他需要一直使用 CPU 的運算功能，那麼此時 CPU 的使用率可能到達 100% ， 但是 CPU 的工作負載則是趨近於『 1 』，因為 CPU 僅負責一個工作嘛！如果同時執行這樣的程式兩支呢？ CPU 的使用率還是 100% ，但是工作負載則變成 2 了！瞭解乎？

所以也就是說，當 CPU 的工作負載越大，代表 CPU 必須要在不同的工作之間進行頻繁的工作切換。 這樣的 CPU 運作情況我們在第零章有談過，忘記的話請回去瞧瞧！因為一直切換工作，所以會導致系統忙碌啊！ 系統如果很忙碌，還要額外進行 at ，不太合理！所以才有 batch 指令的產生！

那麼 batch 如何下達指令呢？很簡單啊！與 at 相同啦！例如下面的範例：

範例一：同樣是機房停電在 2009/3/17 23:00 關機，但若當時系統負載太高，則暫緩執行

[root@www ~]# batch 23:00 2009-3-17

at> sync

at> sync

at> shutdown -h now

at> <EOT>

job 6 at 2009-03-17 23:00

[root@www ~]# atq

6       2009-03-17 23:00 b root

[root@www ~]# atrm 6

你會發現其實 batch 也是使用 atq/atrm 來管理的！這樣瞭解乎？

循環執行的例行性工作排程

相對於 at 是僅執行一次的工作，循環執行的例行性工作排程則是由 cron (crond) 這個系統服務來控制的。剛剛談過 Linux 系統上面原本就有非常多的例行性工作，因此這個系統服務是預設啟動的。另外， 由於使用者自己也可以進行例行性工作排程，所以囉， Linux 也提供使用者控制例行性工作排程的指令 (crontab)。 底下我們分別來聊一聊囉！

使用者的設定

使用者想要建立循環型工作排程時，使用的是 crontab 這個指令啦∼不過，為了安全性的問題， 與 at 同樣的，我們可以限制使用 crontab 的使用者帳號喔！使用的限制資料有：

- /etc/cron.allow：

將可以使用 crontab 的帳號寫入其中，若不在這個檔案內的使用者則不可使用 crontab；

- /etc/cron.deny：

將不可以使用 crontab 的帳號寫入其中，若未記錄到這個檔案當中的使用者，就可以使用 crontab 。

與 at 很像吧！同樣的，以優先順序來說， /etc/cron.allow 比 /etc/cron.deny 要優先， 而判斷上面，這兩個檔案只選擇一個來限制而已，因此，建議你只要保留一個即可， 免得影響自己在設定上面的判斷！一般來說，系統預設是保留 /etc/cron.deny ， 你可以將不想讓他執行 crontab 的那個使用者寫入 /etc/cron.deny 當中，一個帳號一行！

當使用者使用 crontab 這個指令來建立工作排程之後，該項工作就會被紀錄到 /var/spool/cron/ 裡面去了，而且是以帳號來作為判別的喔！舉例來說， dmtsai 使用 crontab 後， 他的工作會被紀錄到 /var/spool/cron/dmtsai 裡頭去！但請注意，不要使用 vi 直接編輯該檔案， 因為可能由於輸入語法錯誤，會導致無法執行 cron 喔！另外， cron 執行的每一項工作都會被紀錄到 /var/log/cron 這個登錄檔中，所以囉，如果你的 Linux 不知道有否被植入木馬時，也可以搜尋一下 /var/log/cron 這個登錄檔呢！

好了，那麼我們就來聊一聊 crontab 的語法吧！

[root@www ~]# crontab [-u username] [-l|-e|-r]

選項與參數：

-u  ：只有 root 才能進行這個任務，亦即幫其他使用者建立/移除 crontab 工作排程；

-e  ：編輯 crontab 的工作內容

-l  ：查閱 crontab 的工作內容

-r  ：移除所有的 crontab 的工作內容，若僅要移除一項，請用 -e 去編輯。

範例一：用 dmtsai 的身份在每天的 12:00 發信給自己

[dmtsai@www ~]$ crontab -e

# 此時會進入 vi 的編輯畫面讓您編輯工作！注意到，每項工作都是一行。

0   12  *  *  * mail dmtsai -s "at 12:00" < /home/dmtsai/.bashrc

#分 時 日 月 週 |<==============指令串========================>|

預設情況下，任何使用者只要不被列入 /etc/cron.deny 當中，那麼他就可以直接下達『 crontab -e 』去編輯自己的例行性命令了！整個過程就如同上面提到的，會進入 vi 的編輯畫面， 然後以一個工作一行來編輯，編輯完畢之後輸入『 :wq 』儲存後離開 vi 就可以了！ 而每項工作 (每行) 的格式都是具有六個欄位，這六個欄位的意義為：

代表意義

分鐘

小時

日期

月份

週

指令

數字範圍

0-59

0-23

1-31

1-12

0-7

呀就指令啊

比較有趣的是那個『週』喔！週的數字為 0 或 7 時，都代表『星期天』的意思！另外， 還有一些輔助的字符，大概有底下這些：

特殊字符

代表意義

*(星號)

代表任何時刻都接受的意思！舉例來說，範例一內那個日、月、週都是 * ， 就代表著『不論何月、何日的禮拜幾的 12:00 都執行後續指令』的意思！

,(逗號)

代表分隔時段的意思。舉例來說，如果要下達的工作是 3:00 與 6:00 時，就會是：

0 3,6 * * * command

時間參數還是有五欄，不過第二欄是 3,6 ，代表 3 與 6 都適用！

-(減號)

代表一段時間範圍內，舉例來說， 8 點到 12 點之間的每小時的 20 分都進行一項工作：

20 8-12 * * * command

仔細看到第二欄變成 8-12 喔！代表 8,9,10,11,12 都適用的意思！

/n(斜線)

那個 n 代表數字，亦即是『每隔 n 單位間隔』的意思，例如每五分鐘進行一次，則：

*/5 * * * * command

很簡單吧！用 * 與 /5 來搭配，也可以寫成 0-59/5 ，相同意思！

我們就來搭配幾個例子練習看看吧！底下的案例請實際用 dmtsai 這個身份作看看喔！後續的動作才能夠搭配起來！

例題：

假若你的女朋友生日是 5 月 2 日，你想要在 5 月 1 日的 23:59 發一封信給他，這封信的內容已經寫在 /home/dmtsai/lover.txt 內了，該如何進行？

答：

直接下達 crontab -e 之後，編輯成為：

59 23 1 5 * mail kiki < /home/dmtsai/lover.txt

那樣的話，每年 kiki 都會收到你的這封信喔！（當然囉，信的內容就要每年變一變啦！）

例題：

假如每五分鐘需要執行 /home/dmtsai/test.sh 一次，又該如何？

答：

同樣使用 crontab -e 進入編輯：

*/5 * * * * /home/dmtsai/test.sh

那個 crontab 每個人都只有一個檔案存在，就是在 /var/spool/cron 裡面啊！ 還有建議您：『指令下達時，最好使用絕對路徑，這樣比較不會找不到執行檔喔！』

例題：

假如你每星期六都與朋友有約，那麼想要每個星期五下午 4:30 告訴你朋友星期六的約會不要忘記，則：

答：

還是使用 crontab -e 啊！

30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt

真的是很簡單吧！呵呵！那麼，該如何查詢使用者目前的 crontab 內容呢？我們可以這樣來看看：

[dmtsai@www ~]$ crontab -l

59 23 1 5 * mail kiki < /home/dmtsai/lover.txt

*/5 * * * * /home/dmtsai/test.sh

30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt

# 注意，若僅想要移除一項工作而已的話，必須要用 crontab -e 去編輯∼

# 如果想要全部的工作都移除，才使用 crontab -r 喔！

[dmtsai@www ~]$ crontab -r

[dmtsai@www ~]$ crontab -l

no crontab for dmtsai

看到了嗎？ crontab 『整個內容都不見了！』所以請注意：『如果只是要刪除某個 crontab 的工作項目，那麼請使用 crontab -e 來重新編輯即可！』如果使用 -r 的參數，是會將所有的 crontab 資料內容都刪掉的！千萬注意了！

系統的設定檔： /etc/crontab

這個『 crontab -e 』是針對使用者的 cron 來設計的，如果是『系統的例行性任務』時， 該怎麼辦呢？是否還是需要以 crontab -e 來管理你的例行性工作排程呢？當然不需要，你只要編輯 /etc/crontab 這個檔案就可以啦！有一點需要特別注意喔！那就是 crontab -e 這個 crontab 其實是 /usr/bin/crontab 這個執行檔，但是 /etc/crontab 可是一個『純文字檔』喔！你可以 root 的身份編輯一下這個檔案哩！

基本上， cron 這個服務的最低偵測限制是『分鐘』，所以『 cron 會每分鐘去讀取一次 /etc/crontab 與 /var/spool/cron 裡面的資料內容 』，因此，只要你編輯完 /etc/crontab 這個檔案，並且將他儲存之後，那麼 cron 的設定就自動的會來執行了！

Tips:

在 Linux 底下的 crontab 會自動的幫我們每分鐘重新讀取一次 /etc/crontab 的例行工作事項，但是某些原因或者是其他的 Unix 系統中，由於 crontab 是讀到記憶體當中的，所以在你修改完 /etc/crontab 之後，可能並不會馬上執行， 這個時候請重新啟動 crond 這個服務吧！『/etc/init.d/crond restart』

廢話少說，我們就來看一下這個 /etc/crontab 的內容吧！

[root@www ~]# cat /etc/crontab

SHELL=/bin/bash                     <==使用哪種 shell 介面

PATH=/sbin:/bin:/usr/sbin:/usr/bin  <==執行檔搜尋路徑

MAILTO=root                         <==若有額外STDOUT，以 email將資料送給誰

HOME=/                              <==預設此 shell 的家目錄所在

# run-parts

01  *  *  *  *   root      run-parts /etc/cron.hourly   <==每小時

02  4  *  *  *   root      run-parts /etc/cron.daily    <==每天

22  4  *  *  0   root      run-parts /etc/cron.weekly   <==每週日

42  4  1  *  *   root      run-parts /etc/cron.monthly  <==每個月 1 號

分 時 日 月 週 執行者身份  指令串

看到這個檔案的內容你大概就瞭解了吧！呵呵，沒錯！這個檔案與將剛剛我們下達 crontab -e 的內容幾乎完全一模一樣！只是有幾個地方不太相同：

- MAILTO=root：

這個項目是說，當 /etc/crontab 這個檔案中的例行性工作的指令發生錯誤時，或者是該工作的執行結果有 STDOUT/STDERR 時，會將錯誤訊息或者是螢幕顯示的訊息傳給誰？預設當然是由系統直接寄發一封 mail 給 root 啦！不過， 由於 root 並無法在用戶端中以 POP3 之類的軟體收信，因此，鳥哥通常都將這個 e-mail 改成自己的帳號，好讓我隨時瞭解系統的狀況！例如： MAILTO=dmtsai@my.host.name

- PATH=....：

還記得我們在第十一章的 BASH 當中一直提到的執行檔路徑問題吧！ 沒錯啦！這裡就是輸入執行檔的搜尋路徑！使用預設的路徑設定就已經很足夠了！

- 01 * * * * root run-parts /etc/cron.hourly：

這個 /etc/crontab 裡面預設定義出四項工作任務，分別是每小時、每天、每週及每個月分別進行一次的工作！ 但是在五個欄位後面接的並不是指令，而是一個新的欄位，那就是『執行後面那串指令的身份』為何！這與使用者的 crontab -e 不相同。由於使用者自己的 crontab 並不需要指定身份，但 /etc/crontab 裡面當然要指定身份啦！以上表的內容來說，系統預設的例行性工作是以 root 的身份來進行的。

那麼後面那串指令是什麼呢？你可以使用『 which run-parts 』搜尋看看，其實那是一個 bash script 啦！如果你直接進入 /usr/bin/run-parts 去看看， 會發現這支指令會將後面接的『目錄』內的所有檔案捉出來執行！這也就是說『 如果你想讓系統每小時主動幫你執行某個指令，將該指令寫成 script，並將該檔案放置到 /etc/cron.hourly/ 目錄下即可』的意思！

現在你知道系統是如何進行他預設的一堆例行性工作排程了嗎？如果你下達『 ll /etc/cron.daily 』就可以看到一堆檔案， 那些檔案就是系統提供的 script ，而這堆 scripts 將會在每天的凌晨 4:02 開始運作！這也是為啥如果你是夜貓族， 就會發現奇怪的是，Linux 系統為何早上 4:02 開始會很忙碌的發出一些硬碟跑動的聲音！因為他必須要進行 makewhatis, updatedb, rpm rebuild 等等的任務嘛！

由於 CentOS 提供的 run-parts 這個 script 的輔助，因此 /etc/crontab 這個檔案裡面支援兩種下達指令的方式， 一種是直接下達指令，一種則是以目錄來規劃，例如：

- 指令型態

01 * * * * dmtsai mail -s "testing" kiki < /home/dmtsai/test.txt

以 dmtsai 這個使用者的身份，在每小時執行一次 mail 指令。

- 目錄規劃

*/5 * * * * root run-parts /root/runcron

建立一個 /root/runcron 的目錄，將要每隔五分鐘執行的『可執行檔』都寫到該目錄下， 就可以讓系統每五分鐘執行一次該目錄下的所有可執行檔。

好！你現在大概瞭解了這一個咚咚吧！OK！假設你現在要作一個目錄，讓系統可以每 2 分鐘去執行這個目錄下的所有可以執行的檔案，你可以寫下如下的這一行在 /etc/crontab 中：

*/2 * * * * root run-parts /etc/cron.min

當然囉， /etc/cron.min 這個目錄是需要存在的喔！那如果我需要執行的是一個『程式』而已， 不需要用到一個目錄呢？該如何是好？例如在偵測網路流量時，我們希望每五分鐘偵測分析一次， 可以這樣寫：

*/5 * * * * root /bin/mrtg /etc/mrtg/mrtg.cfg

如何！建立例行性命令很簡單吧！如果你是系統管理員而且你的工作又是系統維護方面的例行任務時， 直接修改 /etc/crontab 這個檔案即可喔！又便利，又方便管理呢！

一些注意事項

有的時候，我們以系統的 cron 來進行例行性工作的建立時，要注意一些使用方面的特性。 舉例來說，如果我們有四個工作都是五分鐘要進行一次的，那麼是否這四個動作全部都在同一個時間點進行？ 如果同時進行，該四個動作又很耗系統資源，如此一來，每五分鐘不是會讓系統忙得要死？ 呵呵！此時好好的分配一些執行時間就 OK 啦！所以，注意一下：

- 資源分配不均的問題

當大量使用 crontab 的時候，總是會有問題發生的，最嚴重的問題就是『系統資源分配不均』的問題， 以鳥哥的系統為例，我有偵測主機流量的資訊，包括：

- 流量

- 區域內其他 PC 的流量偵測

- CPU 使用率

- RAM 使用率

- 線上人數即時偵測

如果每個流程都在同一個時間啟動的話，那麼在某個時段時，我的系統會變的相當的繁忙， 所以，這個時候就必須要分別設定啦！我可以這樣做：

[root@www ~]# vi /etc/crontab

1,6,11,16,21,26,31,36,41,46,51,56 * * * * root  CMD1

2,7,12,17,22,27,32,37,42,47,52,57 * * * * root  CMD2

3,8,13,18,23,28,33,38,43,48,53,58 * * * * root  CMD3

4,9,14,19,24,29,34,39,44,49,54,59 * * * * root  CMD4

看到了沒？那個『 , 』分隔的時候，請注意，不要有空白字元！（連續的意思）如此一來， 則可以將每五分鐘工作的流程分別在不同的時刻來工作！則可以讓系統的執行較為順暢呦！

- 取消不要的輸出項目

另外一個困擾發生在『 當有執行成果或者是執行的項目中有輸出的資料時，該資料將會 mail 給 MAILTO 設定的帳號 』，好啦，那麼當有一個排程一直出錯（例如 DNS 的偵測系統當中，若 DNS 上層主機掛掉，那麼你就會一直收到錯誤訊息！）怎麼辦？呵呵！還記得十一章談到的資料流重導向吧？ 直接以『命令重導向』將輸出的結果輸出到 /dev/null 這個垃圾桶當中就好了！

- 安全的檢驗

很多時候被植入木馬都是以例行命令的方式植入的，所以可以藉由檢查 /var/log/cron 的內容來視察是否有『非您設定的 cron 被執行了？』這個時候就需要小心一點囉！

- 週與日月不可同時並存

另一個需要注意的地方在於：『你可以分別以週或者是日月為單位作為循環，但你不可使用「幾月幾號且為星期幾」的模式工作』。 這個意思是說，你不可以這樣編寫一個工作排程：

30 12 11 9 5 root echo "just test"   <==這是錯誤的寫法

本來你以為九月十一號且為星期五才會進行這項工作，無奈的是，系統可能會判定每個星期五作一次，或每年的 9 月 11 號分別進行，如此一來與你當初的規劃就不一樣了∼所以囉，得要注意這個地方！上述的寫法是不對的喔！

可喚醒停機期間的工作任務

如果你的 Linux 主機是作為 24 小時全天、全年無休的伺服器之用，那麼你只要有 atd 與 crond 這兩個服務來管理你的例行性工作排程即可。如果你的伺服器並非 24 小時無間斷的開機，那麼你該如何進行例行性工作？ 舉例來說，如果你每天晚上都要關機，等到白天才啟動你的 Linux 主機時，由於 CentOS 預設的工作排程都在 4:02am 每天進行，唔！如此一來不就一堆系統例行工作都沒有人在做了！那可怎麼辦？此時就得要 anacron 這傢伙了！

什麼是 anacron

anacron 並不是用來取代 crontab 的，anacron 存在的目的就在於我們上頭提到的，在處理非 24 小時一直啟動的 Linux 系統的 crontab 的執行！所以 anacron 並不能指定何時執行某項任務， 而是以天為單位或者是在開機後立刻進行 anacron 的動作，他會去偵測停機期間應該進行但是並沒有進行的 crontab 任務，並將該任務執行一遍後，anacron 就會自動停止了。

由於 anacron 會以一天、七天、一個月為期去偵測系統未進行的 crontab 任務，因此對於某些特殊的使用環境非常有幫助。 舉例來說，如果你的 Linux 主機是放在公司給同仁使用的，因為週末假日大家都不在所以也沒有必要開啟， 因此你的 Linux 是週末都會關機兩天的。但是 crontab 大多在每天的凌晨以及週日的早上進行各項任務， 偏偏你又關機了，此時系統很多 crontab 的任務就無法進行。 anacron 剛好可以解決這個問題！

那麼 anacron 又是怎麼知道我們的系統啥時關機的呢？這就得要使用 anacron 讀取的時間記錄檔 (timestamps) 了！ anacron 會去分析現在的時間與時間記錄檔所記載的上次執行 anacron 的時間，兩者比較後若發現有差異， 那就是在某些時刻沒有進行 crontab 囉！此時 anacron 就會開始執行未進行的 crontab 任務了！ 所以 anacron 其實也是透過 crontab 來運作的！因此 anacron 運作的時間通常有兩個，一個是系統開機期間運作，一個是寫入 crontab 的排程中。 這樣才能夠在特定時間分析系統未進行的 crontab 工作嘛！瞭解乎！

anacron 與 /etc/anacrontab

anacron 其實是一支程式並非一個服務！這支程式在 CentOS 當中已經進入 crontab 的排程喔！ 不相信嗎？你可以這樣追蹤看看：

[root@www ~]# ll /etc/cron*/*ana*

-rwxr-xr-x 1 root root 379 Mar 28  2007 /etc/cron.daily/0anacron

-rwxr-xr-x 1 root root 381 Mar 28  2007 /etc/cron.monthly/0anacron

-rwxr-xr-x 1 root root 380 Mar 28  2007 /etc/cron.weekly/0anacron

# 剛好是每天、每週、每月有排程的工作目錄！查閱一下每天的任務

[root@www ~]# cat /etc/cron.daily/0anacron

if [ ! -e /var/run/anacron.pid ]; then

anacron -u cron.daily

fi

# 所以其實也僅是執行 anacron -u 的指令！因此我們得來談談這支程式！

基本上， anacron 的語法如下：

[root@www ~]# anacron [-sfn] [job]..

[root@www ~]# anacron -u [job]..

選項與參數：

-s  ：開始一連續的執行各項工作 (job)，會依據時間記錄檔的資料判斷是否進行；

-f  ：強制進行，而不去判斷時間記錄檔的時間戳記；

-n  ：立刻進行未進行的任務，而不延遲 (delay) 等待時間；

-u  ：僅更新時間記錄檔的時間戳記，不進行任何工作。

job ：由 /etc/anacrontab 定義的各項工作名稱。

所以我們發現其實 /etc/cron.daily/0anacron 僅進行時間戳記的更新，而沒有進行任何 anacron 的動作！ 在我們的 CentOS 中，anacron 的進行其實是在開機完成後才進行的一項工作任務，你也可以將 anacron 排入 crontab 的排程中。但是為了擔心 anacron 誤判時間參數，因此 /etc/cron.daily/ 裡面的 anacron 才會在檔名之前加個 0 (0anacron)，讓 anacron 最先進行！就是為了讓時間戳記先更新！以避免 anacron 誤判 crontab 尚未進行任何工作的意思。

接下來我們看一下 /etc/anacrontab 的內容好了：

[root@www ~]# cat /etc/anacrontab

SHELL=/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin

MAILTO=root

1       65      cron.daily     run-parts /etc/cron.daily

7       70      cron.weekly    run-parts /etc/cron.weekly

30      75      cron.monthly   run-parts /etc/cron.monthly

天數   延遲時間 工作名稱定義   實際要進行的指令串

# 天數單位為天；延遲時間單位為分鐘；工作名稱定義可自訂；

# 指令串則通常與 crontab 的設定相同！

[root@www ~]# more /var/spool/anacron/*

::::::::::::::

/var/spool/anacron/cron.daily

::::::::::::::

20090315

::::::::::::::

/var/spool/anacron/cron.monthly

::::::::::::::

20090301

::::::::::::::

/var/spool/anacron/cron.weekly

::::::::::::::

20090315

# 上面則是三個工作名稱的時間記錄檔以及記錄的時間戳記

由於 /etc/cron.daily 內的任務比較多，因此我們使用每天進行的任務來解釋一下 anacron 的運作情況好了。 anacron 若下達『 anacron -s cron.daily 』時，他會這樣運作的：

1. 由 /etc/anacrontab 分析到 cron.daily 這項工作名稱的天數為 1 天；

2. 由 /var/spool/anacron/cron.daily 取出最近一次執行 anacron 的時間戳記；

3. 由上個步驟與目前的時間比較，若差異天數為 1 天以上 (含 1 天)，就準備進行指令；

4. 若準備進行指令，根據 /etc/anacrontab 的設定，將延遲 65 分鐘

5. 延遲時間過後，開始執行後續指令，亦即『 run-parts /etc/cron.daily 』這串指令；

6. 執行完畢後， anacron 程式結束。

所以說，時間戳記是非常重要的！anacron 是透過該記錄與目前的時間差異，瞭解到是否應該要進行某項任務的工作！ 舉例來說，如果我的主機在 2009/03/15(星期天) 18:00 關機，然後在 2009/03/16(星期一) 8:00 開機，由於我的 crontab 是在早上 04:00 左右進行各項任務，由於該時刻系統是關機的，因此時間戳記依舊為 20090315 (舊的時間)， 但是目前時間已經是 20090316 (新的時間)，因此 run-parts /etc/cron.daily 就會在開機過 65 分鐘後開始運作了。

所以囉， anacron 並不需要額外的設定，使用預設值即可！只是我們的 CentOS 只有在開機時才會執行 anacron 就是了。如果要確定 anacron 是否開機時會主動的執行，你可以下達下列指令：

[root@www ~]# chkconfig --list anacron

anacron      0:off   1:off   2:on    3:on    4:on    5:on    6:off

# 詳細的 chkconfig 說明我們會在後續章節提到，注意看 3, 5

# 的項目，都是 on ！那就是有啟動啦！開機時才會執行的意思！

現在你知道為什麼隔了一陣子才將 CentOS 開機，開機過後約 1 小時左右系統會有一小段時間的忙碌！而且硬碟會跑個不停！那就是因為 anacron 正在執行過去 crontab 未進行的各項工作排程啦！這樣對 anacron 有沒有概念了呢？ ^_^

重點回顧

- 系統可以透過 at 這個指令來排程單一工作的任務！『at TIME』為指令下達的方法，當 at 進入排程後， 系統執行該排程工作時，會到下達時的目錄進行任務；

- at 的執行必須要有 atd 服務的支援，且 /etc/at.deny 為控制是否能夠執行的使用者帳號；

- 透過 atq, atrm 可以查詢與刪除 at 的工作排程；

- batch 與 at 相同，不過 batch 可在 CPU 工作負載小於 0.8 時才進行後續的工作排程；

- 系統的循環例行性工作排程使用 cron 這個服務，同時利用 crontab -e 及 /etc/crontab 進行排程的安排；

- crontab -e 設定項目分為六欄，『分、時、日、月、周、指令』為其設定依據；

- /etc/crontab 設定分為七欄，『分、時、日、月、周、執行者、指令』為其設定依據；

- anacron 配合 /etc/anacrontab 的設定，可以喚醒停機期間系統未進行的 crontab 任務！

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

簡答題：

- 今天假設我有一個指令程式，名稱為： ping.sh 這個檔名！我想要讓系統每三分鐘執行這個檔案一次， 但是偏偏這個檔案會有很多的訊息顯示出來，所以我的 root 帳號每天都會收到差不多四百多封的信件，光是收信就差不多快要瘋掉了！ 那麼請問應該怎麼設定比較好呢？

這個涉及資料流重導向的問題，我們可以將他導入檔案或者直接丟棄！如果該訊息不重要的話， 那麼就予以丟棄，如果訊息很重要的話，才將他保留下來！假設今天這個命令不重要， 所以將他丟棄掉！因此，可以這樣寫：

*/3 * * * * root /usr/local/ping.sh > /dev/null 2>&1

- 您預計要在 2010 年的 2 月 14 日寄出一封給 kiki ，只有該年才寄出！該如何下達指令？

at 1am 2010-02-14

- 下達 crontab -e 之後，如果輸入這一行，代表什麼意思？

* 15 * * 1-5 /usr/local/bin/tea_time.sh

在每星期的 1~5 ，下午 3 點的每分鐘，共進行 60 次 /usr/local/bin/tea_time.sh 這個檔案。 要特別注意的是，每個星期 1~5 的 3 點都會進行 60 次ㄟ！很麻煩吧∼是錯誤的寫法啦∼ 應該是要寫成：

30 15 * * 1-5 /usr/local/bin/tea_time.sh

- 我用 vi 編輯 /etc/crontab 這個檔案，我編輯的那一行是這樣的：

25 00 * * 0 /usr/local/bin/backup.sh

這一行代表的意義是什麼？

這一行代表......沒有任何意義！因為語法錯誤！您必須要瞭解，在 /etc/crontab 當中每一行都必須要有使用者才行！所以，應該要將原本那行改成：

25 00 * * 0 root /usr/local/bin/backup.sh

- 請問，您的系統每天、每週、每個月各有進行什麼工作？

因為 CentOS 系統預設的例行性命令都放置在 /etc/cron.* 裡面，所以，你可以自行去： /etc/cron.daily/, /etc/cron.week/, /etc/cron.monthly/ 這三個目錄內看一看， 就知道啦！ ^_^

- 每個星期六凌晨三點去系統搜尋一下內有 SUID/SGID 的任何檔案！並將結果輸出到 /tmp/uidgid.files

vi /etc/crontab

0 3 * * 6 root find / -perm +6000 > /tmp/uidgid.files

2002/05/30：第一次完成

2003/02/10：重新編排與加入 FAQ

2005/09/07：將舊的文章移動到 此處 。

2005/09/07：呼呼！終於完成風格囉∼同時加入一些習題練習。

2009/03/12：將舊的文件移動到此處。

2009/03/14：加入 batch 這個項目的說明！與 at 有關！

2009/03/15：加入了 anacron 這玩意的簡單說明！

2009/09/11：稍微修訂一下說明語氣與連結資料。

2002/05/30以來統計人數

第十七章、程序管理與 SELinux 初探

切換解析度為 800x600

最近更新日期：2011/04/14

一個程式被載入到記憶體當中運作，那麼在記憶體內的那個資料就被稱為程序(process)。程序是作業系統上非常重要的概念， 所有系統上面跑的資料都會以程序的型態存在。那麼系統的程序有哪些狀態？不同的狀態會如何影響系統的運作？ 程序之間是否可以互相控管等等的，這些都是我們所必須要知道的項目。 另外與程序有關的還有 SELinux 這個加強檔案存取安全性的咚咚，也必須要做個瞭解呢！

1. 什麼是程序 (Process)

1.1 程序與程式 (process & program)： 子程序與父程序, fork-and-exec, 系統服務

1.2 Linux 的多人多工環境

2. 工作管理 (job control)

2.1 什麼是工作管理

2.2 job control 的管理：&, [ctrl]-z, jobs, fg, bg, kill

2.3 離線管理問題： nohup

3. 程序管理

3.1 程序的觀察： ps (ps -l, ps aux, zombie), top, pstree

3.2 程序的管理： signal, kill, killall

3.3 關於程序的執行順序： priority, nice, renice

3.4 系統資源的觀察： free, uname, uptime, netstat, dmesg, vmstat

4. 特殊檔案與程序

4.1 具有 SUID/SGID 權限的指令執行狀態

4.2 /proc/* 代表的意義

4.3 查詢已開啟檔案或已執行程序開啟之檔案： fuser, lsof, pidof

5. SELinux 初探

5.1 什麼是 SELinux： 目標, DAC, MAC

5.2 SELinux 的運作模式： 元件, 安全性本文, domain/type

5.3 SELinux 的啟動、關閉與觀察： getenforce, sestatus, 啟動與關閉, setenforce

5.4 SELinux 網路服務運作範例： 啟動 (ps -Z), 錯誤情況, 解決 (chcon, restorecon)

5.5 SELinux 所需的服務： setroubleshoot, sealert, auditd, audit2why

5.6 SELinux 的政策與規則管理： seinfo, sesearch, getsebool, setsebool, semanage

6. 重點回顧

7. 本章習題

8. 參考資料與延伸閱讀

9. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23890

什麼是程序 (process)

由前面一連幾個章節的資料看來，我們一直強調在 Linux 底下所有的指令與你能夠進行的動作都與權限有關， 而系統如何判定你的權限呢？當然就是第十四章帳號管理當中提到的 UID/GID 的相關概念，以及檔案的屬性相關性囉！再進一步來解釋，你現在大概知道，在 Linux 系統當中：『觸發任何一個事件時，系統都會將他定義成為一個程序，並且給予這個程序一個 ID ，稱為 PID，同時依據啟發這個程序的使用者與相關屬性關係，給予這個 PID 一組有效的權限設定。』 從此以後，這個 PID 能夠在系統上面進行的動作，就與這個 PID 的權限有關了！

看這個定義似乎沒有什麼很奇怪的地方，不過，您得要瞭解什麼叫做『觸發事件』才行啊！ 我們在什麼情況下會觸發一個事件？而同一個事件可否被觸發多次？呵呵！來瞭解瞭解先！

程序與程式 (process & program)

我們如何產生一個程序呢？其實很簡單啦，就是『執行一個程式或指令』就可以觸發一個事件而取得一個 PID 囉！我們說過，系統應該是僅認識 binary file 的，那麼當我們要讓系統工作的時候，當然就是需要啟動一個 binary file 囉，那個 binary file 就是程式 (program) 啦！

那我們知道，每個程式都有三組人馬的權限，每組人馬都具有 r/w/x 的權限，所以：『不同的使用者身份執行這個 program 時，系統給予的權限也都不相同！』舉例來說，我們可以利用 touch 來建立一個空的檔案，當 root 執行這個 touch 指令時，他取得的是 UID/GID = 0/0 的權限，而當 dmtsai (UID/GID=501/501) 執行這個 touch 時，他的權限就跟 root 不同啦！我們將這個概念繪製成圖示來瞧瞧如下：

圖 1.1.1、程式被載入成為程序以及相關資料的示意圖

如上圖所示，程式一般是放置在實體磁碟中，然後透過使用者的執行來觸發。觸發後會載入到記憶體中成為一個個體，那就是程序。 為了作業系統可管理這個程序，因此程序有給予執行者的權限/屬性等參數，並包括程式所需要的指令碼與資料或檔案資料等， 最後再給予一個 PID 。系統就是透過這個 PID 來判斷該 process 是否具有權限進行工作的！他是很重要的哩！

舉個更常見的例子，我們要操作系統的時候，通常是利用連線程式或者直接在主機前面登入，然後取得我們的 shell 對吧！那麼，我們的 shell 是 bash 對吧，這個 bash 在 /bin/bash 對吧，那麼同時間的每個人登入都是執行 /bin/bash 對吧！不過，每個人取得的權限就是不同！也就是說，我們可以這樣看：

圖 1.1.2、程式與程序之間的差異

也就是說，當我們登入並執行 bash 時，系統已經給我們一個 PID 了，這個 PID 就是依據登入者的 UID/GID (/etc/passwd) 來的啦∼以上面的圖 1.1.2 配合圖 1.1.1 來做說明的話，我們知道 /bin/bash 是一個程式 (program)，當 dmtsai 登入後，他取得一個 PID 號碼為 2234 的程序，這個程序的 User/Group 都是 dmtsai ，而當這個程式進行其他作業時，例如上面提到的 touch 這個指令時， 那麼由這個程序衍生出來的其他程序在一般狀態下，也會沿用這個程序的相關權限的！

讓我們將程式與程序作個總結：

- 程式 (program)：通常為 binary program ，放置在儲存媒體中 (如硬碟、光碟、軟碟、磁帶等)， 為實體檔案的型態存在；

- 程序 (process)：程式被觸發後，執行者的權限與屬性、程式的程式碼與所需資料等都會被載入記憶體中， 作業系統並給予這個記憶體內的單元一個識別碼 (PID)，可以說，程序就是一個正在運作中的程式。

- 子程序與父程序：

在上面的說明裡面，我們有提到所謂的『衍生出來的程序』，那是個啥咚咚？這樣說好了，當我們登入系統後，會取得一個 bash 的 shell ，然後，我們用這個 bash 提供的介面去執行另一個指令，例如 /usr/bin/passwd 或者是 touch 等等，那些另外執行的指令也會被觸發成為 PID ，呵呵！那個後來執行指令才產生的 PID 就是『子程序』了，而在我們原本的 bash 環境下，就稱為『父程序』了！借用我們在十一章 Bash 談到的 export 所用的圖示好了：

圖 1.1.3、程序相關係之示意圖

所以你必須要知道，程式彼此之間是有相關性的！以上面的圖示來看，連續執行兩個 bash 後，第二個 bash 的父程序就是前一個 bash。因為每個程序都有一個 PID ，那某個程序的父程序該如何判斷？就透過 Parent PID (PPID) 來判斷即可。此外，由十一章的 export 內容我們也探討過環境變數的繼承問題，子程序可以取得父程序的環境變數啦！ 讓我們來進行底下的練習，以瞭解什麼是子程序/父程序。

例題：

請在目前的 bash 環境下，再觸發一次 bash ，並以『 ps -l 』這個指令觀察程序相關的輸出資訊。

答：

直接執行 bash ，會進入到子程序的環境中，然後輸入 ps -l 後，出現：

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0  8074  8072  2  76   0 -  1287 wait   pts/1    00:00:00 bash

0 S     0  8102  8074  4  76   0 -  1287 wait   pts/1    00:00:00 bash

4 R     0  8118  8102  0  78   0 -  1101 -      pts/1    00:00:00 ps

有看到那個 PID 與 PPID 嗎？第一個 bash 的 PID 與第二個 bash 的 PPID 都是 8074 啊， 因為第二個 bash 是來自於第一個所產生的嘛！另外，每部主機的程式啟動狀態都不一樣， 所以在你的系統上面看到的 PID 與我這裡的顯示一定不同！那是正常的！詳細的 ps 指令我們會在本章稍後介紹， 這裡你只要知道 ps -l 可以查閱到相關的程序資訊即可。

很多朋友常常會發現：『咦！明明我將有問題的程序關閉了，怎麼過一陣子他又自動的產生？ 而且新產生的那個程序的 PID 與原先的還不一樣，這是怎麼回事呢？』不要懷疑，如果不是 crontab 工作排程的影響，肯定有一支父程序存在，所以你殺掉子程序後， 父程序就會主動再生一支！那怎麼辦？正所謂這：『擒賊先擒王』，找出那支父程序，然後將他刪除就對啦！

- fork and exec：程序呼叫的流程

其實子程序與父程序之間的關係還挺複雜的，最大的複雜點在於程序互相之間的呼叫。在 Linux 的程序呼叫通常稱為 fork-and-exec 的流程 (註1)！程序都會藉由父程序以複製 (fork) 的方式產生一個一模一樣的子程序， 然後被複製出來的子程序再以 exec 的方式來執行實際要進行的程式，最終就成為一個子程序的存在。 整個流程有點像底下這張圖：

圖 1.1.4、程序使用 fork and exec 呼叫的情況示意圖

(1)系統先以 fork 的方式複製一個與父程序相同的暫存程序，這個程序與父程序唯一的差別就是 PID 不同！ 但是這個暫存程序還會多一個 PPID 的參數，PPID 如前所述，就是父程序的程序識別碼啦！然後(2)暫存程序開始以 exec 的方式載入實際要執行的程式，以上述圖示來講，新的程式名稱為 qqq ，最終子程序的程式碼就會變成 qqq 了！ 這樣瞭解乎！

- 系統或網路服務：常駐在記憶體的程序

如果就我們之前學到的一些指令資料來看，其實我們下達的指令都很簡單，包括用 ls 顯示檔案啊、用 touch 建立檔案啊、rm/mkdir/cp/mv 等指令管理檔案啊、chmod/chown/passwd 等等的指令來管理權限等等的，不過， 這些指令都是執行完就結束了。也就是說，該項指令被觸發後所產生的 PID 很快就會終止呢！ 那有沒有一直在執行的程序啊？當然有啊！而且多的是呢！

舉個簡單的例子來說好了，我們知道系統每分鐘都會去掃瞄 /etc/crontab 以及相關的設定檔， 來進行工作排程吧？那麼那個工作排程是誰負責的？當然不是鳥哥啊！ 呵呵！是 crond 這個程式所管理的，我們將他啟動在背景當中一直持續不斷的運作， 套句以前 DOS 年代常常說的一句話，那就是『常駐在記憶體當中的程序』啦！

常駐在記憶體當中的程序通常都是負責一些系統所提供的功能以服務使用者各項任務，因此這些常駐程式就會被我們稱為：服務 (daemon)。系統的服務非常的多， 不過主要大致分成系統本身所需要的服務，例如剛剛提到的 crond 及 atd ，還有 syslog 等等的。還有一些則是負責網路連線的服務，例如 Apache, named, postfix, vsftpd... 等等的。這些網路服務比較有趣的地方，在於這些程式被執行後，他會啟動一個可以負責網路監聽的埠口 (port) ，以提供外部用戶端 (client) 的連線要求。

Linux 的多人多工環境

我們現在知道了，其實在 Linux 底下執行一個指令時，系統會將相關的權限、屬性、程式碼與資料等均載入記憶體， 並給予這個單元一個程序識別碼 (PID)，最終該指令可以進行的任務則與這個 PID 的權限有關。根據這個說明，我們就可以簡單的瞭解，為什麼 Linux 這麼多用戶，但是卻每個人都可以擁有自己的環境了吧！^_^ ！底下我們來談談 Linux 多人多工環境的特色：

- 多人環境：

Linux 最棒的地方就在於他的多人多工環境了！那麼什麼是『多人多工』？在 Linux 系統上面具有多種不同的帳號， 每種帳號都有都有其特殊的權限，只有一個人具有至高無上的權力，那就是 root (系統管理員)。除了 root 之外，其他人都必須要受一些限制的！而每個人進入 Linux 的環境設定都可以隨著每個人的喜好來設定 (還記得我們在第十一章 BASH 提過的 ~/.bashrc 吧？對了！就是那個光！)！現在知道為什麼了吧？因為每個人登入後取得的 shell 的 PID 不同嘛！

- 多工行為：

我們在第零章談到 CPU 的速度，目前的 CPU 速度可高達幾個 GHz。 這代表 CPU 每秒鐘可以運作 10^9 這麼多次指令。我們的 Linux 可以讓 CPU 在各個工作間進行切換， 也就是說，其實每個工作都僅佔去 CPU 的幾個指令次數，所以 CPU 每秒就能夠在各個程序之間進行切換啦！ 誰叫 CPU 可以在一秒鐘進行這麼多次的指令運作。

CPU 切換程序的工作，與這些工作進入到 CPU 運作的排程 (CPU 排程，非 crontab 排程) 會影響到系統的整體效能！ 目前 Linux 使用的多工切換行為是非常棒的一個機制，幾乎可以將 PC 的性能整個壓榨出來！ 由於效能非常好，因此當多人同時登入系統時，其實會感受到整部主機好像就為了你存在一般！ 這就是多人多工的環境啦！(註2)

- 多重登入環境的七個基本終端視窗：

在 Linux 當中，預設提供了六個文字界面登入視窗，以及一個圖形界面，你可以使用 [Alt]+[F1].....[F7] 來切換不同的終端機界面，而且每個終端機界面的登入者還可以不同人！ 很炫吧！這個東西可就很有用啦！尤其是在某個程序死掉的時候！

其實，這也是多工環境下所產生的一個情況啦！我們的 Linux 預設會啟動六個終端機登入環境的程式，所以我們就會有六個終端機介面。 您也可以減少啊！就是減少啟動的終端機程式就好了。詳細的資料可以先查閱 /etc/inittab 這個檔案，未來我們在開機管理流程 (第二十章) 會再仔細的介紹的！

- 特殊的程序管理行為：

以前的鳥哥笨笨的，總是以為使用 Windows 98 就可以啦！後來，因為工作的關係，需要使用 Unix 系統，想說我只要在工作機前面就好，才不要跑來跑去的到 Unix 工作站前面去呢！所以就使用 Windows 連到我的 Unix 工作站工作！好死不死，我一個程序跑下來要 2~3 天，唉∼偏偏常常到了第 2.5 天的時候， Windows 98 就給他掛點去！當初真的是給他怕死了∼

後來因為換了新電腦，用了隨機版的 Windows 2000 ，呵呵，這東西真不錯 (指對單人而言) ，在當機的時候， 他可以僅將錯誤的程序踢掉，而不干擾其他的程序進行，呵呵！ 從此以後，就不用擔心會當機連連囉！不過，2000 畢竟還不夠好，因為有的時候還是會死當！

那麼 Linux 會有這樣的問題嗎？老實說， Linux 幾乎可以說絕對不會當機的！因為他可以在任何時候， 將某個被困住的程序殺掉，然後再重新執行該程序而不用重新開機！夠炫吧！那麼如果我在 Linux 下以文字界面登入，在螢幕當中顯示錯誤訊息後就掛了∼動都不能動，該如何是好！？ 這個時候那預設的七個視窗就幫上忙啦！你可以隨意的再按 [Alt]+[F1].....[F7] 來切換到其他的終端機界面，然後以 ps -aux 找出剛剛的錯誤程序，然後給他 kill 一下，哈哈，回到剛剛的終端機界面！恩∼棒！又回復正常囉！

為什麼可以這樣做呢？我們剛剛不是提過嗎？每個程序之間可能是獨立的，也可能有相依性， 只要到獨立的程序當中，刪除有問題的那個程序，當然他就可以被系統移除掉啦！^_^

- bash 環境下的工作管理 (job control)

我們在上一個小節有提到所謂的『父程序、子程序』的關係，那我們登入 bash 之後， 就是取得一個名為 bash 的 PID 了，而在這個環境底下所執行的其他指令， 就幾乎都是所謂的子程序了。那麼，在這個單一的 bash 介面下，我可不可以進行多個工作啊？ 當然可以啦！可以『同時』進行喔！舉例來說，我可以這樣做：

[root@www ~]# cp file1 file2 &

在這一串指令中，重點在那個 & 的功能，他表示將 file1 這個檔案複製為 file2 ，且放置於背景中執行， 也就是說執行這一個命令之後，在這一個終端介面仍然可以做其他的工作！而當這一個指令 (cp file1 file2) 執行完畢之後，系統將會在你的終端介面顯示完成的消息！很便利喔！

- 多人多工的系統資源分配問題考慮：

多人多工確實有很多的好處，但其實也有管理上的困擾，因為使用者越來越多， 將導致你管理上的困擾哩！另外，由於使用者日盛，當使用者達到一定的人數後， 通常你的機器便需要升級了，因為 CPU 的運算與 RAM 的大小可能就會不敷使用！

舉個例子來說，鳥哥之前的網站管理的有點不太好，因為使用了一個很複雜的人數統計程式， 這個程式會一直去取用 MySQL 資料庫的資料，偏偏因為流量大，造成 MySQL 很忙碌。 在這樣的情況下，當鳥哥要登入去寫網頁資料，或者要去使用討論區的資源時， 哇！慢的很！簡直就是『龜速』啊！後來終於將這個程式停止不用了， 以自己寫的一個小程式來取代，呵呵！這樣才讓 CPU 的負載 (loading) 整個降下來∼ 用起來順暢多了！ ^_^

工作管理 (job control)

這個工作管理 (job control) 是用在 bash 環境下的，也就是說：『當我們登入系統取得 bash shell 之後，在單一終端機介面下同時進行多個工作的行為管理 』。舉例來說，我們在登入 bash 後， 想要一邊複製檔案、一邊進行資料搜尋、一邊進行編譯，還可以一邊進行 vi 程式撰寫！ 當然我們可以重複登入那六個文字介面的終端機環境中，不過，能不能在一個 bash 內達成？ 當然可以啊！就是使用 job control 啦！ ^_^

什麼是工作管理？

從上面的說明當中，你應該要瞭解的是：『進行工作管理的行為中， 其實每個工作都是目前 bash 的子程序，亦即彼此之間是有相關性的。 我們無法以 job control 的方式由 tty1 的環境去管理 tty2 的 bash ！』 這個概念請你得先建立起來，後續的範例介紹之後，你就會清楚的瞭解囉！

或許你會覺得很奇怪啊，既然我可以在六個終端介面登入，那何必使用 job control 呢？ 真是脫褲子放屁，多此一舉啊！不要忘記了呢，我們可以在 /etc/security/limits.conf (第十四章) 裡面設定使用者同時可以登入的連線數，在這樣的情況下，某些使用者可能僅能以一個連線來工作呢！ 所以囉，你就得要瞭解一下這種工作管理的模式了！此外，這個章節內容也會牽涉到很多的資料流重導向，所以，如果忘記的話， 務必回到第十一章 BASH Shell 看一看喔！

由於假設我們只有一個終端介面，因此在可以出現提示字元讓你操作的環境就稱為前景 (foreground)，至於其他工作就可以讓你放入背景 (background) 去暫停或運作。要注意的是，放入背景的工作想要運作時， 他必須不能夠與使用者互動。舉例來說， vim 絕對不可能在背景裡面執行 (running) 的！因為你沒有輸入資料他就不會跑啊！ 而且放入背景的工作是不可以使用 [ctrl]+c 來終止的』！

總之，要進行 bash 的 job control 必須要注意到的限制是：

- 這些工作所觸發的程序必須來自於你 shell 的子程序(只管理自己的 bash)；

- 前景：你可以控制與下達指令的這個環境稱為前景的工作 (foreground)；

- 背景：可以自行運作的工作，你無法使用 [ctrl]+c 終止他，可使用 bg/fg 呼叫該工作；

- 背景中『執行』的程序不能等待 terminal/shell 的輸入(input)

接下來讓我們實際來管理這些工作吧！

job control 的管理

如前所述，bash 只能夠管理自己的工作而不能管理其他 bash 的工作，所以即使你是 root 也不能夠將別人的 bash 底下的 job 給他拿過來執行。此外，又分前景與背景，然後在背景裡面的工作狀態又可以分為『暫停 (stop)』與『運作中 (running)』。那實際進行 job 控制的指令有哪些？底下就來談談。

- 直接將指令丟到背景中『執行』的 &

如同前面提到的，我們在只有一個 bash 的環境下，如果想要同時進行多個工作， 那麼可以將某些工作直接丟到背景環境當中，讓我們可以繼續操作前景的工作！那麼如何將工作丟到背景中？ 最簡單的方法就是利用『 & 』這個玩意兒了！舉個簡單的例子，我們要將 /etc/ 整個備份成為 /tmp/etc.tar.gz 且不想要等待，那麼可以這樣做：

[root@www ~]# tar -zpcf /tmp/etc.tar.gz /etc &

[1] 8400  <== [job number] PID

[root@www ~]# tar: Removing leading `/' from member names

# 在中括號內的號碼為工作號碼 (job number)，該號碼與 bash 的控制有關。

# 後續的 8400 則是這個工作在系統中的 PID。至於後續出現的資料是 tar 執行的資料流，

# 由於我們沒有加上資料流重導向，所以會影響畫面！不過不會影響前景的操作喔！

仔細的瞧一瞧，我在輸入一個指令後，在該指令的最後面加上一個『 & 』代表將該指令丟到背景中， 此時 bash 會給予這個指令一個『工作號碼(job number)』，就是那個 [1] 啦！至於後面那個 8400 則是該指令所觸發的『 PID 』了！而且，有趣的是，我們可以繼續操作 bash 呢！很不賴吧！ 不過，那麼丟到背景中的工作什麼時候完成？完成的時候會顯示什麼？如果你輸入幾個指令後，突然出現這個資料：

[1]+  Done                    tar -zpcf /tmp/etc.tar.gz /etc

就代表 [1] 這個工作已經完成 (Done) ，該工作的指令則是接在後面那一串指令列。 這樣瞭解了吧！另外，這個 & 代表：『將工作丟到背景中去執行』喔！ 注意到那個『執行』的字眼！此外，這樣的情況最大的好處是： 不怕被 [ctrl]+c 中斷的啦！ 此外，將工作丟到背景當中要特別注意資料的流向喔！包括上面的訊息就有出現錯誤訊息，導致我的前景被影響。 雖然只要按下 [enter] 就會出現提示字元。但如果我將剛剛那個指令改成：

[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc &

情況會怎樣？在背景當中執行的指令，如果有 stdout 及 stderr 時，他的資料依舊是輸出到螢幕上面的， 所以，我們會無法看到提示字元，當然也就無法完好的掌握前景工作。同時由於是背景工作的 tar ， 此時你怎麼按下 [ctrl]+c 也無法停止螢幕被搞的花花綠綠的！所以囉，最佳的狀況就是利用資料流重導向， 將輸出資料傳送至某個檔案中。舉例來說，我可以這樣做：

[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 &

[1] 8429

[root@www ~]#

呵呵！如此一來，輸出的資訊都給他傳送到 /tmp/log.txt 當中，當然就不會影響到我們前景的作業了。 這樣說，您應該可以更清楚資料流重導向的重要性了吧！^_^

Tips:

工作號碼 (job number) 只與你這個 bash 環境有關，但是他既然是個指令觸發的咚咚，所以當然一定是一個程序， 因此你會觀察到有 job number 也搭配一個 PID ！

- 將『目前』的工作丟到背景中『暫停』：[ctrl]-z

想個情況：如果我正在使用 vi ，卻發現我有個檔案不知道放在哪裡，需要到 bash 環境下進行搜尋，此時是否要結束 vi 呢？呵呵！當然不需要啊！只要暫時將 vi 給他丟到背景當中等待即可。 例如以下的案例：

[root@www ~]# vi ~/.bashrc

# 在 vi 的一般模式下，按下 [ctrl]-z 這兩個按鍵

[1]+  Stopped                 vim ~/.bashrc

[root@www ~]#   <==順利取得了前景的操控權！

[root@www ~]# find / -print

....(輸出省略)....

# 此時螢幕會非常的忙碌！因為螢幕上會顯示所有的檔名。請按下 [ctrl]-z 暫停

[2]+  Stopped                 find / -print

在 vi 的一般模式下，按下 [ctrl] 及 z 這兩個按鍵，螢幕上會出現 [1] ，表示這是第一個工作， 而那個 + 代表最近一個被丟進背景的工作，且目前在背景下預設會被取用的那個工作 (與 fg 這個指令有關 )！而那個 Stopped 則代表目前這個工作的狀態。在預設的情況下，使用 [ctrl]-z 丟到背景當中的工作都是『暫停』的狀態喔！

- 觀察目前的背景工作狀態： jobs

[root@www ~]# jobs [-lrs]

選項與參數：

-l  ：除了列出 job number 與指令串之外，同時列出 PID 的號碼；

-r  ：僅列出正在背景 run 的工作；

-s  ：僅列出正在背景當中暫停 (stop) 的工作。

範例一：觀察目前的 bash 當中，所有的工作，與對應的 PID

[root@www ~]# jobs -l

[1]- 10314 Stopped                 vim ~/.bashrc

[2]+ 10833 Stopped                 find / -print

如果想要知道目前有多少的工作在背景當中，就用 jobs 這個指令吧！一般來說，直接下達 jobs 即可！ 不過，如果你還想要知道該 job number 的 PID 號碼，可以加上 -l 這個參數啦！ 在輸出的資訊當中，例如上表，仔細看到那個 + - 號喔！那個 + 代表預設的取用工作。 所以說：『目前我有兩個工作在背景當中，兩個工作都是暫停的， 而如果我僅輸入 fg 時，那麼那個 [2] 會被拿到前景當中來處理』！

其實 + 代表最近被放到背景的工作號碼， - 代表最近最後第二個被放置到背景中的工作號碼。 而超過最後第三個以後的工作，就不會有 +/- 符號存在了！

- 將背景工作拿到前景來處理：fg

剛剛提到的都是將工作丟到背景當中去執行的，那麼有沒有可以將背景工作拿到前景來處理的？ 有啊！就是那個 fg (foreground) 啦！舉例來說，我們想要將上頭範例當中的工作拿出來處理時：

[root@www ~]# fg %jobnumber

選項與參數：

%jobnumber ：jobnumber 為工作號碼(數字)。注意，那個 % 是可有可無的！

範例一：先以 jobs 觀察工作，再將工作取出：

[root@www ~]# jobs

[1]- 10314 Stopped                 vim ~/.bashrc

[2]+ 10833 Stopped                 find / -print

[root@www ~]# fg      <==預設取出那個 + 的工作，亦即 [2]。立即按下[ctrl]-z

[root@www ~]# fg %1   <==直接規定取出的那個工作號碼！再按下[ctrl]-z

[root@www ~]# jobs

[1]+  Stopped                 vim ~/.bashrc

[2]-  Stopped                 find / -print

經過 fg 指令就能夠將背景工作拿到前景來處理囉！不過比較有趣的是最後一個顯示的結果，我們會發現 + 出現在第一個工作後！ 怎麼會這樣啊？這是因為你剛剛利用 fg %1 將第一號工作捉到前景後又放回背景，此時最後一個被放入背景的將變成 vi 那個指令動作， 所以當然 [1] 後面就會出現 + 了！瞭解乎！另外，如果輸入『 fg - 』 則代表將 - 號的那個工作號碼拿出來，上面就是 [2]- 那個工作號碼啦！

- 讓工作在背景下的狀態變成運作中： bg

我們剛剛提到，那個 [ctrl]-z 可以將目前的工作丟到背景底下去『暫停』， 那麼如何讓一個工作在背景底下『 Run 』呢？我們可以在底下這個案例當中來測試！ 注意喔！底下的測試要進行的快一點！^_^

範例一：一執行 find / -perm +7000 > /tmp/text.txt 後，立刻丟到背景去暫停！

[root@www ~]# find / -perm +7000 > /tmp/text.txt

# 此時，請立刻按下 [ctrl]-z 暫停！

[3]+  Stopped                 find / -perm +7000 > /tmp/text.txt

範例二：讓該工作在背景下進行，並且觀察他！！

[root@www ~]# jobs ; bg %3 ; jobs

[1]-  Stopped                 vim ~/.bashrc

[2]   Stopped                 find / -print

[3]+  Stopped                 find / -perm +7000 > /tmp/text.txt

[3]+ find / -perm +7000 > /tmp/text.txt &  <==用 bg%3 的情況！

[1]+  Stopped                 vim ~/.bashrc

[2]   Stopped                 find / -print

[3]-  Running                 find / -perm +7000 > /tmp/text.txt &

看到哪裡有差異嗎？呼呼！沒錯！就是那個狀態列∼以經由 Stopping 變成了 Running 囉！ 看到差異點，嘿嘿！指令列最後方多了一個 & 的符號囉！ 代表該工作被啟動在背景當中了啦！ ^_^

- 管理背景當中的工作： kill

剛剛我們可以讓一個已經在背景當中的工作繼續工作，也可以讓該工作以 fg 拿到前景來， 那麼，如果想要將該工作直接移除呢？或者是將該工作重新啟動呢？這個時候就得需要給予該工作一個訊號 (signal) ，讓他知道該怎麼作才好啊！此時， kill 這個指令就派上用場啦！

[root@www ~]# kill -signal %jobnumber

[root@www ~]# kill -l

選項與參數：

-l  ：這個是 L 的小寫，列出目前 kill 能夠使用的訊號 (signal) 有哪些？

signal ：代表給予後面接的那個工作什麼樣的指示囉！用 man 7 signal 可知：

-1 ：重新讀取一次參數的設定檔 (類似 reload)；

-2 ：代表與由鍵盤輸入 [ctrl]-c 同樣的動作；

-9 ：立刻強制刪除一個工作；

-15：以正常的程序方式終止一項工作。與 -9 是不一樣的。

範例一：找出目前的 bash 環境下的背景工作，並將該工作『強制刪除』。

[root@www ~]# jobs

[1]+  Stopped                 vim ~/.bashrc

[2]   Stopped                 find / -print

[root@www ~]# kill -9 %2; jobs

[1]+  Stopped                 vim ~/.bashrc

[2]   Killed                  find / -print

# 再過幾秒你再下達 jobs 一次，就會發現 2 號工作不見了！因為被移除了！

範例：找出目前的 bash 環境下的背景工作，並將該工作『正常終止』掉。

[root@www ~]# jobs

[1]+  Stopped                 vim ~/.bashrc

[root@www ~]# kill -SIGTERM %1

# -SIGTERM 與 -15 是一樣的！您可以使用 kill -l 來查閱！

特別留意一下， -9 這個 signal 通常是用在『強制刪除一個不正常的工作』時所使用的， -15 則是以正常步驟結束一項工作(15也是預設值)，兩者之間並不相同呦！舉上面的例子來說， 我用 vi 的時候，不是會產生一個 .filename.swp 的檔案嗎？ 那麼，當使用 -15 這個 signal 時， vi 會嘗試以正常的步驟來結束掉該 vi 的工作， 所以 .filename.swp 會主動的被移除。但若是使用 -9 這個 signal 時，由於該 vi 工作會被強制移除掉，因此， .filename.swp 就會繼續存在檔案系統當中。這樣您應該可以稍微分辨一下了吧？

其實， kill 的妙用是很無窮的啦！他搭配 signal 所詳列的資訊 (用 man 7 signal 去查閱相關資料) 可以讓您有效的管理工作與程序 (Process)，此外，那個 killall 也是同樣的用法！ 至於常用的 signal 您至少需要瞭解 1, 9, 15 這三個 signal 的意義才好。 此外， signal 除了以數值來表示之外，也可以使用訊號名稱喔！ 舉例來說，上面的範例二就是一個例子啦！至於 signal number 與名稱的對應， 呵呵，使用 kill -l 就知道啦(L的小寫)！

另外， kill 後面接的數字預設會是 PID ，如果想要管理 bash 的工作控制，就得要加上 %數字 了， 這點也得特別留意才行喔！

離線管理問題

要注意的是，我們在工作管理當中提到的『背景』指的是在終端機模式下可以避免 [crtl]-c 中斷的一個情境， 並不是放到系統的背景去喔！所以，工作管理的背景依舊與終端機有關啦！ 在這樣的情況下，如果你是以遠端連線方式連接到你的 Linux 主機，並且將工作以 & 的方式放到背景去， 請問，在工作尚未結束的情況下你離線了，該工作還會繼續進行嗎？答案是『否』！不會繼續進行，而是會被中斷掉。

那怎麼辦？如果我的工作需要進行一大段時間，我又不能放置在背景底下，那該如何處理呢？ 首先，你可以參考前一章的 at 來處理即可！因為 at 是將工作放置到系統背景， 而與終端機無關。如果不想要使用 at 的話，那你也可以嘗試使用 nohup 這個指令來處理喔！這個 nohup 可以讓你在離線或登出系統後，還能夠讓工作繼續進行。他的語法有點像這樣：

[root@www ~]# nohup [指令與參數]   <==在終端機前景中工作

[root@www ~]# nohup [指令與參數] & <==在終端機背景中工作

有夠好簡單的指令吧！上述指令需要注意的是， nohup 並不支援 bash 內建的指令，因此你的指令必須要是外部指令才行。 我們來嘗試玩一下底下的任務吧！

# 1. 先編輯一支會『睡著 500 秒』的程式：

[root@www ~]# vim sleep500.sh

#!/bin/bash

/bin/sleep 500s

/bin/echo "I have slept 500 seconds."

# 2. 丟到背景中去執行，並且立刻登出系統：

[root@www ~]# chmod a+x sleep500.sh

[root@www ~]# nohup ./sleep500.sh &

[1] 5074

[root@www ~]# nohup: appending output to ‘nohup.out’ <==會告知這個訊息！

[root@www ~]# exit

如果你再次登入的話，再使用 pstree 去查閱你的程序，會發現 sleep500.sh 還在執行中喔！並不會被中斷掉！ 這樣瞭解意思了嗎？由於我們的程式最後會輸出一個訊息，但是 nohup 與終端機其實無關了， 因此這個訊息的輸出就會被導向『 ~/nohup.out 』，所以你才會看到上述指令中，當你輸入 nohup 後， 會出現那個提示訊息囉。

如果你想要讓在背景的工作在你登出後還能夠繼續的執行，那麼使用 nohup 搭配 & 是不錯的運作情境喔！ 可以參考看看！

程序管理

本章一開始就提到所謂的『程序』的概念，包括程序的觸發、子程序與父程序的相關性等等， 此外，還有那個『程序的相依性』以及所謂的『殭屍程序』等等需要說明的呢！為什麼程序管理這麼重要呢？這是因為：

- 首先，本章一開始就談到的，我們在操作系統時的各項工作其實都是經過某個 PID 來達成的 (包括你的 bash 環境)， 因此，能不能進行某項工作，就與該程序的權限有關了。

- 再來，如果您的 Linux 系統是個很忙碌的系統，那麼當整個系統資源快要被使用光時， 您是否能夠找出最耗系統的那個程序，然後刪除該程序，讓系統恢復正常呢？

- 此外，如果由於某個程式寫的不好，導致產生一個有問題的程序在記憶體當中，您又該如何找出他，然後將他移除呢？

- 如果同時有五六項工作在您的系統當中運作，但其中有一項工作才是最重要的， 該如何讓那一項重要的工作被最優先執行呢？

所以囉，一個稱職的系統管理員，必須要熟悉程序的管理流程才行，否則當系統發生問題時，還真是很難解決問題呢！ 底下我們會先介紹如何觀察程序與程序的狀態，然後再加以程序控制囉！

程序的觀察

既然程序這麼重要，那麼我們如何查閱系統上面正在運作當中的程序呢？很簡單啊！ 利用靜態的 ps 或者是動態的 top，還能以 pstree 來查閱程序樹之間的關係喔！

- ps ：將某個時間點的程序運作情況擷取下來

[root@www ~]# ps aux  <==觀察系統所有的程序資料

[root@www ~]# ps -lA  <==也是能夠觀察所有系統的資料

[root@www ~]# ps axjf <==連同部分程序樹狀態

選項與參數：

-A  ：所有的 process 均顯示出來，與 -e 具有同樣的效用；

-a  ：不與 terminal 有關的所有 process ；

-u  ：有效使用者 (effective user) 相關的 process ；

x   ：通常與 a 這個參數一起使用，可列出較完整資訊。

輸出格式規劃：

l   ：較長、較詳細的將該 PID 的的資訊列出；

j   ：工作的格式 (jobs format)

-f  ：做一個更為完整的輸出。

鳥哥個人認為 ps 這個指令的 man page 不是很好查閱，因為很多不同的 Unix 都使用這個 ps 來查閱程序狀態， 為了要符合不同版本的需求，所以這個 man page 寫的非常的龐大！因此，通常鳥哥都會建議你，直接背兩個比較不同的選項， 一個是只能查閱自己 bash 程序的『 ps -l 』一個則是可以查閱所有系統運作的程序『 ps aux 』！注意，你沒看錯，是『 ps aux 』沒有那個減號 (-) ！先來看看關於自己 bash 程序狀態的觀察：

- 僅觀察自己的 bash 相關程序： ps -l

範例一：將目前屬於您自己這次登入的 PID 與相關資訊列示出來(只與自己的 bash 有關)

[root@www ~]# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 13639 13637  0  75   0 -  1287 wait   pts/1    00:00:00 bash

4 R     0 13700 13639  0  77   0 -  1101 -      pts/1    00:00:00 ps

系統整體的程序運作是非常多的，但如果使用 ps -l 則僅列出與你的操作環境 (bash) 有關的程序而已， 亦即最上層的父程序會是你自己的 bash 而沒有延伸到 init 這支程序去！那麼 ps -l 秀出來的資料有哪些呢？ 我們就來觀察看看：

- F：代表這個程序旗標 (process flags)，說明這個程序的總結權限，常見號碼有：

- 若為 4 表示此程序的權限為 root ；

- 若為 1 則表示此子程序僅進行複製(fork)而沒有實際執行(exec)。

- S：代表這個程序的狀態 (STAT)，主要的狀態有：

- R (Running)：該程式正在運作中；

- S (Sleep)：該程式目前正在睡眠狀態(idle)，但可以被喚醒(signal)。

- D ：不可被喚醒的睡眠狀態，通常這支程式可能在等待 I/O 的情況(ex>列印)

- T ：停止狀態(stop)，可能是在工作控制(背景暫停)或除錯 (traced) 狀態；

- Z (Zombie)：僵屍狀態，程序已經終止但卻無法被移除至記憶體外。

- UID/PID/PPID：代表『此程序被該 UID 所擁有/程序的 PID 號碼/此程序的父程序 PID 號碼』

- C：代表 CPU 使用率，單位為百分比；

- PRI/NI：Priority/Nice 的縮寫，代表此程序被 CPU 所執行的優先順序，數值越小代表該程序越快被 CPU 執行。詳細的 PRI 與 NI 將在下一小節說明。

- ADDR/SZ/WCHAN：都與記憶體有關，ADDR 是 kernel function，指出該程序在記憶體的哪個部分，如果是個 running 的程序，一般就會顯示『 - 』 / SZ 代表此程序用掉多少記憶體 / WCHAN 表示目前程序是否運作中，同樣的， 若為 - 表示正在運作中。

- TTY：登入者的終端機位置，若為遠端登入則使用動態終端介面 (pts/n)；

- TIME：使用掉的 CPU 時間，注意，是此程序實際花費 CPU 運作的時間，而不是系統時間；

- CMD：就是 command 的縮寫，造成此程序的觸發程式之指令為何。

所以你看到的 ps -l 輸出訊息中，他說明的是：『bash 的程式屬於 UID 為 0 的使用者，狀態為睡眠 (sleep)， 之所以為睡眠因為他觸發了 ps (狀態為 run) 之故。此程序的 PID 為 13639，優先執行順序為 75 ， 下達 bash 所取得的終端介面為 pts/1 ，運作狀態為等待 (wait) 。』這樣已經夠清楚了吧？ 您自己嘗試解析一下那麼 ps 那一行代表的意義為何呢？ ^_^

接下來讓我們使用 ps 來觀察一下系統內所有的程序狀態吧！

- 觀察系統所有程序： ps aux

範例二：列出目前所有的正在記憶體當中的程序：

[root@www ~]# ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root         1  0.0  0.0   2064   616 ?        Ss   Mar11   0:01 init [5]

root         2  0.0  0.0      0     0 ?        S<   Mar11   0:00 [migration/0]

root         3  0.0  0.0      0     0 ?        SN   Mar11   0:00 [ksoftirqd/0]

.....(中間省略).....

root     13639  0.0  0.2   5148  1508 pts/1    Ss   11:44   0:00 -bash

root     14232  0.0  0.1   4452   876 pts/1    R+   15:52   0:00 ps aux

root     18593  0.0  0.0   2240   476 ?        Ss   Mar14   0:00 /usr/sbin/atd

你會發現 ps -l 與 ps aux 顯示的項目並不相同！在 ps aux 顯示的項目中，各欄位的意義為：

- USER：該 process 屬於那個使用者帳號的？

- PID ：該 process 的程序識別碼。

- %CPU：該 process 使用掉的 CPU 資源百分比；

- %MEM：該 process 所佔用的實體記憶體百分比；

- VSZ ：該 process 使用掉的虛擬記憶體量 (Kbytes)

- RSS ：該 process 佔用的固定的記憶體量 (Kbytes)

- TTY ：該 process 是在那個終端機上面運作，若與終端機無關則顯示 ?，另外， tty1-tty6 是本機上面的登入者程序，若為 pts/0 等等的，則表示為由網路連接進主機的程序。

- STAT：該程序目前的狀態，狀態顯示與 ps -l 的 S 旗標相同 (R/S/T/Z)

- START：該 process 被觸發啟動的時間；

- TIME ：該 process 實際使用 CPU 運作的時間。

- COMMAND：該程序的實際指令為何？

一般來說，ps aux 會依照 PID 的順序來排序顯示，我們還是以 13639 那個 PID 那行來說明！該行的意義為『 root 執行的 bash PID 為 13639，佔用了 0.2% 的記憶體容量百分比，狀態為休眠 (S)，該程序啟動的時間為 11:44 ， 且取得的終端機環境為 pts/1 。』與 ps aux 看到的其實是同一個程序啦！這樣可以理解嗎？ 讓我們繼續使用 ps 來觀察一下其他的資訊吧！

範例三：以範例一的顯示內容，顯示出所有的程序：

[root@www ~]# ps -lA

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0     1     0  0  76   0 -   435 -      ?        00:00:01 init

1 S     0     2     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/0

1 S     0     3     1  0  70  -5 -     0 worker ?        00:00:00 events/0

....(以下省略)....

# 你會發現每個欄位與 ps -l 的輸出情況相同，但顯示的程序則包括系統所有的程序。

範例四：列出類似程序樹的程序顯示：

[root@www ~]# ps axjf

PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND

0     1     1     1 ?           -1 Ss       0   0:01 init [5]

.....(中間省略).....

1  4586  4586  4586 ?           -1 Ss       0   0:00 /usr/sbin/sshd

4586 13637 13637 13637 ?           -1 Ss       0   0:00  \_ sshd: root@pts/1

13637 13639 13639 13639 pts/1    14266 Ss       0   0:00      \_ -bash

13639 14266 14266 13639 pts/1    14266 R+       0   0:00          \_ ps axjf

.....(後面省略).....

看出來了吧？其實鳥哥在進行一些測試時，都是以網路連線進主機來測試的，所以囉，你會發現其實程序之間是有相關性的啦！ 不過，其實還可以使用 pstree 來達成這個程序樹喔！以上面的例子來看，鳥哥是透過 sshd 提供的網路服務取得一個程序， 該程序提供 bash 給我使用，而我透過 bash 再去執行 ps axjf ！這樣可以看的懂了嗎？其他各欄位的意義請 man ps (雖然真的很難 man 的出來！) 囉！

範例五：找出與 cron 與 syslog 這兩個服務有關的 PID 號碼？

[root@www ~]# ps aux | egrep '(cron|syslog)'

root   4286  0.0  0.0  1720   572 ?      Ss  Mar11   0:00 syslogd -m 0

root   4661  0.0  0.1  5500  1192 ?      Ss  Mar11   0:00 crond

root  14286  0.0  0.0  4116   592 pts/1  R+  16:15   0:00 egrep (cron|syslog)

# 所以號碼是 4286 及 4661 這兩個囉！就是這樣找的啦！

除此之外，我們必須要知道的是『僵屍 (zombie) 』程序是什麼？ 通常，造成僵屍程序的成因是因為該程序應該已經執行完畢，或者是因故應該要終止了， 但是該程序的父程序卻無法完整的將該程序結束掉，而造成那個程序一直存在記憶體當中。 如果你發現在某個程序的 CMD 後面還接上 <defunct> 時，就代表該程序是僵屍程序啦，例如：

apache  8683  0.0  0.9 83384 9992 ?   Z  14:33   0:00 /usr/sbin/httpd <defunct>

當系統不穩定的時候就容易造成所謂的僵屍程序，可能是因為程式寫的不好啦，或者是使用者的操作習慣不良等等所造成。 如果你發現系統中很多僵屍程序時，記得啊！要找出該程序的父程序，然後好好的做個追蹤，好好的進行主機的環境最佳化啊！ 看看有什麼地方需要改善的，不要只是直接將他 kill 掉而已呢！不然的話，萬一他一直產生，那可就麻煩了！ @_@

事實上，通常僵屍程序都已經無法控管，而直接是交給 init 這支程式來負責了，偏偏 init 是系統第一支執行的程式， 他是所有程式的父程式！我們無法殺掉該程式的 (殺掉他，系統就死掉了！)，所以囉，如果產生僵屍程序， 而系統過一陣子還沒有辦法透過核心非經常性的特殊處理來將該程序刪除時，那你只好透過 reboot 的方式來將該程序抹去了！

- top：動態觀察程序的變化

相對於 ps 是擷取一個時間點的程序狀態， top 則可以持續偵測程序運作的狀態！使用方式如下：

[root@www ~]# top [-d 數字] | top [-bnp]

選項與參數：

-d  ：後面可以接秒數，就是整個程序畫面更新的秒數。預設是 5 秒；

-b  ：以批次的方式執行 top ，還有更多的參數可以使用喔！

通常會搭配資料流重導向來將批次的結果輸出成為檔案。

-n  ：與 -b 搭配，意義是，需要進行幾次 top 的輸出結果。

-p  ：指定某些個 PID 來進行觀察監測而已。

在 top 執行過程當中可以使用的按鍵指令：

? ：顯示在 top 當中可以輸入的按鍵指令；

P ：以 CPU 的使用資源排序顯示；

M ：以 Memory 的使用資源排序顯示；

N ：以 PID 來排序喔！

T ：由該 Process 使用的 CPU 時間累積 (TIME+) 排序。

k ：給予某個 PID 一個訊號  (signal)

r ：給予某個 PID 重新制訂一個 nice 值。

q ：離開 top 軟體的按鍵。

其實 top 的功能非常多！可以用的按鍵也非常的多！可以參考 man top 的內部說明文件！ 鳥哥這裡僅是列出一些鳥哥自己常用的選項而已。接下來讓我們實際觀察一下如何使用 top 與 top 的畫面吧！

範例一：每兩秒鐘更新一次 top ，觀察整體資訊：

[root@www ~]# top -d 2

top - 17:03:09 up 7 days, 16:16,  1 user,  load average: 0.00, 0.00, 0.00

Tasks:  80 total,   1 running,  79 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.5%us,  0.5%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:    742664k total,   681672k used,    60992k free,   125336k buffers

Swap:  1020088k total,       28k used,  1020060k free,   311156k cached

<==如果加入 k 或 r 時，就會有相關的字樣出現在這裡喔！

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

14398 root      15   0  2188 1012  816 R  0.5  0.1   0:00.05 top

1 root      15   0  2064  616  528 S  0.0  0.1   0:01.38 init

2 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0

3 root      34  19     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0

top 也是個挺不錯的程序觀察工具！但不同於 ps 是靜態的結果輸出， top 這個程式可以持續的監測整個系統的程序工作狀態。 在預設的情況下，每次更新程序資源的時間為 5 秒，不過，可以使用 -d 來進行修改。 top 主要分為兩個畫面，上面的畫面為整個系統的資源使用狀態，基本上總共有六行，顯示的內容依序是：

- 第一行(top...)：這一行顯示的資訊分別為：

- 目前的時間，亦即是 17:03:09 那個項目；

- 開機到目前為止所經過的時間，亦即是 up 7days, 16:16 那個項目；

- 已經登入系統的使用者人數，亦即是 1 user項目；

- 系統在 1, 5, 15 分鐘的平均工作負載。我們在第十六章談到的 batch 工作方式為負載小於 0.8 就是這個負載囉！代表的是 1, 5, 15 分鐘，系統平均要負責運作幾個程序(工作)的意思。 越小代表系統越閒置，若高於 1 得要注意你的系統程序是否太過繁複了！

- 第二行(Tasks...)：顯示的是目前程序的總量與個別程序在什麼狀態(running, sleeping, stopped, zombie)。 比較需要注意的是最後的 zombie 那個數值，如果不是 0 ！好好看看到底是那個 process 變成僵屍了吧？

- 第三行(Cpus...)：顯示的是 CPU 的整體負載，每個項目可使用 ? 查閱。需要特別注意的是 %wa ，那個項目代表的是 I/O wait， 通常你的系統會變慢都是 I/O 產生的問題比較大！因此這裡得要注意這個項目耗用 CPU 的資源喔！ 另外，如果是多核心的設備，可以按下數字鍵『1』來切換成不同 CPU 的負載率。

- 第四行與第五行：表示目前的實體記憶體與虛擬記憶體 (Mem/Swap) 的使用情況。 再次重申，要注意的是 swap 的使用量要盡量的少！如果 swap 被用的很大量，表示系統的實體記憶體實在不足！

- 第六行：這個是當在 top 程式當中輸入指令時，顯示狀態的地方。

至於 top 下半部分的畫面，則是每個 process 使用的資源情況。比較需要注意的是：

- PID ：每個 process 的 ID 啦！

- USER：該 process 所屬的使用者；

- PR ：Priority 的簡寫，程序的優先執行順序，越小越早被執行；

- NI ：Nice 的簡寫，與 Priority 有關，也是越小越早被執行；

- %CPU：CPU 的使用率；

- %MEM：記憶體的使用率；

- TIME+：CPU 使用時間的累加；

top 預設使用 CPU 使用率 (%CPU) 作為排序的重點，如果你想要使用記憶體使用率排序，則可以按下『M』， 若要回復則按下『P』即可。如果想要離開 top 則按下『 q 』吧！如果你想要將 top 的結果輸出成為檔案時， 可以這樣做：

範例二：將 top 的資訊進行 2 次，然後將結果輸出到 /tmp/top.txt

[root@www ~]# top -b -n 2 > /tmp/top.txt

# 這樣一來，嘿嘿！就可以將 top 的資訊存到 /tmp/top.txt 檔案中了。

這玩意兒很有趣！可以幫助你將某個時段 top 觀察到的結果存成檔案，可以用在你想要在系統背景底下執行。 由於是背景底下執行，與終端機的螢幕大小無關，因此可以得到全部的程序畫面！那如果你想要觀察的程序 CPU 與記憶體使用率都很低，結果老是無法在第一行顯示時，該怎辦？我們可以僅觀察單一程序喔！如下所示：

範例三：我們自己的 bash PID 可由 $$ 變數取得，請使用 top 持續觀察該 PID

[root@www ~]# echo $$

13639  <==就是這個數字！他是我們 bash 的 PID

[root@www ~]# top -d 2 -p 13639

top - 17:31:56 up 7 days, 16:45,  1 user,  load average: 0.00, 0.00, 0.00

Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:    742664k total,   682540k used,    60124k free,   126548k buffers

Swap:  1020088k total,       28k used,  1020060k free,   311276k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

13639 root      15   0  5148 1508 1220 S  0.0  0.2   0:00.18 bash

看到沒！就只會有一支程序給你看！很容易觀察吧！好，那麼如果我想要在 top 底下進行一些動作呢？ 比方說，修改 NI 這個數值呢？可以這樣做：

範例四：承上題，上面的 NI 值是 0 ，想要改成 10 的話？

# 在範例三的 top 畫面當中直接按下 r 之後，會出現如下的圖樣！

top - 17:34:24 up 7 days, 16:47,  1 user,  load average: 0.00, 0.00, 0.00

Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 99.5%id,  0.0%wa,  0.0%hi,  0.5%si,  0.0%st

Mem:    742664k total,   682540k used,    60124k free,   126636k buffers

Swap:  1020088k total,       28k used,  1020060k free,   311276k cached

PID to renice: 13639  <==按下 r 然後輸入這個 PID 號碼

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

13639 root      15   0  5148 1508 1220 S  0.0  0.2   0:00.18 bash

在你完成上面的動作後，在狀態列會出現如下的資訊：

Renice PID 13639 to value: 10   <==這是 nice 值

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

接下來你就會看到如下的顯示畫面！

top - 17:38:58 up 7 days, 16:52,  1 user,  load average: 0.00, 0.00, 0.00

Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:    742664k total,   682540k used,    60124k free,   126648k buffers

Swap:  1020088k total,       28k used,  1020060k free,   311276k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

13639 root      26  10  5148 1508 1220 S  0.0  0.2   0:00.18 bash

看到不同處了吧？底線的地方就是修改了之後所產生的效果！一般來說，如果鳥哥想要找出最損耗 CPU 資源的那個程序時，大多使用的就是 top 這支程式啦！然後強制以 CPU 使用資源來排序 (在 top 當中按下 P 即可)， 就可以很快的知道啦！ ^_^。多多愛用這個好用的東西喔！

- pstree

[root@www ~]# pstree [-A|U] [-up]

選項與參數：

-A  ：各程序樹之間的連接以 ASCII 字元來連接；

-U  ：各程序樹之間的連接以萬國碼的字元來連接。在某些終端介面下可能會有錯誤；

-p  ：並同時列出每個 process 的 PID；

-u  ：並同時列出每個 process 的所屬帳號名稱。

範例一：列出目前系統上面所有的程序樹的相關性：

[root@www ~]# pstree -A

init-+-acpid

|-atd

|-auditd-+-audispd---{audispd}  <==這行與底下一行為 auditd 分出來的子程序

|        `-{auditd}

|-automount---4*[{automount}]   <==預設情況下，相似的程序會以數字顯示

....(中間省略)....

|-sshd---sshd---bash---pstree   <==就是我們指令執行的那個相依性！

....(底下省略)....

# 注意一下，為了節省版面，所以鳥哥已經刪去很多程序了！

範例二：承上題，同時秀出 PID 與 users

[root@www ~]# pstree -Aup

init(1)-+-acpid(4555)

|-atd(18593)

|-auditd(4256)-+-audispd(4258)---{audispd}(4261)

|              `-{auditd}(4257)

|-automount(4536)-+-{automount}(4537) <==程序相似但 PID 不同！

|                 |-{automount}(4538)

|                 |-{automount}(4541)

|                 `-{automount}(4544)

....(中間省略)....

|-sshd(4586)---sshd(16903)---bash(16905)---pstree(16967)

....(中間省略)....

|-xfs(4692,xfs)   <==因為此程序擁有者並非執行 pstree 者！所以列出帳號

....(底下省略)....

# 在括號 () 內的即是 PID 以及該程序的 owner 喔！不過，由於我是使用

# root 的身份執行此一指令，所以屬於 root 的程序就不會顯示出來啦！

如果要找程序之間的相關性，這個 pstree 真是好用到不行！直接輸入 pstree 可以查到程序相關性，如上表所示，還會使用線段將相關性程序連結起來哩！ 一般連結符號可以使用 ASCII 碼即可，但有時因為語系問題會主動的以 Unicode 的符號來連結， 但因為可能終端機無法支援該編碼，或許會造成亂碼問題。因此可以加上 -A 選項來克服此類線段亂碼問題。

由 pstree 的輸出我們也可以很清楚的知道，所有的程序都是依附在 init 這支程序底下的！ 仔細看一下，這支程序的 PID 是一號喔！因為他是由 Linux 核心所主動呼叫的第一支程式！所以 PID 就是一號了。 這也是我們剛剛提到僵屍程序時有提到，為啥發生僵屍程序需要重新開機？ 因為 init 要重新啟動，而重新啟動 init 就是 reboot 囉！

如果還想要知道 PID 與所屬使用者，加上 -u 及 -p 兩個參數即可。我們前面不是一直提到， 如果子程序掛點或者是老是砍不掉子程序時，該如何找到父程序嗎？呵呵！用這個 pstree 就對了！ ^_^

程序的管理

程序之間是可以互相控制的！舉例來說，你可以關閉、重新啟動伺服器軟體，伺服器軟體本身是個程序， 你既然可以讓她關閉或啟動，當然就是可以控制該程序啦！那麼程序是如何互相管理的呢？其實是透過給予該程序一個訊號 (signal) 去告知該程序你想要讓她作什麼！因此這個訊號就很重要啦！

我們也在本章之前的 bash 工作管理當中提到過， 要給予某個已經存在背景中的工作某些動作時，是直接給予一個訊號給該工作號碼即可。那麼到底有多少 signal 呢？ 你可以使用 kill -l (小寫的 L ) 或者是 man 7 signal 都可以查詢到！主要的訊號代號與名稱對應及內容是：

代號

名稱

內容

1

SIGHUP

啟動被終止的程序，可讓該 PID 重新讀取自己的設定檔，類似重新啟動

2

SIGINT

相當於用鍵盤輸入 [ctrl]-c 來中斷一個程序的進行

9

SIGKILL

代表強制中斷一個程序的進行，如果該程序進行到一半， 那麼尚未完成的部分可能會有『半產品』產生，類似 vim會有 .filename.swp 保留下來。

15

SIGTERM

以正常的結束程序來終止該程序。由於是正常的終止， 所以後續的動作會將他完成。不過，如果該程序已經發生問題，就是無法使用正常的方法終止時， 輸入這個 signal 也是沒有用的。

17

SIGSTOP

相當於用鍵盤輸入 [ctrl]-z 來暫停一個程序的進行

上面僅是常見的 signal 而已，更多的訊號資訊請自行 man 7 signal 吧！一般來說，你只要記得『1, 9, 15』這三個號碼的意義即可。那麼我們如何傳送一個訊號給某個程序呢？就透過 kill 或 killall 吧！底下分別來看看：

- kill -signal PID

kill 可以幫我們將這個 signal 傳送給某個工作 (%jobnumber) 或者是某個 PID (直接輸入數字)。 要再次強調的是： kill 後面直接加數字與加上 %number 的情況是不同的！ 這個很重要喔！因為工作控制中有 1 號工作，但是 PID 1 號則是專指『 init 』這支程式！你怎麼可以將 init 關閉呢？ 關閉 init ，你的系統就當掉了啊！所以記得那個 % 是專門用在工作控制的喔！ 我們就活用一下 kill 與剛剛上面提到的 ps 來做個簡單的練習吧！

例題：

以 ps 找出 syslog 這個程序的 PID 後，再使用 kill 傳送訊息，使得 syslog 可以重新讀取設定檔。

答：

由於需要重新讀取設定檔，因此 signal 是 1 號。至於找出 syslog 的 PID 可以是這樣做：

ps aux | grep 'syslog' | grep -v 'grep'| awk '{print $2}'

接下來則是實際使用 kill -1 PID，因此，整串指令會是這樣：

kill -SIGHUP $(ps aux|grep 'syslog'|grep -v 'grep'|awk '{print $2}')

如果要確認有沒有重新啟動 syslog ，可以參考登錄檔的內容，使用如下指令查閱：

tail -5 /var/log/messages

如果你有看到類似『Mar 19 15:08:20 www syslogd 1.4.1: restart』之類的字樣，就是表示 syslogd 在 3/19 有重新啟動 (restart) 過了！

瞭解了這個用法以後，如果未來你想要將某個莫名其妙的登入者的連線刪除的話，就可以透過使用 pstree -p 找到相關程序， 然後再以 kill -9 將該程序刪除，該條連線就會被踢掉了！這樣很簡單吧！

- killall -signal 指令名稱

由於 kill 後面必須要加上 PID (或者是 job number)，所以，通常 kill 都會配合 ps, pstree 等指令，因為我們必須要找到相對應的那個程序的 ID 嘛！但是，如此一來，很麻煩∼有沒有可以利用『下達指令的名稱』來給予訊號的？舉例來說，能不能直接將 syslog 這個程序給予一個 SIGHUP 的訊號呢？可以的！用 killall 吧！

[root@www ~]# killall [-iIe] [command name]

選項與參數：

-i  ：interactive 的意思，互動式的，若需要刪除時，會出現提示字元給使用者；

-e  ：exact 的意思，表示『後面接的 command name 要一致』，但整個完整的指令

不能超過 15 個字元。

-I  ：指令名稱(可能含參數)忽略大小寫。

範例一：給予 syslogd 這個指令啟動的 PID 一個 SIGHUP 的訊號

[root@www ~]# killall -1 syslogd

# 如果用 ps aux 仔細看一下，syslogd 才是完整的指令名稱。但若包含整個參數，

# 則 syslogd -m 0 才是完整的呢！

範例二：強制終止所有以 httpd 啟動的程序

[root@www ~]# killall -9 httpd

範例三：依次詢問每個 bash 程式是否需要被終止運作！

[root@www ~]# killall -i -9 bash

Kill bash(16905) ? (y/N) n <==這個不殺！

Kill bash(17351) ? (y/N) y <==這個殺掉！

# 具有互動的功能！可以詢問你是否要刪除 bash 這個程式。要注意，若沒有 -i 的參數，

# 所有的 bash 都會被這個 root 給殺掉！包括 root 自己的 bash 喔！ ^_^

總之，要刪除某個程序，我們可以使用 PID 或者是啟動該程序的指令名稱， 而如果要刪除某個服務呢？呵呵！最簡單的方法就是利用 killall ， 因為他可以將系統當中所有以某個指令名稱啟動的程序全部刪除。 舉例來說，上面的範例二當中，系統內所有以 httpd 啟動的程序，就會通通的被刪除啦！ ^_^

關於程序的執行順序

我們知道 Linux 是多人多工的環境，由 top 的輸出結果我們也發現， 系統同時間有非常多的程序在運行中，只是絕大部分的程序都在休眠 (sleeping) 狀態而已。 想一想，如果所有的程序同時被喚醒，那麼 CPU 應該要先處理那個程序呢？也就是說，那個程序被執行的優先序比較高？ 這就得要考慮到程序的優先執行序 (Priority) 與 CPU 排程囉！

Tips:

CPU 排程與前一章的例行性工作排程並不一樣。 CPU 排程指的是每支程序被 CPU 運作的演算規則， 而例行性工作排程則是將某支程式安排在某個時間再交由系統執行。 CPU 排程與作業系統較具有相關性！

- Priority 與 Nice 值

我們知道 CPU 一秒鐘可以運作多達數 G 的微指令次數，透過核心的 CPU 排程可以讓各程序被 CPU 所切換運作， 因此每個程序在一秒鐘內或多或少都會被 CPU 執行部分的指令碼。如果程序都是集中在一個佇列中等待 CPU 的運作， 而不具有優先順序之分，也就是像我們去遊樂場玩熱門遊戲需要排隊一樣，每個人都是照順序來！ 你玩過一遍後還想再玩 (沒有執行完畢)，請到後面繼續排隊等待。情況有點像底下這樣：

圖 3.3.1、並沒有優先順序的程序佇列示意圖

上圖中假設 pro1, pro2 是緊急的程序， pro3, pro4 是一般的程序，在這樣的環境中，由於不具有優先順序， 唉啊！pro1, pro2 還是得要繼續等待而沒有優待呢！如果 pro3, pro4 的工作又臭又長！那麼緊急的 pro1, pro2 就得要等待個老半天才能夠完成！真麻煩啊！所以囉，我們想要將程序分優先順序啦！如果優先序較高則運作次數可以較多次， 而不需要與較慢優先的程序搶位置！我們可以將程序的優先順序與 CPU 排程進行如下圖的解釋：

圖 3.3.2、具有優先順序的程序佇列示意圖

如上圖所示，具高優先權的 pro1, pro2 可以被取用兩次，而較不重要的 pro3, pro4 則運作次數較少。 如此一來 pro1, pro2 就可以較快被完成啦！要注意，上圖僅是示意圖，並非較優先者一定會被運作兩次啦！ 為了要達到上述的功能，我們 Linux 給予程序一個所謂的『優先執行序 (priority, PRI)』， 這個 PRI 值越低代表越優先的意思。不過這個 PRI 值是由核心動態調整的， 使用者無法直接調整 PRI 值的。先來瞧瞧 PRI 曾在哪裡出現？

[root@www ~]# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 18625 18623  2  75   0 -  1514 wait   pts/1    00:00:00 bash

4 R     0 18653 18625  0  77   0 -  1102 -      pts/1    00:00:00 ps

由於 PRI 是核心動態調整的，我們使用者也無權去干涉 PRI ！那如果你想要調整程序的優先執行序時，就得要透過 Nice 值了！Nice 值就是上表的 NI 啦！一般來說， PRI 與 NI 的相關性如下：

PRI(new) = PRI(old) + nice

不過你要特別留意到，如果原本的 PRI 是 50 ，並不是我們給予一個 nice = 5 ，就會讓 PRI 變成 55 喔！ 因為 PRI 是系統『動態』決定的，所以，雖然 nice 值是可以影響 PRI ，不過， 最終的 PRI 仍是要經過系統分析後才會決定的。另外， nice 值是有正負的喔，而既然 PRI 越小越早被執行， 所以，當 nice 值為負值時，那麼該程序就會降低 PRI 值，亦即會變的較優先被處理。此外，你必須要留意到：

- nice 值可調整的範圍為 -20 ~ 19 ；

- root 可隨意調整自己或他人程序的 Nice 值，且範圍為 -20 ~ 19 ；

- 一般使用者僅可調整自己程序的 Nice 值，且範圍僅為 0 ~ 19 (避免一般用戶搶佔系統資源)；

- 一般使用者僅可將 nice 值越調越高，例如本來 nice 為 5 ，則未來僅能調整到大於 5；

這也就是說，要調整某個程序的優先執行序，就是『調整該程序的 nice 值』啦！那麼如何給予某個程序 nice 值呢？有兩種方式，分別是：

- 一開始執行程式就立即給予一個特定的 nice 值：用 nice 指令；

- 調整某個已經存在的 PID 的 nice 值：用 renice 指令。

- nice ：新執行的指令即給予新的 nice 值

[root@www ~]# nice [-n 數字] command

選項與參數：

-n  ：後面接一個數值，數值的範圍 -20 ~ 19。

範例一：用 root 給一個 nice 值為 -5 ，用於執行 vi ，並觀察該程序！

[root@www ~]# nice -n -5 vi &

[1] 18676

[root@www ~]# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 18625 18623  0  75   0 -  1514 wait   pts/1    00:00:00 bash

4 T     0 18676 18625  0  72  -5 -  1242 finish pts/1    00:00:00 vi

4 R     0 18678 18625  0  77   0 -  1101 -      pts/1    00:00:00 ps

# 原本的 bash PRI 為 75  ，所以 vi 預設應為 75。不過由於給予 nice  為 -5 ，

# 因此 vi 的 PRI 降低了！但並非降低到 70 ，因為核心還會動態調整！

[root@www ~]# kill -9 %1 <==測試完畢將 vi 關閉

就如同前面說的， nice 是用來調整程序的執行優先順序！這裡只是一個執行的範例罷了！ 通常什麼時候要將 nice 值調大呢？舉例來說，系統的背景工作中， 某些比較不重要的程序之進行：例如備份工作！由於備份工作相當的耗系統資源， 這個時候就可以將備份的指令之 nice 值調大一些，可以使系統的資源分配的更為公平！

- renice ：已存在程序的 nice 重新調整

[root@www ~]# renice [number] PID

選項與參數：

PID ：某個程序的 ID 啊！

範例一：找出自己的 bash PID ，並將該 PID 的 nice 調整到 10

[root@www ~]# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 18625 18623  0  75   0 -  1514 wait   pts/1    00:00:00 bash

4 R     0 18712 18625  0  77   0 -  1102 -      pts/1    00:00:00 ps

[root@www ~]# renice 10 18625

18625: old priority 0, new priority 10

[root@www ~]# ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 S     0 18625 18623  0  85  10 -  1514 wait   pts/1    00:00:00 bash

4 R     0 18715 18625  0  87  10 -  1102 -      pts/1    00:00:00 ps

如果要調整的是已經存在的某個程序的話，那麼就得要使用 renice 了。使用的方法很簡單， renice 後面接上數值及 PID 即可。因為後面接的是 PID ，所以你務必要以 ps 或者其他程序觀察的指令去找出 PID 才行啊！

由上面這個範例當中我們也看的出來，雖然修改的是 bash 那個程序，但是該程序所觸發的 ps 指令當中的 nice 也會繼承而為 10 喔！瞭解了吧！整個 nice 值是可以在父程序 --> 子程序之間傳遞的呢！ 另外，除了 renice 之外，其實那個 top 同樣的也是可以調整 nice 值的！

系統資源的觀察

除了系統的程序之外，我們還必須就系統的一些資源進行檢查啊！舉例來說，我們使用 top 可以看到很多系統的資源對吧！那麼，還有沒有其他的工具可以查閱的？ 當然有啊！底下這些工具指令可以玩一玩！

- free ：觀察記憶體使用情況

[root@www ~]# free [-b|-k|-m|-g] [-t]

選項與參數：

-b  ：直接輸入 free 時，顯示的單位是 Kbytes，我們可以使用 b(bytes), m(Mbytes)

k(Kbytes), 及 g(Gbytes) 來顯示單位喔！

-t  ：在輸出的最終結果，顯示實體記憶體與 swap 的總量。

範例一：顯示目前系統的記憶體容量

[root@www ~]# free -m

total       used    free   shared   buffers    cached

Mem:        725        666      59        0       132       287

-/+ buffers/cache:     245     479

Swap:       996          0     996

仔細看看，我的系統當中有 725MB 左右的實體記憶體，我的 swap 有 1GB 左右， 那我使用 free -m 以 MBytes 來顯示時，就會出現上面的資訊。Mem 那一行顯示的是實體記憶體的量， Swap 則是虛擬記憶體的量。 total 是總量， used 是已被使用的量， free 則是剩餘可用的量。 後面的 shared/buffers/cached 則是在已被使用的量當中，用來作為緩衝及快取的量。

仔細的看到範例一的輸出喔，我們的 Linux 測試用主機是很平凡的，根本沒有什麼工作， 但是，我的實體記憶體是幾乎被用光光的情況呢！不過，至少有 132MB 用在緩衝記憶 (buffers) 工作， 287MB 則用在快取 (cached) 工作，也就是說，系統是『很有效率的將所有的記憶體用光光』， 目的是為了讓系統的存取效能加速啦！

很多朋友都會問到這個問題『我的系統明明很輕鬆，為何記憶體會被用光光？』現在瞭了吧？ 被用光是正常的！而需要注意的反而是 swap 的量。一般來說， swap 最好不要被使用，尤其 swap 最好不要被使用超過 20% 以上， 如果您發現 swap 的用量超過 20% ，那麼，最好還是買實體記憶體來插吧！ 因為， Swap 的效能跟實體記憶體實在差很多，而系統會使用到 swap ， 絕對是因為實體記憶體不足了才會這樣做的！如此，瞭解吧！

Tips:

Linux 系統為了要加速系統效能，所以會將最常使用到的或者是最近使用到的檔案資料快取 (cache) 下來， 這樣未來系統要使用該檔案時，就直接由記憶體中搜尋取出，而不需要重新讀取硬碟，速度上面當然就加快了！ 因此，實體記憶體被用光是正常的喔！

- uname：查閱系統與核心相關資訊

[root@www ~]# uname [-asrmpi]

選項與參數：

-a  ：所有系統相關的資訊，包括底下的資料都會被列出來；

-s  ：系統核心名稱

-r  ：核心的版本

-m  ：本系統的硬體名稱，例如 i686 或 x86_64 等；

-p  ：CPU 的類型，與 -m 類似，只是顯示的是 CPU 的類型！

-i  ：硬體的平台 (ix86)

範例一：輸出系統的基本資訊

[root@www ~]# uname -a

Linux www.vbird.tsai 2.6.18-92.el5 #1 SMP Tue Jun 10 18:49:47 EDT 2008 i686

i686 i386 GNU/Linux

這個咚咚我們前面使用過很多次了喔！uname 可以列出目前系統的核心版本、 主要硬體平台以及 CPU 類型等等的資訊。以上面範例一的狀態來說，我的 Linux 主機使用的核心名稱為 Linux，而主機名稱為 www.vbird.tsai，核心的版本為 2.6.18-92.el5 ，該核心版本建立的日期為 2008/6/10，適用的硬體平台為 i386 以上等級的硬體平台喔。

- uptime：觀察系統啟動時間與工作負載

這個指令很單純呢！就是顯示出目前系統已經開機多久的時間，以及 1, 5, 15 分鐘的平均負載就是了。還記得 top 吧？沒錯啦！這個 uptime 可以顯示出 top 畫面的最上面一行！

[root@www ~]# uptime

15:39:13 up 8 days, 14:52,  1 user,  load average: 0.00, 0.00, 0.00

# top 這個指令已經談過相關資訊，不再聊！

- netstat ：追蹤網路或插槽檔

這個 netstat 也是挺好玩的，其實這個指令比較常被用在網路的監控方面，不過，在程序管理方面也是需要瞭解的啦！ 這個指令的執行如下所示：基本上， netstat 的輸出分為兩大部分，分別是網路與系統自己的程序相關性部分：

[root@www ~]# netstat -[atunlp]

選項與參數：

-a  ：將目前系統上所有的連線、監聽、Socket 資料都列出來

-t  ：列出 tcp 網路封包的資料

-u  ：列出 udp 網路封包的資料

-n  ：不以程序的服務名稱，以埠號 (port number) 來顯示；

-l  ：列出目前正在網路監聽 (listen) 的服務；

-p  ：列出該網路服務的程序 PID

範例一：列出目前系統已經建立的網路連線與 unix socket 狀態

[root@www ~]# netstat

Active Internet connections (w/o servers) <==與網路較相關的部分

Proto Recv-Q Send-Q Local Address        Foreign Address      State

tcp        0    132 192.168.201.110:ssh  192.168.:vrtl-vmf-sa ESTABLISHED

Active UNIX domain sockets (w/o servers)  <==與本機的程序自己的相關性(非網路)

Proto RefCnt Flags       Type       State         I-Node Path

unix  20     [ ]         DGRAM                    9153   /dev/log

unix  3      [ ]         STREAM     CONNECTED     13317  /tmp/.X11-unix/X0

unix  3      [ ]         STREAM     CONNECTED     13233  /tmp/.X11-unix/X0

unix  3      [ ]         STREAM     CONNECTED     13208  /tmp/.font-unix/fs7100

....(中間省略)....

在上面的結果當中，顯示了兩個部分，分別是網路的連線以及 linux 上面的 socket 程序相關性部分。 我們先來看看網際網路連線情況的部分：

- Proto ：網路的封包協定，主要分為 TCP 與 UDP 封包，相關資料請參考伺服器篇；

- Recv-Q：非由使用者程式連結到此 socket 的複製的總 bytes 數；

- Send-Q：非由遠端主機傳送過來的 acknowledged 總 bytes 數；

- Local Address ：本地端的 IP:port 情況

- Foreign Address：遠端主機的 IP:port 情況

- State ：連線狀態，主要有建立(ESTABLISED)及監聽(LISTEN)；

我們看上面僅有一條連線的資料，他的意義是：『透過 TCP 封包的連線，遠端的 192.168.:vrtl.. 連線到本地端的 192.168.201.110:ssh ，這條連線狀態是建立 (ESTABLISHED) 的狀態！』至於更多的網路環境說明， 就得到鳥哥的另一本伺服器篇查閱囉！

除了網路上的連線之外，其實 Linux 系統上面的程序是可以接收不同程序所發送來的資訊，那就是 Linux 上頭的插槽檔 (socket file)。我們在第六章的檔案種類有稍微提到 socket 檔案， 但當時未談到程序的概念，所以沒有深入談論。socket file 可以溝通兩個程序之間的資訊，因此程序可以取得對方傳送過來的資料。 由於有 socket file，因此類似 X Window 這種需要透過網路連接的軟體，目前新版的 distributions 就以 socket 來進行視窗介面的連線溝通了。上表中 socket file 的輸出欄位有：

- Proto ：一般就是 unix 啦；

- RefCnt：連接到此 socket 的程序數量；

- Flags ：連線的旗標；

- Type ：socket 存取的類型。主要有確認連線的 STREAM 與不需確認的 DGRAM 兩種；

- State ：若為 CONNECTED 表示多個程序之間已經連線建立。

- Path ：連接到此 socket 的相關程式的路徑！或者是相關資料輸出的路徑。

以上表的輸出為例，最後那三行在 /tmp/.xx 底下的資料，就是 X Window 視窗介面的相關程序啦！ 而 PATH 指向的就是這些程序要交換資料的插槽檔案囉！好！那麼 netstat 可以幫我們進行什麼任務呢？ 很多喔！我們先來看看，利用 netstat 去看看我們的哪些程序有啟動哪些網路的『後門』呢？

範例二：找出目前系統上已在監聽的網路連線及其 PID

[root@www ~]# netstat -tlnp

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address    Foreign Address  State   PID/Program name

tcp        0      0 127.0.0.1:2208   0.0.0.0:*        LISTEN  4566/hpiod

tcp        0      0 0.0.0.0:111      0.0.0.0:*        LISTEN  4328/portmap

tcp        0      0 127.0.0.1:631    0.0.0.0:*        LISTEN  4597/cupsd

tcp        0      0 0.0.0.0:728      0.0.0.0:*        LISTEN  4362/rpc.statd

tcp        0      0 127.0.0.1:25     0.0.0.0:*        LISTEN  4629/sendmail:

tcp        0      0 127.0.0.1:2207   0.0.0.0:*        LISTEN  4571/python

tcp        0      0 :::22            :::*             LISTEN  4586/sshd

# 除了可以列出監聽網路的介面與狀態之外，最後一個欄位還能夠顯示此服務的

# PID 號碼以及程序的指令名稱喔！例如最後一行的 4586 就是該 PID

範例三：將上述的本地端 127.0.0.1:631 那個網路服務關閉的話？

[root@www ~]# kill -9 4597

[root@www ~]# killall -9 cupsd

很多朋友常常有疑問，那就是，我的主機目前到底開了幾個門(ports)！其實，不論主機提供什麼樣的服務， 一定必須要有相對應的 program 在主機上面執行才行啊！舉例來說，我們鳥園的 Linux 主機提供的就是 WWW 服務，那麼我的主機當然有一個程式在提供 WWW 的服務啊！那就是 Apache 這個軟體所提供的啦！ ^_^。 所以，當我執行了這個程式之後，我的系統自然就可以提供 WWW 的服務了。那如何關閉啊？ 就關掉該程式所觸發的那個程序就好了！例如上面的範例三所提供的例子啊！ ^_^

- dmesg ：分析核心產生的訊息

系統在開機的時候，核心會去偵測系統的硬體，你的某些硬體到底有沒有被捉到，那就與這個時候的偵測有關。 但是這些偵測的過程要不是沒有顯示在螢幕上，就是很飛快的在螢幕上一閃而逝！能不能把核心偵測的訊息捉出來瞧瞧？ 可以的，那就使用 dmesg 吧！

所有核心偵測的訊息，不管是開機時候還是系統運作過程中，反正只要是核心產生的訊息，都會被記錄到記憶體中的某個保護區段。 dmesg 這個指令就能夠將該區段的訊息讀出來的！因為訊息實在太多了，所以執行時可以加入這個管線指令『 | more 』來使畫面暫停！

範例一：輸出所有的核心開機時的資訊

[root@www ~]# dmesg | more

範例二：搜尋開機的時候，硬碟的相關資訊為何？

[root@www ~]# dmesg | grep -i hd

ide0: BM-DMA at 0xd800-0xd807, BIOS settings: hda:DMA, hdb:DMA

ide1: BM-DMA at 0xd808-0xd80f, BIOS settings: hdc:pio, hdd:pio

hda: IC35L040AVER07-0, ATA DISK drive

hdb: ASUS DRW-2014S1, ATAPI CD/DVD-ROM drive

hda: max request size: 128KiB

....(底下省略)....

由範例二就知道我這部主機的硬碟的格式是什麼了吧！沒錯啦！還可以查閱能不能找到網路卡喔！網路卡的代號是 eth ，所以，直接輸入 dmesg | grep -i eth 試看看呢！

- vmstat ：偵測系統資源變化

如果你想要動態的瞭解一下系統資源的運作，那麼這個 vmstat 確實可以玩一玩！vmstat 可以偵測『 CPU / 記憶體 / 磁碟輸入輸出狀態 』等等，如果你想要瞭解一部繁忙的系統到底是哪個環節最累人， 可以使用 vmstat 分析看看。底下是常見的選項與參數說明：

[root@www ~]# vmstat [-a] [延遲 [總計偵測次數]] <==CPU/記憶體等資訊

[root@www ~]# vmstat [-fs]                      <==記憶體相關

[root@www ~]# vmstat [-S 單位]                  <==設定顯示數據的單位

[root@www ~]# vmstat [-d]                       <==與磁碟有關

[root@www ~]# vmstat [-p 分割槽]                <==與磁碟有關

選項與參數：

-a  ：使用 inactive/active(活躍與否) 取代 buffer/cache 的記憶體輸出資訊；

-f  ：開機到目前為止，系統複製 (fork) 的程序數；

-s  ：將一些事件 (開機至目前為止) 導致的記憶體變化情況列表說明；

-S  ：後面可以接單位，讓顯示的資料有單位。例如 K/M 取代 bytes 的容量；

-d  ：列出磁碟的讀寫總量統計表

-p  ：後面列出分割槽，可顯示該分割槽的讀寫總量統計表

範例一：統計目前主機 CPU 狀態，每秒一次，共計三次！

[root@www ~]# vmstat 1 3

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------

r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

0  0     28  61540 137000 291960    0    0     4     5   38   55  0  0 100  0  0

0  0     28  61540 137000 291960    0    0     0     0 1004   50  0  0 100  0  0

0  0     28  61540 137000 291964    0    0     0     0 1022   65  0  0 100  0  0

利用 vmstat 甚至可以進行追蹤喔！你可以使用類似『 vmstat 5 』代表每五秒鐘更新一次，且無窮的更新！直到你按下 [ctrl]-c 為止。如果你想要即時的知道系統資源的運作狀態，這個指令就不能不知道！那麼上面的表格各項欄位的意義為何？ 基本說明如下：

第十八章、認識系統服務 (daemons)

切換解析度為 800x600

最近更新日期：2009/09/14

在 Unix-Like 的系統中，你會常常聽到 daemon 這個字眼！那麼什麼是傳說中的 daemon 呢？這些 daemon 放在什麼地方？他的功能是什麼？該如何啟動這些 daemon ？又如何有效的將這些 daemon 管理妥當？此外，要如何視察這些 daemon 開了多少個 ports ？又這些 ports 要如何關閉？還有還有，曉得你系統的這些 port 各代表的是什麼服務嗎？ 這些都是最基礎需要注意的呢！尤其是在架設網站之前，這裡的觀念就顯的更重要了。

1. 什麼是 daemon 與服務 (service)

1.1 daemon 的主要分類： stand alone, super daemon, 工作形態, 命名規則

1.2 服務與埠口的對應： /etc/services

1.3 daemon 的啟動腳本與啟動方式： 設定檔, stand alone, service, super daemon

2. 解析 super daemon 的設定檔

2.1 預設值設定檔：xinetd.conf： 重要參數說明

2.2 一個簡單的 rsync 範例設定

3. 服務的防火牆管理 xinetd, TCP Wrappers

3.1 /etc/hosts.allow, /etc/hosts.deny 管理： ldd, 設定檔語法

3.2 TCP Wrappers 特殊功能

4. 系統開啟的服務

4.1 觀察系統啟動的服務

4.2 設定開機後立即啟動服務的方法： chkconfig, ntsysv

4.3 CentOS 5.x 預設啟動的服務簡易說明

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23894

什麼是 daemon 與服務 (service)

我們在第十七章就曾經談過『服務』這東西！ 當時的說明是『常駐在記體體中的程序，且可以提供一些系統或網路功能，那就是服務』。而服務一般的英文說法是『 service 』。

但如果你常常上網去查看一些資料的話，尤其是 Unix-Like 的相關作業系統，應該常常看到『請啟動某某 daemon 來提供某某功能』，唔！那麼 daemon 與 service 有關囉？否則為什麼都能夠提供某些系統或網路功能？此外，這個 daemon 是什麼東西呀？ daemon 的字面上的意思就是『守護神、惡魔？』還真是有點奇怪呦！^_^""！

簡單的說，系統為了某些功能必須要提供一些服務 (不論是系統本身還是網路方面)，這個服務就稱為 service 。 但是 service 的提供總是需要程式的運作吧！否則如何執行呢？所以達成這個 service 的程式我們就稱呼他為 daemon 囉！ 舉例來說，達成循環型例行性工作排程服務 (service) 的程式為 crond 這個 daemon 啦！這樣說比較容易理解了吧！

Tips:

你不必去區分什麼是 daemon 與 service ！事實上，你可以將這兩者視為相同！因為達成某個服務是需要一支 daemon 在背景中運作， 沒有這支 daemon 就不會有 service ！所以不需要分的太清楚啦！

一般來說，當我們以文字模式或圖形模式 (非單人維護模式) 完整開機進入 Linux 主機後， 系統已經提供我們很多的服務了！包括列印服務、工作排程服務、郵件管理服務等等； 那麼這些服務是如何被啟動的？他們的工作型態如何？底下我們就來談一談囉！

daemon 的主要分類

如果依據 daemon 的啟動與管理方式來區分，基本上，可以將 daemon 分為可獨立啟動的 stand alone ， 與透過一支 super daemon 來統一管理的服務這兩大類，這兩類 daemon 的說明如下：

- stand_alone：此 daemon 可以自行單獨啟動服務

就字面上的意思來說，stand alone 就是『獨立的啟動』的意思。這種類型的 daemon 可以自行啟動而不必透過其他機制的管理； daemon 啟動並載入到記憶體後就一直佔用記憶體與系統資源。最大的優點就是：因為是一直存在記憶體內持續的提供服務， 因此對於發生用戶端的要求時，stand alone 的 daemon 回應速度較快。常見的 stand alone daemon 有 WWW 的 daemon (httpd)、FTP 的 daemon (vsftpd) 等等。

- super daemon： 一支特殊的 daemon 來統一管理

這一種服務的啟動方式則是藉由一個統一的 daemon 來負責喚起服務！這個特殊的 daemon 就被稱為 super daemon 。 早期的 super daemon 是 inetd 這一個，後來則被 xinetd 所取代了。這種機制比較有趣的地方在於， 當沒有用戶端的要求時，各項服務都是未啟動的情況，等到有來自用戶端的要求時， super daemon 才喚醒相對應的服務。當用戶端的要求結束後，被喚醒的這個服務也會關閉並釋放系統資源。

這種機制的好處是： (1)由於 super daemon 負責喚醒各項服務，因此 super daemon 可以具有安全控管的機制，就是類似網路防火牆的功能啦！ (2)由於服務在用戶端的連線結束後就關閉，因此不會一直佔用系統資源。但是缺點是什麼呢？ 因為有用戶端的連線才會喚醒該服務，而該服務載入到記憶體的時間需要考慮進去，因此服務的反應時間會比較慢一些啦！ 常見的 super daemon 所管理的服務例如 telnet 這個玩意兒就是啦！

圖 1.1.1、Super daemon 的運作示意圖

如上所示，Super daemon 是常駐在記憶體中的， Program 1, 2, 3 則是啟動某些服務的程式 (未被啟動狀態)。當有用戶端的要求時， Super daemon 才會去觸發相關的程式載入成為 daemon 而存在於記憶體中，此時，用戶端的要求才會被 Super daemon 導向 Daemon 1 去達成連線！當用戶端的要求結束時，Daemon 1 將會被移除，圖中實線的連線就會中斷囉！

- 窗口類型的解說

那麼這兩種啟動的方式哪一個比較好呢？見仁見智啦！而且還要看該主機的工作負荷與實際的用途說！ 例如當你的主機是用來作為 WWW 伺服器的，那麼 httpd 自然就以 stand alone 的啟動方式較佳！事實上，我們常常開玩笑的說明 stand alone 與 super daemon 的情況，可以銀行的窗口來作為說明的範例喔！

- 個別窗口負責單一服務的 stand alone：

在銀行裡面，假設有一種單一服務的窗口，例如存錢窗口，所以當你需要存錢的時候，直接前往該窗口，就有『專人』為你服務啦！ 這就是 stand alone 的情況。

- 統一窗口負責各種業務的 super daemon：

在銀行裡面假設還有另外一種複合型態的統一窗口，同時提供轉帳、資金調度、提款等等的業務，那當你需要其中一項業務的時候， 就需要前往該窗口。但是坐在窗口的這個營業員，拿到你的需求單之後，往後面一丟『喂！那個轉帳的仁兄！該你的工作了』 那麼那個仁兄就開始工作去！然而裡頭還有資金調度與提款等負責業務的仁兄呢？他們在幹嘛？嘿嘿！看看報、喝喝茶囉！

那麼這裡就會引出另外一個問題啦！假設銀行今天的人潮特別的洶湧，所以這個窗口後面除了你之外還有很多的人！ 那麼想一想，這個窗口是要『一個完成再來下一個』還是『全部都把你們的單據拿來，我全部處理掉』呢？呵呵！ 是不是不太一樣？基本上，針對這種 super daemon 的處理模式有兩種，分別是這樣：

- multi-threaded (多重執行緒)：

就是我們提到的，全部的客戶之要求都給他拿來，一次給他交辦下去，所以一個服務同時會負責好幾個程序。

- single-threaded (單一執行緒)：

這個就是目前我們『人類的銀行』最常見的方式啦，不論如何，反正一個一個來，第一個沒有處理完之前，後面的請排隊！嘿嘿！ 所以如果 client 的要求突然大增的話，那麼這些晚到的 client 可得等上一等！

圖 1.1.2、單執行與多重執行的 super daemon 運作方式

如上所示，左側為多重執行的方式， daemon 會一直被觸發多支程序來提供不同 client 的服務，所以不論你是第幾個登入者， 都可以享用 daemon 的服務。至於右側則是單一執行的方式，僅會有一支 daemon 被喚醒，第一個用戶達成連線後， 後續想要連線的用戶就得要等待，因此她們的連線不會成功的。

另外，需要注意的是，既然銀行裡頭有這兩種窗口同時存在，所以囉，在 Linux 系統裡面，這兩種 daemon 的啟動方式也是可以同時存在的啦！也就是說，某些服務可以使用 stand alone 來啟動，而有些其他的服務則可以使用 xinetd 這個 super daemon 來管理，大致的情況就是這樣啦！瞭乎！

- daemon 工作形態的類型

如果以 daemon 提供服務的的工作狀態來區分，又可以將 daemon 分為兩大類，分別是：

- signal-control

這種 daemon 是透過訊號來管理的，只要有任何用戶端的需求進來，他就會立即啟動去處理！例如印表機的服務 (cupsd)。

- interval-control

這種 daemon 則主要是『每隔一段時間就主動的去執行某項工作』，所以，你要作的是在設定檔指定服務要進行的時間與工作， 該服務在指定的時間才會去完成工作。我們在第十六章提到的 atd 與 crond 就屬於這種類型的 daemon 啦 (每分鐘偵測一次設定檔)

另外，如果你對於開發程式很有興趣的話，那麼可以自行查閱一下『 man 3 daemon 』看看系統對於 daemon 的詳細說明吧！ ^_^。

- daemon 的命名規則

每一個服務的開發者，當初在開發他們的服務時，都有特別的故事啦！不過，無論如何，這些服務的名稱被建立之後，被掛上 Linux 使用時，通常在服務的名稱之後會加上一個 d ，例如例行性命令的建立的 at, 與 cron 這兩個服務， 他的程式檔名會被取為 atd 與 crond，這個 d 代表的就是 daemon 的意思。所以，在第十七章中，我們使用了 ps 與 top 來觀察程序時，都會發現到很多的 {xxx}d 的程序，呵呵！通常那就是一些 daemon 的程序囉！

服務與埠口的對應

從第十七章與前一小節對服務的說明後，你應該要知道的是， 系統所有的功能都是某些程序所提供的，而程序則是透過觸發程式而產生的。同樣的，系統提供的網路服務當然也是這樣的！ 只是由於網路牽涉到 TCP/IP 的概念，所以顯的比較複雜一些就是了。

玩過網際網路 (Internet) 的朋友應該知道 IP 這玩意兒，大家都說 IP 就是代表你的主機在網際網路上面的『門牌號碼』。 但是你的主機總是可以提供非常多的網路服務而不止一項功能而已，但我們僅有一個 IP 呢！當用戶端連線過來我們的主機時， 我們主機是如何分辨不同的服務要求呢？那就是透過埠號 (port number) 啦！埠號簡單的想像，他就是你家門牌上面的第幾層樓！ 這個 IP 與 port 就是網際網路連線的最重要機制之一囉。我們拿底下的網址來說明：

- http://ftp.isu.edu.tw/

- ftp://ftp.isu.edu.tw/

有沒有發現，兩個網址都是指向 ftp.isu.edu.tw 這個義守大學的 FTP 網站，但是瀏覽器上面顯示的結果卻是不一樣的？ 是啊！這是因為我們指向不同的服務嘛！一個是 http 這個 WWW 的服務，一個則是 ftp 這個檔案傳輸服務，當然顯示的結果就不同了。

圖 1.2.1、 port 與 daemon 的對應，用戶端連線協定不同，服務導向埠號亦不同

事實上，為了統一整個網際網路的埠號對應服務的功能，好讓所有的主機都能夠使用相同的機制來提供服務與要求服務， 所以就有了『通訊協定』這玩意兒。也就是說，有些約定俗成的服務都放置在同一個埠號上面啦！舉例來說， 網址列上面的 http 會讓瀏覽器向 WWW 伺服器的 80 埠號進行連線的要求！而 WWW 伺服器也會將 httpd 這個軟體啟動在 port 80， 這樣兩者才能夠達成連線的！

嗯！那麼想一想，系統上面有沒有什麼設定可以讓服務與埠號對應在一起呢？那就是 /etc/services 啦！

[root@www ~]# cat /etc/services

....(前面省略)....

ftp             21/tcp

ftp             21/udp          fsp fspd

ssh             22/tcp                          # SSH Remote Login Protocol

ssh             22/udp                          # SSH Remote Login Protocol

....(中間省略)....

http            80/tcp          www www-http    # WorldWideWeb HTTP

http            80/udp          www www-http    # HyperText Transfer Protocol

....(底下省略)....

# 這個檔案的內容是以底下的方式來編排的：

# <daemon name>   <port/封包協定>   <該服務的說明>

像上面說的是，第一欄為 daemon 的名稱、第二欄為該 daemon 所使用的埠號與網路資料封包協定， 封包協定主要為可靠連線的 TCP 封包以及較快速但為非連線導向的 UDP 封包。 舉個例子說，那個遠端連線機制使用的是 ssh 這個服務，而這個服務的使用的埠號為 22 ！就是這樣啊！

Tips:

請特別注意！雖然有的時候你可以藉由修改 /etc/services 來更改一個服務的埠號，不過並不建議如此做， 因為很有可能會造成一些協定的錯誤情況！這裡特此說明一番呦！(除非你要架設一個地下網站，否則的話，使用 /etc/services 原先的設定就好啦！)

daemon 的啟動腳本與啟動方式

提供某個服務的 daemon 雖然只是一支程式而已，但是這支 daemon 的啟動還是需要執行檔、設定檔、執行環境等等， 舉例來說，你可以查閱一下 httpd 這個程式 (man httpd) ，裡面可談到不少的選項與參數呢！此外，為了管理上面的方便， 所以通常 distribution 都會記錄每一支 daemon 啟動後所取得程序的 PID 在 /var/run/ 這個目錄下呢！ 還有還有，在啟動這些服務之前，你可能也要自行處理一下 daemon 能夠順利執行的環境是否正確等等。鳥哥這裡要講的是， 要啟動一支 daemon 考慮的事情很多，並非單純執行一支程式就夠了。

為了解決上面談到的問題，因此通常 distribution 會給我們一個簡單的 shell script 來進行啟動的功能。 該 script 可以進行環境的偵測、設定檔的分析、PID 檔案的放置，以及相關重要交換檔案的鎖住 (lock) 動作， 你只要執行該 script ，上述的動作就一口氣連續的進行，最終就能夠順利且簡單的啟動這個 daemon 囉！ 這也是為何我們會希望你可以詳細的研究一下第十三章的原因啊。

OK！那麼這些 daemon 的啟動腳本 (shell script) 放在哪裡啊？還有， CentOS 5.x 通常將 daemon 相關的檔案放在哪裡？ 以及某些重要的設定檔又是放置到哪裡？基本上是放在這些地方：

- /etc/init.d/* ：啟動腳本放置處

系統上幾乎所有的服務啟動腳本都放置在這裡！事實上這是公認的目錄，我們的 CentOS 實際上放置在 /etc/rc.d/init.d/ 啦！ 不過還是有設定連結檔到 /etc/init.d/ 的！既然這是公認的目錄，因此建議您記憶這個目錄即可！

- /etc/sysconfig/* ：各服務的初始化環境設定檔

幾乎所有的服務都會將初始化的一些選項設定寫入到這個目錄下，舉例來說，登錄檔的 syslog 這支 daemon 的初始化設定就寫入在 /etc/sysconfig/syslog 這裡呢！而網路的設定則寫在 /etc/sysconfig/network 這個檔案中。 所以，這個目錄內的檔案也是挺重要的；

- /etc/xinetd.conf, /etc/xinetd.d/* ：super daemon 設定檔

super daemon 的主要設定檔 (其實是預設值) 為 /etc/xinetd.conf ，不過我們上面就談到了， super daemon 只是一個統一管理的機制，他所管理的其他 daemon 的設定則寫在 /etc/xinetd.d/* 裡頭喔！

- /etc/* ：各服務各自的設定檔

第六章就講過了，大家的設定檔都是放置在 /etc/ 底下的喔！

- /var/lib/* ：各服務產生的資料庫

一些會產生資料的服務都會將他的資料寫入到 /var/lib/ 目錄中。舉例來說，資料庫管理系統 MySQL 的資料庫預設就是寫入 /var/lib/mysql/ 這個目錄下啦！

- /var/run/* ：各服務的程序之 PID 記錄處

我們在第十七章談到可以使用訊號 (signal) 來管理程序， 既然 daemon 是程序，所以當然也可以利用 kill 或 killall 來管理啦！不過為了擔心管理時影響到其他的程序， 因此 daemon 通常會將自己的 PID 記錄一份到 /var/run/ 當中！例如登錄檔的 PID 就記錄在 /var/run/syslogd.pid 這個檔案中。如此一來， /etc/init.d/syslog 就能夠簡單的管理自己的程序囉。

上面談到的部分是設定檔，那麼 stand alone 與 super daemon 所管理的服務啟動方式怎麼作呢？他是這樣做的喔：

- Stand alone 的 /etc/init.d/* 啟動

剛剛談到了幾乎系統上面所有服務的啟動腳本都在 /etc/init.d/ 底下，這裡面的腳本會去偵測環境、搜尋設定檔、 載入 distribution 提供的函數功能、判斷環境是否可以運作此 daemon 等等，等到一切都偵測完畢且確定可以運作後， 再以 shell script 的 case....esac 語法來啟動、關閉、 觀察此 daemon 喔！我們可以簡單的以 /etc/init.d/syslog 這個登錄檔啟動腳本來進行說明：

[root@www ~]# /etc/init.d/syslog

用法: /etc/init.d/syslog {start|stop|status|restart|condrestart}

# 什麼參數都不加的時候，系統會告訴你可以用的參數有哪些，如上所示。

範例一：觀察 syslog 這個 daemon 目前的狀態

[root@www ~]# /etc/init.d/syslog status

syslogd (pid 4264) 正在執行...

klogd (pid 4267) 正在執行...

# 代表 syslog 管理兩個 daemon ，這兩個 daemon 正在運作中啦！

範例二：重新讓 syslog 讀取一次設定檔

[root@www ~]# /etc/init.d/syslog restart

正在關閉核心記錄器:          [  確定  ]

正在關閉系統記錄器:          [  確定  ]

正在啟動系統記錄器:          [  確定  ]

正在啟動核心記錄器:          [  確定  ]

[root@www ~]# /etc/init.d/syslog status

syslogd (pid 4793) 正在執行...

klogd (pid 4796) 正在執行...

# 因為重新啟動過，所以 PID 與第一次觀察的值就不一樣了！這樣瞭解乎？

由於系統的環境都已經幫你製作妥當，所以利用 /etc/init.d/* 來啟動、關閉與觀察，就非常的簡單！話雖如此， CentOS 還是有提供另外一支可以啟動 stand alone 服務的腳本喔，那就是 service 這個程式。 其實 service 僅是一支 script 啦，他可以分析你下達的 service 後面的參數，然後根據你的參數再到 /etc/init.d/ 去取得正確的服務來 start 或 stop 哩！他的語法是這樣的啦：

[root@www ~]# service [service name] (start|stop|restart|...)

[root@www ~]# service --status-all

選項與參數：

service name：亦即是需要啟動的服務名稱，需與 /etc/init.d/ 對應；

start|...   ：亦即是該服務要進行的工作。

--status-all：將系統所有的 stand alone 的服務狀態通通列出來

範例三：重新啟動 crond 這支 daemon ：

[root@www ~]# service crond restart

[root@www ~]# /etc/init.d/crond restart

# 這兩種方法隨便你用哪一種來處理都可以！不過鳥哥比較喜歡使用 /etc/init.d/*

範例四：顯示出目前系統上面所有服務的運作狀態

[root@www ~]# service --status-all

acpid (pid 4536) 正在執行...

anacron 已停止

atd (pid 4694) 正在執行...

....(底下省略)....

這樣就將一堆服務的運作狀態列出，你也可以根據這個輸出的結果來查詢你的某些服務是否正確運作了啊！^_^！ 其實，在上面的範例當中，啟動方式以 service 這個程式，或者直接去到 /etc/init.d/ 底下啟動，都一樣啦！自行去解析 /sbin/service 就知道為啥了！ ^_^

Tips:

事實上，在 Linux 系統中，要『開或關某個 port 』，就是需要『 啟動或關閉某個服務』啦！因此，你可以找出某個 port 對應的服務，程式對應的服務， 進而啟動或關閉他，那麼那個經由該服務而啟動的 port ，自然就會關掉了！

- Super daemon 的啟動方式

其實 Super daemon 本身也是一支 stand alone 的服務，看圖 1.1.1 就知道啦！因為 super daemon 要管理後續的其他服務嘛，他當然自己要常駐在記憶體中啦！所以 Super daemon 自己啟動的方式與 stand alone 是相同的！ 但是他所管理的其他 daemon 就不是這樣做囉！必須要在設定檔中設定為啟動該 daemon 才行。設定檔就是 /etc/xinetd.d/* 的所有檔案。那如何得知 super daemon 所管理的服務是否有啟動呢？你可以這樣做：

[root@www ~]# grep -i 'disable' /etc/xinetd.d/*

....(前面省略)....

/etc/xinetd.d/rsync:          disable = yes

/etc/xinetd.d/tcpmux-server:  disable = yes

/etc/xinetd.d/time-dgram:     disable = yes

/etc/xinetd.d/time-stream:    disable = yes

因為 disable 是『取消』的意思，因此如果『 disable = yes 』則代表取消此項服務的啟動，如果是『 disable = no 』 才是有啟動該服務啦！假設我想要啟動如上的 rsync 這個服務，那麼你可以這樣做：

# 1. 先修改設定檔成為啟動的模樣：

[root@www ~]# vim /etc/xinetd.d/rsync

# 請將 disable 那一行改成如下的模樣 (原本是 yes 改成 no 就對了)

service rsync

{

disable = no

....(後面省略)....

# 2. 重新啟動 xinetd 這個服務

[root@www ~]# /etc/init.d/xinetd restart

正在停止 xinetd:             [  確定  ]

正在啟動 xinetd:             [  確定  ]

# 3. 觀察啟動的埠口

[root@www ~]# grep 'rsync' /etc/services  <==先看看埠口是哪一號

rsync           873/tcp               # rsync

rsync           873/udp               # rsync

[root@www ~]# netstat -tnlp | grep 873

tcp    0 0 0.0.0.0:873      0.0.0.0:*     LISTEN      4925/xinetd

# 注意看！啟動的服務並非 rsync 喔！而是 xinetd ，因為他要控管 rsync 嘛！

# 若有疑問，一定要去看看圖 1.1.1 才行！

也就是說，你先修改 /etc/xinetd.d/ 底下的設定檔，然後再重新啟動 xinetd 就對了！而 xinetd 是一個 stand alone 啟動的服務！這部份得要特別留意呢！

解析 super daemon 的設定檔

前一小節談到的 super daemon 我們現在知道他是一支總管程序，這個 super daemon 是 xinetd 這一支程序所達成的。 而且由圖 1.1.1 我們知道這個 xinetd 可以進行安全性或者是其他管理機制的控管， 由圖 1.1.2 則可以瞭解 xinetd 也能夠控制連線的行為。這些控制的手段都可以讓我們的某些服務更為安全， 資源管理更為合理。而由於 super daemon 可以作這樣的管理，因此一些對用戶端開放較多權限的服務 (例如 telnet)， 或者本身不具有管理機制或防火牆機制的服務，就可以透過 xinetd 來管理啊！

既然這傢伙這麼重要，那麼底下我們就來談談 xinetd 這個服務的預設設定檔 /etc/xinetd.conf ，以及各個設定項目的意義囉！

預設值設定檔：xinetd.conf

先來看一看預設的 /etc/xinetd.conf 這個檔案的內容是什麼吧！

[root@www ~]# vim /etc/xinetd.conf

defaults

{

# 服務啟動成功或失敗，以及相關登入行為的記錄檔

log_type        = SYSLOG daemon info  <==登錄檔的記錄服務類型

log_on_failure  = HOST   <==發生錯誤時需要記錄的資訊為主機 (HOST)

log_on_success  = PID HOST DURATION EXIT <==成功啟動或登入時的記錄資訊

# 允許或限制連線的預設值

cps         = 50 10 <==同一秒內的最大連線數為 50 個，若超過則暫停 10 秒

instances   = 50    <==同一服務的最大同時連線數

per_source  = 10    <==同一來源的用戶端的最大連線數

# 網路 (network) 相關的預設值

v6only          = no <==是否僅允許 IPv6 ？可以先暫時不啟動 IPv6 支援！

# 環境參數的設定

groups          = yes

umask           = 002

}

includedir /etc/xinetd.d <==更多的設定值在 /etc/xinetd.d 那個目錄內

為什麼 /etc/xinetd.conf 可以稱為預設值的設定檔呢？因為如果你有啟動某個 super daemon 管理的服務， 但是該服務的設定值並沒有指定上述的那些項目，那麼該服務的設定值就以上述的預設值為主！ 至於上述的預設值會將 super daemon 管理的服務設定為：『一個服務最多可以有 50 個同時連線， 但每秒鐘發起的「新」連線最多僅能有 50 條，若超過 50 條則該服務會暫停 10 秒鐘。同一個來源的用戶最多僅能達成 10 條連線。 而登入的成功與失敗所記錄的資訊並不相同。』這樣說，可以比較清楚了吧？ ^_^ 至於更多的參數說明，我們會在底下再強調的！

既然這只是個預設參數檔，那麼自然有更多的服務參數檔案囉∼沒錯∼而所有的服務參數檔都在 /etc/xinetd.d 裡面，這是因為上表當中的最後一行啊！這樣瞭了吧！ ^_^。那麼每個參數檔案的內容是怎樣呢？一般來說，他是這樣的：

service  <service_name>

{

<attribute>   <assign_op>   <value>   <value> ...

.............

}

第一行一定都有個 service ，至於那個 <service_name> 裡面的內容，則與 /etc/services 有關，因為他可以對照著 /etc/services 內的服務名稱與埠號來決定所要啟用的 port 是哪個啊！ 然後相關的參數就在兩個大刮號中間。attribute 是一些 xinetd 的管理參數， assign_op 則是參數的設定方法。 assign_op 的主要設定形式為：

= ： 表示後面的設定參數就是這樣啦！

+= ： 表示後面的設定為『在原來的設定裡頭加入新的參數』

-= ： 表示後面的設定為『在原來的參數捨棄這裡輸入的參數！』

用途不太相同，敬請留意呦！好了！底下再來說一說那些 attribute 與 value ！

attribute (功能)

說明與範例

一般設定項目：服務的識別、啟動與程式

disable

(啟動與否)

·         設定值：[yes|no]，預設 disable = yes

disable 為取消的意思，此值可設定該服務是否要啟動。預設所有的 super daemon 管理的服務都不啟動的。 若要啟動就得要設定為『 disable = no 』

id

(服務識別)

·         設定值：[服務的名稱]

雖然服務在設定檔開頭『 service 服務名稱』已經指定了，不過有時後會有重複的設定值，此時可以用 id 來取代服務名稱。 你可以參考一下 /etc/xinetd.d/time-stream 來思考一下原理。

server

(程式檔名)

·         設定值：[program 的完整檔名]

這個就是指出這個服務的啟動程式！例如 /usr/bin/rsync 為啟動 rsync 服務的指令，所以這個設定值就會成為： 『 server = /usr/bin/rsync 』

server_args

(程式參數)

·         設定值：[程式相關的參數]

這裡應該輸入的就是你的 server 那裡需要輸入的一些參數啦！例如 rsync 需要加入 --daemon ， 所以這裡就設定：『 server_args = --daemon 』。與上面 server 搭配，最終啟動服務的方式『/usr/bin/rsync --daemon』

user

(服務所屬UID)

·         設定值：[使用者帳號]

如果 xinetd 是以 root 的身份啟動來管理的，那麼這個項目可以設定為其他使用者。此時這個 daemon 將會以此設定值指定的身份來啟動該服務的程序喔！舉例來說，你啟動 rsync 時會以這個設定值作為該程序的 UID。

group

跟 user 的意思相同！此項目填入群組名稱即可。

一般設定項目：連線方式與連線封包協定

socket_type

(封包類型)

·         設定值：[stream|dgram|raw]，與封包有關

stream 為連線機制較為可靠的 TCP 封包，若為 UDP 封包則使用 dgram 機制。raw 代表 server 需要與 IP 直接對談！舉例來說 rsync 使用 TCP ，故設定為『socket_type = stream 』

protocol

(封包類型)

·         設定值：[tcp|udp]，通常使用 socket_type 取代此設定

使用的網路通訊協定，需參考 /etc/protocols 內的通訊協定，一般使用 tcp 或 udp。由於與 socket_type 重複， 因此這個項目可以不指定。

wait

(連線機制)

·         設定值：[yes(single)|no(multi)]，預設 wait = no

這就是我們剛剛提到的 Multi-threaded 與 single-threaded ！一般來說，我們希望大家的要求都可以同時被啟用，所以可以設定『 wait = no 』 此外，一般 udp 設定為 yes 而 tcp 設定為 no。

instances

(最大連線數)

·         設定值：[數字或 UNLIMITED]

這個服務可接受的最大連線數量。如果你只想要開放 30 個人連線 rsync 時，可在設定檔內加入：『 instances = 30 』

per_source

(單一用戶來源)

·         設定值：[一個數字或 UNLIMITED]

如果想要控制每個來源 IP 僅能有一個最大的同時連線數，就指定這個項目吧！例如同一個 IP 最多只能連 10 條連線『 per_source = 10 』

cps

(新連線限制)

·         設定值：[兩個數字]

為了避免短時間內大量的連線要求導致系統出現忙碌的狀態而有這個 cps 的設定值。第一個數字為一秒內能夠接受的最多新連線要求， 第二個數字則為，若超過第一個數字那暫時關閉該服務的秒數。

一般設定項目：登錄檔的記錄

log_type

(登錄檔類型)

·         設定值：[登錄項目 等級]

當資料記錄時，以什麼登錄項目記載？且需要記載的等級為何(預設為 info 等級)。這兩個設定值得要看過下一章登錄檔後才會知道哩！這邊你先有印象即可。

log_on_success

log_on_failure

(登錄狀態)

·         設定值：[PID,HOST,USERID,EXIT,DURATION]

在『成功登入』或『失敗登入』之後，需要記錄的項目：PID 為紀錄該 server 啟動時候的 process ID ， HOST 為遠端主機的 IP、USERID 為登入者的帳號、EXIT 為離開的時候記錄的項目、DURATION 為該使用者使用此服務多久？

進階設定項目：環境、網路埠口與連線機制等

env

(額外變數設定)

·         設定值：[變數名稱=變數內容]

這一個項目可以讓你設定環境變數，環境變數的設定規則可以參考第十一章。

port

(非正規埠號)

·         設定值：[一組數字(小於 65534)]

這裡可以設定不同的服務與對應的 port ，但是請記住你的 port 與服務名稱必須與 /etc/services 內記載的相同才行！不過，若服務名稱是你自訂的，那麼這個 port 就可以隨你指定

redirect

(服務轉址)

·         設定值：[IP port]

將 client 端對我們 server 的要求，轉到另一部主機上去！呵呵！這個好玩呦！ 例如當有人要使用你的 ftp 時，你可以將他轉到另一部機器上面去！那個 IP_Address 就代表另一部遠端主機的 IP 囉！

includedir

(呼叫外部設定)

·         設定值：[目錄名稱]

表示將某個目錄底下的所有檔案都給他塞進來 xinetd.conf 這個設定裡頭！這東西有用多了， 如此一來我們可以一個一個設定不同的項目！而不需要將所有的服務都寫在 xinetd.conf 當中！你可以在 /etc/xinetd.conf 發現這個設定呦！

安全控管項目：

bind

(服務介面鎖定)

·         設定值：[IP]

這個是設定『允許使用此一服務的介面卡』的意思！舉個例子來說，你的 Linux 主機上面有兩個 IP ，而你只想要讓 IP1 可以使用此一服務，但 IP2 不能使用此服務，這裡就可以將 IP1 寫入即可！那麼 IP2 就不可以使用此一 server 囉

interface

·         設定值：[IP]

與 bind 相同

only_from

(防火牆機制)

·         設定值：[0.0.0.0, 192.168.1.0/24, hostname, domainname]

這東西用在安全機制上面，也就是管制『只有這裡面規定的 IP 或者是主機名稱可以登入！』如果是 0.0.0.0 表示所有的 PC 皆可登入，如果是 192.168.1.0/24 則表示為 C class 的網域！亦即由 192.168.1.1 ~ 192.168.1.255 皆可登入！另外，也可以選擇 domain name ，例如 .dic.ksu.edu.tw 就可以允許崑山資傳系網域的 IP 登入你的主機使用該 server ！

no_access

(防火牆機制)

·         設定值：[0.0.0.0, 192.168.1.0/24, hostname, domainname]

跟 only_from 差不多啦！就是用來管理可否進入你的 Linux 主機啟用你的 server 服務的管理項目！ no_access 表示『不可登入』的 PC 囉！

access_times

(時間控管)

·         設定值：[00:00-12:00, HH:MM-HH:MM]

這個項目在設定『該服務 server 啟動的時間』，使用的是 24 小時的設定！例如你的 ftp 要在 8 點到 16 點開放的話，就是： 08:00-16:00。

umask

·         設定值：[000, 777, 022]

還記得在第七章提到的 umask 這個東西嗎？呵呵！沒錯！ 就是那個鬼玩意兒囉！可以設定使用者建立目錄或者是檔案時候的屬性！系統建議值是 022 。

OK！我們就利用上面這些參數來架構出我們所需要的一些服務的設定吧！參考看看底下的設定方法囉！ ^_^

一個簡單的 rsync 範例設定

我們知道透過 super daemon 控管的服務可以多一層管理的手續來達成類似防火牆的機制， 那麼該如何仔細的設定這些類似防火牆機制的設定參數呢？底下我們使用 rsync 這個可以進行遠端鏡射 (mirror) 的服務來說明。 rsync 可以讓兩部主機上面的某個目錄一模一樣，在遠端異地備援系統上面是挺好用的一個機制。 而且預設一裝好 CentOS 就已經存在這玩意兒了！那就來瞧瞧預設的 rsync 設定檔吧！

[root@www ~]# vim /etc/xinetd.d/rsync

service rsync  <==服務名稱為 rsync

{

disable = no                     <==預設是關閉的！剛剛被我們打開了

socket_type     = stream         <==使用 TCP 的連線機制之故

wait            = no             <==可以同時進行大量連線功能

user            = root           <==啟動服務為 root 這個身份

server          = /usr/bin/rsync <==就是這支程式啟動 rsync 的服務囉

server_args     = --daemon       <==這是必要的選項啊！

log_on_failure  += USERID        <==登入錯誤時，額外記錄使用者 ID

}

能不能修改 user 成為其他身份呢？由於在 /etc/services 當中規定 rsync 使用的埠口號碼為 873 ，這個埠口小於 1024 ，所以理論上啟動這個埠口的身份一定要是 root 才行！這裡 user 就請您先別亂改囉！ 由於鳥哥的測試主機在安裝時已經有捉到網路卡，目前有兩個介面，一個是 192.168.1.100 ，一個則是 127.0.0.1， 假設我將 192.168.1.100 設計為對外網域， 127.0.0.1 為內部網域，且內外網域的分別權限設定為：

- 對內部 127.0.0.1 網域開放較多權限的部分：

- 這裡的設定值需綁在 127.0.0.1 這個介面上；

- 對 127.0.0.0/8 開放登入權限；

- 不進行任何連線的限制，包括總連線數量與時間；

- 但是 127.0.0.100 及 127.0.0.200 不允許登入 rsync 服務。

- 對外部 192.168.1.100 網域較多限制的設定：

- 對外設定綁住 192.168.1.100 這個介面；

- 這個介面僅開放 140.116.0.0/16 這個 B 等級的網域及 .edu.tw 網域可以登入；

- 開放的時間為早上 1-9 點以及晚上 20-24 點兩個時段；

- 最多允許 10 條同時連線的限制。

Tips:

有資訊背景的朋友當然知道 127.0.0.1 是內部迴圈測試用的 IP ，用他來設計網路是沒有意義的。 不過，我們這裡僅是作一個設計的介紹，而且我們尚未談到伺服器篇的網路部分，所以大家先這樣實際測試吧！ ^_^

在這樣的規劃情況下，我們可以將剛剛上頭的 /etc/xinetd.d/rsync 這個檔案修改成為：

[root@www ~]# vim /etc/xinetd.d/rsync

# 先針對對內的較為鬆散的限制來設定：

service rsync

{

disable = no                        <==要啟動才行啊！

bind            = 127.0.0.1         <==服務綁在這個介面上！

only_from       = 127.0.0.0/8       <==只開放這個網域的來源登入

no_access       = 127.0.0.{100,200} <==限制這兩個不可登入

instances       = UNLIMITED         <==取代 /etc/xinetd.conf 的設定值

socket_type     = stream            <==底下的設定則保留

wait            = no

user            = root

server          = /usr/bin/rsync

server_args     = --daemon

log_on_failure  += USERID

}

# 再針對外部的連線來進行限制呢！

service rsync

{

disable = no

bind            = 192.168.1.100

only_from       = 140.116.0.0/16

only_from      += .edu.tw           <==因為累加，所以利用 += 設定

access_times    = 01:00-9:00 20:00-23:59 <==時間有兩時段，有空格隔開

instances       = 10                <==只有 10 條連線

socket_type     = stream

wait            = no

user            = root

server          = /usr/bin/rsync

server_args     = --daemon

log_on_failure  += USERID

}

在上面這個設定檔中，鳥哥共寫了兩段 service rsync 的設定，一段針對內部網域一段針對外部網域， 如果設計完畢你將他重新啟動後，就會出現如下的狀態喔！

# 0. 先看看原本的 873 狀態為何！

[root@www ~]# netstat -tnlp | grep 873

tcp    0 0 0.0.0.0:873      0.0.0.0:*     LISTEN      4925/xinetd

# 仔細看，僅針對 0.0.0.0 這個全域網域監聽而已哩！

# 1. 重新啟動 xinetd 吧！不是啟動 rsync 喔！別搞錯。

[root@www ~]# /etc/init.d/xinetd restart

[root@www ~]# netstat -tnlp | grep 873

tcp    0 0 192.168.1.100:873     0.0.0.0:*       LISTEN    7227/xinetd

tcp    0 0 127.0.0.1:873         0.0.0.0:*       LISTEN    7227/xinetd

# 有沒有看到兩個介面啊∼而且， PID 會是同一個呢！

如同上面的設定，我們就可以將某個系統服務針對不同的用戶端來源指定不同的使用權限！這樣子系統服務可以安全多了！ 如果未來你的某些服務想要使用這個咚咚來設定也是 OK 的喔！更多的設定資料就有待您自己的理解了。

服務的防火牆管理 xinetd, TCP Wrappers

一般來說，系統的防火牆分析主要可以透過封包過濾或者是透過軟體分析，我們的 Linux 預設有提供一個軟體分析的工具， 那就是 /etc/hosts.deny, /etc/hosts.allow 這兩個可愛的設定檔！另外，如果有安裝 tcp wrappers 套件時， 我們甚至可以加上一些額外的追蹤功能呢！底下就讓我們分別來談談這些玩意兒吧！

/etc/hosts.allow, /etc/hosts.deny 管理

我們在前面幾章知道了要管制 at 的使用可以透過修訂 /etc/at.{allow|deny} 來管理，至於 crontab 則是使用 /etc/cron.{allow|deny} 來管理的。那麼有沒有辦法透過個什麼機制，就能夠管理某些程式的網路使用呢？ 就有點像管理某些程式是否能夠接受或者是拒絕來自網際網路的連線的意思啦！有的！那就是 /etc/hosts.{allow|deny} 囉。

任何以 xinetd 管理的服務，都可以透過 /etc/hosts.allow, /etc/hosts.deny 來設定防火牆。那麼什麼是防火牆呢？簡單的說，就是針對來源 IP 或網域進行允許或拒絕的設定， 以決定該連線是否能夠成功達成連接的一種方式就是了。其實我們剛剛修改 /etc/xinetd.d/rsync 裡頭的 no_access, only_from 也可以進行這方面的防火牆設定。不過，使用 /etc/hosts.allow, /etc/hosts.deny 則更容易集中控管，在設定與查詢方面也較為方便！ 那麼就讓我們談談這兩個檔案的設定技巧吧！

其實 /etc/hosts.allow 與 /etc/hosts.deny 也是 /usr/sbin/tcpd 的設定檔，而這個 /usr/sbin/tcpd 則是用來分析進入系統的 TCP 網路封包的一個軟體，TCP 是一種連線導向的網路連線封包，包括 www, email, ftp 等等都是使用 TCP 封包來達成連線的喔。 所以囉，顧名思義，這個套件本身的功能就是在分析 TCP 網路資料封包啦！而 TCP 封包的檔頭主要記錄了來源與目主機的 IP 與 port ，因此藉由分析 TCP 封包並搭配 /etc/hosts.{allow,deny} 的規則比對，就可以決定該連線是否能夠進入我們的主機啦。 所以啦，我們要使用 TCP Wrappers 來控管的就是：

1. 來源 IP 或/與 整個網域的 IP 網段；

2. port (就是服務啦，前面有談到啟動某個埠口是 daemon 的責任啊)

基本上只要一個服務受到 xinetd 管理，或者是該服務的程式支援 TCP Wrappers 函式的功能時，那麼該服務的防火牆方面的設定就能夠以 /etc/hosts.{allow,deny} 來處理囉。換個方式來說，只要不支援 TCP Wrappers 函式功能的軟體程式就無法使用 /etc/hosts.{allow,deny} 的設定值啦，這樣說，有沒有比較清楚啊。不過，那要如何得知一個服務的程式有沒有支援 TCP Wrappers 呢，你可以這樣簡單的處理喔。

範例一：測試一下達成 sshd 及 httpd 這兩個程式有無支援 TCP Wrappers 的功能

[root@www ~]# ldd $(which sshd httpd)

/usr/sbin/sshd:

libwrap.so.0 => /usr/lib64/libwrap.so.0 (0x00002abcbfaed000)

libpam.so.0 => /lib64/libpam.so.0 (0x00002abcbfcf6000)

....(中間省略)....

/usr/sbin/httpd:

libm.so.6 => /lib64/libm.so.6 (0x00002ad395843000)

libpcre.so.0 => /lib64/libpcre.so.0 (0x00002ad395ac6000)

....(底下省略)....

# 重點在於軟體有沒有支援 libwrap.so 那個函式庫囉

ldd (library dependency discovery) 這個指令可以查詢某個程式的動態函式庫支援狀態，因此透過這個 ldd 我們可以輕鬆的就查詢到 sshd, httpd 有無支援 tcp wrappers 所提供的 libwrap.so 這個函式庫檔案。從上表的輸出中我們可以發現， sshd 有支援但是 httpd 則沒有支援。因此我們知道 sshd 可以使用 /etc/hosts.{allow,deny} 進行類似防火牆的抵擋機制，但是 httpd 則沒有此項功能喔！

- 設定檔語法

這兩個檔案的設定語法都是一樣的，基本上，看起來應該像這樣：

<service(program_name)> : <IP, domain, hostname> : <action>

<服務   (亦即程式名稱)> : <IP 或領域 或主機名稱> : < 動作 >

# 上頭的 < > 是不存在於設定檔中的喔！

重點是兩個，第一個是找出你想要管理的那個程式的檔名，第二個才是寫下來你想要放行或者是抵擋的 IP 或網域呢。 那麼程式的檔名要如何寫呢？其實就是寫下檔名啦！舉例來說上面我們談到過 rsync 設定檔內不是有 server 的參數嗎？ rsync 設定檔內 /usr/bin/rsync 為其參數值，那麼在我們這裡就得要寫成 rsync 即可喔！依據 rsync 的設定檔資料，我們將抵擋的 127.0.0.100, 127.0.0.200, 及放行的 140.116.0.0/16 寫在這裡，內容有點像這樣：

Tips:

關於 IP, 網域, 網段, 還有相關的網路知識，在這個基礎篇當中我們不會談到，你只要記得底下寫的 140.116.0.0/255.255.0.0 代表一個網域就是了。詳細的資料請先自行參考伺服器架設篇的內容！

[root@www ~]# vim /etc/hosts.deny

rsync : 127.0.0.100 127.0.0.200 : deny

當然也可以寫成兩行，亦即是：

[root@www ~]# vim /etc/hosts.deny

rsync : 127.0.0.100       : deny

rsync : 127.0.0.200       : deny

這樣一來，對方就無法以 rsync 進入你的主機啦！方便吧！不過，既然如此，為什麼要設定成 /etc/hosts.allow 及 /etc/hosts.deny 兩個檔案呢？其實只要有一個檔案存在就夠了， 不過，為了設定方便起見，我們存在兩個檔案，其中需要注意的是：

- 寫在 hosts.allow 當中的 IP 與網段，為預設『可通行』的意思，亦即最後一個欄位 allow 可以不用寫；

- 而寫在 hosts.deny 當中的 IP 與網段則預設為 deny ，第三欄的 deny 亦可省略；

- 這兩個檔案的判斷依據是： (1) 以 /etc/hosts.allow 為優先，而 (2) 若分析到的 IP 或網段並沒有記錄在 /etc/hosts.allow ，則以 /etc/hosts.deny 來判斷。

也就是說， /etc/hosts.allow 的設定優先於 /etc/hosts.deny 囉！基本上，只要 hosts.allow 也就夠了，因為我們可以將 allow 與 deny 都寫在同一個檔案內，只是這樣一來似乎顯得有點雜亂無章，因此，通常我們都是：

1. 允許進入的寫在 /etc/hosts.allow 當中；

2. 不許進入的則寫在 /etc/hosts.deny 當中。

此外，我們還可以使用一些特殊參數在第一及第二個欄位喔！內容有：

- ALL：代表全部的 program_name 或者是 IP 都接受的意思，例如 ALL: ALL: deny

- LOCAL：代表來自本機的意思，例如： ALL: LOCAL: allow

- UNKNOWN：代表不知道的 IP 或者是 domain 或者是服務時；

- KNOWN：代表為可解析的 IP, domain 等等資訊時；

再強調一次，那個 service_name 其實是啟動該服務的程式，舉例來說， /etc/init.d/sshd 這個 script 裡面， 實際上啟動 ssh 服務的是 sshd 這個程式，所以，你的 service_name 自然就是 sshd 囉！ 而 /etc/xinetd.d/telnet (你的系統可能尚未安裝) 內有個 server 的設定項目， 那個項目指到 in.telnetd 這個程式來啟動的喔！要注意的很！(請分別使用 vi 進這兩支 scripts 查閱) 好了，我們還是以 rsync 為例子來說明好了，現在假設一個比較安全的流程來設定，就是：

1. 只允許 140.116.0.0/255.255.0.0 與 203.71.39.0/255.255.255.0 這兩個網域，及 203.71.38.123 這個主機可以進入我們的 rsync 伺服器；

2. 此外，其他的 IP 全部都擋掉！

這樣的話，我可以這樣設定：

[root@www ~]# vim /etc/hosts.allow

rsync:  140.116.0.0/255.255.0.0

rsync:  203.71.39.0/255.255.255.0

rsync:  203.71.38.123

rsync:  LOCAL

[root@www ~]# vim /etc/hosts.deny

rsync: ALL  <==利用 ALL 設定讓所有其他來源不可登入

TCP Wrappers 特殊功能

那麼有沒有更安全的設定？例如，當有其他人掃瞄我的 rsync port 時，我就將他的 IP 記住，以做為未來的查詢與認證之用呢？ 是有的！只是，那就得要有額外的動作參數加在第三欄了，而且你還需要安裝了 TCP Wrappers 軟體才行。要確定有沒有安裝 TCP Wrappers 可以使用『 rpm -q tcp_wrappers 』來查詢喔。至於更加細部的主要動作則有：

- spawn (action)

可以利用後續接的 shell 來進行額外的工作，且具有變數功能，主要的變數內容為： %h (hostname), %a (address), %d (daemon)等等；

- twist (action)

立刻以後續的指令進行，且執行完後終止該次連線的要求 (DENY)

為了達成追蹤來源目標的相關資訊的目的，此時我們需要 safe_finger 這個指令的輔助才行。而且我們還希望用戶端的這個惡意者能夠被警告。 整個流程可以是這樣的：

1. 利用 safe_finger 去追蹤出對方主機的資訊 (包括主機名稱、使用者相關資訊等)；

2. 將該追蹤到的結果以 email 的方式寄給我們本機的 root ；

3. 在對方螢幕上面顯示不可登入且警告他已經被記錄的訊息

由於是抵擋的機制，因此我們這個 spawn 與 twist 的動作大多是寫在 /etc/hosts.deny 檔案中的。我們將上述的動作寫成類似如下的東東：

[root@www ~]# vim /etc/hosts.deny

rsync : ALL: spawn (echo "security notice from host $(/bin/hostname)" ;\

echo; /usr/sbin/safe_finger @%h ) | \

/bin/mail -s "%d-%h security" root & \

: twist ( /bin/echo -e "\n\nWARNING connection not allowed.\n\n" )

上面其實是針對一個 rsync 所寫的資訊，你可以看到上面這四行共有三個冒號來隔開成四個咚咚，這四個咚咚的意義是：

1. rsync： 指的就是 rsync 這個服務的程式囉；

2. ALL： 指的是來源，這個範圍指的當然是全部的所有來源囉，因為是 ALL 嘛！

3. spawn (echo "security notice from host $(/bin/hostname)" ; echo ; /usr/sbin/safe_finger @%h ) | /bin/mail -s "%d-%h security" root &： 由於要將一些偵測的資料送給 root 的郵件信箱，因此需要使用資料流匯整的括號( )，括號內的重點在於 safe_finger 的項目，他會偵測到用戶端主機的相關資訊，然後使用管線命令將這些資料送給 mail 處理， mail 會將該資訊以標頭為 security 的字樣寄給 root 啦！由於 spawn 只是中間的過程，所以還能夠有後續的動作哩！

4. twist ( /bin/echo -e "\n\nWARNING connection not allowed.\n\n" )： 這個動作會將 Warning 的字樣傳送到用戶端主機的螢幕上！ 然後將該連線中斷。

在上面的例子中，第三行的 root 那個帳號，可以寫成你的個人帳號或者其他 e-mail ，這樣就能夠寄到你常用的 email 囉， 這樣也比較好管理囉。如此一來，當未經允許的電腦嘗試登入你的主機時，對方的螢幕上就會顯示上面的最後一行，並且將他的 IP 寄到 root ( 或者是你自己的信箱 )那裡去！

系統開啟的服務

好了，現在假設你已經知道了 daemons 的啟動檔案放置的目錄，也知道了服務與 port 的對應，那麼要如何查詢目前系統上面已經啟動了的服務呢？不要再打混了！已經學過了 ps 與 top 應該要會應用才對耶！沒錯，可以使用 ps 與 top 來找尋已經啟動了的服務的程序與他的 PID 呢！不過，我們怎麼知道該服務啟動的 port 是哪一個？呵呵！好問題！可以直接使用 netstat 這個網路狀態觀察指令來檢查我們的 port 呢！甚至他也可以幫我們找到該 port 的程序呢 (PID)！這個指令的相關用途，我們在 第十七章程序管理已經談過了，不清楚的話請回去查一查先∼這裡僅介紹如何使用喔∼

觀察系統啟動的服務

觀察系統已啟動的服務方式很多，不過，我們最常使用 netstat 來觀察。基本上，以 ps 來觀察整個系統上面的服務是比較妥當的，因為他可以將全部的 process 都找出來。不過，我們比較關心的還是在於有啟動網路監聽的服務啊， 所以鳥哥會比較喜歡使用 netstat 來查閱啦。

範例一：找出目前系統開啟的『網路服務』有哪些？

[root@www ~]# netstat -tulp

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address       Foreign Address State  PID/Program name

tcp        0      0 www.vbird.tsai:2208 *:*             LISTEN 4575/hpiod

tcp        0      0 *:737               *:*             LISTEN 4371/rpc.statd

tcp        0      0 *:sunrpc            *:*             LISTEN 4336/portmap

tcp        0      0 www.vbird.tsai:ipp  *:*             LISTEN 4606/cupsd

tcp        0      0 www.vbird.tsai:smtp *:*             LISTEN 4638/sendmail: acce

tcp        0      0 *:ssh               *:*             LISTEN 4595/sshd

udp        0      0 *:filenet-tms       *:*                    4755/avahi-daemon:

....(底下省略)....

# 看一下上頭， Local Address 的地方會出現主機名稱與服務名稱的，要記得的是，

# 可以加上 -n 來顯示 port number ，而服務名稱與 port 對應則在 /etc/services

範例二：找出所有的有監聽網路的服務 (包含 socket 狀態)：

[root@www ~]# netstat -lnp

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address  Foreign Address  State   PID/Program name

tcp        0      0 127.0.0.1:2208 0.0.0.0:*        LISTEN  4575/hpiod

....(中間省略)....

Active UNIX domain sockets (only servers)

Proto RefCnt Flags   Type   State     I-Node PID/Program name Path

....(中間省略)....

unix  2      [ ACC ] STREAM LISTENING 10624  4701/xfs         /tmp/.font-unix/fs7100

unix  2      [ ACC ] STREAM LISTENING 12824  5015/Xorg        /tmp/.X11-unix/X0

unix  2      [ ACC ] STREAM LISTENING 12770  4932/gdm-binary  /tmp/.gdm_socket

....(以下省略)....

# 仔細的瞧一瞧啊，除了原有的網路監聽 port 之外，還會有 socket 顯示在上面，

# 我們可以清楚的知道有哪些服務被啟動呢！

範例三：觀察所有的服務狀態

[root@www ~]# service --status-all

# 這個指令有趣喔！本章之前有談過這指令，自行查詢囉！

利用 netstat 可以取得很多跟網路有關的服務資訊，透過這個指令，我們可以輕易的瞭解到網路的狀態， 並且可以透過 PID 與 kill 的相關功能，將有問題的資料給他剔除說∼ 當然啦，要更詳細的取得 PPID 的話，才能夠完全的抵擋有問題的程序啦！

另外，除了已經存在系統當中的 daemon 之外，如何在一開機就完整的啟動我們所需要的服務呢？ 底下我們就來談一談 chkconfig 及 ntsysv 這兩個好用的東西！

設定開機後立即啟動服務的方法

就如同上面提到的，我們使用 netstat 僅能觀察到目前已經啟動的 daemon ，使用 service 這個指令或者是『 /etc/init.d/* start 』的方法則僅能在目前的環境下立即啟動某個服務而已。 那麼重新開機後呢？該服務是否還是繼續的自動啟動？這個時候我們就得要了解一下，到底我的 Linux 主機是怎麼開機的呢？

1. 打開電腦電源，開始讀取 BIOS 並進行主機的自我測試；

2. 透過 BIOS 取得第一個可開機裝置，讀取主要開機區 (MBR) 取得開機管理程式；

3. 透過開機管理程式的設定，取得 kernel 並載入記憶體且偵測系統硬體；

4. 核心主動呼叫 init 程式；

5. init 程式開始執行系統初始化 (/etc/rc.d/rc.sysinit)

6. 依據 init 的設定進行 daemon start (/etc/rc.d/rc[0-6].d/*)

7. 載入本機設定 (/etc/rc.d/rc.local)

關於更多開機流程的詳細說明，我們會在第二十章時再來跟大家說明。 由上面的流程你可以看到系統服務在開機時就可以被啟動的地方是在第六個步驟，而事實上第六個步驟就是以不同的執行等級呼叫不同的服務啦！ 那麼什麼叫做執行等級呢？

我們在啟動 Linux 系統時，可以進入不同的模式喔，這模式我們稱為執行等級 (run level)。不同的執行等級有不同的功能與服務， 目前你先知道正常的執行等級有兩個，一個是具有 X 視窗介面的 run level 5 ，另一個則是純文字介面的 run level 3。 由於預設我們是以圖形介面登入系統的，因此可以想像得到的是，我們應該是在 run level 5 的環境中啦！ 那你怎麼知道 run level 5 有哪些服務預設可以啟動呢？這就得要使用特殊的指令來查詢啊！

- chkconfig： 管理系統服務預設開機啟動與否

[root@www ~]# chkconfig --list [服務名稱]

[root@www ~]# chkconfig [--level [0123456]] [服務名稱] [on|off]

選項與參數：

--list ：僅將目前的各項服務狀態列出來

--level：設定某個服務在該 level 下啟動 (on) 或關閉 (off)

範例一：列出目前系統上面所有被 chkconfig 管理的服務

[root@www ~]# chkconfig --list |more

NetworkManager  0:off   1:off   2:off   3:off   4:off   5:off   6:off

acpid           0:off   1:off   2:off   3:on    4:on    5:on    6:off

....(中間省略)....

yum-updatesd    0:off   1:off   2:on    3:on    4:on    5:on    6:off

xinetd based services:  <==底下為 super daemon 所管理的服務

chargen-dgram:  off

chargen-stream: off

....(底下省略)....

# 你可以發現上面的表格有分為兩個區塊，一個具有 1, 2, 3 等數字，一個則被 xinetd

# 管理。沒錯！從這裡我們就能夠發現服務有 stand alone 與 super daemon 之分。

範例二：顯示出目前在 run level 3 為啟動的服務

[root@www ~]# chkconfig --list | grep '3:on'

範例三：讓 atd 這個服務在 run level 為 3, 4, 5 時啟動：

[root@www ~]# chkconfig --level 345 atd on

瞧！ chkconfig 是否很容易管理我們所需要的服務呢？真的很方便啦∼ 你可以輕鬆的透過 chkconfig 來管理 super daemon 的服務喔！另外，你得要知道的是， chkconfig 僅是設定開機時預設會啟動的服務而已， 所以該服務目前的狀態如何是不知道的。我們舉個底下的例子來說明好了：

範例四：先觀察 httpd ，再觀察預設有無啟動，之後以 chkconfig 設定為預設啟動

[root@www ~]# /etc/init.d/httpd status

httpd 已停止  <==根本就沒有啟動

[root@www ~]# chkconfig --list httpd

httpd           0:off   1:off   2:off   3:off   4:off   5:off   6:off

# 原因是預設並沒有啟動啊！

[root@www ~]# chkconfig httpd on; chkconfig --list httpd

httpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

# 已經設定為『開機預設啟動』了，再來觀察看看到底該服務啟動沒？

[root@www ~]# /etc/init.d/httpd status

httpd 已停止

# 哈！竟然還是沒有啟動喔！怎麼會這樣啊？

上面的範例四並沒有啟動 httpd 的原因很簡單，因為我們並沒有使用 /etc/init.d/httpd start 嘛！我們僅是設定開機時啟動而已啊！那我們又沒有重新開機，所以當然使用 chkconfig 並不會導致該服務立即被啟動！也不會讓該服務立即被關閉，而是只有在開機時才會被載入或取消載入而已喔。而既然 chkconfig 可以設定開機是否啟動，那麼我們能不能用來管理 super daemon 的啟動與關閉呢？非常好！我們就來試看看底下的案例：

範例五：查閱 rsync 是否啟動，若要將其關閉該如何處理？

[root@www ~]# /etc/init.d/rsync status

-bash: /etc/init.d/rsync: No such file or directory

# rsync 是 super daemon 管理的，所以當然不可以使用 stand alone 的啟動方式來觀察

[root@www ~]# netstat -tlup | grep rsync

tcp  0 0 192.168.201.110:rsync  *:*     LISTEN     4618/xinetd

tcp  0 0 www.vbird.tsai:rsync   *:*     LISTEN     4618/xinetd

[root@www ~]# chkconfig --list rsync

rsync           on   <==預設啟動呢！將它處理成預設不啟動吧

[root@www ~]# chkconfig rsync off; chkconfig --list rsync

rsync           off  <==看吧！關閉了喔！現在來處理一下 super daemon 的東東！

[root@www ~]# /etc/init.d/xinetd restart; netstat -tlup | grep rsync

最後一個指令你會發現原本 rsync 不見了！這樣是否很輕易的就能夠啟動與關閉你的 super daemon 管理的服務呢！

- ntsysv： 類圖形介面管理模式

基本上， chkconfig 真的已經很好用了，不過，我們的 CentOS 還有提供一個更不錯用的， 那就是 ntsysv 了！注意喔， chkconfig 很多的 distributions 都存在，但是 ntsysv 則是 Red Hat 系統特有的！

[root@www ~]# ntsysv [--level <levels>]

選項與參數：

--level ：後面可以接不同的 run level ，例如 ntsysv --level 35

一般我們都是直接輸入 ntsysv 即可進入管理畫面了，整個畫面如下圖所示：

圖 4.2.1、 ntsysv 的執行示意圖

上圖中的中間部分是每個服務預設開機是否會啟動的設定值，若中括號內出現星號 (*) 代表預設開機會啟動，否則就是不會在開機時啟動啦。 你可以使用上下鍵來移動中括號內的游標到你想要變更的那個服務上頭，然後按下空白鍵就能夠選取或取消囉。如果一切都選擇完畢後， 你可以使用 [tab] 按鍵來移動游標到 [OK] [Cancel] 等按鈕上面，當然啦，按下 [Ok] 就是確認你的選取會生效囉。 總結一下上述的按鈕功能：

- 上下鍵： 可以在中間的方框當中，在各個服務之間移動；

- 空白鍵： 可以用來選擇你所需要的服務，前面的 [*] 會有 * 出現；

- tab 鍵： 可以在方框、OK、Cancel 之間移動；

- [F1]鍵： 可以顯示該服務的說明

圖 4.2.2、 ntsysv 的執行示意圖

上圖是鳥哥將游標游動到 atd 這個服務上頭後，再按下 [F1] 所出現的結果，所以囉，你可以透過 ntsysv 去觀察預設開機啟動的服務， 還能夠查閱該服務的基本功能為何，這樣就能夠稍微釐清一下該服務是否需要存在囉！這樣理解了吧！

- chkconfig： 設定自己的系統服務

[root@www ~]# chkconfig [--add|--del] [服務名稱]

選項與參數：

--add ：增加一個服務名稱給 chkconfig 來管理，該服務名稱必須在 /etc/init.d/ 內

--del ：刪除一個給 chkconfig 管理的服務

現在你知道 chkconfig 與 ntsysv 是真好用的東西，那麼如果我自己寫了一個程式並且想要讓該程式成為系統服務好讓 chkconfig 來管理時， 可以怎麼進行呢？只要將該服務加入 init 可以管理的 script 當中，亦即是 /etc/init.d/ 當中即可。 舉個例子，我們在 /etc/init.d/ 裡面建立一個 myvbird 檔案，該檔案僅是一個簡單的服務範例，基本上，沒有任何用途.... 對於該檔案的必須性是這樣的：

- myvbird 將在 run level 3 及 5 啟動；

- myvbird 在 /etc/rc.d/rc[35].d 當中啟動時，以 80 順位啟動，以 70 順位結束。

關於所謂的順位問題，我們會在第二十章介紹，這裡你先看看即可。 你該如何進行呢？可以這樣做：

[root@www ~]# vim /etc/init.d/myvbird

#!/bin/bash

# chkconfig: 35 80 70

# description: 沒啥！只是用來作為練習之用的一個範例

echo "Nothing"

這個檔案很好玩喔！你可以參考你自己系統上面的檔案；基本上，比較重要的是第二行，他的語法是： 『 chkconfig: [runlevels] [啟動順位] [停止順位] 』其中， runlevels 為不同的 run level 狀態，啟動順位 (start number) 與 結束順位 (stop number) 則是在 /etc/rc.d/rc[35].d 內建立以 S80myvbird 及 K70myvbird 為檔名的設定方式！

[root@www ~]# chkconfig --list myvbird

service myvbird supports chkconfig, but is not referenced in any

runlevel (run 'chkconfig --add myvbird')

# 尚未加入 chkconfig 的管理機制中！所以需要再動點手腳

[root@www ~]# chkconfig --add myvbird; chkconfig --list myvbird

myvbird         0:off   1:off   2:off   3:on    4:off   5:on    6:off

# 看吧！加入了 chkconfig 的管理當中了！

# 很有趣吧！如果要將這些資料都刪除的話，那麼就下達這樣的情況：

[root@www ~]# chkconfig --del myvbird

[root@www ~]# rm /etc/init.d/myvbird

chkconfig 真的是個不錯用的工具吧！尤其是當你想要自己建立自己的服務時！ ^_^

CentOS 5.x 預設啟動的服務簡易說明

隨著 Linux 上面軟體支援性越來越多，加上自由軟體蓬勃的發展，我們可以在 Linux 上面用的 daemons 真的越來越多了。所以，想要寫完所有的 daemons 介紹幾乎是不可能的，因此，鳥哥這裡僅介紹幾個很常見的 daemons 而已， 更多的資訊呢，就得要麻煩你自己使用 ntsysv 或者是 vi /etc/init.d/* 裡面的檔案去瞧一瞧囉∼ ^_^！ 底下的建議主要是針對 Linux 單機伺服器的角色來說明的，不是桌上型的環境喔！

CentOS 5.x 預設啟動的服務內容

服務名稱

功能簡介

acpid

(系統)進階電源管理的介面，這是一個新的電源管理模組， 可以監聽來自核心層的電源相關事件而予以回應。 CentOS 的設定檔在 /etc/acpi/events/power.conf 中，預設僅有當你按下 power 按鈕時，系統會自動關機喔！(註1)

anacron

(可關閉)

(系統)與循環型的工作排程 cron 有關，可在排程過期後還可以喚醒來繼續執行， 設定檔在 /etc/anacrontab。詳情請參考第十六章的說明。

apmd

(可關閉)

(系統)設定檔在 /etc/sysconfig/apmd ，也是電源管理模組啦！ 可偵測電池電量，當電池電力不足時，可以自動關機以保護電腦主機。

atd

(系統)單一的例行性工作排程，詳細說明請參考第十六章。 抵擋機制的設定檔在 /etc/at.{allow,deny} 喔！

auditd

(系統)還記得前一章的 SELinux 所需服務吧？ 這就是其中一項，可以讓系統需 SELinux 稽核的訊息寫入 /var/log/audit/audit.log 中。若此服務沒有啟動，則訊息會傳給 syslog 管理。

autofs

(可關閉)

(系統)可用來自動掛載來自網路上的其他伺服器所提供的網路磁碟機 (一般是 NFS)。 不過我們是單機系統，所以目前還沒必要這個服務。

avahi-daemon

(可關閉)

(系統)也是一個用戶端的服務，可以透過 Zeroconf 自動的分析與管理網路。 Zeroconf 較常用在筆記型電腦與行動裝置上，所以我們可以先關閉他啦！(註2)

bluetooth

(可關閉)

(系統)用在藍芽裝置的搜尋上，如果 Linux 是當作伺服器使用時， 這個服務可以暫時關閉也沒關係！

cpuspeed

(系統)可以用來管理 CPU 的頻率功能。若系統閒置時，此項功能可以自動的降低 CPU 頻率來節省電量與降低 CPU 溫度喔！

crond

(系統)系統設定檔為 /etc/crontab，詳細資料可參考第十六章的說明。

cups

(可關閉)

(網路)用來管理印表機的服務，可以提供網路連線的功能，有點類似列印伺服器的功能哩！ 你可以在 Linux 本機上面以瀏覽器的 http://localhost:631 來管理印表機喔！由於我們目前沒有印表機，所以可以暫時關閉他。

firstboot

(可關閉)

(系統)還記得系統第一次進入圖形介面還需要進行一些額外的設定嗎？ 就是這個服務的幫忙啦！既然已經安裝妥當，現在你可以將這個服務關閉囉。

gpm

(系統)在 tty1~tty6 的環境下你竟然可以使用滑鼠功能來複製貼上，就是這個 gpm 提供的能力啦！

haldaemon

(可關閉)

(系統)通常用在桌上型電腦的環境中，可偵測類似 usb 的裝置呢！ 不過，如果是伺服器環境，這個服務倒是可以關閉啦！如果是桌上型電腦，那最好可以啟動囉！(註3)

hidd

(可關閉)

(系統)也是藍芽服務的功能啦！可以提供鍵盤、滑鼠等藍芽裝置的偵測哩！ 須搭配 bluetooth。伺服器環境倒是不需要此項服務。

hplip

(可關閉)

(系統)主要是針對 HP 的印表機功能所開發的腳本服務，如果你的環境中並沒有 HP 相關設備，這個服務就給他關閉吧！

ip6tables

(可關閉)

(網路)是針對本機的防火牆功能！這個防火牆主要是針對 IPv6 的版本， 如果你的網路環境並沒有 IPv6 的設備，那麼這個服務是可以關閉的。

iptables

(網路)本機防火牆功能，是核心支援的呢！所以功能與效能都非常棒！當然不能夠取消啊！ 只是設定上就得要努力研究啦！我們會在伺服器篇介紹網路相關資訊的。

irqbalance

(系統)如果你的系統是多核心的硬體，那麼這個服務要啟動， 因為它可以自動的分配系統中斷 (IRQ) 之類的硬體資源。

isdn

(可關閉)

(網路)ISDN 是一種寬頻設備 (數據機的一種) ，但是在台灣我們比較常使用 ADSL 及光纖設備， 所以這個服務是可以關閉啦。

kudzu

(可關閉)

(系統)如果你有增加新的硬體時，這個服務可以在開機時自動的偵測硬體， 並且會自動的呼叫相關的設定軟體，方便你在開機時就處理好你的硬體啊！

lm_sensors

(可關閉)

(系統)這個服務可以幫你偵測主機板的相關偵測晶片，舉例來說， 某些主機板會主動的偵測 CPU 溫度、頻率、電壓等，這個 lm_sensors 能夠將這些溫度、頻率等數據顯示出來喔！ 我們會在第二十一章談這玩意兒。

lvm2-monitor

(系統)我們已經談過 LVM 囉！所以我們當然要啟動這個服務比較妥當。

mcstrans

(系統)與 SELinux 有關的服務，最好也啟動啊！

mdmonitor

(可關閉)

(系統)可以偵測所有軟體的狀態，暫時似乎也不需要啟動這個服務哩！

messagebus

(可關閉)

(系統)可用來溝通各個軟體之間的訊息，有點類似剪貼簿的感覺。 不過在伺服器環境則沒有強烈需求就是了。

microcode_ctl

(可關閉)

(系統)Intel 的 CPU 會提供一個外掛的微指令集提供系統運作， 不過，如果你沒有下載 Intel 相關的指令集檔案，那麼這個服務不需要啟動的，也不會影響系統運作。(註4)

netfs

(可關閉)

(網路)可以進行網路磁碟機 (NFS, SMB/CIFS) 的掛載與卸載功能。 目前我們尚未使用網路，因此這個服務可以先關閉。

network

(網路)提供網路設定的功能，所以一定要啟動的啦！

nfslock

(可關閉)

(網路)NFS 為一種 Unix like 的網路磁碟機，但在進行檔案的分享時， 為了擔心同一檔案多重編輯的問題，所以會有這個鎖住 (lock) 的服務！可以避免同一個檔案被兩個不同的人編輯時所造成的檔案錯誤問題。

pcscd

(可關閉)

(系統)智慧卡偵測的服務，可以關閉他啦。

portmap

(網路)用在遠端程序呼叫的服務，很多服務都使用這個玩意兒來輔助連線的， 因此建議不要取消他，除非你確定你的系統沒有使用到任何的 RPC 服務喔！

readahead_early

readahead_later

(可關閉)

(系統)在系統開機的時候可以先將某些程式載入到記憶體中，以方便快速的載入， 可加快一些啟動的速度。

restorecond

(系統)利用 /etc/selinux/restorecond.conf 的設定來判斷當新建檔案時，該檔案的 SELinux 類型應該如何還原。需要注意的是，如果你的系統有很多非正規的 SELinux 檔案類型設定時，這個 daemon 最好關閉，否則他會將你設定的 type 修改回預設值。

rpcgssd

rpcidmapd

(可關閉)

(網路)與 NFS 有關的用戶端功能，在你還沒有玩到網路階段時， 這兩個咚咚也能夠先取消啦！

sendmail

(網路)這就是電子郵件的軟體啊！我們想要擁有可寄信的功能時， 這個服務可不能關閉。不過，預設這個服務僅能支援本機的功能，無法收受來自網際網路的郵件喔！

setroubleshoot

(系統)一定要啟動啊！因為這玩意兒可以將你的 SELinux 相關訊息記錄在 /var/log/messages 裡面，非常有幫助喔！

smartd

(系統)這個服務可以自動的偵測硬碟狀態，如果硬碟發生問題的話， 還能夠自動的回報給系統管理員，是個非常有幫助的服務喔！不可關閉他啊！

sshd

(網路)這個是遠端連線伺服器的軟體功能， 這個通訊協定比 telnet 好的地方在於 sshd 在傳送資料時可以進行加密喔！這個服務不要關閉他啦！

syslog

(系統)這個服務可以記錄系統所產生的各項訊息， 包括 /var/log/messages 內的幾個重要的登錄檔啊。

xfs

(可關閉)

(系統)這個是 X Font Server，主要提供圖形介面的字型的一個服務， 如果你不啟動 X 視窗的話，那麼這個服務可以不啟動。但是如果你有需要用到 X 時，一定要啟動這玩意兒，否則圖形介面是無法啟動的喔。

xinetd

(系統)就是 super daemon 啊，不必講了吧 ^_^

yum-updatesd

(系統)可以透過 yum 的功能進行軟體的線上升級機制， 若有升級的軟體釋出時，就能夠以郵件或者是 syslog 來通知系統管理原來手動升級啊。

上面的服務是 CentOS 5.x 預設有啟動的，這些預設啟動的服務很多是針對桌上型電腦所設計的，所以囉，如果你的 Linux 主機用途是在伺服器上面的話，那麼有很多服務是可以關閉的啦！如果你還有某些不明白的服務想要關閉的， 請務必要搞清楚該服務的功能為何喔！舉例來說，那個 syslog 就不能關閉，如果你關掉他的話，系統就不會記錄登錄檔， 那你的系統所產生的警告訊息就無法記錄起來，你將無法進行 debug 喔。

底下鳥哥繼續說明一些可能在你的系統當中的服務，只是預設並沒有啟動這個服務就是了。只是說明一下， 各服務的用途還是需要您自行查詢相關的文章囉。

其他服務的簡易說明

服務名稱

功能簡介

dovecot

(網路)可以設定 POP3/IMAP 等收受信件的服務，如果你的 Linux 主機是 email server 才需要這個服務，否則不需要啟動他啦！

httpd

(網路)這個服務可以讓你的 Linux 伺服器成為 www server 喔！

named

(網路)這是領域名稱伺服器 (Domain Name System) 的服務， 這個服務非常重要，但是設定非常困難！目前應該不需要這個服務啦！

nfs

(網路)這就是 Network Filesystem，是 Unix-Like 之間互相作為網路磁碟機的一個功能。

ntpd

(網路)服務的全名是 Network Time Protocol ，這個服務可以用來進行網路校時， 讓你系統的時間永遠都是正確的哩！

smb

(網路)這個服務可以讓 Linux 模擬成為 Windows 上面的網路上的芳鄰。 如果你的 Linux 主機想要做為 Windows 用戶端的網路磁碟機伺服器，這玩意兒得要好好玩一玩。

squid

(網路)作為代理伺服器的一個服務，可作為一個區域網路的防火牆之用。

vsftpd

(網路)作為檔案傳輸伺服器 (FTP) 的服務。

重點回顧

- 服務 (daemon) 主要可以分為 stand alone (服務可單獨啟動) 及 super daemon (透過 xinetd 統一管理的服務) 兩種。

- super daemon 由於是經過一個統一的 xinetd 來管理，因此可以具有類似防火牆管理功能。此外，管理的連線機制又可以分為 multi-threaded 及 single-threaded。

- 啟動 daemon 的程式通常最末會加上一個 d ，例如 sshd, vsftpd, httpd 等

- stand alone daemon 啟動的腳本放置到 /etc/init.d/ 這個目錄中，super daemon 的設定檔在 /etc/xinetd.d/* 內， 而啟動的方式則為 /etc/init.d/xinetd restart

- 立即啟動 stand alone daemon 的方法亦可以使用 service 這個指令

- Super daemon 的設定檔 /etc/xinetd.conf ，個別 daemon 設定檔則在 /etc/xinetd.d/* 內。在設定檔內還可以設定連線用戶端的連線與否， 具有類似防火牆的功能喔。

- 若想要統一管理防火牆的功能，可以透過 /etc/hosts.{allow,deny} ，若有安裝 TCP Wrappers 時，還能夠使用額外的 spawn 功能等

- 若想要設定開機時啟動某個服務時，可以透過 chkconfig, ntsysv 等指令。

- 一些不需要的服務可以關閉喔！

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：透過安裝、設定、啟動、觀察與管理防火牆等機制，完整的瞭解一個服務的啟動與觀察現象。

- 目標：瞭解 daemon 的控管機制，以 super daemon 為例；

- 前提：需要對本章已經瞭解，尤其是 super daemno 部分；

- 需求：最好已經連上 Internet ，因為會動用到安裝軟體

在本情境中，我們使用 telnet 這個服務來觀察，假設最終我們只開放 .edu.tw 的網域來使用本機的 telnet 服務喔！ 可以這樣做看看：

- 先看看 telnet 伺服器有沒有安裝。 telnet 伺服器在 CentOS 上面指的是 telnet-server 這支程式，所以可以這樣看看：

[root@www ~]# rpm -q telnet-server

package telnet-server is not installed

[root@www ~]# yum install telnet-server

==============================================================

Package          Arch    Version         Repository    Size

==============================================================

Installing:

telnet-server    i386    1:0.17-39.el5   base          35 k

Transaction Summary

==============================================================

Install      1 Package(s)

Update       0 Package(s)

Remove       0 Package(s)

Total download size: 35 k

Is this ok [y/N]: y

Downloading Packages:

telnet-server-0.17-39.el5.i386.rpm          |  35 kB     00:00

warning: rpmts_HdrFromFdno: Header V3 DSA signature: NOKEY, key ID e8562897

Importing GPG key 0xE8562897 "CentOS-5 Key (CentOS 5 Official Signing Key)

<centos-5-key@centos.org>" from /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

Is this ok [y/N]: y

Running rpm_check_debug

Running Transaction Test

Finished Transaction Test

Transaction Test Succeeded

Running Transaction

Installing     : telnet-server           [1/1]

Installed: telnet-server.i386 1:0.17-39.el5

Complete!

- 如果已經安裝了，那麼直接來察看一下設定檔，看看 telnet 是 stand alone 還是 super daemon 呢？最簡單的方法就是 chkconfig 了！

[root@www ~]# chkconfig --list telnet

telnet          off  <==只有 on 或 off 者為 super daemon

[root@www ~]# ll /etc/xinetd.d/telnet

-rw-r--r-- 1 root root 305 Dec  1  2007 /etc/xinetd.d/telnet

# 看吧！果然是 super daemon 哩！

[root@www ~]# grep '^telnet' /etc/services

telnet          23/tcp

telnet          23/udp

由上面可以看到， telnet 是 super daemon ，而起啟動的埠口在 port 23 這個地方。

- 如果要啟動的話，可以這樣來處置喔：

[root@www ~]# chkconfig telnet on; chkconfig --list telnet

telnet          on

[root@www ~]# /etc/init.d/xinetd restart

正在停止 xinetd:                       [  確定  ]

正在啟動 xinetd:                       [  確定  ]

[root@www ~]# netstat -tlnp | grep xinetd

tcp  0  0 0.0.0.0:23   0.0.0.0:*     LISTEN      2487/xinetd

# 確認一下，確實有啟動 port 23 喔！ ^_^

- 現在假設我們僅要針對 .edu.tw 來開放，至於其他的來源則予以關閉。我們這裡選擇 /etc/hosts.{allow,deny} 來處理，你必須要這樣做：

# 1. 先找到 telnet 的主程式是哪一支？

[root@www ~]# grep server /etc/xinetd.d/telnet

server          = /usr/sbin/in.telnetd

# 2. 開始指定開放的網域：

[root@www ~]# vim /etc/hosts.allow

in.telnetd : .edu.tw

[root@www ~]# vim /etc/hosts.deny

in.telnetd: ALL

簡單！搞定！ ^_^

簡答題部分：

- 使用 netstat -tul 與 netstat -tunl 有什麼差異？為何會這樣？

使用 n 時， netstat 就不會使用主機名稱與服務名稱 (hostname & service_name) 來顯示， 取而代之的則是以 IP 及 port number 來顯示的。IP 的分析與 /etc/hosts 及 /etc/resolv.conf 有關， 這個在未來伺服器篇才會提到。至於 port number 則與 /etc/services 有關，請自行參考喔！ ^_^

- 你能否找出來，啟動 port 3306 這個埠口的服務為何？

透過搜尋 /etc/services 內容，得到 port 3306 為 mysql 所啟動的埠口喔！查詢 google， 可得到 mysql 為一種網路資料庫系統軟體。

- 你可以透過哪些指令查詢到目前系統預設開機會啟動的服務？

本章提到的 chkconfig 以及 ntsysv 都可以查閱的到！

- 承上，那麼哪些服務『目前』是在啟動的狀態？

可以透過 service --status-all，或者是透過 netstat -anl 等方式。也可以透過 pstree 去查詢喔！ 只是相關對應的服務 daemon 檔名就得要個別查詢了。

- tcp wrappers 軟體功能與 xinetd 的功能中，可以使用哪兩個檔案進行網路防火牆的控管？

/etc/hosts.{allow,deny}

參考資料與延伸閱讀

- 註1：進階電源管理介面設定 (Advanced Configuration and Power Interface, ACPI) 官網 http://acpid.sourceforge.net/

- 註2：Zeroconf 自動網路管理機制 http://www.zeroconf.org/

- 註3：桌上型電腦的自動硬體偵測服務 http://www.freedesktop.org/wiki/Software/hal

- 註4：CPU 微指令集載入服務的說明 http://www.urbanmyth.org/microcode/

2002/07/10：第一次完成

2003/02/11：重新編排與加入 FAQ

2005/10/03：將原本舊版的資料移動到 此處 。

2005/10/12：經過一段時間的修訂，將原本在 系統設定工具 的內容移動到此，並新增完畢！

2009/03/25：將原本舊的基於 FC4 的資料移動到此處。

2009/04/02：加入一些預設啟動的服務說明。

2009/09/14：加入情境模擬，並且修訂課後練習題的部分了。

2002/07/10以來統計人數

第十九章、認識與分析登錄檔

切換解析度為 800x600

最近更新日期：2009/09/14

當你的 Linux 系統出現不明原因的問題時，很多人都告訴你，你要查閱一下登錄檔才能夠知道系統出了什麼問題了，所以說， 了解登錄檔是很重要的事情呢。登錄檔可以記錄系統在什麼時間、哪個主機、哪個服務、出現了什麼訊息等資訊， 這些資訊也包括使用者識別資料、系統故障排除須知等資訊。如果你能夠善用這些登錄檔資訊的話，你的系統出現錯誤時， 你將可以在第一時間發現，而且也能夠從中找到解決的方案，而不是昏頭轉向的亂問人呢。 此外，登錄檔所記錄的資訊量是非常大的，要人眼分析實在很困難。此時利用 shell script 或者是其他軟體提供的分析工具來處理複雜的登錄檔，可以幫助你很多很多喔！

1. 什麼是登錄檔： 登錄檔的重要性, 常見檔名, 服務與程式

2. syslogd ：記錄登錄檔的服務

2.1 登錄檔內容的一般格式

2.2 syslog 的設定檔： /etc/syslog.conf, 預設的 syslog.conf 內容

2.3 登錄檔的安全性設置

2.4 登錄檔伺服器的設定

3. 登錄檔的輪替 (logrotate)

3.1 logrotate 的設定檔

3.2 實際測試 logrotate 的動作

3.3 自訂登錄檔的輪替功能

4. 分析登錄檔

4.1 CentOS 預設提供的 logwatch

4.2 鳥哥自己寫的登錄檔分析工具：

5. 本章習題練習

6. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23895

什麼是登錄檔

『詳細而確實的分析以及備份系統的登錄檔』是一個系統管理員應該要進行的任務之一。 那麼什麼是登錄檔呢？簡單的說，就是記錄系統活動資訊的幾個檔案， 例如：何時、何地 (來源 IP)、何人 (什麼服務名稱)、做了什麼動作 (訊息登錄囉)。 換句話說就是：記錄系統在什麼時候由哪個程序做了什麼樣的行為時，發生了何種的事件等等。

要知道的是，我們的 Linux 主機在背景之下有相當多的 daemons 同時在工作著，這些工作中的程序總是會顯示一些訊息， 這些顯示的訊息最終會被記載到登錄檔當中啦。也就是說，記錄這些系統的重要訊息就是登錄檔的工作啦！

登錄檔的重要性

為什麼說登錄檔很重要，重要到系統管理員需要隨時注意他呢？我們可以這麼說：

- 解決系統方面的錯誤：

用 Linux 這麼久了，你應該偶而會發現系統可能會出現一些錯誤，包括硬體捉不到或者是某些系統程式無法順利運作的情況。 此時你該如何是好？由於系統會將硬體偵測過程記錄在登錄檔內，你只要透過查詢登錄檔就能夠瞭解系統作了啥事！ 並且由第十七章我們也知道 SELinux 與登錄檔的關係更加的強烈！所以囉，查詢登錄檔可以克服一些系統問題啦！

- 解決網路服務的問題：

你可能在做完了某些網路服務的設定後，卻一直無法順利啟動該服務，此時該怎辦？去廟裡面拜拜抽籤嗎？ 三太子大大可能無法告訴你要怎麼處理呢！由於網路服務的各種問題通常都會被寫入特別的登錄檔， 其實你只要查詢登錄檔就會知道出了什麼差錯，還不需要請示三太子大大啦！舉例來說，如果你無法啟動郵件伺服器 (sendmail)， 那麼查詢一下 /var/log/maillog 通常可以得到不錯的解答！

- 過往事件記錄簿：

這個東西相當的重要！例如：你發現 WWW 服務 (apache 軟體) 在某個時刻流量特別大，你想要瞭解為什麼時， 可以透過登錄檔去找出該時段是哪些 IP 在連線與查詢的網頁資料為何，就能夠知道原因。 此外，萬一哪天你的系統被入侵，並且被利用來攻擊他人的主機，由於被攻擊主機會記錄攻擊者，因此你的 IP 就會被對方記錄。這個時候你要如何告知對方你的主機是由於被入侵所導致的問題， 並且協助對方繼續往惡意來源追查呢？呵呵！此時登錄檔可是相當重要的呢！

Tips:

所以我們常說『天助自助者』是真的啦！你可以透過 (1)察看螢幕上面的錯誤訊息與 (2)登錄檔的錯誤資訊，幾乎可以解決大部分的 Linux 問題！

Linux 常見的登錄檔檔名

登錄檔可以幫助我們瞭解很多系統重要的事件，包括登入者的部分資訊，因此登錄檔的權限通常是設定為僅有 root 能夠讀取而已。 而由於登錄檔可以記載系統這麼多的詳細資訊，所以啦，一個有經驗的主機管理員會隨時隨地查閱一下自己的登錄檔， 以隨時掌握系統的最新脈動！那麼常見的幾個登錄檔有哪些呢？一般而言，有下面幾個：

- /var/log/cron：

還記得第十六章例行性工作排程吧？你的 crontab 排程有沒有實際被進行？ 進行過程有沒有發生錯誤？你的 /etc/crontab 是否撰寫正確？在這個登錄檔內查詢看看。

- /var/log/dmesg：

記錄系統在開機的時候核心偵測過程所產生的各項資訊。由於 CentOS 預設將開機時核心的硬體偵測過程取消顯示， 因此額外將資料記錄一份在這個檔案中；

- /var/log/lastlog：

可以記錄系統上面所有的帳號最近一次登入系統時的相關資訊。第十四章講到的 lastlog 指令就是利用這個檔案的記錄資訊來顯示的。

- /var/log/maillog 或 /var/log/mail/*：

記錄郵件的往來資訊，其實主要是記錄 sendmail (SMTP 協定提供者) 與 dovecot (POP3 協定提供者) 所產生的訊息啦。 SMTP 是發信所使用的通訊協定， POP3 則是收信使用的通訊協定。 sendmail 與 dovecot 則分別是兩套達成通訊協定的軟體。

- /var/log/messages：

這個檔案相當的重要，幾乎系統發生的錯誤訊息 (或者是重要的資訊) 都會記錄在這個檔案中； 如果系統發生莫名的錯誤時，這個檔案是一定要查閱的登錄檔之一。

- /var/log/secure：

基本上，只要牽涉到『需要輸入帳號密碼』的軟體，那麼當登入時 (不管登入正確或錯誤) 都會被記錄在此檔案中。 包括系統的 login 程式、圖形介面登入所使用的 gdm 程式、 su, sudo 等程式、還有網路連線的 ssh, telnet 等程式， 登入資訊都會被記載在這裡；

- /var/log/wtmp, /var/log/faillog：

這兩個檔案可以記錄正確登入系統者的帳號資訊 (wtmp) 與錯誤登入時所使用的帳號資訊 (faillog) ！ 我們在第十一章談到的 last 就是讀取 wtmp 來顯示的， 這對於追蹤一般帳號者的使用行為很有幫助！

- /var/log/httpd/*, /var/log/news/*, /var/log/samba/*：

不同的網路服務會使用它們自己的登錄檔案來記載它們自己產生的各項訊息！上述的目錄內則是個別服務所制訂的登錄檔。

常見的登錄檔就是這幾個，但是不同的 Linux distributions ，通常登錄檔的檔名不會相同 (除了 /var/log/messages 之外 )。所以說，你還是得要查閱你 Linux 主機上面的登錄檔設定資料， 才能知道你的登錄檔主要檔名喔！

登錄檔所需相關服務 (daemon) 與程式

那麼這些登錄檔是怎麼產生的呢？基本上有兩種方式，一種是由軟體開發商自行定義寫入的登錄檔與相關格式， 例如 WWW 軟體 apache 就是這樣處理的。另一種則是由 Linux distribution 提供的登錄檔管理服務來統一管理。 你只要將訊息丟給這個服務後，他就會自己分門別類的將各種訊息放置到相關的登錄檔去！CentOS 提供 syslogd 這個服務來統一管理登錄檔喔！

除了這個 syslogd 之外，我們的核心也需要額外的登錄服務來記錄核心產生的各項資訊， 這個專門記錄核心資訊的登錄檔服務就是 klogd 啦。所以說，登錄檔所需的服務主要就是 syslogd 與 klogd 這兩者。

不過要注意的是，如果你任憑登錄檔持續記錄的話，由於系統產生的資訊天天都有，那麼你的登錄檔的容量將會長大到無法無天∼ 如果你的登錄檔容量太大時，可能會導致大檔案讀寫效率不佳的問題 (因為要從磁碟讀入記憶體，越大的檔案消耗記憶體量越多)。 所以囉，你需要對登錄檔備份與更新。那...需要手動處理喔？當然不需要，我們可以透過 logrotate (登錄檔輪替) 這玩意兒來自動化處理登錄檔容量與更新的問題喔！

所謂的 logrotate 基本上，就是將舊的登錄檔更改名稱，然後建立一個空的登錄檔，如此一來， 新的登錄檔將重新開始記錄，然後只要將舊的登錄檔留下一陣子，嗯！那就可以達到將登錄檔『輪轉』的目的啦！ 此外，如果舊的紀錄 (大概要保存幾個月吧！) 保存了一段時間沒有問題，那麼就可以讓系統自動的將他砍掉， 免得佔掉很多寶貴的硬碟空間說！

總結一下，針對登錄檔所需的功能，我們需要的服務與程式有：

- syslogd：主要登錄系統與網路等服務的訊息；

- klogd：主要登錄核心產生的各項資訊；

- logrotate：主要在進行登錄檔的輪替功能。

由於我們著眼點在於想要瞭解系統上面軟體所產生的各項資訊，因此本章主要針對 syslogd 與 logrotate 來介紹。 接著下來我們來談一談怎麼樣規劃這兩個玩意兒。就由 syslogd 這支程式先談起吧！畢竟得先有登錄檔，才可以進行 logrotate 呀！您說是吧！

syslogd ：記錄登錄檔的服務

剛剛提到說 Linux 的登錄檔主要是由 syslogd 在負責，那麼你的 Linux 是否有啟動 syslogd 呢？而且是否有設定開機時啟動呢？呵呵！檢查一下先：

[root@www ~]# ps aux | grep syslog

USER   PID %CPU %MEM  VSZ  RSS TTY  STAT START  TIME COMMAND

root  4294  0.0  0.0 1716  568 ?    Ss   Mar31  0:00 syslogd -m 0

# 瞧！確實有啟動的！

[root@www ~]# chkconfig --list syslog

syslog    0:off  1:off  2:on   3:on   4:on   5:on   6:off

# 預設情況下，文字介面與圖形介面 (3, 5) 都有啟動喔！

看到 syslog 這個服務名稱了吧？所以知道他已經在系統中工作囉！好了，既然本章主要是講登錄檔，那麼你知道登錄檔的內容是如何展現的？ syslog 的設定檔在哪裡？如何設定？如果你的 Linux 主機想要當作整個區網的登錄檔伺服器時，又該如何設定？ 底下就讓我們來玩玩這玩意！

登錄檔內容的一般格式

一般來說，系統產生的訊息經過 syslog 而記錄下來的資料中，每條訊息均會記錄底下的幾個重要資料：

- 事件發生的日期與時間；

- 發生此事件的主機名稱；

- 啟動此事件的服務名稱 (如 samba, xinetd 等) 或函式名稱 (如 libpam ..)；

- 該訊息的實際資料內容。

當然，這些資訊的『詳細度』是可以修改的，而且，這些資訊可以作為系統除錯之用呢！ 我們拿登錄時一定會記載帳號資訊的 /var/log/secure 為例好了：

[root@www ~]# cat /var/log/secure

1 Mar 14 15:38:00 www atd[18701]: pam_unix(atd:session): session opened for

user root by (uid=0)

2 Mar 14 15:38:00 www atd[18701]: pam_unix(atd:session): session closed for

user root

3 Mar 16 16:01:51 www su: pam_unix(su-l:auth): authentication failure; logn

ame=vbird uid=500 euid=0 tty=pts/1 ruser=vbird rhost=  user=root

4 Mar 16 16:01:55 www su: pam_unix(su-l:session): session opened for user

root by vbird(uid=500)

5 Mar 16 16:02:22 www su: pam_unix(su-l:session): session closed for user root

|--日期/時間---|-H-|-----服務與相關函數-------|--訊息說明------>

我們拿第一筆資料來說明好了，該資料是說：『在三月14日 (Mar 14) 的下午 15:38 分，由 www 這部主機的 atd [PID 為 18701] 傳來的消息，這個消息是透過 pam_unix 這個模組所提出的。訊息內容為 root (uid=0) 這個帳號已經開啟 atd 的活動了。』有夠清楚吧！ 那請您自行翻譯一下後面的 4 條訊息內容是什麼喔！

其實還有很多的資訊值得查閱的呢！尤其是 /var/log/messages 的內容。記得一個好的系統管理員， 要常常去『巡視』登錄檔的內容喔！尤其是發生底下幾種情況時：

- 當你覺得系統似乎不太正常時；

- 某個 daemon 老是無法正常啟動時；

- 某個使用者老是無法登入時；

- 某個 daemon 執行過程老是不順暢時；

還有很多啦！反正覺得系統不太正常，就得要查詢查詢登錄檔就是了。

Tips:

提供一個鳥哥常做的檢查方式。當我老是無法成功的啟動某個服務時，我會在最後一次啟動該服務後，立即檢查登錄檔， 先 (1)找到現在時間所登錄的資訊『第一欄位』； (2)找到我想要查詢的那個服務『第三欄位』， (3)最後再仔細的查閱第四欄位的資訊，來藉以找到錯誤點。

syslog 的設定檔：/etc/syslog.conf

什麼？登錄檔還有設定檔？喔！不是啦∼是 syslogd 這個 daemon 的設定檔啦！ 我們現在知道 syslogd 可以負責主機產生的各個資訊的登錄，而這些資訊本身是有『嚴重等級』之分的， 而且，這些資料最終要傳送到哪個檔案去是可以修改的呢，所以我們才會在一開頭的地方講說， 每個 Linux distributions 放置的登錄檔檔名可能會有所差異啊！

基本上， syslog 針對各種服務與訊息記錄在某些檔案的設定檔就是 /etc/syslog.conf， 這個檔案規定了『(1)什麼服務 (2)的什麼等級訊息 (3)需要被記錄在哪裡(裝置或檔案)』 這三個咚咚，所以設定的語法會是這樣：

服務名稱[.=!]訊息等級          訊息記錄的檔名或裝置或主機

# 底下以 mail 這個服務產生的 info 等級為例：

mail.info                      /var/log/maillog_info

# 這一行說明：mail 服務產生的大於等於 info 等級的訊息，都記錄到

# /var/log/maillog_info 檔案中的意思。

我們將上面的資料簡單的分為三部分來說明：

- 服務名稱

syslog 本身有規範一些服務，你可以透過這些服務來儲存系統的訊息。syslog 認識的服務主要有底下這些： (可使用 man 3 syslog 查詢到相關的資訊)

服務類別

說明

auth (authpriv)

主要與認證有關的機制，例如 login, ssh, su 等需要帳號/密碼的咚咚；

cron

就是例行性工作排程 cron/at 等產生訊息記錄的地方；

daemon

與各個 daemon 有關的訊息；

kern

就是核心 (kernel) 產生訊息的地方；

lpr

亦即是列印相關的訊息啊！

mail

只要與郵件收發有關的訊息紀錄都屬於這個；

news

與新聞群組伺服器有關的東西；

syslog

就是 syslogd 這支程式本身產生的資訊啊！

user, uucp, local0 ~ local7

與 Unix like 機器本身有關的一些訊息。

上面談到的都是 syslog 自行制訂的服務名稱，軟體開發商可以透過呼叫上述的服務名稱來記錄他們的軟體。 舉例來說， sendmail 與 postfix 及 dovecot 都是與郵件有關的軟體，這些軟體在設計登錄檔記錄時，都會主動呼叫 syslogd 內的 mail 服務名稱 (LOG_MAIL)，所以上述三個軟體 (sendmail, postfix, dovecot) 產生的訊息在 syslog 看起來，就會『是 mail 』類型的服務了。我們可以將這個概念繪製如底下的圖示來理解：

圖 2.2.1、 syslog 所制訂的服務名稱與軟體呼叫的方式

另外，每種服務所產生的資料量其實差異是很大的，舉例來說， mail 的登錄檔訊息多的要命， 每一封信件進入後， mail 至少需要記錄『寄信人的資訊；與收信者的訊息』等等； 而如果是用來做為工作站主機的，那麼登入者 (利用 login 登錄主機處理事情) 的數量一定不少，那個 authpriv 所管轄的內容可就多的要命了。

為了讓不同的資訊放置到不同的檔案當中，好讓我們分門別類的進行登錄檔的管理， 所以囉，將各種類別的服務之登錄檔，記錄在不同的檔案裡面，就是我們 /etc/syslog.conf 所要作的規範了！

- 訊息等級

同一個服務所產生的訊息也是有差別的，有啟動時僅通知系統而已的一般訊息 (information)， 有出現還不至於影響到正常運作的警告訊息 (warn) ，還有系統硬體發生嚴重錯誤時，所產生的重大問題訊息 (error 等等)； 訊息到底有多少種嚴重的等級呢？基本上，syslog 將訊息分為七個主要的等級，依序是這樣的(由不重要排列到重要訊息等級)：

等級

等級名稱

說明

1

info

僅是一些基本的訊息說明而已；

2

notice

比 info 還需要被注意到的一些資訊內容；

3

warning

(warn)

警示的訊息，可能有問題，但是還不至於影響到某個 daemon 運作的資訊；基本上， info, notice, warn 這三個訊息都是在告知一些基本資訊而已，應該還不至於造成一些系統運作困擾；

4

err

(error)

一些重大的錯誤訊息，例如設定檔的某些設定值造成該服務服法啟動的資訊說明， 通常藉由 err 的錯誤告知，應該可以瞭解到該服務無法啟動的問題呢！

5

crit

比 error 還要嚴重的錯誤資訊，這個 crit 是臨界點 (critical) 的縮寫，這個錯誤已經很嚴重了喔！

6

alert

警告警告，已經很有問題的等級，比 crit 還要嚴重！

7

emerg

(panic)

疼痛等級，意指系統已經幾乎要當機的狀態！ 很嚴重的錯誤資訊了。通常大概只有硬體出問題，導致整個核心無法順利運作，就會出現這樣的等級的訊息吧！

除了這些有等級的訊息外，還有兩個特殊的等級，那就是 debug(錯誤偵測等級) 與 none (不需登錄等級) 兩個，當我們想要作一些錯誤偵測，或者是忽略掉某些服務的資訊時， 就用這兩個咚咚吧！

特別留意一下在訊息等級之前還有 [.=!] 的連結符號喔！他代表的意思是這樣的：

- . ：代表『比後面還要高的等級 (含該等級) 都被記錄下來』的意思，例如： mail.info 代表只要是 mail 的資訊，而且該資訊等級高於 info (含 info 本身)時，就會被記錄下來的意思。

- .=：代表所需要的等級就是後面接的等級而已， 其他的不要！

- .!：代表不等於， 亦即是除了該等級外的其他等級都記錄。

一般來說，我們比較常使用的是『.』這個連結符號啦！^_^

- 訊息記錄的檔名或裝置或主機

再來則是這個訊息要放置在哪裡的紀錄了。通常我們使用的都是記錄的檔案啦！但是也可以輸出到裝置呦！ 例如印表機之類的！也可以記錄到不同的主機上頭去呢！底下就是一些常見的放置處：

- 檔案的絕對路徑：通常就是放在 /var/log 裡頭的檔案啦！

- 印表機或其他：例如 /dev/lp0 這個印表機裝置

- 使用者名稱：顯示給使用者囉！

- 遠端主機：例如 @www.vbird.tsai 當然啦，要對方主機也能支援才行！

- *：代表『目前在線上的所有人』，類似 wall 這個指令的意義！

- syslog.conf 語法練習

基本上，整個 syslog 的設定檔就只是這樣而已，底下我們來思考一些例題，好讓你可以更清楚的知道如何設定 syslogd 啊！

例題：

如果我要將我的 mail 相關的資料給他寫入 /var/log/maillog 當中，那麼在 /etc/syslog.conf 的語法如何設計？

答：

基本的寫法是這樣的：

mail.info　　　/var/log/maillog

注意到上面喔，當我們的等級使用 info 時，那麼『任何大於 info 等級(含 info 這個等級)之上的訊息， 都會被寫入到後面接的檔案之中！』這樣可以瞭解嗎？也就是說，我們可以將所有 mail 的登錄資訊都紀錄在 /var/log/maillog 裡面的意思啦！

例題：

我要將新聞群組資料 (news) 及例行性工作排程 (cron) 的訊息都寫入到一個稱為 /var/log/cronnews 的檔案中，但是這兩個程序的警告訊息則額外的記錄在 /var/log/cronnews.warn 中， 那該如何設定我的 syslog.conf 呢？

答：

很簡單啦！既然是兩個程序，那麼只好以分號來隔開了，此外，由於第二個指定檔案中，我只要記錄警告訊息， 因此設定上需要指定『.=』這個符號，所以語法成為了：

news.*;cron.*　　　　　/var/log/cronnews

news.=warn;cron.=warn　/var/log/cronnews.warn

上面那個『.=』就是在指定等級的意思啦！由於指定了等級，因此，只有這個等級的訊息才會被紀錄在這個檔案裡面呢！ 此外你也必須要注意，news 與 cron 的警告訊息也會寫入 /var/log/cronnews 內喔！

例題：

我的 messages 這個檔案需要記錄所有的資訊，但是就是不想要記錄 cron, mail 及 news 的資訊，那麼應該怎麼寫才好？

答：

可以有兩種寫法，分別是：

*.*;news,cron,mail.none　　　　　　/var/log/messages

*.*;news.none;cron.none;mail.none　/var/log/messages

使用『,』分隔時，那麼等級只要接在最後一個即可，如果是以『;』來分的話， 那麼就需要將服務與等級都寫上去囉！這樣會設定了吧！

- CentOS 5.x 預設的 syslog.conf 內容

瞭解語法之後，我們來看一看 syslog 有哪些系統服務已經在記錄了呢？就是瞧一瞧 /etc/syslog.conf 這個檔案的預設內容囉！ (注意！如果需要將該行做為註解時，那麼就加上 # 符號就可以啦)

# 來自 CentOS 5.x 的相關資料

[root@www ~]# vim /etc/syslog.conf

1 #kern.*                                              /dev/console

2 *.info;mail.none;news.none;authpriv.none;cron.none   /var/log/messages

3 authpriv.*                                           /var/log/secure

4 mail.*                                              -/var/log/maillog

5 cron.*                                               /var/log/cron

6 *.emerg                                              *

7 uucp,news.crit                                       /var/log/spooler

8 local7.*                                             /var/log/boot.log

9 news.=crit                                         /var/log/news/news.crit

10 news.=err                                          /var/log/news/news.err

11 news.notice                                        /var/log/news/news.notice

上面總共僅有十一行設定值，每一行的意義是這樣的：

1. #kern.*：只要是核心產生的訊息，全部都送到 console(終端機) 去。console 通常是由外部裝置連接到系統而來， 舉例來說，很多封閉型主機 (沒有鍵盤、螢幕的系統) 可以透過連接 RS232 連接口將訊息傳輸到外部的系統中， 例如以筆記型電腦連接到封閉主機的 RS232 插口。這個項目通常應該是用在系統出現嚴重問題而無法使用預設的螢幕觀察系統時， 可以透過這個項目來連接取得核心的訊息。(註1)

2. *.info;mail.none;news.none;authpriv.none;cron.none：由於 mail, news, authpriv, cron 等類別產生的訊息較多， 且已經寫入底下的數個檔案中，因此在 /var/log/messages 裡面就不記錄這些項目。除此之外的其他訊息都寫入 /var/log/messages 中。這也是為啥我們說這個 messages 檔案很重要的緣故！

3. authpriv.*：認證方面的訊息均寫入 /var/log/secure 檔案；

4. mail.*：郵件方面的訊息則均寫入 /var/log/maillog 檔案；

5. cron.*：例行性工作排程均寫入 /var/log/cron 檔案；

6. *.emerg：當產生最嚴重的錯誤等級時，將該等級的訊息以 wall 的方式廣播給所有在系統登入的帳號得知， 要這麼做的原因是希望在線的使用者能夠趕緊通知系統管理員來處理這麼可怕的錯誤問題。

7. uucp,news.crit：uucp 是早期 Unix-like 系統進行資料傳遞的通訊協定，後來常用在新聞群組的用途中。 news 則是新聞群組。當新聞群組方面的資訊有嚴重錯誤時就寫入 /var/log/spooler 檔案中；

8. local7.*：將本機開機時應該顯示到螢幕的訊息寫入到 /var/log/boot.log 檔案中；

9. 後面的 news.=crit、news.=err、news.notice 則主要在分別記錄新聞群組產生的不同等級的訊息。

在上面的第四行關於 mail 的記錄中，在記錄的檔案 /var/log/maillog 前面還有個減號『 - 』是幹嘛用的？由於郵件所產生的訊息比較多，因此我們希望郵件產生的訊息先儲存在速度較快的記憶體中 (buffer) ，等到資料量夠大了才一次性的將所有資料都填入磁碟內，這樣將有助於登錄檔的存取性能。 只不過由於訊息是暫存在記憶體內，因此若不正常關機導致登錄資訊未回填到登錄檔中，可能會造成部分資料的遺失。

此外，每個 Linux distributions 的 syslog.conf 設定差異是頗大的，如果你想要找到相對應的登錄資訊時， 可得要查閱一下 /etc/syslog.conf 這個檔案才行！否則可能會發生分析到錯誤的資訊喔！舉例來說， 鳥哥有自己寫一支分析登錄檔的 script，這個 script 是依據 Red Hat 系統預設的登錄檔所寫的，因此不同的 distributions 想要使用這支程式時，就得要自行設計與修改一下 /etc/syslog.conf 才行喔！否則就可能會分析到錯誤的資訊囉。 那麼如果你有自己的需要而得要修訂登錄檔時，該如何進行？

- 自行增加登錄檔檔案功能

如果你有其他的需求，所以需要特殊的檔案來幫你記錄時，呵呵！別客氣，千萬給他記錄在 /etc/syslog.conf 當中，如此一來，你就可以重複的將許多的資訊記錄在不同的檔案當中，以方便你的管理呢！ 讓我們來作個練習題吧！如果你想要讓『所有的資訊』都額外寫入到 /var/log/admin.log 這個檔案時， 你可以怎麼作呢？先自己想一想，並且作一下，再來看看底下的作法啦！

# 1. 先設定好所要建立的檔案設置！

[root@www ~]# vim /etc/syslog.conf

# Add by VBird 2009/04/08       <==再次強調，自己修改的時候加入一些說明

*.info      /var/log/admin.log  <==有用的是這行啦！

# 2. 重新啟動 syslog 呢！

[root@www ~]# /etc/init.d/syslog restart

[root@www ~]# ll /var/log/admin.log

-rw------- 1 root root 118 Apr  8 13:50 /var/log/admin.log

# 瞧吧！建立了這個登錄檔出現囉！

很簡單吧！如此一來，所有的資訊都會寫入 /var/log/admin.log 裡面了！

登錄檔的安全性設置

好了，由上一個小節裡面我們知道了 syslog.conf 的設定，也知道了登錄檔內容的重要性了， 所以，如果幻想你是一個很厲害的駭客，想利用他人的電腦幹壞事，然後又不想留下證據， 你會怎麼作？對啦！就是離開的時候將屁股擦乾淨，將所有可能的訊息都給他抹煞掉， 所以第一個動腦筋的地方就是登錄檔的清除工作啦∼ 如果你的登錄檔不見了，那該怎辦？

Tips:

哇！鳥哥教人家幹壞事……喂！不要亂講話∼俺的意思是，如果改天你發現你的登錄檔不翼而飛了， 或者是發現你的登錄檔似乎不太對勁的時候，最常發現的就是網友常常會回報說，他的 /var/log 這個目錄『不見了！』不要笑！這是真的事情！請記得，『趕快清查你的系統！』

傷腦筋呢！有沒有辦法防止登錄檔被刪除？或者是被 root 自己不小心變更呢？有呀！拔掉網路線或電源線就好了……呵呵！ 別擔心，基本上，我們可以透過一個隱藏的屬性來設定你的登錄檔，成為『 只可以增加資料，但是不能被刪除 』的狀態，那麼或許可以達到些許的保護！不過，如果你的 root 帳號被破解了，那麼底下的設定還是無法保護的，因為你要記得『 root 是可以在系統上面進行任何事情的 』，因此，請將你的 root 這個帳號的密碼設定的安全一些！千萬不要輕忽這個問題呢！

Tips:

為什麼登錄檔還要防止被自己 (root) 不小心所修改過呢？ 鳥哥在教 Linux 的課程時，我的學生常常會舉手說：『老師，我的登錄檔不能記錄資訊了！糟糕！是不是被入侵了啊？』 怪怪！明明是電腦教室的主機，使用的是 Private IP 而且學校計中還有抵擋機制，不可能被攻擊吧？ 查詢了才知道原來同學很喜歡使用『 :wq 』來離開 vim 的環境，但是 syslog 的登錄檔只要『被編輯過』就無法繼續記錄！ 所以才會導致不能記錄的問題。此時你得要 (1)改變使用 vim 的習慣； (2)重新啟動 syslog 讓他再繼續提供服務才行喔！

既然如此，那麼我們就來處理一下隱藏屬性的東東吧！我們在第七章談到過 lsattr 與 chattr 這兩個東西啦！如果將一個檔案以 chattr 設定 i 這個屬性時，那麼該檔案連 root 都不能殺掉！而且也不能新增資料，嗯！真安全！但是，如此一來登錄檔的功能豈不是也就消失了？ 因為沒有辦法寫入呀！所以囉，我們要使用的是 a 這個屬性！你的登錄檔如果設定了這個屬性的話，那麼 他將只能被增加，而不能被刪除！嗯！ 這個項目就非常的符合我們登錄檔的需求啦！因此，你可以這樣的增加你的登錄檔的隱藏屬性。

Tips:

請注意，底下的這個 chattr 的設定狀態：『僅適合已經對 Linux 系統很有概念的朋友』來設定， 對於新手來說，建議你直接使用系統的預設值就好了，免得到最後登錄檔無法寫入∼ 那就比較糗一點！ @_@

[root@www ~]# chattr +a /var/log/messages

[root@www ~]# lsattr /var/log/messages

-----a------- /var/log/messages

加入了這個屬性之後，你的 /var/log/messages 登錄檔從此就僅能被增加，而不能被刪除，直到 root 以『 chattr -a /var/log/messages 』取消這個 a 的參數之後，才能被刪除或移動喔！

雖然，為了你登錄檔的資訊安全，這個 chattr 的 +a 旗標可以幫助你維護好這個檔案， 不過，如果你的系統已經被取得 root 的權限，而既然 root 可以下達 chattr -a 來取消這個旗標， 所以囉，還是有風險的啦！此外，前面也稍微提到，新手最好還是先不要增加這個旗標， 很容易由於自己的忘記，導致系統的重要訊息無法記錄呢。

基本上，鳥哥認為，這個旗標最大的用處除了在保護你登錄檔的資料外， 他還可以幫助你避免掉不小心寫入登錄檔的狀況喔。要注意的是，當『 你不小心 "手動" 更動過登錄檔後，例如那個 /var/log/messages ， 你不小心用 vi 開啟他，離開卻下達 :wq 的參數，呵呵！那麼該檔案未來將不會再繼續進行登錄動作！ 』這個問題真的很常發生！由於你以 vi 儲存了登錄檔，則 syslogd 會誤判為該檔案已被更動過， 將導致 syslogd 不再寫入該檔案新的內容∼很傷腦筋的！

要讓該登錄檔可以繼續寫入，你只要重新啟動 syslog (/etc/init.d/syslog restart) 即可。 不過，總是比較麻煩。所以啊，如果你針對登錄檔下達 chattr +a 的參數，嘿嘿！ 未來你就不需要害怕不小心更動到該檔案了！因為無法寫入嘛！除了可以新增之外∼ ^_^

不過，也因為這個 +a 的屬性讓該檔案無法被刪除與修改，所以囉，當我們進行登錄檔案輪替時 (logrotate) ，將會無法移動該登錄檔的檔名呢！所以會造成很大的困擾。這個困擾雖然可以使用 logrotate 的設定檔來解決，但是，還是先將登錄檔的 +a 旗標拿掉吧！

[root@www ~]# chattr -a /var/log/messages

登錄檔伺服器的設定

我們在之前稍微提到的，在 syslog.conf 檔案當中，可以將登錄資料傳送到印表機或者是遠端主機上面去。這樣做有什麼意義呢？ 如果你將登錄資訊直接傳送到印表機上面的話，那麼萬一不小心你的系統被 cracker 所入侵， 他也將你的 /var/log/ 砍掉了，怎麼辦？沒關係啊！反正你已經將重要資料直接以印表機記錄起來了， 嘿嘿！他是無法逃開的啦！^_^

再想像一個環境，你的辦公室內有十部 Linux 主機，每一部負責一個網路服務， 你為了要瞭解每部主機的狀態，因此，你常常需要登入這十部主機去查閱你的登錄檔∼ 哇！光用想的，每天要進入十部主機去查資料，想到就煩∼沒關係∼這個時候我們可以讓某一部主機當成 『登錄檔伺服器』，用他來記錄所有的十部 linux 主機的資訊，嘿嘿！這樣我就直接進入一部主機就可以了！ 省時又省事，真方便∼

那要怎麼達到這樣的功能呢？很簡單啦，我們 CentOS 5.x 預設的 syslog 本身就已經具有這個登錄檔伺服器的功能了， 只是預設並沒有啟動該功能而已。你可以透過 man syslogd 去查詢一下相關的選項就能夠知道啦！ 既然是登錄檔伺服器，那麼我們的 Linux 主機當然會啟動一個埠口來監聽了，那個預設的埠口就是 UDP 的 514 喔！

圖 2.4.1、登錄檔伺服器的架構

如上圖所示，伺服器會啟動監聽的埠口，用戶端則將登錄檔再轉出一份送到伺服器去。 而既然是登錄檔『伺服器』，所以當然有伺服器與用戶端 (client) 囉！這兩者的設定分別是這樣的：

# 1. Server 端：修改 syslogd 的啟動設定檔，通常在 /etc/sysconfig 內！

[root@www ~]# vim /etc/sysconfig/syslog

# 找到底下這一行：

SYSLOGD_OPTIONS="-m 0"

# 改成底下這樣子！

SYSLOGD_OPTIONS="-m 0 -r"

# 2. 重新啟動與觀察 syslogd 喔！

[root@www ~]# /etc/init.d/syslog restart

[root@www ~]# netstat -lunp | grep syslog

Proto Recv-Q Send-Q Local Address  Foreign Address State   PID/Program name

udp        0      0 0.0.0.0:514    0.0.0.0:*               13981/syslogd

# 嘿嘿！你的登錄檔主機已經設定妥當囉！很簡單吧！

透過這個簡單的動作，你的 Linux 主機已經可以接收來自其他主機的登錄資訊了！ 當然啦，你必須要知道網路方面的相關基礎，這裡鳥哥只是先介紹， 未來瞭解了網路相關資訊後，再回頭來這裡瞧一瞧先！ ^_^

至於 client 端的設定就簡單多了！只要指定某個資訊傳送到這部主機即可！ 舉例來說，我們的登錄檔伺服器 IP 為 192.168.1.100 ，而 client 端希望所有的資料都送給主機， 所以，可以在 /etc/syslog.conf 裡面新增這樣的一行：

[root@www ~]# vim /etc/syslog.conf

*.*       @192.168.1.100

再重新啟動 syslog 後，立刻就搞定了！而未來主機上面的登錄檔當中，每一行的『主機名稱』就會顯示來自不同主機的資訊了。 很簡單吧！ ^_^。接下來，讓我們來談一談，那麼如何針對登錄檔來進行輪轉 (rotate) 呢？

登錄檔的輪替(logrotate)

假設我們已經將登錄資料寫入了記錄檔中了，也已經利用 chattr 設定了 +a 這個屬性了，那麼該如何進行 logrotate 的工作呢？這裡請特別留意的是：『syslog 利用的是 daemon 的方式來啟動的， 當有需求的時候立刻就會被執行的，但是 logrotate 卻是在規定的時間到了之後才來進行登錄檔的輪替， 所以這個 logrotate 程序當然就是掛在 cron 底下進行的呦！』 仔細看一下 /etc/cron.daily/ 裡面的檔案，嘿嘿∼看到了吧！ /etc/cron.daily/logrotate 就是記錄了每天要進行的登錄檔輪替的行為啦！ ^_^！底下我們就來談一談怎麼樣設計這個 logrotate 吧！

logrotate 的設定檔

既然 logrotate 主要是針對登錄檔來進行輪替的動作，所以囉，他當然必須要記載『 在什麼狀態下才將登錄檔進行輪替』的設定啊！那麼 logrotate 這個程式的參數設定檔在哪裡呢？呵呵！那就是：

- /etc/logrotate.conf

- /etc/logrotate.d/

那個 logrotate.conf 才是主要的參數檔案，至於 logrotate.d 是一個目錄， 該目錄裡面的所有檔案都會被主動的讀入 /etc/logrotate.conf 當中來進行！另外，在 /etc/logrotate.d/ 裡面的檔案中，如果沒有規定到的一些細部設定，則以 /etc/logrotate.conf 這個檔案的規定來指定為預設值！

好了，剛剛我們提到 logrotate 的主要功能就是將舊的登錄檔案移動成舊檔， 並且重新建立一個新的空的檔案來記錄，他的執行結果有點類似底下的圖示：

圖 3.1.1、 登錄檔進行 logrotate 的結果

由上面的圖示我們可以清楚的知道，當第一次執行完 rotate 之後，原本的 messages 會變成 messages.1 而且會製造一個空的 messages 給系統來儲存登錄檔。而第二次執行之後，則 messages.1 會變成 messages.2 而 messages 會變成 messages.1 ，又造成一個空的 messages 來儲存登錄檔！那麼如果我們僅設定保留三個登錄檔而已的話，那麼執行第四次時，則 messages.3 這個檔案就會被刪除，並由後面的較新的保存登錄檔所取代！基本的工作就是這樣啦！

那麼多久進行一次這樣的 logrotate 工作呢？這些都記錄在 logrotate.conf 裡面，我們來看一下預設的 logrotate 的內容吧！

[root@www ~]# vim /etc/logrotate.conf

# 底下的設定是 "logrotate 的預設設定值" ，如果個別的檔案設定了其他的參數，

# 則將以個別的檔案設定為主，若該檔案沒有設定到的參數則以這個檔案的內容為預設值！

weekly    <==預設每個禮拜對登錄檔進行一次 rotate 的工作

rotate 4  <==保留幾個登錄檔呢？預設是保留四個！

create    <==由於登錄檔被更名，因此建立一個新的來繼續儲存之意！

#compress <==被更動的登錄檔是否需要壓縮？如果登錄檔太大則可考慮此參數啟動

include /etc/logrotate.d

# 將 /etc/logrotate.d/ 這個目錄中的所有檔案都讀進來執行 rotate 的工作！

/var/log/wtmp {       <==僅針對 /var/log/wtmp 所設定的參數

monthly           <==每個月一次，取代每週！

minsize 1M        <==檔案容量一定要超過 1M 後才進行 rotate (略過時間參數)

create 0664 root utmp <==指定新建檔案的權限與所屬帳號/群組

rotate 1          <==僅保留一個，亦即僅有 wtmp.1 保留而已。

}

# 這個 wtmp 可記錄登入者與系統重新開機時的時間與來源主機及登入期間的時間。

# 由於具有 minsize 的參數，因此不見得每個月一定會進行一次喔！要看檔案容量。

# 由於僅保留一個登錄檔而已，不滿意的話可以將他改成 rotate 5 吧！

由這個檔案的設定我們可以知道 /etc/logrotate.d 其實就是由 /etc/logrotate.conf 所規劃出來的目錄，所以，其實我們可以將所有的資料都給他寫入 /etc/logrotate.conf 即可，但是這樣一來這個檔案就實在是太複雜了，尤其是當我們使用很多的服務在系統上面時， 每個服務都要去修改 /etc/logrotate.conf 的設定也似乎不太合理∼ 所以，如果獨立出來一個目錄，那麼每個以 RPM 打包方式所建立的服務的登錄檔輪替設定， 就可以獨自成為一個檔案，並且放置到 /etc/logrotate.d/ 當中即可，真是方便又合理的做法啊！ ^_^

一般來說，這個 /etc/logrotate.conf 是『預設的輪替狀態』而已， 我們的各個服務都可以擁有自己的登錄檔輪替設定，你也可以自行修改成自己喜歡的樣式啊！ 例如，如果你的系統的空間夠大，並且擔心除錯以及駭客的問題，那麼可以：

- 將 rotate 4 改成 rotate 9 左右，以保存較多的備份檔案；

- 大部分的登錄檔不需要 compress 囉！但是空間太小就需要 compress ！尤其是很佔硬碟空間的 httpd 更需要 compress 的！

好了，上面我們大致介紹了 /var/log/wtmp 這個檔案的設定，現在你知道了 logrotate.conf 的設定語法是：

登錄檔的絕對路徑檔名 ... {

個別的參數設定值，如 monthly, compress 等等

}

底下我們再以 /etc/logrotate.d/syslog 這個輪替 syslog 服務的檔案，來看看該如何設定他的 rotate 呢？

[root@www ~]# vi /etc/logrotate.d/syslog

/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \

/var/log/boot.log /var/log/cron {

sharedscripts

postrotate

/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true

/bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true

endscript

}

在上面的語法當中，我們知道正確的 logrotate 的寫法為：

- 檔名：被處理的登錄檔絕對路徑檔名寫在前面，可以使用空白字元分隔多個登錄檔；

- 參數：上述檔名進行輪替的參數使用 { } 包括起來；

- 執行腳本：可呼叫外部指令來進行額外的命令下達，這個設定需與 sharedscripts .... endscript 設定合用才行。至於可用的環境為：

- prerotate：在啟動 logrotate 之前進行的指令，例如修改登錄檔的屬性等動作；

- postrotate：在做完 logrotate 之後啟動的指令，例如重新啟動 (kill -HUP) 某個服務！

- Prerotate 與 postrotate 對於已加上特殊屬性的檔案處理上面，是相當重要的執行程序！

那麼 /etc/logrotate.d/syslog 內設定的六個檔案的輪替功能就變成了：

- 該設定只對 /var/log/ 內的 messages, secure, maillog, spooler, boot.log, cron 有效；

- 登錄檔輪替每週一次、保留四個、且輪替下來的登錄檔不進行壓縮(未更改預設值)；

- 輪替完畢後 (postrotate) 取得 syslog 的 PID 後，以 kill -HUP 重新啟動 syslogd

假設我們有針對 /var/log/messages 這個檔案增加 chattr +a 的屬性時， 依據 logrotate 的工作原理，我們知道，這個 /var/log/messages 將會被更名成為 /var/log/messages.1 才是。但是由於加上這個 +a 的參數啊，所以更名是不可能成功的！ 那怎麼辦呢？呵呵！就利用 prerotate 與 postrotate 來進行登錄檔輪替前、後所需要作的動作啊！ 果真如此時，那麼你可以這樣修改一下這個檔案喔！

[root@www ~]# vi /etc/logrotate.d/syslog

/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \

/var/log/boot.log /var/log/cron {

sharedscripts

prerotate

/usr/bin/chattr -a /var/log/messages

endscript

sharedscripts

postrotate

/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true

/bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true

/usr/bin/chattr +a /var/log/messages

endscript

}

看到否？就是先給他去掉 a 這個屬性，讓登錄檔 /var/log/messages 可以進行輪替的動作， 然後執行了輪替之後，再給他加入這個屬性！請特別留意的是，那個 /bin/kill -HUP ... 的意義，這一行的目的在於將系統的 syslogd 重新以其參數檔 (syslog.conf) 的資料讀入一次！也可以想成是 reload 的意思啦！ 由於我們建立了一個新的空的紀錄檔，如果不執行此一行來重新啟動服務的話， 那麼記錄的時候將會發生錯誤呦！(請回到第十七章讀一下 kill 後面的 signal 的內容說明)

實際測試 logrotate 的動作

好了，設定完成之後，我們來測試看看這樣的設定是否可行呢？給他執行底下的指令：

[root@www ~]# logrotate [-vf] logfile

選項與參數：

-v  ：啟動顯示模式，會顯示 logrotate 運作的過程喔！

-f  ：不論是否符合設定檔的資料，強制每個登錄檔都進行 rotate 的動作！

範例一：執行一次 logrotate 看看整個流程為何？

[root@www ~]# logrotate -v /etc/logrotate.conf

reading config file /etc/logrotate.conf <==讀取主要設定檔

including /etc/logrotate.d              <==呼叫外部的設定

reading config file acpid               <==就是外部設定啊！

....(中間省略)....

Handling 21 logs                        <==共有 21 個登錄檔被記錄

....(中間省略)....

rotating pattern: /var/log/messages /var/log/secure /var/log/maillog \

/var/log/spooler /var/log/boot.log /var/log/cron  weekly (4 rotations)

empty log files are rotated, old logs are removed

considering log /var/log/messages       <==開始處理 messages

log does not need rotating            <==因為時間未到，不需要更動！

....(底下省略)....

範例二：強制進行 logrotate 的動作

[root@www ~]# logrotate -vf /etc/logrotate.conf

....(前面省略)....

rotating log /var/log/messages, log->rotateCount is 4

renaming /var/log/messages.4 to /var/log/messages.5 (rotatecount 4, logstart 1, i 4),

renaming /var/log/messages.3 to /var/log/messages.4 (rotatecount 4, logstart 1, i 3),

renaming /var/log/messages.2 to /var/log/messages.3 (rotatecount 4, logstart 1, i 2),

renaming /var/log/messages.1 to /var/log/messages.2 (rotatecount 4, logstart 1, i 1),

renaming /var/log/messages.0 to /var/log/messages.1 (rotatecount 4, logstart 1, i 0),

old log /var/log/messages.0 does not exist

....(底下省略)....

# 看到否？整個 rotate 的動作就是這樣一步一步進行的∼

[root@www ~]# ll /var/log/messages*; lsattr /var/log/messages

-rw------- 1 root root    63 Apr  8 15:19 /var/log/messages

-rw------- 1 root root   670 Apr  8 14:22 /var/log/messages.1

-rw------- 1 root root 24984 Apr  1 19:26 /var/log/messages.2

-rw------- 1 root root  1911 Mar 28 11:32 /var/log/messages.3

-rw------- 1 root root 25193 Mar 22 04:02 /var/log/messages.4

-----a------- /var/log/messages <==主動加入 a 的隱藏屬性囉！

上面那個 -f 具有『強制執行』的意思，如果一切的設定都沒有問題的話，那麼理論上，你的 /var/log 這個目錄就會起變化囉！而且應該不會出現錯誤訊息才對！嘿嘿！這樣就 OK 了！很棒不是嗎？！

由於 logrotate 的工作已經加入 crontab 裡頭了！所以現在每天系統都會自動的給他查看 logrotate 囉！不用擔心的啦！只是要注意一下那個 /var/log/messages 裡頭是否常常有類似底下的字眼：

Apr 8 15:19:47 www syslogd 1.4.1: restart (remote reception).

這說明的是 syslogd 重新啟動的時間啦 (就是因為 /etc/logrotate.d/syslog 的設定之緣故！) 底下我們來進行一些例題的練習，讓你更詳細的瞭解 logrotate 的功用啊！

自訂登錄檔的輪替功能

假設前提是這樣的，前一小節當中，假設你已經建立了 /var/log/admin.log 這個檔案， 現在，你想要將該檔案加上 +a 這個隱藏標籤，而且設定底下的相關資訊：

- 登錄檔輪替一個月進行一次；

- 該登錄檔若大於 10MB 時，則主動進行輪替，不需要考慮一個月的期限；

- 保存五個備份檔案；

- 備份檔案需要壓縮

那你可以怎麼樣設定呢？呵呵∼很簡單啊！看看底下的動作吧！

# 1. 先建立 +a 這個屬性啊！

[root@www ~]# chattr +a /var/log/admin.log

[root@www ~]# lsattr /var/log/admin.log

-----a------- /var/log/admin.log

[root@www ~]# mv /var/log/admin.log /var/log/admin.log.1

mv: cannot move `/var/log/admin.log' to `/var/log/admin.log.1':

Operation not permitted

# 這裡確定了加入 a 的隱藏屬性！所以 root 無法移動此登錄檔！

# 2. 開始建立 logrotate 的設定檔，增加一個檔案在 /etc/logrotate.d 內就對了！

[root@www ~]# vi /etc/logrotate.d/admin

# This configuration is from VBird 2009/04/08

/var/log/admin.log {

monthly   <==每個月進行一次

size=10M  <==檔案容量大於 10M 則開始處置

rotate 5  <==保留五個！

compress  <==進行壓縮工作！

sharedscripts

prerotate

/usr/bin/chattr -a /var/log/admin.log

endscript

sharedscripts

postrotate

/usr/bin/killall -HUP syslogd

/usr/bin/chattr +a /var/log/admin.log

endscript

}

# 3. 測試一下 logrotate 相關功能的資訊顯示：

[root@www ~]# logrotate -v /etc/logrotate.conf

....(前面省略)....

rotating pattern: /var/log/admin.log  10485760 bytes (5 rotations)

empty log files are rotated, old logs are removed

considering log /var/log/admin.log

log does not need rotating

not running prerotate script, since no logs will be rotated

not running postrotate script, since no logs were rotated

....(底下省略)....

# 因為還不足一個月，檔案也沒有大於 10M，所以不需進行輪替！

# 4. 測試一下強制 logrotate 與相關功能的資訊顯示：

[root@www ~]# logrotate -vf /etc/logrotate.d/admin

reading config file /etc/logrotate.d/admin

reading config info for /var/log/admin.log

Handling 1 logs

rotating pattern: /var/log/admin.log  forced from command line (5 rotations)

empty log files are rotated, old logs are removed

considering log /var/log/admin.log

log needs rotating

rotating log /var/log/admin.log, log->rotateCount is 5

renaming /var/log/admin.log.5.gz to /var/log/admin.log.6.gz (rotatecount 5, logstart 1, i 5),

old log /var/log/admin.log.5.gz does not exist

renaming /var/log/admin.log.4.gz to /var/log/admin.log.5.gz (rotatecount 5, logstart 1, i 4),

old log /var/log/admin.log.4.gz does not exist

renaming /var/log/admin.log.3.gz to /var/log/admin.log.4.gz (rotatecount 5, logstart 1, i 3),

old log /var/log/admin.log.3.gz does not exist

renaming /var/log/admin.log.2.gz to /var/log/admin.log.3.gz (rotatecount 5, logstart 1, i 2),

old log /var/log/admin.log.2.gz does not exist

renaming /var/log/admin.log.1.gz to /var/log/admin.log.2.gz (rotatecount 5, logstart 1, i 1),

old log /var/log/admin.log.1.gz does not exist

renaming /var/log/admin.log.0.gz to /var/log/admin.log.1.gz (rotatecount 5, logstart 1, i 0),

old log /var/log/admin.log.0.gz does not exist

log /var/log/admin.log.6.gz doesn't exist -- won't try to dispose of it

running prerotate script

renaming /var/log/admin.log to /var/log/admin.log.1

running postrotate script

compressing log with: /bin/gzip

[root@www ~]# lsattr /var/log/admin.log*

-----a------- /var/log/admin.log

------------- /var/log/admin.log.1.gz  <==有壓縮過喔！

看到了嗎？透過這個方式，我們可以建立起屬於自己的 logrotate 設定檔案， 很簡便吧！尤其是要注意的， /etc/syslog.conf 與 /etc/logrotate.d/* 檔案常常要搭配起來，例如剛剛我們提到的兩個案例中所建立的 /var/log/admin.log 就是一個很好的例子∼建立後，還要使用 logrotate 來輪替啊！ ^_^

分析登錄檔

登錄檔的分析是很重要的！你可以自行以 vi 進入登錄檔去查閱相關的資訊。而系統也提供一些軟體可以讓你從登錄檔中取得資料， 例如之前談過的 last, lastlog, dmesg 等等指令。不過，這些資料畢竟都非常的分散，如果你想要一口氣讀取所有的登錄資訊， 其實有點困擾的。不過，好在 CentOS 有提供 logwatch 這個登錄檔分析程式，你可以藉由該程式來瞭解登錄檔資訊。 此外，鳥哥也依據 Red Hat 系統的 syslog 寫了一支小程式給大家使用喔！

CentOS 預設提供的 logwatch

雖然有一些有用的系統指令，不過，要瞭解系統的狀態，還是得要分析整個登錄檔才行∼ 事實上，目前已經有相當多的登錄檔分析工具，例如 CentOS 5.x 上面預設的 logwatch 這個套件所提供的分析工具， 他會每天分析一次登錄檔案，並且將資料以 email 的格式寄送給 root 呢！ 你也可以直接到 logwatch 的官方網站上面看看：

- http://www.logwatch.org/

logwatch 分析的結果如下所示：

[root@www ~]# mail

Mail version 8.1 6/6/93.  Type ? for help.

"/var/spool/mail/root": 433 messages 433 new

>N  1 logwatch@www.vbird.t  Fri Sep  5 11:42  43/1542  "Logwatch for www.vbird.tsai (Linux)"

N  2 logwatch@www.vbird.t  Sat Sep  6 15:34  92/2709  "Logwatch for www.vbird.tsai (Linux)"

N  3 logwatch@www.vbird.t  Mon Sep  8 15:26  43/1542  "Logwatch for www.vbird.tsai (Linux)"

....(中間省略)....

N431 logwatch@www.vbird.t  Wed Apr  8 04:02  53/1772  "Logwatch for www.vbird.tsai (Linux)"

& 431

Message 431:

From root@www.vbird.tsai  Wed Apr  8 04:02:05 2009

Date: Wed, 8 Apr 2009 04:02:05 +0800

To: root@www.vbird.tsai

From: logwatch@www.vbird.tsai

Subject: Logwatch for www.vbird.tsai (Linux)

MIME-Version: 1.0

Content-Transfer-Encoding: 7bit

Content-Type: text/plain; charset="iso-8859-1"

# 先會說明分析的日期與相關的分析期間！

################### Logwatch 7.3 (03/24/06) ####################

Processing Initiated: Wed Apr  8 04:02:05 2009

Date Range Processed: yesterday

( 2009-Apr-07 )

Period is day.

Detail Level of Output: 0

Type of Output: unformatted

Logfiles for Host: www.vbird.tsai

##################################################################

# 底下則是依據各種服務來進行各項分析！先是登入者的 ssh 服務分析

--------------------- SSHD Begin ------------------------

Users logging in through sshd:

root:

192.168.100.101: 1 time

192.168.100.254: 1 time

---------------------- SSHD End -------------------------

# 磁碟容量分析！可以避免你的系統使用過量磁碟，導致的系統不穩問題！

--------------------- Disk Space Begin ------------------------

Filesystem            Size  Used Avail Use% Mounted on

/dev/hda2             9.5G  3.8G  5.3G  42% /

/dev/hda3             4.8G  1.1G  3.5G  23% /home

/dev/hda1              99M   21M   73M  23% /boot

---------------------- Disk Space End -------------------------

###################### Logwatch End #########################

由於鳥哥的測試用主機尚未啟動許多服務，所以分析的項目很少。若你的系統已經啟動許多服務的話， 那麼分析的項目理應會多很多才對。

鳥哥自己寫的登錄檔分析工具：

雖然已經有了類似 logwatch 的工具，但是鳥哥自己想要分析的資料畢竟與對方不同∼ 所以囉，鳥哥就自己寫了一支小程式 (shell script 的語法) 用來分析自己的登錄檔， 這支程式分析的登錄檔資料其實是固定的，包括有：

- /var/log/secure

- /var/log/messages

- /var/log/maillog

當然啦，還不只這些啦，包括各個主要常見的服務，如 pop3, mail, ftp, su 等會使用到 pam 的服務， 都可以透過鳥哥寫的這個小程式來分析與處理呢∼整個資料還會輸出一些系統資訊。如果你想要使用這個程式的話， 歡迎下載：

- http://linux.vbird.org/download/index.php?action=detail&fileid=69

安裝的方法也很簡單，只要將上述檔案下載並解壓縮後，就會得到一個名為 logfile 的目錄， 將此目錄移動到 /usr/local/virus/ 目錄下並修改一下： /usr/local/virus/logfile.sh 檔案， 裡面的 email 與相關的資訊只要修改一下，你就可以使用啦∼啊！還要記得，將這支程式的執行寫入 /etc/crontab 當中喔！ 可以在每天的 12:10am 執行這支小程式啦！ ^_^

[root@www ~]# mkdir /usr/local/virus

[root@www ~]# tar -zxvf logfile-0.1-4-2.tgz -C /usr/local/virus

[root@www ~]# cd /usr/local/virus/logfile

[root@www logfile]# vi logfile.sh

email="root@localhost" <==大約在 93 行左右，請填入你的 email ，否則保留預設值

basedir="/usr/local/virus/logfile" <==保留預設值，除非你的執行目錄不同與此！

[root@www logfile]# sh logfile.sh

# 開始嘗試分析系統的登錄檔，依據你的登錄檔大小，分析的時間不固定！

[root@www logfile]# vi /etc/crontab

10 0 * * * root /usr/local/virus/logfile/logfile.sh

# 增加這一行！讓系統在每天的凌晨自己進行登錄檔分析！

[root@www logfile]# mail

# 自己找到剛剛輸出的結果，該結果的輸出有點像底下這樣：

# 先進行程式的宣告！你也可以在底下的連結找到一些錯誤回報！

##########################################################

歡迎使用本程式來查驗您的登錄檔

本程式目前版本為： Version 0.1-4-2

程式最後更新日期為： 2006-09-22

若在您的系統中發現本程式有問題, 歡迎與我聯絡！

鳥哥的首頁 http://linux.vbird.org

問題回報： http://phorum.vbird.org/viewtopic.php?t=3425

##########################################################

# 先看看你的硬體與作業系統的相關情況，尤其是 partition 的使用量更需要隨時注意！

=============== 系統彙整 =================================

核心版本  : Linux version 2.6.18-92.el5 (mockbuild@builder16.centos.org)

CPU 資訊  : Intel(R) Celeron(TM) CPU

: 1200.062 MHz

主機名稱  : www.vbird.tsai

統計日期  : 2009/April/08 17:00:59 ( Wednesday )

分析的日期: Apr  8

已開機期間: 7 days, 22:46,

目前主機掛載的 partitions

Filesystem            Size  Used Avail Use% Mounted on

/dev/hda2             9.5G  3.8G  5.3G  42% /

/dev/hda3             4.8G  1.1G  3.5G  23% /home

/dev/hda1              99M   21M   73M  23% /boot

tmpfs                 363M     0  363M   0% /dev/shm

# 這個程式會將針對 internet 與內部監聽的埠口分開來顯示！

================= Ports 的相關分析資訊 =======================

主機啟用的 port 與相關的 process owner：

僅對本機介面開放的 ports (PID|owner|command)

tcp 25|(root)|sendmail: accepting connections

tcp 631|(root)|cupsd

tcp 2207|(root)|python ./hpssd.py

tcp 2208|(root)|./hpiod

對外部介面開放的 ports (PID|owner|command)

tcp 22|(root)|/usr/sbin/sshd

tcp 111|(rpc)|portmap

tcp 737|(root)|rpc.statd

udp 111|(rpc)|portmap

udp 514|(root)|syslogd -m 0 -r

udp 631|(root)|cupsd

udp 731|(root)|rpc.statd

udp 734|(root)|rpc.statd

udp 5353|(avahi)|avahi-daemon: running [www.local]

udp 32768|(avahi)|avahi-daemon: running [www.local]

udp 32769|(avahi)|avahi-daemon: running [www.local]

# 以下針對有啟動的服務個別進行分析！

================= SSH 的登錄檔資訊彙整 =======================

今日沒有使用 SSH 的紀錄

================= Sednamil 的登錄檔資訊彙整 ==================

您的主機有進行 SASL 身份認證的功能

今日沒有 sendmail 的相關資訊

================= 全部的登錄檔資訊彙整 =======================

1. 重要的登錄記錄檔 ( Secure file )

說明：已經取消了 pop3 的資訊！

Apr  8 15:46:22 www su: session opened for user vbird by root(uid=0)

Apr  8 15:47:02 www su: session closed for user vbird

2. 使用 last 這個指令輸出的結果

wtmp begins Wed Apr  8 15:19:47 2009

3. 將特重要的 /var/log/messages 列出來瞧瞧！

已經取消 crond 與 snmpd 的訊息

Apr  8 15:19:47 www syslogd 1.4.1: restart (remote reception).

Apr  8 15:34:25 www syslogd 1.4.1: restart (remote reception).

目前鳥哥都是透過這支程式去分析自己管理的主機，然後再據以瞭解系統狀況，如果有特殊狀況則即時進行系統處理！ 而且鳥哥都是將上述的 email 調整成自己可以在 Internet 上面讀到的郵件，這樣我每天都可以收到正確的登錄檔分析資訊哩！

重點回顧

- 登錄檔可以記錄一個事件的何時、何地、何人、何事等四大資訊，故系統有問題時務必查詢登錄檔；

- 系統的登錄檔預設都集中放置到 /var/log/ 目錄內，其中又以 messages 記錄的資訊最多！

- 登錄檔記錄的主要服務與程式為： syslogd, klogd, log

- syslogd 的設定檔在 /etc/syslog.conf ，內容語法為：『 服務.等級 記載裝置或檔案』

- syslogd 本身有提供登錄檔伺服器的功能，透過修改 /etc/sysconfig/syslog 內容即可達成；

- logrotate 程式利用 crontab 來進行登錄檔的輪替功能；

- logrotate 的設定檔為 /etc/logrotate.conf ，而額外的設定則可寫入 /etc/logrotate.d/* 內；

- logwatch 為 CentOS 5 預設提供的一個登錄檔分析軟體。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

實作題：

- 請在你的 CentOS 5.x 上面，依照鳥哥提供的 logfile.sh 去安裝，並將結果取出分析看看。

簡答題部分：

- syslogd 可以作為登錄檔伺服器，請以 man page 的方式配合 network 關鍵字，查出 syslogd 需要加上什麼選項就能夠成為登錄檔伺服器？

透過 man syslogd ，查詢到 -r 的選項。

- 如果你想要將 auth 這個服務的結果中，只要訊息等級高於 warn 就給予發送 email 到 root 的信箱，該如何處理？

利用 vim 去編輯 /etc/syslog.conf 檔案，內容為

auth.warn root

- 啟動系統登錄資訊時，需要啟動哪兩個 daemon 呢？

syslogd 記錄系統軟體， klogd 記錄核心資訊。

- syslogd 以及 logrotate 個別透過什麼機制來執行？

syslogd 為 stand alone daemon 的機制； logrotate 則是透過 crontab 來執行的！只是個指令而已。

參考資料與延伸閱讀

- 註1：關於 console 的說明可以參考底下的連結：

http://en.wikipedia.org/wiki/Console

http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.files/doc/aixfiles/console.htm

- 關於 logfile 也有網友提供英文版喔！我將他放置到： http://linux.vbird.org//download/vbird/logfile_en.txt

2002/06/24：第一次完成

2003/02/11：重新編排與加入 FAQ

2005/10/12：舊的文章已經被移動到 此處。

2005/10/24：終於寫完了∼啊！怎麼寫這麼久？？

2006/07/23：修改了 /etc/logrotate.d/syslog 的設定資料

2009/03/31：將舊的基於 FC4 版本的資料移動至 此處

2009/09/14：加入了一些例題而已。這一篇太簡單了∼想不到什麼好的題目說∼

2010/12/24：感謝網友 eujiang 提供的英文版 logfile.sh 程式喔！

2002/06/24以來統計人數

第二十章、開機流程、模組管理與 Loader

切換解析度為 800x600

最近更新日期：2009/09/14

系統開機其實是一項非常複雜的程序，因為核心得要偵測硬體並載入適當的驅動程式後， 接下來則必須要呼叫程序來準備好系統運作的環境，以讓使用者能夠順利的操作整部主機系統。 如果你能夠理解開機的原理，那麼將有助於你在系統出問題時能夠很快速的修復系統喔！ 而且還能夠順利的配置多重作業系統的多重開機問題。為了多重開機的問題，你就不能不學學 grub 這個 Linux 底下優秀的開機管理程式 (boot loader)。 而在系統運作期間，你也得要學會管理核心模組呢！

1. Linux 的開機流程分析

1.1 開機流程一覽

1.2 BIOS, boot loader 與 kernel 載入

1.3 第一支程式 init 及設定檔 /etc/inittab 與 runlevel

1.4 init 處理系統初始化流程 (/etc/rc.d/rc.sysinit)

1.5 啟動系統服務與相關啟動設定檔 (/etc/rc.d/rc N & /etc/sysconfig)

1.6 使用者自訂開機啟動程序 (/etc/rc.d/rc.local)

1.7 根據 /etc/inittab 之設定，載入終端機或 X-Window 介面

1.8 開機過程會用到的主要設定檔： /etc/modprobe.conf, /etc/sysconfig/*

1.9 Run level 的切換： runlevel, init

2. 核心與核心模組

2.1 核心模組與相依性： depmod

2.2 核心模組的觀察： lsmod, modinfo

2.3 核心模組的載入與移除：insmod, modprobe, rmmod

2.4 核心模組的額外參數設定：/etc/modprobe.conf

3. Boot loader: Grub

3.1 boot loader 的兩個 stage

3.2 grub 的設定檔 /boot/grub/menu.lst 與選單類型： 磁碟代號, menu.lst

3.3 initrd 的重要性與建立新 initrd 檔案： mkinitrd

3.4 測試與安裝 grub： grub-install, grub shell

3.5 開機前的額外功能修改

3.6 關於核心功能當中的 vga 設定

3.7 BIOS 無法讀取大硬碟的問題

3.8 為個別選單加上密碼： grub-md5-crypt

4. 開機過程的問題解決

4.1 忘記 root 密碼的解決之道

4.2 init 設定檔錯誤

4.3 BIOS 磁碟對應的問題 (device.map)

4.4 因檔案系統錯誤而無法開機

4.5 利用 chroot 切換到另一顆硬碟工作

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23891

Linux 的開機流程分析

開機不是只要按一下電源鈕而關機只要關掉電源鈕就可以了嗎？有何大學問？話是這樣沒錯啦，但是由於 Linux 是一套多人多工的作業系統，你難保你在關機時沒有人在線上，如果你關機的時候碰巧一大群人在線上工作， 那會讓當時在線上工作的人馬上斷線的！那不是害死人了！一些資料可是無價之寶哩！

另外 Linux 在執行的時候，雖然你在畫面上只會看到黑壓壓的一片，完全沒有任何畫面， 但其實他是有很多的程序在背景底下執行的，例如登錄檔管控程式、前面提到的例行性工作排程等， 當然還有一大堆網路服務，如郵件伺服器、WWW 伺服器等等。你如果隨便關機的話， 是很容易傷害硬碟及資料傳輸的動作的！所以在 Linux 下關機可是一門大學問喔。

開機流程一覽

既然開機是很嚴肅的一件事，那我們就來瞭解一下整個開機的過程吧！ 好讓大家比較容易發現開機過程裡面可能會發生問題的地方，以及出現問題後的解決之道！ 不過，由於開機的過程中，那個開機管理程式 (Boot Loader) 使用的軟體可能不一樣，例如目前各大 Linux distributions 的主流為 grub，但早期 Linux 預設是使用 LILO ，台灣地區則很多朋友喜歡使用 spfdisk 。 但無論如何，我們總是得要瞭解整個 boot loader 的工作情況，才能瞭解為何進行多重開機的設定時， 老是聽人家講要先安裝 Windows 再安裝 Linux 的原因∼

假設以個人電腦架設的 Linux 主機為例 (先回到第零章計算機概論看看相關的硬體常識喔)， 當你按下電源按鍵後電腦硬體會主動的讀取 BIOS 來載入硬體資訊及進行硬體系統的自我測試， 之後系統會主動的去讀取第一個可開機的裝置 (由 BIOS 設定的) ，此時就可以讀入開機管理程式了。

開機管理程式可以指定使用哪個核心檔案來開機，並實際載入核心到記憶體當中解壓縮與執行， 此時核心就能夠開始在記憶體內活動，並偵測所有硬體資訊與載入適當的驅動程式來使整部主機開始運作， 等到核心偵測硬體與載入驅動程式完畢後，一個最陽春的作業系統就開始在你的 PC 上面跑了。

主機系統開始運作後，此時 Linux 才會呼叫外部程式開始準備軟體執行的環境， 並且實際的載入所有系統運作所需要的軟體程式哩！最後系統就會開始等待你的登入與操作啦！ 簡單來說，系統開機的經過可以彙整成底下的流程的：

1. 載入 BIOS 的硬體資訊與進行自我測試，並依據設定取得第一個可開機的裝置；

2. 讀取並執行第一個開機裝置內 MBR 的 boot Loader (亦即是 grub, spfdisk 等程式)；

3. 依據 boot loader 的設定載入 Kernel ，Kernel 會開始偵測硬體與載入驅動程式；

4. 在硬體驅動成功後，Kernel 會主動呼叫 init 程式，而 init 會取得 run-level 資訊；

5. init 執行 /etc/rc.d/rc.sysinit 檔案來準備軟體執行的作業環境 (如網路、時區等)；

6. init 執行 run-level 的各個服務之啟動 (script 方式)；

7. init 執行 /etc/rc.d/rc.local 檔案；

8. init 執行終端機模擬程式 mingetty 來啟動 login 程式，最後就等待使用者登入啦；

大概的流程就是上面寫的那個樣子啦，你會發現 init 這個傢伙佔的比重非常重！ 所以我們才會在第十七章的 pstree 指令中談到這傢伙。 那每一個程序的內容主要是在幹嘛呢？底下就分別來談一談吧！

BIOS, boot loader 與 kernel 載入

我們在第三章曾經談過簡單的開機流程與 MBR 的功能， 當時為了多重開機而進行的簡短的介紹。現在你已經有足夠的 Linux 基礎了，所以底下讓我們來加強說明啦！

- BIOS, 開機自我測試與 MBR

我們在第零章的計算機概論就曾談過電腦主機架構， 在個人電腦架構下，你想要啟動整部系統首先就得要讓系統去載入 BIOS (Basic Input Output System)，並透過 BIOS 程式去載入 CMOS 的資訊，並且藉由 CMOS 內的設定值取得主機的各項硬體設定， 例如 CPU 與周邊設備的溝通時脈啊、開機裝置的搜尋順序啊、硬碟的大小與類型啊、 系統時間啊、各周邊匯流排的是否啟動 Plug and Play (PnP, 隨插即用裝置) 啊、 各周邊設備的 I/O 位址啊、以及與 CPU 溝通的 IRQ 岔斷等等的資訊。

在取得這些資訊後，BIOS 還會進行開機自我測試 (Power-on Self Test, POST) (註1)。 然後開始執行硬體偵測的初始化，並設定 PnP 裝置，之後再定義出可開機的裝置順序， 接下來就會開始進行開機裝置的資料讀取了 (MBR 相關的任務開始)。

由於我們的系統軟體大多放置到硬碟中嘛！所以 BIOS 會指定開機的裝置好讓我們可以讀取磁碟中的作業系統核心檔案。 但由於不同的作業系統他的檔案系統格式不相同，因此我們必須要以一個開機管理程式來處理核心檔案載入 (load) 的問題， 因此這個開機管理程式就被稱為 Boot Loader 了。那這個 Boot Loader 程式安裝在哪裡呢？就在開機裝置的第一個磁區 (sector) 內，也就是我們一直談到的 MBR (Master Boot Record, 主要開機記錄區)。

那你會不會覺得很奇怪啊？既然核心檔案需要 loader 來讀取，那每個作業系統的 loader 都不相同， 這樣的話 BIOS 又是如何讀取 MBR 內的 loader 呢？很有趣的問題吧！其實 BIOS 是透過硬體的 INT 13 中斷功能來讀取 MBR 的，也就是說，只要 BIOS 能夠偵測的到你的磁碟 (不論該磁碟是 SATA 還是 IDE 介面)，那他就有辦法透過 INT 13 這條通道來讀取該磁碟的第一個磁區內的 MBR 啦！(註2) 這樣 boot loader 也就能夠被執行囉！

Tips:

我們知道每顆硬碟的第一個磁區內含有 446 bytes的 MBR 區域，那麼如果我的主機上面有兩顆硬碟的話， 系統會去哪顆硬碟的 MBR 讀取 boot loader 呢？這個就得要看 BIOS 的設定了。 基本上，我們常常講的『系統的 MBR』其實指的是 第一個開機裝置的 MBR 才對！ 所以，改天如果你要將開機管理程式安裝到某顆硬碟的 MBR 時， 要特別注意當時系統的『第一個開機裝置』是哪個，否則會安裝到錯誤的硬碟上面的 MBR 喔！重要重要！

- Boot Loader 的功能

剛剛說到 Loader 的最主要功能是要認識作業系統的檔案格式並據以載入核心到主記憶體中去執行。 由於不同作業系統的檔案格式不一致，因此每種作業系統都有自己的 boot loader 啦！用自己的 loader 才有辦法載入核心檔案嘛！那問題就來啦，你應該有聽說過多重作業系統吧？也就是在一部主機上面安裝多種不同的作業系統。 既然你 (1)必須要使用自己的 loader 才能夠載入屬於自己的作業系統核心，而 (2)系統的 MBR 只有一個，那你怎麼會有辦法同時在一部主機上面安裝 Windows 與 Linux 呢？

這就得要回到第八章的磁碟檔案系統去回憶一下檔案系統功能了。 其實每個檔案系統 (filesystem, 或者是 partition) 都會保留一塊開機磁區 (boot sector) 提供作業系統安裝 boot loader ， 而通常作業系統預設都會安裝一份 loader 到他根目錄所在的檔案系統的 boot sector 上。如果我們在一部主機上面安裝 Windows 與 Linux 後，該 boot sector, boot loader 與 MBR 的相關性會有點像下圖：

圖 1.2.1、 boot loader 安裝在 MBR, boot sector 與作業系統的關係

如上圖所示，每個作業系統預設是會安裝一套 boot loader 到他自己的檔案系統中 (就是每個 filesystem 左下角的方框)，而在 Linux 系統安裝時，你可以選擇將 boot loader 安裝到 MBR 去，也可以選擇不安裝。 如果選擇安裝到 MBR 的話，那理論上你在 MBR 與 boot sector 都會保有一份 boot loader 程式的。 至於 Windows 安裝時，他預設會主動的將 MBR 與 boot sector 都裝上一份 boot loader！所以啦， 你會發現安裝多重作業系統時，你的 MBR 常常會被不同的作業系統的 boot loader 所覆蓋啦！ ^_^

我們剛剛提到的兩個問題還是沒有解決啊！雖然各個作業系統都可以安裝一份 boot loader 到他們的 boot sector 中， 這樣作業系統可以透過自己的 boot loader 來載入核心了。問題是系統的 MBR 只有一個哩！ 你要怎麼執行 boot sector 裡面的 loader 啊？這個我們得要回憶一下第三章約略提過的 boot loader 的功能了。boot loader 主要的功能如下：

- 提供選單：使用者可以選擇不同的開機項目，這也是多重開機的重要功能！

- 載入核心檔案：直接指向可開機的程式區段來開始作業系統；

- 轉交其他 loader：將開機管理功能轉交給其他 loader 負責。

由於具有選單功能，因此我們可以選擇不同的核心來開機。而由於具有控制權轉交的功能，因此我們可以載入其他 boot sector 內的 loader 啦！不過 Windows 的 loader 預設不具有控制權轉交的功能，因此你不能使用 Windows 的 loader 來載入 Linux 的 loader 喔！這也是為啥第三章談到 MBR 與多重開機時，會特別強調先裝 Windows 再裝 Linux 的緣故。 我們將上述的三個功能以底下的圖示來解釋你就看的懂了！(與第三章的圖示也非常類似啦！)

圖 1.2.2、 開機管理程式的選單功能與控制權轉交功能示意圖

如上圖所示，我的 MBR 使用 Linux 的 grub 這個開機管理程式，並且裡面假設已經有了三個選單， 第一個選單可以直接指向 Linux 的核心檔案並且直接載入核心來開機；第二個選單可以將開機管理程式控制權交給 Windows 來管理，此時 Windows 的 loader 會接管開機流程，這個時候他就能夠啟動 windows 了。第三個選單則是使用 Linux 在 boot sector 內的開機管理程式，此時就會跳出另一個 grub 的選單啦！瞭解了嗎？

而最終 boot loader 的功能就是『載入 kernel 檔案』啦！

- 載入核心偵測硬體與 initrd 的功能

當我們藉由 boot loader 的管理而開始讀取核心檔案後，接下來， Linux 就會將核心解壓縮到主記憶體當中， 並且利用核心的功能，開始測試與驅動各個周邊裝置，包括儲存裝置、CPU、網路卡、音效卡等等。 此時 Linux 核心會以自己的功能重新偵測一次硬體，而不一定會使用 BIOS 偵測到的硬體資訊喔！也就是說，核心此時才開始接管 BIOS 後的工作了。 那麼核心檔案在哪裡啊？一般來說，他會被放置到 /boot 裡面，並且取名為 /boot/vmlinuz 才對！

[root@www ~]# ls --format=single-column -F /boot

config-2.6.18-92.el5      <==此版本核心被編譯時選擇的功能與模組設定檔

grub/                     <==就是開機管理程式 grub 相關資料目錄

initrd-2.6.18-92.el5.img  <==虛擬檔案系統檔！

System.map-2.6.18-92.el5  <==核心功能放置到記憶體位址的對應表

vmlinuz-2.6.18-92.el5     <==就是核心檔案啦！最重要者！

從上表我們也可以知道此版本的 Linux 核心為 2.6.18-92.el5 這個版本！為了硬體開發商與其他核心功能開發者的便利， 因此 Linux 核心是可以透過動態載入核心模組的 (就請想成驅動程式即可)，這些核心模組就放置在 /lib/modules/ 目錄內。 由於模組放置到磁碟根目錄內 (要記得 /lib 不可以與 / 分別放在不同的 partition ！)， 因此在開機的過程中核心必須要掛載根目錄，這樣才能夠讀取核心模組提供載入驅動程式的功能。 而且為了擔心影響到磁碟內的檔案系統，因此開機過程中根目錄是以唯讀的方式來掛載的喔。

一般來說，非必要的功能且可以編譯成為模組的核心功能，目前的 Linux distributions 都會將他編譯成為模組。 因此 USB, SATA, SCSI... 等磁碟裝置的驅動程式通常都是以模組的方式來存在的。 現在來思考一種情況，假設你的 linux 是安裝在 SATA 磁碟上面的，你可以透過 BIOS 的 INT 13 取得 boot loader 與 kernel 檔案來開機，然後 kernel 會開始接管系統並且偵測硬體及嘗試掛載根目錄來取得額外的驅動程式。

問題是，核心根本不認識 SATA 磁碟，所以需要載入 SATA 磁碟的驅動程式， 否則根本就無法掛載根目錄。但是 SATA 的驅動程式在 /lib/modules 內，你根本無法掛載根目錄又怎麼讀取到 /lib/modules/ 內的驅動程式？是吧！非常的兩難吧！在這個情況之下，你的 Linux 是無法順利開機的！ 那怎辦？沒關係，我們可以透過虛擬檔案系統來處理這個問題。

虛擬檔案系統 (Initial RAM Disk) 一般使用的檔名為 /boot/initrd ，這個檔案的特色是，他也能夠透過 boot loader 來載入到記憶體中， 然後這個檔案會被解壓縮並且在記憶體當中模擬成一個根目錄， 且此模擬在記憶體當中的檔案系統能夠提供一支可執行的程式，透過該程式來載入開機過程中所最需要的核心模組， 通常這些模組就是 USB, RAID, LVM, SCSI 等檔案系統與磁碟介面的驅動程式啦！等載入完成後， 會幫助核心重新呼叫 /sbin/init 來開始後續的正常開機流程。

圖 1.2.3、 BIOS 與 boot loader 及核心載入流程示意圖

如上圖所示，boot loader 可以載入 kernel 與 initrd ，然後在記憶體中讓 initrd 解壓縮成為根目錄， kernel 就能夠藉此載入適當的驅動程式，最終釋放虛擬檔案系統，並掛載實際的根目錄檔案系統， 就能夠開始後續的正常開機流程。更詳細的 initrd 說明，你可以自行使用 man initrd 去查閱看看。 底下讓我們來瞭解一下 CentOS 5.x 的 initrd 檔案內容有什麼吧！ ^_^

# 1. 先將 /boot/initrd 複製到 /tmp/initrd 目錄中，等待解壓縮：

[root@www ~]# mkdir /tmp/initrd

[root@www ~]# cp /boot/initrd-2.6.18-92.el5.img /tmp/initrd/

[root@www ~]# cd /tmp/initrd

[root@www initrd]# file initrd-2.6.18-92.el5.img

initrd-2.6.18-92.el5.img: gzip compressed data, ...

# 原來是 gzip 的壓縮檔！因為是 gzip ，所以副檔名給他改成 .gz 吧！

# 2. 將上述的檔案解壓縮：

[root@www initrd]# mv initrd-2.6.18-92.el5.img initrd-2.6.18-92.el5.gz

[root@www initrd]# gzip -d initrd-2.6.18-92.el5.gz

[root@www initrd]# file initrd-2.6.18-92.el5

initrd-2.6.18-92.el5: ASCII cpio archive (SVR4 with no CRC)

# 搞了老半天，原來還是 cpio 的指令壓縮成的檔案啊！解壓縮看看！

# 3. 用 cpio 解壓縮

[root@www initrd]# cpio -ivcdu < initrd-2.6.18-92.el5

[root@www initrd]# ll

drwx------ 2 root root    4096 Apr 10 02:05 bin

drwx------ 3 root root    4096 Apr 10 02:05 dev

drwx------ 2 root root    4096 Apr 10 02:05 etc

-rwx------ 1 root root    1888 Apr 10 02:05 init

-rw------- 1 root root 5408768 Apr 10 02:00 initrd-2.6.18-92.el5

drwx------ 3 root root    4096 Apr 10 02:05 lib

drwx------ 2 root root    4096 Apr 10 02:05 proc

lrwxrwxrwx 1 root root       3 Apr 10 02:05 sbin -> bin

drwx------ 2 root root    4096 Apr 10 02:05 sys

drwx------ 2 root root    4096 Apr 10 02:05 sysroot

# 看！是否很像根目錄！尤其也是有 init 這個執行檔！務必看一下權限！

# 接下來看看 init 這個檔案內有啥咚咚？

# 4. 觀察 init 檔案內較重要的執行項目

[root@www initrd]# cat init

#!/bin/nash                  <==使用類似 bash 的 shell 來執行

mount -t proc /proc /proc    <==掛載記憶體的虛擬檔案系統

....(中間省略)....

echo Creating initial device nodes

mknod /dev/null c 1 3        <==建立系統所需要的各項裝置！

....(中間省略)....

echo "Loading ehci-hcd.ko module"

insmod /lib/ehci-hcd.ko      <==載入各項核心模組，就是驅動程式！

....(中間省略)....

echo Creating root device.

mkrootdev -t ext3 -o defaults,ro hdc2 <==嘗試掛載根目錄啦！

....(底下省略)....

嘿嘿！透過上述執行檔的內容，我們可以知道 initrd 有載入模組並且嘗試掛載了虛擬檔案系統。 接下來就能夠順利的運作啦！那麼是否一定需要 initrd 呢？

例題：

是否沒有 initrd 就無法順利開機？

答：

不見得的！需要 initrd 最重要的原因是，當開機時無法掛載根目錄的情況下， 此時就一定需要 initrd ，例如你的根目錄在特殊的磁碟介面 (USB, SATA, SCSI) ， 或者是你的檔案系統較為特殊 (LVM, RAID) 等等，才會需要 initrd。

如果你的 Linux 是安裝在 IDE 介面的磁碟上，並且使用預設的 ext2/ext3 檔案系統， 那麼不需要 initrd 也能夠順利的開機進入 Linux 的！

在核心完整的載入後，您的主機應該就開始正確的運作了，接下來，就是要開始執行系統的第一支程式： /sbin/init。

第一支程式 init 及設定檔 /etc/inittab 與 runlevel

在核心載入完畢、進行完硬體偵測與驅動程式載入後，此時你的主機硬體應該已經準備就緒了 (ready) ， 此時核心會主動的呼叫第一支程式，那就是 /sbin/init 囉。這也是為啥第十七章的 pstree 指令介紹時，你會發現 init 的 PID 號碼是一號啦。 /sbin/init 最主要的功能就是準備軟體執行的環境，包括系統的主機名稱、網路設定、語系處理、檔案系統格式及其他服務的啟動等。 而所有的動作都會透過 init 的設定檔，亦即是 /etc/inittab 來規劃，而 inittab 內還有一個很重要的設定項目，那就是預設的 runlevel (開機執行等級) 啦！

- Run level：執行等級有哪些？

那麼什麼是 run level 呢？他有什麼功用啊？其實很簡單啦， Linux 就是藉由設定 run level 來規定系統使用不同的服務來啟動，讓 Linux 的使用環境不同。基本上，依據有無網路與有無 X Window 而將 run level 分為 7 個等級，分別是：

- 0 - halt (系統直接關機)

- 1 - single user mode (單人維護模式，用在系統出問題時的維護)

- 2 - Multi-user, without NFS (類似底下的 runlevel 3，但無 NFS 服務)

- 3 - Full multi-user mode (完整含有網路功能的純文字模式)

- 4 - unused (系統保留功能)

- 5 - X11 (與 runlevel 3 類似，但加載使用 X Window)

- 6 - reboot (重新開機)

由於 run level 0, 4, 6 不是關機、重新開機就是系統保留的，所以：『 您當然不能將預設的 run level 設定為這三個值 』， 否則系統就會不斷的自動關機或自動重新開機.... 好了，那麼我們開機時，到底是如何取得系統的 run level 的？當然是 /etc/inittab 所設定的囉！ 那麼 /etc/inittab 到底有什麼資訊呢？我們先來看看這個檔案的內容好了：

- /etc/inittab 的內容與語法

[root@www ~]# vim /etc/inittab

id:5:initdefault:                 <==預設的 runlevel 設定, 此 runlevel 為 5

si::sysinit:/etc/rc.d/rc.sysinit  <==準備系統軟體執行的環境的腳本執行檔

# 7 個不同 run level 的，需要啟動的服務的 scripts 放置路徑：

l0:0:wait:/etc/rc.d/rc 0    <==runlevel 0 在 /etc/rc.d/rc0.d/

l1:1:wait:/etc/rc.d/rc 1    <==runlevel 1 在 /etc/rc.d/rc1.d/

l2:2:wait:/etc/rc.d/rc 2    <==runlevel 2 在 /etc/rc.d/rc2.d/

l3:3:wait:/etc/rc.d/rc 3    <==runlevel 3 在 /etc/rc.d/rc3.d/

l4:4:wait:/etc/rc.d/rc 4    <==runlevel 4 在 /etc/rc.d/rc4.d/

l5:5:wait:/etc/rc.d/rc 5    <==runlevel 5 在 /etc/rc.d/rc5.d/

l6:6:wait:/etc/rc.d/rc 6    <==runlevel 6 在 /etc/rc.d/rc6.d/

# 是否允許按下 [ctrl]+[alt]+[del] 就重新開機的設定項目：

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

# 底下兩個設定則是關於不斷電系統的 (UPS)，一個是沒電力時的關機，一個是復電的處理

pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

1:2345:respawn:/sbin/mingetty tty1  <==其實 tty1~tty6 是由底下這六行決定的。

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:2345:respawn:/sbin/mingetty tty4

5:2345:respawn:/sbin/mingetty tty5

6:2345:respawn:/sbin/mingetty tty6

x:5:respawn:/etc/X11/prefdm -nodaemon <==X window 則是這行決定的！

讓我們解析一下這個檔案吧！首先，這個檔案的語法是利用冒號 (:) 將設定分隔成為四個欄位，每個欄位的意義與說明如下：

[設定項目]:[run level]:[init 的動作行為]:[指令項目]

1. 設定項目：最多四個字元，代表 init 的主要工作項目，只是一個簡單的代表說明。

2. run level：該項目在哪些 run level 底下進行的意思。如果是 35 則代表 runlevel 3 與 5 都會執行。

3. init 的動作項目：主要可以進行的動作項目意義有：

inittab 設定值

意義說明

initdefault

代表預設的 run level 設定值

sysinit

代表系統初始化的動作項目

ctrlaltdel

代表 [ctrl]+[alt]+[del] 三個按鍵是否可以重新開機的設定

wait

代表後面欄位設定的指令項目必須要執行完畢才能繼續底下其他的動作

respawn

代表後面欄位的指令可以無限制的再生 (重新啟動)。舉例來說， tty1 的 mingetty 產生的可登入畫面， 在你登出而結束後，系統會再開一個新的可登入畫面等待下一個登入。

1. 更多的設定項目請參考 man inittab 的說明。

2. 指令項目：亦即應該可以進行的指令，通常是一些 script 囉。

- init 的處理流程

事實上 /etc/inittab 的設定也有點類似 shell script 啦，因為該檔案內容的設定也是一行一行的從上往下處理的， 因此我們可以知道 CentOS 的 init 依據 inittab 設定的處理流程會是：

1. 先取得 runlevel 亦即預設執行等級的相關等級 (以鳥哥的測試機為例，為 5 號)；

2. 使用 /etc/rc.d/rc.sysinit 進行系統初始化

3. 由於 runlevel 是 5 ，因此只進行『l5:5:wait:/etc/rc.d/rc 5』，其他行則略過

4. 設定好 [ctrl]+[alt]+[del] 這組的組合鍵功能

5. 設定不斷電系統的 pf, pr 兩種機制；

6. 啟動 mingetty 的六個終端機 (tty1 ~ tty6)

7. 最終以 /etc/X11/perfdm -nodaemon 啟動圖形介面啦！

現在你可以知道為啥 [ctrl]+[alt]+[del] 可以重新開機而我們預設提供 6 個虛擬終端機 (tty1~tty6) 給你使用了吧！由於整個設定都是依據 /etc/inittab 來決定的，因此如果你想要修改任何細節的話， 可以這樣做喔：

- 如果不想讓使用者利用 [crtl]+[alt]+[del] 來重新啟動系統，可以將『 ca::ctrlaltdel:/sbin/shutdown -t3 -r now 』加上註解 (#) 來取消該設定

- 規定開機的預設 run level 是純文字的 3 號或者是具有圖形介面的 5 號 ，可經由 『 id:5:initdefault: 』那個數字來決定！ 以鳥哥自己這個檔案為例，我是使用預設的圖形介面。如果你想要關閉圖形介面的話，將該行 5 改成 3 即可。

- 如果不想要啟動六個終端機 (tty1~tty6)，那麼可以將『 6:2345:respawn:/sbin/mingetty tty6』關閉數個。但務必至少啟動一個喔！

所以說，你現在會自行修改登入時的預設 run level 設定值了嗎？夠簡單的吧？ 一般來說，我們預設都是 3 或者是 5 來作為預設的 run level 的。但有時後可能需要進入 run level 1， 也就是單人維護模式的環境當中。這個 run level 1 有點像是 Windows 系統當中的『安全模式』啦， 專門用來處理當系統有問題時的操作環境。此外，當系統發現有問題時，舉例來說，不正常關機造成 filesystem 的不一致現象時，系統會主動的進入單人維護模式呢！

好了， init 在取得 run level 之後，接下來要幹嘛？ 上面 /etc/inittab 檔案內容不是有提到 sysinit 嗎？準備初始化系統了吧！

init 處理系統初始化流程 (/etc/rc.d/rc.sysinit)

還記得上面提到 /etc/inittab 裡頭有這一句『 si::sysinit:/etc/rc.d/rc.sysinit 』吧？ 這表示：『我開始載入各項系統服務之前，得先做好整個系統環境，我主要利用 /etc/rc.d/rc.sysinit 這個 shell script 來設定好我的系統環境的。』夠清楚了吧？ 所以，我想要知道到底 CentOS 開機的過程當中幫我進行了什麼動作，就得要仔細的分析 /etc/rc.d/rc.sysinit 囉。

Tips:

老實說，這個檔案的檔名在各不同的 distributions 當中都不相同， 例如 SuSE server 9 就使用 /etc/init.d/boot 與 /etc/init.d/rc 來進行的。 所以，你最好還是自行到 /etc/inittab 去察看一下系統的工作喔！ ^_^

如果你使用 vim 去查閱過 /etc/rc.d/rc.sysinit 的話，那麼可以發現他主要的工作大抵有這幾項：

1. 取得網路環境與主機類型：

讀取網路設定檔 /etc/sysconfig/network ，取得主機名稱與預設通訊閘 (gateway) 等網路環境。

2. 測試與掛載記憶體裝置 /proc 及 USB 裝置 /sys：

除掛載記憶體裝置 /proc 之外，還會主動偵測系統上是否具有 usb 的裝置， 若有則會主動載入 usb 的驅動程式，並且嘗試掛載 usb 的檔案系統。

3. 決定是否啟動 SELinux ：

我們在第十七章談到的 SELinux 在此時進行一些檢測， 並且檢測是否需要幫所有的檔案重新編寫標準的 SELinux 類型 (auto relabel)。

4. 啟動系統的亂數產生器

亂數產生器可以幫助系統進行一些密碼加密演算的功能，在此需要啟動兩次亂數產生器。

5. 設定終端機 (console) 字形：

6. 設定顯示於開機過程中的歡迎畫面 (text banner)；

7. 設定系統時間 (clock) 與時區設定：需讀入 /etc/sysconfig/clock 設定值

8. 周邊設備的偵測與 Plug and Play (PnP) 參數的測試：

根據核心在開機時偵測的結果 (/proc/sys/kernel/modprobe ) 開始進行 ide / scsi / 網路 / 音效 等周邊設備的偵測，以及利用以載入的核心模組進行 PnP 裝置的參數測試。

9. 使用者自訂模組的載入

使用者可以在 /etc/sysconfig/modules/*.modules 加入自訂的模組，則此時會被載入到系統當中

10. 載入核心的相關設定：

系統會主動去讀取 /etc/sysctl.conf 這個檔案的設定值，使核心功能成為我們想要的樣子。

11. 設定主機名稱與初始化電源管理模組 (ACPI)

12. 初始化軟體磁碟陣列：主要是透過 /etc/mdadm.conf 來設定好的。

13. 初始化 LVM 的檔案系統功能

14. 以 fsck 檢驗磁碟檔案系統：會進行 filesystem check

15. 進行磁碟配額 quota 的轉換 (非必要)：

16. 重新以可讀寫模式掛載系統磁碟：

17. 啟動 quota 功能：所以我們不需要自訂 quotaon 的動作

18. 啟動系統虛擬亂數產生器 (pseudo-random)：

19. 清除開機過程當中的暫存檔案：

20. 將開機相關資訊載入 /var/log/dmesg 檔案中。

在 /etc/rc.d/rc.sysinit 將基本的系統設定資料都寫好了，也將系統的資料設定完整！ 而如果你想要知道到底開機的過程中發生了什麼事情呢？那麼就執行『 dmesg 』吧。 另外，基本上，在這個檔案當中所進行的很多工作的預設設定檔，其實都在 /etc/sysconfig/ 當中呢！ 所以，請記得將 /etc/sysconfig/ 內的檔案好好的瞧一瞧喔！ ^_^

在這個過程當中，比較值得注意的是自訂模組的載入！在 CentOS 當中，如果我們想要載入核心模組的話， 可以將整個模組寫入到 /etc/sysconfig/modules/*.modules 當中，在該目錄下， 只要記得檔名最後是以 .modules 結尾即可。 這個過程是非必要的，因為我們目前的預設模組實在已經很夠用了，除非是您的主機硬體實在太新了， 非要自己載入新的模組不可，否則，在經過 /etc/rc.d/rc.sysinit 的處理後， 你的主機系統應該是已經跑得很順暢了啦！就等著你將系統相關的服務與網路服務啟動囉！

啟動系統服務與相關啟動設定檔 (/etc/rc.d/rc N & /etc/sysconfig)

載入核心讓整個系統準備接受指令來工作，再經過 /etc/rc.d/rc.sysinit 的系統模組與相關硬體資訊的初始化後，你的 CentOS 系統應該已經順利工作了。 只是，我們還得要啟動系統所需要的各項『服務』啊！這樣主機才能提供我們相關的網路或者是主機功能嘛！ 這個時候，依據我們在 /etc/inittab 裡面提到的 run level 設定值，就可以來決定啟動的服務項目了。 舉例來說，使用 run level 3 當然就不需要啟動 X Window 的相關服務囉，您說是吧？

那麼各個不同的 run level 服務啟動的各個 shell script 放在哪？還記得 /etc/inittab 裡面提到的：

l0:0:wait:/etc/rc.d/rc 0

l1:1:wait:/etc/rc.d/rc 1

l2:2:wait:/etc/rc.d/rc 2

l3:3:wait:/etc/rc.d/rc 3

l4:4:wait:/etc/rc.d/rc 4

l5:5:wait:/etc/rc.d/rc 5  <==本例中，以此項目來解釋

l6:6:wait:/etc/rc.d/rc 6

上面提到的就是各個 run level 要執行的各項腳本放置處啦！主要是透過 /etc/rc.d/rc 這個指令來處理相關任務！ 由於鳥哥使用預設的 runlevel 5 ，因此我們主要針對上述特殊字體那行來解釋好了： /etc/rc.d/rc 5 的意義是這樣的 (建議您自行使用 vim 去觀察一下 /etc/rc.d/rc 這個檔案，你會更有概念！)：

- 透過外部第一號參數 ($1) 來取得想要執行的腳本目錄。亦即由 /etc/rc.d/rc 5 可以取得 /etc/rc5.d/ 這個目錄來準備處理相關的腳本程式；

- 找到 /etc/rc5.d/K??* 開頭的檔案，並進行『 /etc/rc5.d/K??* stop 』的動作；

- 找到 /etc/rc5.d/S??* 開頭的檔案，並進行『 /etc/rc5.d/S??* start 』的動作；

透過上面的說明我們可以知道所有的項目都與 /etc/rc5.d/ 有關，那麼我們就來瞧瞧這個目錄下有些什麼玩意兒吧！

[root@www ~]# ll /etc/rc5.d/

lrwxrwxrwx 1 root root 16 Sep  4  2008 K02dhcdbd -> ../init.d/dhcdbd

....(中間省略)....

lrwxrwxrwx 1 root root 14 Sep  4  2008 K91capi -> ../init.d/capi

lrwxrwxrwx 1 root root 23 Sep  4  2008 S00microcode_ctl -> ../init.d/microcode_ctl

lrwxrwxrwx 1 root root 22 Sep  4  2008 S02lvm2-monitor -> ../init.d/lvm2-monitor

....(中間省略)....

lrwxrwxrwx 1 root root 17 Sep  4  2008 S10network -> ../init.d/network

....(中間省略)....

lrwxrwxrwx 1 root root 11 Sep  4  2008 S99local -> ../rc.local

lrwxrwxrwx 1 root root 16 Sep  4  2008 S99smartd -> ../init.d/smartd

....(底下省略)....

在這個目錄下的檔案很有趣，主要具有幾個特點：

- 檔名全部以 Sxx 或 Kxx ，其中 xx 為數字，且這些數字在檔案之間是有相關性的！

- 全部是連結檔，連結到 stand alone 服務啟動的目錄 /etc/init.d/ 去

我們在第十八章談過服務的啟動主要是以『/etc/init.d/服務檔名 {start,stop}』來啟動與關閉的，那麼透過剛剛 /etc/rc.d/rc 程式的解說，我們可以清楚的瞭解到了 /etc/rc5.d/[SK]xx 其實就是跑到 /etc/init.d/ 去找到相對應的服務腳本， 然後分別進行 start (Sxx) 或 stop (Kxx) 的動作而已啦！舉例來說，以上述的表格內的 K91capi 及 S10network 為例好了， 透過 /etc/rc.d/rc 5 的執行，這兩個檔案會這樣進行：

- /etc/rc5.d/K91capi stop --> /etc/init.d/capi stop

- /etc/rc5.d/S10network start --> /etc/init.d/network start

所以說，你有想要啟動該 runlevel 時就執行的服務，那麼利用 Sxx 並指向 /etc/init.d/ 的特定服務啟動腳本後， 該服務就能夠在開機時啟動啦！就這麼簡單！問題是，你需要自行處理這個 K, S 開頭的連結檔嗎？ 並不需要的，第十八章談到的 chkconfig 就是在負責處理這個連結檔啦！這樣有沒有跟第十八章的觀念串在一起了呢？ ^_^

那麼為什麼 K 與 S 後面要有數字呢？因為各不同的服務其實還是互有關係的。舉例來說，如果要啟動 WWW 服務，總是得要有網路吧？所以 /etc/init.d/network 就會比較先被啟動啦！那麼您就會知道在 S 或者是 K 後面接的數字是啥意思了吧？嘿嘿，那就是執行的順序啦！那麼哪個檔案被最後執行呢？ 看到最後一個被執行的項目是啥？沒錯，就是 S99local ，亦即是： /etc/rc.d/rc.local 這個檔案啦！

使用者自訂開機啟動程序 (/etc/rc.d/rc.local)

在完成預設 runlevel 指定的各項服務的啟動後，如果我還有其他的動作想要完成時，舉例來說， 我還想要寄一封 mail 給某個系統管理帳號，通知他，系統剛剛重新開機完畢，那麼是否應該要製作一個 shell script 放置在 /etc/init.d/ 裡面，然後再以連結方式連結到 /etc/rc5.d/ 裡面呢？呵呵！當然不需要！還記得上一小節提到的 /etc/rc.d/rc.local 吧？ 這個檔案就可以執行您自己想要執行的系統指令了。

也就是說，我有任何想要在開機時就進行的工作時，直接將他寫入 /etc/rc.d/rc.local ， 那麼該工作就會在開機的時候自動被載入喔！而不必等我們登入系統去啟動呢！ 是否很方便啊！一般來說，鳥哥就很喜歡把自己製作的 shell script 完整檔名寫入 /etc/rc.d/rc.local ，如此一來，開機就會將我的 shell script 執行過，真是好棒那！

根據 /etc/inittab 之設定，載入終端機或 X-Window 介面

在完成了系統所有服務的啟動後，接下來 Linux 就會啟動終端機或者是 X Window 來等待使用者登入啦！ 實際參考的項目是 /etc/inittab 內的這一段：

1:2345:respawn:/sbin/mingetty tty1

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:2345:respawn:/sbin/mingetty tty4

5:2345:respawn:/sbin/mingetty tty5

6:2345:respawn:/sbin/mingetty tty6

x:5:respawn:/etc/X11/prefdm -nodaemon

這一段代表，在 run level 2, 3, 4, 5 時，都會執行 /sbin/mingetty 這個咚咚， 而且執行六個，這也是為何我們 Linux 會提供『六個純文字終端機』的設定所在啊！ 因為 mingetty 就是在啟動終端機的指令說。

要注意的是那個 respawn 的 init 動作項目，他代表『當後面的指令被終止 (terminal) 時， init 會主動的重新啟動該項目。』這也是為何我們登入 tty1 終端機介面後，以 exit 離開後， 系統還是會重新顯示等待使用者輸入的畫面的原因啊！

如果改天您不想要有六個終端機時，可以取消某些終端機介面嗎？當然可以啊！ 就將上面表格當中的某些項目註解掉即可！例如不想要 tty5 與 tty6 ，就將那兩行註解， 則下次重新開機後，您的 Linux 就只剩下『 F1 ~ F4 』有效而已，這樣說，可以瞭解吧！！^_^

至於如果我們使用的是 run level 5 呢？那麼除了這六個終端機之外， init 還會執行 /etc/X11/prefdm -nodaemon 那個指令喔！該指令我們會在第二十四章、X Window 再來詳談！ 他主要的功能就是在啟動 X Window 啦！

開機過程會用到的主要設定檔

我們在 /sbin/init 的運作過程中有談到許多執行腳本，包括 /etc/rc.d/rc.sysinit 以及 /etc/rc.d/rc 等等， 其實這些腳本都會使用到相當多的系統設定檔，這些開機過程會用到的設定檔則大多放置在 /etc/sysconfig/ 目錄下。 同時，由於核心還是需要載入一些驅動程式 (核心模組)，此時系統自訂的裝置與模組對應檔 (/etc/modprobe.conf) 就顯的挺重要了喔！

- 關於模組： /etc/modprobe.conf

還記得我們在 /etc/rc.d/rc.sysinit 當中談到的載入使用者自訂模組的地方嗎？就是在 /etc/sysconfig/modules/ 目錄下啊！ 雖然核心提供的預設模組已經很足夠我們使用了，但是，某些條件下我們還是得對模組進行一些參數的規劃， 此時就得要使用到 /etc/modprobe.conf 囉！舉例來說，鳥哥的 CentOS 主機的 modprobe.conf 有點像這樣：

[root@www ~]# cat /etc/modprobe.conf

alias eth0 8139too               <==讓 eth0 使用 8139too 的模組

alias scsi_hostadapter pata_sis

alias snd-card-0 snd-trident

options snd-card-0 index=0       <==額外指定 snd-card-0 的參數功能

options snd-trident index=0

這個檔案大多在指定系統內的硬體所使用的模組啦！這個檔案通常系統是可以自行產生的，所以你不必手動去訂正他！ 不過，如果系統捉到錯誤的驅動程式，或者是你想要使用更新的驅動程式來對應相關的硬體配備時， 你就得要自行手動的處理一下這個檔案了。

以上表的第一行為例，鳥哥使用螃蟹卡 (Realtek 的晶片組) 來作為我的網路卡，那螃蟹卡使用的模組就是 8139too 啦！這樣看的懂了吧？當我要啟動網路卡時，系統會跑到這個檔案來查閱一下，然後載入 8139too 驅動程式來驅動網路卡囉！更多的相關說明，請 man modprobe.conf 喔！

- /etc/sysconfig/*

不說您也知道，整個開機的過程當中，老是讀取的一些服務的相關設定檔都是記錄在 /etc/sysconfig 目錄下的！那麼該目錄底下有些啥玩意兒？我們找幾個重要的檔案來談談：

- authconfig：

這個檔案主要在規範使用者的身份認證的機制，包括是否使用本機的 /etc/passwd, /etc/shadow 等， 以及 /etc/shadow 密碼記錄使用何種加密演算法，還有是否使用外部密碼伺服器提供的帳號驗證 (NIS, LDAP) 等。 系統預設使用 MD5 加密演算法，並且不使用外部的身份驗證機制；

- clock：

此檔案在設定 Linux 主機的時區，可以使用格林威治時間(GMT)，也可以使用台灣的本地時間 (local)。基本上，在 clock 檔案內的設定項目『 ZONE 』所參考的時區位於 /usr/share/zoneinfo 目錄下的相對路徑中。而且要修改時區的話，還得將 /usr/share/zoneinfo/Asia/Taipei 這個檔案複製成為 /etc/localtime 才行！

- i18n：

i18n 在設定一些語系的使用方面，例如最麻煩的文字介面下的日期顯示問題！ 如果你是以中文安裝的，那麼預設語系會被選擇 zh_TW.UTF8 ，所以在純文字介面之下， 你的檔案日期顯示可能就會呈現亂碼！這個時候就需要更改一下這裡啦！更動這個 i18n 的檔案，將裡面的 LC_TIME 改成 en 即可！

- keyboard & mouse：

keyboard 與 mouse 就是在設定鍵盤與滑鼠的形式；

- network：

network 可以設定是否要啟動網路，以及設定主機名稱還有通訊閘 (GATEWAY) 這兩個重要資訊呢！

- network-scripts/：

至於 network-scripts 裡面的檔案，則是主要用在設定網路卡∼ 這部份我們在伺服器架設篇才會提到！

總而言之一句話，這個目錄下的檔案很重要的啦！開機過程裡面常常會讀取到的！

Run level 的切換

在我們完成上面的所有資訊後，其實整個 Linux 主機就已經在等待我們使用者的登入啦！ 但是，相信您應該還是會有一點疑問的地方，那就是：『我該如何切換 run level 呢？』會不會很難啊？不會啦！很簡單∼但是依據執行的時間而有不同的方式啊！

事實上，與 run level 有關的啟動其實是在 /etc/rc.d/rc.sysinit 執行完畢之後。也就是說，其實 run level 的不同僅是 /etc/rc[0-6].d 裡面啟動的服務不同而已。不過，依據開機是否自動進入不同 run level 的設定，我們可以說：

1. 要每次開機都執行某個預設的 run level ，則需要修改 /etc/inittab 內的設定項目， 亦即是『 id:5:initdefault: 』裡頭的數字啊；

2. 如果僅只是暫時變更系統的 run level 時，則使用 init [0-6] 來進行 run level 的變更。 但下次重新開機時，依舊會是以 /etc/inittab 的設定為準。

假設原本我們是以 run level 5 登入系統的，但是因為某些因素，想要切換成為 run level 3 時， 該怎麼辦呢？很簡單啊，執行『 init 3 』即可切換。但是 init 3 這個動作到底做了什麼呢？ 我們不是說了嗎？事實上，不同的 run level 只是載入的服務不同罷了， 亦即是 /etc/rc5.d/ 還有 /etc/rc3.d 內的 Sxxname 與 Kxxname 有差異而已。 所以說，當執行 init 3 時，系統會：

- 先比對 /etc/rc3.d/ 及 /etc/rc5.d 內的 K 與 S 開頭的檔案；

- 在新的 runlevel 亦即是 /etc/rc3.d/ 內有多的 K 開頭檔案，則予以關閉；

- 在新的 runlevel 亦即是 /etc/rc3.d/ 內有多的 S 開頭檔案，則予以啟動；

也就是說，兩個 run level 都存在的服務就不會被關閉啦！如此一來，就很容易切換 run level 了， 而且還不需要重新開機呢！真方便。那我怎麼知道目前的 run level 是多少呢？ 直接在 bash 當中輸入 runlevel 即可啊！

[root@www ~]# runlevel

N 5

# 左邊代表前一個 runlevel ，右邊代表目前的 runlevel。

# 由於之前並沒有切換過 runlevel ，因此前一個 runlevel 不存在 (N)

# 將目前的 runlevel 切換成為 3 (注意， tty7 的資料會消失！)

[root@www ~]# init 3

NIT: Sending processes the TERM signal

Applying Intel CPU microcode update:        [  OK  ]

Starting background readahead:              [  OK  ]

Starting irqbalance:                        [  OK  ]

Starting httpd:                             [  OK  ]

Starting anacron:                           [  OK  ]

# 這代表，新的 runlevel 亦即是 runlevel3 比前一個 runlevel 多出了上述 5 個服務

[root@www ~]# runlevel

5 3

# 看吧！前一個是 runlevel 5 ，目前的是 runlevel 3 啦！

那麼你能不能利用 init 來進行關機與重新開機呢？可以的啦！利用『 init 0 』就能夠關機， 而『 init 6 』就能夠重新開機！為什麼？往前翻一下 runlevel 的定義即可瞭解吧！

核心與核心模組

談完了整個開機的流程，您應該會知道，在整個開機的過程當中，是否能夠成功的驅動我們主機的硬體配備， 是核心 (kernel) 的工作！而核心一般都是壓縮檔，因此在使用核心之前，就得要將他解壓縮後， 才能載入主記憶體當中。

另外，為了應付日新月異的硬體，目前的核心都是具有『可讀取模組化驅動程式』的功能， 亦即是所謂的『 modules (模組化)』的功能啦！所謂的模組化可以將他想成是一個『外掛程式』， 該外掛程式可能由硬體開發廠商提供，也有可能我們的核心本來就支援∼不過，較新的硬體， 通常都需要硬體開發商提供驅動程式模組啦！

那麼核心與核心模組放在哪？

- 核心： /boot/vmlinuz 或 /boot/vmlinuz-version；

- 核心解壓縮所需 RAM Disk： /boot/initrd (/boot/initrd-version)；

- 核心模組： /lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel；

- 核心原始碼： /usr/src/linux 或 /usr/src/kernels/ (要安裝才會有，預設不安裝)

如果該核心被順利的載入系統當中了，那麼就會有幾個資訊紀錄下來：

- 核心版本： /proc/version

- 系統核心功能： /proc/sys/kernel

問題來啦，如果我有個新的硬體，偏偏我的作業系統不支援，該怎麼辦？很簡單啊！

- 重新編譯核心，並加入最新的硬體驅動程式原始碼；

- 將該硬體的驅動程式編譯成為模組，在開機時載入該模組

上面第一點還很好理解，反正就是重新編譯核心就是了。不過，核心編譯很不容易啊！ 我們會在後續章節約略介紹核心編譯的整個程序。比較有趣的則是將該硬體的驅動程式編譯成為模組啦！ 關於編譯的方法，可以參考後續的第二十二章、原始碼與 tarball的介紹。 我們這個章節僅是說明一下，如果想要載入一個已經存在的模組時，該如何是好？

核心模組與相依性

既然要處理核心模組，自然就得要瞭解瞭解我們核心提供的模組之間的相關性啦！ 基本上，核心模組的放置處是在 /lib/modules/$(uname -r)/kernel 當中，裡面主要還分成幾個目錄：

arch    ：與硬體平台有關的項目，例如 CPU 的等級等等；

crypto  ：核心所支援的加密的技術，例如 md5 或者是 des 等等；

drivers ：一些硬體的驅動程式，例如顯示卡、網路卡、PCI 相關硬體等等；

fs      ：核心所支援的 filesystems ，例如 vfat, reiserfs, nfs 等等；

lib     ：一些函式庫；

net     ：與網路有關的各項協定資料，還有防火牆模組 (net/ipv4/netfilter/*) 等等；

sound   ：與音效有關的各項模組；

如果要我們一個一個的去檢查這些模組的主要資訊，然後定義出他們的相依性， 我們可能會瘋掉吧！所以說，我們的 Linux 當然會提供一些模組相依性的解決方案囉∼ 對啦！那就是檢查 /lib/modules/$(uname -r)/modules.dep 這個檔案啦！他記錄了在核心支援的模組的各項相依性。

那麼這個檔案如何建立呢？挺簡單！利用 depmod 這個指令就可以達到建立該檔案的需求了！

[root@www ~]# depmod [-Ane]

選項與參數：

-A  ：不加任何參數時， depmod 會主動的去分析目前核心的模組，並且重新寫入

/lib/modules/$(uname -r)/modules.dep 當中。若加入 -A 參數時，則 depmod

會去搜尋比 modules.dep 內還要新的模組，如果真找到新模組，才會更新。

-n  ：不寫入 modules.dep ，而是將結果輸出到螢幕上(standard out)；

-e  ：顯示出目前已載入的不可執行的模組名稱

範例一：若我做好一個網路卡驅動程式，檔名為 a.ko，該如何更新核心相依性？

[root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net

[root@www ~]# depmod

以上面的範例一為例，我們的 Linux kernel 2.6.x 版本的核心模組副檔名一定是 .ko 結尾的， 當你使用 depmod 之後，該程式會跑到模組標準放置目錄 /lib/modules/$(uname -r)/kernel ， 並依據相關目錄的定義將全部的模組捉出來分析，最終才將分析的結果寫入 modules.dep 檔案中的吶！ 這個檔案很重要喔！因為他會影響到本章稍後會介紹的 modprobe 指令的應用！

核心模組的觀察

那你到底曉不曉得目前核心載入了多少的模組呢？粉簡單啦！利用 lsmod 即可！

[root@www ~]# lsmod

Module                  Size  Used by

autofs4                24517  2

hidp                   23105  2

....(中間省略)....

8139too                28737  0

8139cp                 26305  0

mii                     9409  2 8139too,8139cp <==mii 還被 8139cp, 8139too 使用

....(中間省略)....

uhci_hcd               25421  0  <==底下三個是 USB 相關的模組！

ohci_hcd               23261  0

ehci_hcd               33357  0

使用 lsmod 之後，系統會顯示出目前已經存在於核心當中的模組，顯示的內容包括有：

- 模組名稱(Module)；

- 模組的大小(size)；

- 此模組是否被其他模組所使用 (Used by)。

也就是說，模組其實真的有相依性喔！舉上表為例， mii 這個模組會被 8139too 所使用。 簡單的說，就是『當你要載入 8139too 時，需要先載入 mii 這個模組才可以順利的載入 8139too』的意思。 那麼除了顯示出目前的模組外，我還可以查閱每個模組的資訊嗎？舉例來說，我們知道 8139too 是螃蟹卡的驅動程式，那麼 mii 是什麼咚咚？就用 modinfo 來觀察吧！

[root@www ~]# modinfo [-adln] [module_name|filename]

選項與參數：

-a  ：僅列出作者名稱；

-d  ：僅列出該 modules 的說明 (description)；

-l  ：僅列出授權 (license)；

-n  ：僅列出該模組的詳細路徑。

範例一：由上個表格當中，請列出 mii 這個模組的相關資訊：

[root@www ~]# modinfo mii

filename:       /lib/modules/2.6.18-92.el5/kernel/drivers/net/mii.ko

license:        GPL

description:    MII hardware support library

author:         Jeff Garzik <jgarzik@pobox.com>

srcversion:     16DCEDEE4B5629C222C352D

depends:

vermagic:       2.6.18-92.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1

# 可以看到這個模組的來源，以及該模組的簡易說明！(是硬體支援函式庫)

範例二：我有一個模組名稱為 a.ko ，請問該模組的資訊為？

[root@www ~]# modinfo a.ko

....(省略)....

事實上，這個 modinfo 除了可以『查閱在核心內的模組』之外，還可以檢查『某個模組檔案』， 因此，如果你想要知道某個檔案代表的意義為何，利用 modinfo 加上完整檔名吧！ 看看就曉得是啥玩意兒囉！ ^_^

核心模組的載入與移除

好了，如果我想要自行手動載入模組，又該如何是好？有很多方法啦，最簡單而且建議的，是使用 modprobe 這個指令來載入模組， 這是因為 modprobe 會主動的去搜尋 modules.dep 的內容，先克服了模組的相依性後， 才決定需要載入的模組有哪些，很方便。至於 insmod 則完全由使用者自行載入一個完整檔名的模組， 並不會主動的分析模組相依性啊！

[root@www ~]# insmod [/full/path/module_name] [parameters]

範例一：請嘗試載入 cifs.ko 這個『檔案系統』模組

[root@www ~]# insmod /lib/modules/$(uname -r)/kernel/fs/cifs/cifs.ko

[root@www ~]# lsmod | grep cifs

cifs                  212789  0

他立刻就將該模組載入囉∼但是 insmod 後面接的模組必須要是完整的『檔名』才行！那如何移除這個模組呢？

[root@www ~]# rmmod [-fw] module_name

選項與參數：

-f  ：強制將該模組移除掉，不論是否正被使用；

-w  ：若該模組正被使用，則 rmmod 會等待該模組被使用完畢後，才移除他！

範例一：將剛剛載入的 cifs 模組移除！

[root@www ~]# rmmod cifs

範例二：請載入 vfat 這個『檔案系統』模組

[root@www ~]# insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko

insmod: error inserting '/lib/modules/2.6.18-92.el5/kernel/fs/vfat/vfat.ko':

-1 Unknown symbol in module

# 無法載入 vfat 這個模組啊！傷腦筋！

使用 insmod 與 rmmod 的問題就是，你必須要自行找到模組的完整檔名才行，而且如同上述範例二的結果， 萬一模組有相依屬性的問題時，你將無法直接載入或移除該模組呢！所以近年來我們都建議直接使用 modprobe 來處理模組載入的問題，這個指令的用法是：

[root@www ~]# modprobe [-lcfr] module_name

選項與參數：

-c  ：列出目前系統所有的模組！(更詳細的代號對應表)

-l  ：列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名；

-f  ：強制載入該模組；

-r  ：類似 rmmod ，就是移除某個模組囉∼

範例一：載入 cifs 模組

[root@www ~]# modprobe cifs

# 很方便吧！不需要知道完整的模組檔名，這是因為該完整檔名已經記錄到

# /lib/modules/`uname -r`/modules.dep 當中的緣故啊！如果要移除的話：

[root@www ~]# modprobe -r cifs

使用 modprobe 真的是要比 insmod 方便很多！因為他是直接去搜尋 modules.dep 的紀錄， 所以囉，當然可以克服模組的相依性問題，而且還不需要知道該模組的詳細路徑呢！ 好方便！ ^_^

例題：

嘗試使用 modprobe 載入 vfat 這個模組，並且觀察該模組的相關模組是哪個？

答：

我們使用 modprobe 來載入，再以 lsmod 來觀察與 grep 擷取關鍵字看看：

[root@www ~]# modprobe vfat

[root@www ~]# lsmod | grep vfat

vfat                   15809  0

fat                    51165  1 vfat <==原來就是 fat 這個模組啊！

[root@www ~]# modprobe -r vfat <==測試完移除此模組

核心模組的額外參數設定： /etc/modprobe.conf

這個檔案我們之前已經談過了，這裡只是再強調一下而已，如果您想要修改某些模組的額外參數設定， 就在這個檔案內設定吧！我們假設一個案例好了，假設我的網路卡 eth0 是使用 ne ， 但是 eth1 同樣也使用 ne ，為了避免同一個模組會導致網路卡的錯亂， 因此，我可以先找到 eth0 與 eth1 的 I/O 與 IRQ ，假設：

- eth0 ： I/O (0x300) 且 IRQ=5

- eth1 ： I/O (0x320) 且 IRQ=7

則：

[root@www ~]# vi /etc/modprobe.conf

alias eth0 ne

alias eth1 ne

options eth0 io=0x300 irq=5

options eth1 io=0x320 irq=7

嘿嘿！如此一來，我的 Linux 就不會捉錯網路卡的對應囉！因為被我強制指定某個 I/O 咯嘛！ ^_^

Boot Loader: Grub

在看完了前面的整個開機流程，以及核心模組的整理之後，你應該會發現到一件事情， 那就是『 boot loader 是載入核心的重要工具』啊！沒有 boot loader 的話，那麼 kernel 根本就沒有辦法被系統載入的呢！所以，底下我們會先談一談 boot loader 的功能， 然後再講一講現階段 Linux 裡頭最主流的 grub 這個 boot loader 吧！

boot loader 的兩個 stage

我們在第一小節開機流程的地方曾經講過，在 BIOS 讀完資訊後，接下來就是會到第一個開機裝置的 MBR 去讀取 boot loader 了。這個 boot loader 可以具有選單功能、直接載入核心檔案以及控制權移交的功能等， 系統必須要有 loader 才有辦法載入該作業系統的核心就是了。但是我們都知道， MBR 是整個硬碟的第一個 sector 內的一個區塊，充其量整個大小也才 446 bytes 而已。 我們的 loader 功能這麼強，光是程式碼與設定資料不可能只佔不到 446 bytes 的容量吧？那如何安裝？

為了解決這個問題，所以 Linux 將 boot loader 的程式碼執行與設定值載入分成兩個階段 (stage) 來執行：

- Stage 1：執行 boot loader 主程式：

第一階段為執行 boot loader 的主程式，這個主程式必須要被安裝在開機區，亦即是 MBR 或者是 boot sector 。但如前所述，因為 MBR 實在太小了，所以，MBR 或 boot sector 通常僅安裝 boot loader 的最小主程式， 並沒有安裝 loader 的相關設定檔；

- Stage 2：主程式載入設定檔：

第二階段為透過 boot loader 載入所有設定檔與相關的環境參數檔案 (包括檔案系統定義與主要設定檔 menu.lst)， 一般來說，設定檔都在 /boot 底下。

那麼這些設定檔是放在哪裡啊？這些與 grub 有關的檔案都放置到 /boot/grub 中，那我們就來看看有哪些檔案吧！

[root@www ~]# ls -l /boot/grub

-rw-r--r--  device.map              <==grub 的裝置對應檔(底下會談到)

-rw-r--r--  e2fs_stage1_5           <==ext2/ext3 檔案系統之定義檔

-rw-r--r--  fat_stage1_5            <==FAT 檔案系統之定義檔

-rw-r--r--  ffs_stage1_5            <==FFS 檔案系統之定義檔

-rw-------  grub.conf               <==grub 在 Red Hat 的設定檔

-rw-r--r--  iso9660_stage1_5        <==光碟機檔案系統定義檔

-rw-r--r--  jfs_stage1_5            <==jfs 檔案系統定義檔

lrwxrwxrwx  menu.lst -> ./grub.conf <==其實 menu.lst 才是設定檔！

-rw-r--r--  minix_stage1_5          <==minix 檔案系統定義檔

-rw-r--r--  reiserfs_stage1_5       <==reiserfs 檔案系統定義檔

-rw-r--r--  splash.xpm.gz           <==開機時在 grub 底下的背景圖示

-rw-r--r--  stage1                  <==stage 1 的相關說明

-rw-r--r--  stage2                  <==stage 2 的相關說明

-rw-r--r--  ufs2_stage1_5           <==UFS 的檔案系統定義檔

-rw-r--r--  vstafs_stage1_5         <==vstafs 檔案系統定義檔

-rw-r--r--  xfs_stage1_5            <==xfs 檔案系統定義檔

從上面的說明你可以知道 /boot/grub/ 目錄下最重要的就是設定檔 (menu.lst) 以及各種檔案系統的定義！ 我們的 loader 讀取了這種檔案系統定義資料後，就能夠認識檔案系統並讀取在該檔案系統內的核心檔案囉。 至於 grub 的設定檔檔名，其實應該是 menu.lst 的，只是在 Red Hat 裡面被定義成為 /boot/grub.conf 而已。 鳥哥建議您還是記憶 menu.lst 比較好喔！

所以從上面的檔案來看， grub 認識的檔案系統真的非常多喔！正因為如此，所以 grub 才會取代 Lilo 這個老牌的 boot loader 嘛！好了，接下來就來瞧瞧設定檔內有啥設定值吧！

grub 的設定檔 /boot/grub/menu.lst 與選單類型

grub 是目前使用最廣泛的 Linux 開機管理程式，舊的 Lilo 這個開機管理程式現在已經很少見了， 所以本章才會將 Lilo 的介紹捨棄的說。grub 的優點挺多的，包括有：

- 認識與支援較多的檔案系統，並且可以使用 grub 的主程式直接在檔案系統中搜尋核心檔名；

- 開機的時候，可以『自行編輯與修改開機設定項目』，類似 bash 的指令模式；

- 可以動態搜尋設定檔，而不需要在修改設定檔後重新安裝 grub 。亦即是我們只要修改完 /boot/grub/menu.lst 裡頭的設定後，下次開機就生效了！

上面第三點其實就是 Stage 1, Stage 2 分別安裝在 MBR (主程式) 與檔案系統當中 (設定檔與定義檔) 的原因啦！ 好了，接下來，讓我們好好瞭解一下 grub 的設定檔： /boot/grub/menu.lst 這玩意兒吧！ 要注意喔，那個 lst 是 LST 的小寫，不要搞錯囉！

- 硬碟與分割槽在 grub 中的代號

安裝在 MBR 的 grub 主程式，最重要的任務之一就是從磁碟當中載入核心檔案， 以讓核心能夠順利的驅動整個系統的硬體。所以囉， grub 必須要認識硬碟才行啊！那麼 grub 到底是如何認識硬碟的呢？ 嘿嘿！ grub 對硬碟的代號設定與傳統的 Linux 磁碟代號可完全是不同的！grub 對硬碟的識別使用的是如下的代號：

(hd0,0)

夠神了吧？跟 /dev/hda1 風馬牛不相干∼怎麼辦啊？其實只要注意幾個東西即可，那就是：

- 硬碟代號以小括號 ( ) 包起來；

- 硬碟以 hd 表示，後面會接一組數字；

- 以『搜尋順序』做為硬碟的編號，而不是依照硬碟排線的排序！(這個重要！)

- 第一個搜尋到的硬碟為 0 號，第二個為 1 號，以此類推；

- 每顆硬碟的第一個 partition 代號為 0 ，依序類推。

所以說，第一顆『搜尋到的硬碟』代號為：『(hd0)』，而該顆硬碟的第一號分割槽為『(hd0,0)』，這樣說瞭解了吧？ 反正你要記得，在 grub 裡面，他開始的數字是 0 而不是 1 就是了！

Tips:

在較舊的主機板上面，通常第一顆硬碟會插在 IDE 1 的 master 上，就會是 /dev/hda，所以常常我們可能會誤會 /dev/hda 就是 (hd0)，其實不是喔！要看你的 BIOS 設定值才行！有的主機板 BIOS 可以調整開機的硬碟搜尋順序，那麼就要注意了，因為 grub 的硬碟代號可能會跟著改變吶！留意留意！

所以說，整個硬碟代號為：

硬碟搜尋順序

在 Grub 當中的代號

第一顆

(hd0) (hd0,0) (hd0,1) (hd0,4)....

第二顆

(hd1) (hd1,0) (hd1,1) (hd1,4)....

第三顆

(hd2) (hd2,0) (hd2,1) (hd2,4)....

這樣應該比較好看出來了吧？第一顆硬碟的 MBR 安裝處的硬碟代號就是『(hd0)』， 而第一顆硬碟的第一個分割槽的 boot sector 代號就是『(hd0,0)』第一顆硬碟的第一個邏輯分割槽的 boot sector 代號為『(hd0,4)』瞭了吧！

例題：

假設你的系統僅有一顆 SATA 硬碟，請說明該硬碟的第一個邏輯分割槽在 Linux 與 grub 當中的檔名與代號：

答：

因為是 SATA 磁碟，加上使用邏輯分割槽，因此 Linux 當中的檔名為 /dev/sda5 才對 (1~4 保留給 primary 與 extended 使用)。 至於 grub 當中的磁碟代號則由於僅有一顆磁碟，因此代號會是『 (hd0,4) 』才對。

- /boot/grub/menu.lst 設定檔：

瞭解了 grub 當中最麻煩的硬碟代號後，接下來，我們就可以瞧一瞧設定檔的內容了。先看一下鳥哥的 CentOS 內的 /boot/grub/menu.lst 好了：

[root@www ~]# vim /boot/grub/menu.lst

default=0     <==預設開機選項，使用第 1 個開機選單 (title)

timeout=5     <==若 5 秒內未動鍵盤，使用預設選單開機

splashimage=(hd0,0)/grub/splash.xpm.gz <==背景圖示所在的檔案

hiddenmenu    <==讀秒期間是否顯示出完整的選單畫面(預設隱藏)

title CentOS (2.6.18-92.el5)    <==第一個選單的內容

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd /initrd-2.6.18-92.el5.img

在 title 以前的四行，都是屬於 grub 的整體設定，包括預設的等待時間與預設的開機項目， 還有顯示的畫面特性等等。至於 title 後面才是指定開機的核心檔案或者是 boot loader 控制權。 在整體設定方面的項目主要常見的有：

- default=0

這個必須要與 title 作為對照，在設定檔裡面有幾個 title ，開機的時候就會有幾個選單可以選擇。 由於 grub 啟始號碼為 0 號，因此 default=0 代表使用『第一個 title 項目』來開機的意思。 default 的意思是，如果在讀秒時間結束前都沒有動到鍵盤， grub 預設使用此 title 項目 (在此為 0 號) 來開機。

- timeout=5

開機時會進行讀秒，如果在 5 秒鐘內沒有按下任何按鍵，就會使用上面提到的 default 後面接的那個 title 項目來開機的意思。如果你覺得 5 秒太短，那可以將這個數值調大 (例如 30 秒) 即可。此外，如果 timeout=0 代表直接使用 default 值進行開機而不讀秒，timeout=-1 則代表直接進入選單不讀秒了！

- splashimage=(hd0,0)/grub/splash.xpm.gz

有沒有發現你的 CentOS 在開機的時候背景不是黑白而是有色彩變化的呢？那就是這個檔案提供的背景圖示啦(註3)！不過這個檔案的實際路徑寫法怎麼會是這樣啊？很簡單啊∼上述的意思是：在 (hd0,0) 這個分割槽內的最頂層目錄中，底下的 grub/splash.xpm.gz 那個檔案的意思。 由於鳥哥將 /boot 這個目錄獨立成為 /dev/hda1 ，因此這邊就會寫成『在 /dev/hda1 裡面的 grub/splash.xpm.gz 』的意思啦！想一想，如果你的 /boot 目錄並沒有獨立成為一個分割槽， 這裡會寫成如何？

- hiddenmenu

這個說的是，開機時是否要顯示選單？目前 CentOS 預設是不要顯示選單， 如果您想要顯示選單，那就將這個設定值註解掉！

整體設定的地方大概是這樣，而底下那個 title 則是顯示開機的設定項目。如同前一小節提到的，開機時可以選擇 (1)直接指定核心檔案開機或 (2)將 boot loader 控制權轉移到下個 loader (此過程稱為 chain-loader)。每個 title 後面接的是『該開機項目名稱的顯示』，亦即是在選單出現時，選單上面的名稱而已。 那麼這兩種方式的設定有啥不同呢？

1. 直接指定核心開機

既然要指定核心開機，所以當然要找到核心檔案啦！此外，有可能還需要用到 initrd 的 RAM Disk 設定檔。但是如前說的， 尚未開機完成，所以我們必須要以 grub 的硬碟識別方式找出完整的 kernel 與 initrd 檔名才行。 因此，我們可能需要有底下的方式來設定才行！

1. 先指定核心檔案放置的 partition，再讀取檔案 (目錄樹)，

最後才加入檔案的實際檔名與路徑 (kernel 與 initrd)；

鳥哥的 /boot 為 /dev/hda1 ，因此核心檔案的設定則成為：

root    (hd0,0)          <==代表核心檔案放在那個 partition 當中

kernel  /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd  /initrd-2.6.18-92.el5.img

上面的 root, kernel, initrd 後面接的參數的意義說明如下：

root ：代表的是『核心檔案放置的那個 partition 而不是根目錄』喔！不要搞錯了！ 以鳥哥的案例來說，我的根目錄為 /dev/hda2 而 /boot 獨立為 /dev/hda1 ，因為與 /boot 有關， 所以磁碟代號就會成為 (hd0,0) 囉。

kernel ：至於 kernel 後面接的則是核心的檔名，而在檔名後面接的則是核心的參數。 由於開機過程中需要掛載根目錄，因此 kernel 後面接的那個 root=LABEL=/1 指的是『Linux 的根目錄在哪個 partition 』的意思。 還記得第八章談過的 LABEL 掛載功能吧？ 是的，這裡使用 LABEL 來掛載根目錄。至於 rhgb 為色彩顯示而 quiet 則是安靜模式 (螢幕不會輸出核心偵測的資訊)。

initrd ：就是前面提到的 initrd 製作出 RAM Disk 的檔案檔名啦！

2. 直接指定 partition 與檔名，不需要額外指定核心檔案所在裝置代號

kernel  (hd0,0)/vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd  (hd0,0)/initrd-2.6.18-92.el5.img

老實說，鳥哥比較喜歡這種樣式的檔名寫法，因為這樣我們就能夠知道核心檔案是在哪個裝置內的某個檔名， 而不會去想到我們的根目錄 (/, root) 啦！讓我們來想想 /boot 有獨立分割與無獨立分割的情況吧！

例題：

我的系統分割是： /dev/hda1 (/), /dev/hda2 (swap) 而已，且我的核心檔案為 /boot/vmlinuz，請問 grub 的 menu.lst 內該如何撰寫核心檔案位置？

答：

我們使用疊代的方式來瞭解一下好了。由於核心檔名為 /boot/vmlinuz，轉成裝置檔名與代號會成為如下的過程：

原始檔案：  /boot/vmlinuz ↓

Linux 裝置：(/dev/hda1)/boot/vmlinuz ↓

grub  裝置：(hd0,0)/boot/vmlinuz

所以最終的 kernel 寫法會變成：

kernel (hd0,0)/boot/vmlinuz root=/dev/hda1 ...

例題：

同上，只是我的分割情況變成： /dev/sda1 (/boot), /dev/sda5 (/) 時？

答：

由於 /boot 被獨立出來了，所以情況會不一樣喔！如下所示：

原始檔案：  /boot/vmlinuz ↓

Linux 裝置：(/dev/sda1)/vmlinuz ↓

grub  裝置：(hd0,0)/vmlinuz

所以最終的 kernel 寫法會變成：

kernel (hd0,0)/vmlinuz root=/dev/sda5 ...

1. 利用 chain loader 的方式轉交控制權

所謂的 chain loader (開機管理程式的鏈結) 僅是在將控制權交給下一個 boot loader 而已， 所以 grub 並不需要認識與找出 kernel 的檔名 ，『 他只是將 boot 的控制權交給下一個 boot sector 或 MBR 內的 boot loader 而已 』 所以通常他也不需要去查驗下一個 boot loader 的檔案系統！

一般來說， chain loader 的設定只要兩個就夠了，一個是預計要前往的 boot sector 所在的分割槽代號， 另一個則是設定 chainloader 在那個分割槽的 boot sector (第一個磁區) 上！假設我的 Windows 分割槽在 /dev/hda1 ，且我又只有一顆硬碟，那麼要 grub 將控制權交給 windows 的 loader 只要這樣就夠了：

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

root (hd0,0)    <==設定使用此分割槽

chainloader +1  <== +1 可以想成第一個磁區，亦即是 boot sector

上面的範例中，我們可以很簡單的這樣想：那個 (hd0,0) 就是 Windows 的 C 槽所在磁碟， 而 chainloader +1 就是讓系統載入該分割槽當中的第一個磁區 (就是 boot sector) 內的開機管理程式。 不過，由於 Windows 的開機碟需要設定為活化 (active) 狀態，且我們的 grub 預設會去檢驗該分割槽的檔案系統。 因此我們可以重新將上面的範例改寫成這樣：

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

rootnoverify (hd0,0)   <==不檢驗此分割槽

chainloader +1

makeactive             <==設定此分割槽為開機碟(active)

grub 的功能還不止此，他還能夠隱藏某些分割槽。舉例來說，我的 /dev/hda5 是安裝 Linux 的分割槽， 我不想讓 Windows 能夠認識這個分割槽時，你可以這樣做：

[root@www ~]# vi /boot/grub/menu.lst

....前略....

title Windows partition

hide (hd0,4)           <==隱藏 (hd0,4) 這個分割槽

rootnoverify (hd0,0)

chainloader +1

makeactive

initrd 的重要性與建立新 initrd 檔案

我們在本章稍早之前『 boot loader 與 kernel 載入』的地方已經提到過 initrd 這玩意兒，他的目的在於提供開機過程中所需要的最重要核心模組，以讓系統開機過程可以順利完成。 會需要 initrd 的原因，是因為核心模組放置於 /lib/modules/$(uname -r)/kernel/ 當中， 這些模組必須要根目錄 (/) 被掛載時才能夠被讀取。但是如果核心本身不具備磁碟的驅動程式時， 當然無法掛載根目錄，也就沒有辦法取得驅動程式，因此造成兩難的地步。

initrd 可以將 /lib/modules/.... 內的『開機過程當中一定需要的模組』包成一個檔案 (檔名就是 initrd)， 然後在開機時透過主機的 INT 13 硬體功能將該檔案讀出來解壓縮，並且 initrd 在記憶體內會模擬成為根目錄， 由於此虛擬檔案系統 (Initial RAM Disk) 主要包含磁碟與檔案系統的模組，因此我們的核心最後就能夠認識實際的磁碟， 那就能夠進行實際根目錄的掛載啦！所以說：『initrd 內所包含的模組大多是與開機過程有關，而主要以檔案系統及硬碟模組 (如 usb, SCSI 等) 為主』的啦！

一般來說，需要 initrd 的時刻為：

- 根目錄所在磁碟為 SATA、USB 或 SCSI 等連接介面；

- 根目錄所在檔案系統為 LVM, RAID 等特殊格式；

- 根目錄所在檔案系統為非傳統 Linux 認識的檔案系統時；

- 其他必須要在核心載入時提供的模組。

Tips:

之前鳥哥忽略 initrd 這個檔案的重要性，是因為鳥哥很窮... ^_^。因為鳥哥的 Linux 主機都是較早期的硬體， 使用的是 IDE 介面的硬碟，而且並沒有使用 LVM 等特殊格式的檔案系統，而 Linux 核心本身就認識 IDE 介面的磁碟， 因此不需要 initrd 也可以順利開機完成的。自從 SATA 硬碟流行起來後，沒有 initrd 就沒辦法開機了！ 因為 SATA 硬碟使用的是 SCSI 模組來驅動的，而 Linux 預設將 SCSI 功能編譯成為模組....

一般來說，各 distribution 提供的核心都會附上 initrd 檔案，但如果妳有特殊需要所以想重製 initrd 檔案的話， 可以使用 mkinitrd 來處理的。這個檔案的處理方式很簡單， man mkinitrd 就知道了！ ^_^。 我們還是簡單的介紹一下去！

[root@www ~]# mkinitrd [-v] [--with=模組名稱] initrd檔名 核心版本

選項與參數：

-v  ：顯示 mkinitrd 的運作過程

--with=模組名稱：模組名稱指的是模組的名字而已，不需要填寫檔名。舉例來說，

目前核心版本的 ext3 檔案系統模組為底下的檔名：

/lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko

那妳應該要寫成： --with=ext3 就好了 (省略 .ko)

initrd檔名：妳所要建立的 initrd 檔名，盡量取有意義又好記的名字。

核心版本  ：某一個核心的版本，如果是目前的核心則是『 $(uname -r) 』

範例一：以 mkinitrd 的預設功能建立一個 initrd 虛擬磁碟檔案

[root@www ~]# mkinitrd -v initrd_$(uname -r) $(uname -r)

Creating initramfs

Looking for deps of module ehci-hcd

Looking for deps of module ohci-hcd

....(中間省略)....

Adding module ehci-hcd  <==最終加入 initrd 的就是底下的模組

Adding module ohci-hcd

Adding module uhci-hcd

Adding module jbd

Adding module ext3

Adding module scsi_mod

Adding module sd_mod

Adding module libata

Adding module pata_sis

[root@www ~]# ll initrd_*

-rw------- 1 root root 2406443 Apr 30 02:55 initrd_2.6.18-92.el5

# 由於目前的核心版本可使用 uname -r 取得，因此鳥哥使用較簡單的指令來處理囉∼

# 此時 initrd 會被建立起來，妳可以將他移動到 /boot 等待使用。

範例二：增加 8139too 這個模組的 initrd 檔案

[root@www ~]# mkinitrd -v --with=8139too initrd_vbirdtest $(uname -r)

....(前面省略)....

Adding module mii

Adding module 8139too  <==看到沒！這樣就加入了！

initrd 建立完成之後，同時核心也處理完畢後，我們就可以使用 grub 來建立選單了！底下繼續瞧一瞧吧！

測試與安裝 grub

如果你的 Linux 主機本來就是使用 grub 作為 loader 的話，那麼你就不需要重新安裝 grub 了， 因為 grub 本來就會主動去讀取設定檔啊！您說是吧！但如果你的 Linux 原來使用的並非 grub ， 那麼就需要來安裝啦！如何安裝呢？首先，你必須要使用 grub-install 將一些必要的檔案複製到 /boot/grub 裡面去，你應該這樣做的：

Tips:

安裝些什麼呢？因為 boot loader 有兩個 stage ，而設定檔得要放置到適當的地方。 這個 grub-install 就是在安裝設定檔 (包括檔案系統定義檔與 menu.lst 等等) 而已！ 如果要將 grub 的 stage1 主程式安裝起來，就得要使用 grub shell 的功能喔！本章稍後會介紹。

[root@www ~]# grub-install [--root-directory=DIR] INSTALL_DEVICE

選項與參數：

--root-directory=DIR 那個 DIR 為實際的目錄，使用 grub-install 預設會將

grub 所有的檔案都複製到 /boot/grub/* ，如果想要複製到其他目錄與裝置去，

就得要用這個參數。

INSTALL_DEVICE 安裝的裝置代號啦！

範例一：將 grub 安裝在目前系統的 MBR 底下，我的系統為 /dev/hda：

[root@www ~]# grub-install /dev/hda

# 因為原本 /dev/hda 就是使用 grub ，所以似乎不會出現什麼特別的訊息。

# 如果去查閱一下 /boot/grub 的內容，會發現所有的檔案都更新了，因為我們重裝了！

範例二：我的 /home 為獨立的 /dev/hda3 ，如何安裝 grub 到 /dev/hda3 (boot sector)

[root@www ~]# grub-install --root-directory=/home /dev/hda3

Probing devices to guess BIOS drives. This may take a long time.

Installation finished. No error reported.

This is the contents of the device map /home/boot/grub/device.map.

Check if this is correct or not. If any of the lines is incorrect,

fix it and re-run the script `grub-install'.

(fd0)   /dev/fd0

(hd0)   /dev/hda   <==會給予裝置代號的對應表！

[root@www ~]# ll /home/boot/grub/

-rw-r--r-- 1 root root     30 Apr 30 11:12 device.map

-rw-r--r-- 1 root root   7584 Apr 30 11:12 e2fs_stage1_5

....(底下省略)....

# 看！檔案都安裝進來了！但是注意到，我們並沒有設定檔喔！那要自己建立！

所以說， grub-install 是安裝 grub 相關的檔案 (例如檔案系統定義檔) 到你的裝置上面去等待在開機時被讀取，但還需要設定好設定檔 (menu.lst) 後，再以 grub shell 來安裝 grub 主程式到 MBR 或者是 boot sector 上面去喔！好了，那我們來思考一下想要安裝的資料。

例題：

我預計開機時要直接顯示選單，且選單倒數為 30 秒。另外，在原本的 menu.lst 當中新增三個開機選單，分別如下說明：

1. 假設 /dev/hda1 內含有 boot loader ，此 loader 如何取得控制權？

2. 如何重新讀取 MBR 內的 loader ？

3. 利用你原本的系統核心檔案，建立一個可強制進入單人維護模式的選單

答：

第一點很簡單，就利用上一小節的說明來處理即可。至於第二點，MBR 的讀取讀的是整顆硬碟的第一個磁區， 因此 root (hd0) 才是對的。第三點則與核心的後續參數有關。整個檔案可以被改寫成這樣：

[root@www ~]# vim /boot/grub/menu.lst

default=0

timeout=30

splashimage=(hd0,0)/grub/splash.xpm.gz

#hiddenmenu

title CentOS (2.6.18-92.el5)

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet

initrd /initrd-2.6.18-92.el5.img

title /dev/hda1 boot sector  <==本例中的第一個新增選單

root (hd0,0)

chainloader +1

title MBR loader             <==新增的第二個選單

root (hd0)           <==MBR 為整顆磁碟的第一個磁區，所以用整顆磁碟的代號

chainloader +1

title single user mode       <==新增的第三個選單(其實由原本的title複製來的)

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet single

initrd /initrd-2.6.18-92.el5.img

下次開機時，你就會發現有四個選單可以選擇，而預設會以第一個選單來開機喔！

我們已經將設定檔處理完畢，但是你要知道的是，我們並不知道 /dev/hda1 到底有沒有包含 grub 的主程式， 因此我們想要將 grub 主程式再次的安裝到 /dev/hda1 的 boot sector ，也想要重新安裝 grub 到 MBR 上面去。 此時我們就得要使用 grub shell 囉！整個安裝與 grub shell 的動作其實很簡單， 如果您有興趣研究的話，可以使用 info grub 去查閱∼鳥哥這裡僅介紹幾個有用的指令而已。

- 用『 root (hdx,x) 』選擇含有 grub 目錄的那個 partition 代號；

- 用『 find /boot/grub/stage1 』看看能否找到安裝資訊檔案；

- 用『 find /boot/vmlinuz 』看看能否找到 kernel file (不一定要成功！)；

- 用『 setup (hdx,x) 』或『 setup (hdx) 』將 grub 安裝在 boot sector 或 MBR；

- 用『 quit 』來離開 grub shell ！

由於我們最需要安裝的就是那個 stage1 啦！那才是 grub 的主程式嘛！而且設定檔通常與主程式擺在同一個目錄下。 因此我們需要使用 root (hd0,0) 去找到 /boot/grub/stage1 喔！接下來，請用 grub 來進入 grub shell 吧！進入 grub 後，會出現一個『 grub> 』的提示字元啊！

[root@www ~]# grub

# 1. 先設定一下含有 grub 目錄的那個 partition 啊！

grub> root (hd0,0)

Filesystem type is ext2fs, partition type 0x83

# 鳥哥主機的分割中，/boot/grub 在 /boot 的分割槽，亦即是 /dev/hda1 內喔！

# 另外， grub 也能夠分辨出該分割槽的檔案系統 (ext2)。

# 2. 搜尋一下，是否存在 stage1 這個資訊檔案？

grub> find /boot/grub/stage1

(hd0,2)

# 見鬼！怎麼會只有一個！我們明明有 /boot/grub 與 /home/boot/grub 啊！

# 因為 /boot 是獨立的，因此要找到該檔名就得要用如下的方式：

grub> find /grub/stage1

(hd0,0)

# 這樣就能夠找到囉！要特別注意 grub 找到不是目錄樹，而是裝置內的檔案。

# 3. 搜尋一下是否可以找到核心？ /boot/vmlinuz-2.6.18-92.el5 ？

grub> find /boot/vmlinuz-2.6.18-92.el5

Error 15: File not found

grub> find /vmlinuz-2.6.18-92.el5

(hd0,0)

# 再次強調，因為 /boot/ 是獨立的，因此就會變成上頭的模樣囉！

# 4. 將主程式安裝上去吧！安裝到 MBR 看看！

grub> setup (hd0)

Checking if "/boot/grub/stage1" exists... no <==因為 /boot 是獨立的

Checking if "/grub/stage1" exists... yes     <==所以這個檔名才是對的！

Checking if "/grub/stage2" exists... yes

Checking if "/grub/e2fs_stage1_5" exists... yes

Running "embed /grub/e2fs_stage1_5 (hd0)"...  15 sectors are embedded.

succeeded

Running "install /grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/grub/stage2

/grub/grub.conf"... succeeded  <==將 stage1 程式安裝妥當囉！

Done.

# 很好！確實有裝起來∼這樣 grub 就在 MBR 當中了！

# 5. 那麼重複安裝到我的 /dev/hda1 呢？亦即是 boot sector 當中？

grub> setup (hd0,0)

Checking if "/boot/grub/stage1" exists... no

Checking if "/grub/stage1" exists... yes

Checking if "/grub/stage2" exists... yes

Checking if "/grub/e2fs_stage1_5" exists... yes

Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)

Running "embed /grub/e2fs_stage1_5 (hd0,0)"... failed (this is not fatal)

Running "install /grub/stage1 (hd0,0) /grub/stage2 p /grub/grub.conf "...

succeeded

Done.

# 雖然無法將 stage1_5 安裝到 boot sector 去，不過，還不會有問題，

# 重點是最後面那個 stage1 要安裝後，顯示 succeeded 字樣就可以了！

grub> quit

如此一來，就已經將 grub 安裝到 MBR 及 /dev/hda1 的 boot sector 裡面去了！ 而且讀取的是 (hd0,0) 裡面的 /grub/menu.lst 那個檔案喔！真是很重要啊！重要到不行！

最後總結一下：

1. 如果是從其他 boot loader 轉成 grub 時，得先使用 grub-install 安裝 grub 設定檔；

2. 開始編輯 menu.lst 這個重要的設定檔；

3. 透過 grub 來將主程式安裝到系統中，如 MBR 的 (hd0) 或 boot sector 的 (hd0,0) 等等。

開機前的額外功能修改

事實上，上一個小節設定好之後，你的 grub 就已經在你的 Linux 系統上面了，而且同時存在於 MBR 與 boot sector 當中呢！所以，我們已經可以重新開機來查閱看看啦！ 另外，如果你正在進行開機，那麼請注意，我們可以在預設選單 (鳥哥的範例當中是 30 秒) 按下任意鍵， 還可以進行 grub 的『線上編修』功能喔！真是棒啊！先來看看開機畫面吧！

圖 3.5.1、grub 開機畫面示意圖

由於鳥哥將隱藏選單的功能取消了，因此你會直接看到這四個選單，同時會有讀秒的咚咚在倒數。 選單部分的畫面其實就是 title 後面的文字啦！你現在知道如何修改 title 後面的文字了吧！ ^_^。 如果你使用上下鍵去選擇第二 (/dev/hda1 boot sector) 或第三 (MBR loader) 時，會發現同樣的畫面重複出現！ 這是因為那兩個是 loader 移交而已嘛！而我們都使用相同的 grub 與相同的 menu.lst 設定檔！ 因此這個畫面就會重複出現了！這樣瞭解乎？

另外，如果你再仔細看的話，會發現到上圖中底部還有一些細部的選項，似乎有個 'e' edit 的樣子！ 沒錯∼ grub 支援線上編修指令喔！這是個很有用的功能！假如剛剛你將 menu.lst 的內容寫錯了，導致出現無法開機的問題時， 我們可以查閱該 title 選單的內容並加以修改喔！舉例來說，我想要知道第一個選單的實際內容時，將反白光棒移動到第一個選單， 再按下 'e' 會進入如下畫面：

圖 3.5.2、grub 單一選單內容

哈哈！這不就是我們在 menu.lst 裡面設定的東西嗎？沒錯！此時你還可以繼續進一步修改喔！ 注意看到上圖最底下的說明，你還可以使用：

- e：進入 grub shell 的編輯畫面；

- o：在游標所在行底下再新增一行；

- d：將游標所在行刪除。

我們說過， grub 是可以直接使用核心檔案來開機的，所以，如果您很清楚的知道你的根目錄 (/) 在那個 partition ，而且知道你的核心檔案檔名 (通常都會有個 /boot/vmlinuz 連結到正確的檔名)， 那麼直接在圖三的畫面當中，以上述的 o, d, e 三個按鍵來編修，成為類似底下這樣：

圖 3.5.3、grub edit 的線上編修功能

按下 [Enter] 按鍵後，然後輸入 b 來 boot ，就可以開機啦！所以說，萬一你的 /boot/grub/menu.lst 設定錯誤，或者是因為安裝的緣故，或者是因為核心檔案的緣故，導致無法順利開機時，記得啊，可以在 grub 的選單部分， 使用 grub shell 的方式去查詢 (find) 或者是直接指定核心檔案，就能夠開機啦！ ^_^

另外，很多時候我們的 grub 可能會發生錯誤，導致『連 grub 都無法啟動』，那麼根本就無法使用 grub 的線上編修功能嘛！怎麼辦？沒關係啊！我們可以利用具有 grub 開機的 CD 來開機， 然後再以 CD 的 grub 的線上編修，嘿嘿！同樣可以使用硬碟上面的核心檔案來開機啦！很好玩吧！ ^_^

關於核心功能當中的 vga 設定

事實上，你的 tty1~tty6 除了 80x24 的解析度外，還能夠有其他解析度的支援喔！但前提之下是你的核心必須支援 FRAMEBUFFER_CONSOLE 這個核心功能選項才行。如何確定有沒有支援呢？你可以查閱 /boot/config-2.6.18-92.el5 這個檔案，然後這樣搜尋：

[root@www ~]# grep 'FRAMEBUFFER_CONSOLE' /boot/config-2.6.18-92.el5

CONFIG_FRAMEBUFFER_CONSOLE=y

# 這個項目如果出現 y 那就是有支援啦！如果被註解或是 n ，那就是沒支援啦！

那麼如何調整 tty1 ~ tty6 終端機的解析度呢？先參考底下的表格再說 (此為十進位數值)：

彩度\解析度

640x480

800x600

1024x768

1280x1024

bit

256

769

771

773

775

8 bit

32768

784

787

790

793

15 bit

65536

785

788

791

794

16 bit

16.8M

786

789

792

795

32 bit

假設你想要將你的終端機螢幕解析度調整到 1024x768 ，且色彩深度為 15bit 色的時候，就得要指定 vga=790 那個數字！ 舉例來說，鳥哥的 tty1 就想要這樣的解析度時，你可以這樣做：

[root@www ~]# vim /boot/grub/menu.lst

....(前面省略)....

title CentOS (2.6.18-92.el5)

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

initrd /initrd-2.6.18-92.el5.img

....(後面省略)....

重新開機並選擇此選單進入 Linux，你跑到 tty1 去看看，嘿嘿！就已經是 1024x768 的解析度囉！ 只是字會變的很小，但是畫面的範圍會加大就是了。不過，某些版本支援的是 16 進位制，所以還需要修改一下格式呢！ 一般使用上表當中的值應該就可以了。不過，由於不同的作業系統與硬體可能會有不一樣的情況，因此， 上面的值不見得一定可以在您的機器上面測試成功，建議您可以分別設定看看哩∼以找出可以使用的值！ ^_^

BIOS 無法讀取大硬碟的問題

現今的硬碟容量越來越大，如果你使用舊的主機板來安插大容量硬碟時，可能由於系統 BIOS 或者是其他問題， 導致 BIOS 無法判斷該硬碟的容量，此時你的系統讀取可能會有問題。為什麼呢？

我們在本章一開始的開機流程講過，當進入 Linux 核心功能後，他會主動的再去偵測一下整個系統， 因此 BIOS 捉不到的硬體在 Linux 核心反而可能會可以捉到而正常使用。舉例來說，過去很多朋友常常會發現， 『我的系統使用 DVD 開機安裝時，可以順利的安裝好 Linux ，但是第一次開機時， 螢幕只出現黑壓壓的一片，且出現 grub> 的字樣，而無法進入 Linux 系統中』，這又是怎麼一回事？

- 在安裝的過程中，由於是使用 DVD 或 CD 開機，因此載入 Linux 核心不成問題，而核心會去偵測系統硬體，因此可以捉到 BIOS 捉不到的硬碟，此時你確實可以安裝 Linux 在大容量的硬碟上，且不會出現任何問題。

- 但是在進入硬碟開機時，由於 kernel 與 initrd 檔案都是透過 BIOS 的 INT 13 通道讀取的， 因此你的 kernel 與 initrd 如果放置在 BIOS 無法判斷的磁區中，當然就無法被系統載入，而僅會出現 grub shell (grub>) 等待你的處理而已。

更多 grub 錯誤的代碼查詢可以到底下的連結查閱：

- http://orgs.man.ac.uk/documentation/grub/grub_toc.html#SEC_Contents

現在你知道問題所在啦！那就是 BIOS 無法讀取大容量磁碟內的 kernel 與 initrd 檔案。 那如何解決呢？很簡單啦！就讓 kernel 與 initrd 檔案放置在大硬碟的最前頭，由於 BIOS 至少可以讀到大磁碟的 1024 磁柱內的資料，因此就能夠讀取核心與虛擬檔案系統的檔案囉。那如何讓 kernel 與 initrd 放置到整顆硬碟的最前面呢？簡單的要命吧！就建立 /boot 獨立分割槽，並將 /boot 放置到最前面即可！更多其他的解決方案可參考文後的延伸閱讀(註4)

萬一你已經安裝了 Linux 且發生了上述的問題，那該怎辦？你可以這樣作的：

- 最簡單的做法，就是直接重灌，並且製作出 /boot 掛載的 partition ，同時確認該 partition 是在 1024 cylinder 之前才行。

- 如果實在不想重灌，沒有關係，利用我們剛剛上頭提到的 grub 功能，額外建立一個可開機軟碟， 或者是直接以光碟機開機，然後以 grub 的編寫能力進入 Linux 。

- 另外的辦法其實是騙過 BIOS ，直接將硬碟的 cylinder, head, sector 等等資訊直接寫到 BIOS 當中去，如此一來你的 BIOS 可能就可以讀得到與支援的到你的大硬碟了。

不過，鳥哥還是建議您可以重新安裝，並且製作出 /boot 這個 partition 啦！ ^_^！這也是為啥這次更版中， 鳥哥特別強調要分割出 /boot 這個分割槽的原因啊！

為個別選單加上密碼

想像一個環境，如果你管理的是一間電腦教室，這間電腦教室因為可對外開放，但是你又擔心某些 partition 被學生不小心的弄亂，因此你可能會想要將某些開機選單作個保護。這個時候，為每個選單作個加密的密碼就是個可行的方案啦！ 那如何在開機的過程裡面提供密碼保護呢？首先，你必須要建立密碼，而且還需要是加密過後的喔！ 否則人家跑到 /boot/grub/menu.lst 不就可以探查到你的開機密碼了？那如何建立加密的密碼呢？ 我們可以透過 grub 提供的 md5 編碼來處理的，如下所示：

[root@www ~]# grub-md5-crypt

Password: <==輸入密碼

Retype password: <==再輸入一次

$1$kvlI0/$byrbNgkt/.REKPQdfg287. <==這就是產生的 md5 密碼！

上面產生的最後一行，由 $ 開始到 . 結束的那行，就是你的密碼經過 md5 編碼過後的咚咚！ 將這個密碼複製下來吧！假設我們要將第一個選項加入這個密碼，而第四個選項加入另外的密碼， 那你應該要這樣做：

[root@www ~]# vim /boot/grub/menu.lst

....(前面省略)....

title CentOS (2.6.18-92.el5)

password --md5 $1$kvlI0/$byrbNgkt/.REKPQdfg287.

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

initrd /initrd-2.6.18-92.el5.img

....(中間省略)....

title single user mode

password --md5 $1$GFnI0/$UuiZc/7snugLtVN4J/WyM/

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet single

initrd /initrd-2.6.18-92.el5.img

上表的案例中，我們兩個選單進入的密碼並不相同，可以進行同學的分類啦！不過這樣也造成一個問題， 那就是一定要輸入密碼才能夠進入開機流程，如果你在遠端使用 reboot 重新開機，並且主機前面並沒有任何人的話.... 你的主機並不會主動進入開機程序喔！ ^_^

你必須要注意的是：password 這個項目一定要在 title 底下的第一行。 不過，此項功能還是可能被破解的，因為使用者可以透過編輯模式 (e) 進入選單，並刪除密碼欄位並按下 b 就能夠進行開機流程了！真糟糕！那怎辦？只好透過整體的 password (放在所有的 title 之前) ， 然後在 title 底下的第一行設定 lock ，那使用者想要編輯時，也得要輸入密碼才行啊！設定有點像這樣：

[root@www ~]# vim /boot/grub/menu.lst

default=0

timeout=30

password --md5 $1$kvlI0/$byrbNgkt/.REKPQdfg287.  <==放在整體設定處

splashimage=(hd0,0)/grub/splash.xpm.gz

#hiddenmenu

title CentOS (2.6.18-92.el5)

lock  <==多了鎖死的功能

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet vga=790

initrd /initrd-2.6.18-92.el5.img

那麼重新開機後，畫面會像這樣：

圖 3.8.1、 grub 加密的示意圖

你可以看到最下方僅出現 p 的功能，由於 2, 3, 4 選單並沒有使用 lock ，因此這三個選單使用者還是可以執行開機程序， 但是第一個選單由於有 lock 項目，因此除非你輸入正確的密碼，否則第一個選單是無法被載入執行的。 另外，這個項目也能夠避免你的 menu.lst 在開機的過程中被亂改，是具有保密 menu.lst 的功能啦！ 與剛剛的選單密碼功能不同。

開機過程的問題解決

很多時候，我們可能因為做了某些設定，或者是因為不正常關機 (例如未經通知的停電等等) 而導致系統的 filesystem 錯亂，此時，Linux 可能無法順利開機成功，那怎麼辦呢？難道要重灌？當然不需要啦！ 進入 run level 1 (單人維護模式) 去處理處理，應該就 OK 的啦！底下我們就來談一談如何處理幾個常見的問題！

忘記 root 密碼的解決之道

大家都知道鳥哥的記憶力不佳，容易忘東忘西的，那如果連 root 的密碼都忘記了，怎麼辦？ 其實在 Linux 環境中 root 密碼忘記時還是可以救回來的！只要能夠進入並且掛載 / ， 然後重新設定一下 root 的密碼，就救回來啦！這是因為開機流程中，若強制核心進入 runlevel 1 時， 預設是不需要密碼即可取得一個 root 的 shell 來救援的。整個動作有點像這樣：

1. 重新開機！一定要重新開機！怎麼重開都沒關係；

2. 在開機進入 grub 選單後， (1)在你要進入的選單上面點 'e' 進入詳細設定； (2)將光棒移動到 kernel 上方並點 'e' 進入編輯畫面； (3)然後出現如下畫面來處理：

grub edit> kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/ rhgb quiet single

重點就是那個特殊字體的咚咚啦！按下 [enter] 再按下 b 就能夠開機進入單人維護模式了。

1. 進入單人維護模式後，系統會以 root 的權限直接給你一個 shell ，此時你就能夠執行『 passwd 』這個指令來重建 root 的密碼啦！然後直接『 init 5 』就可以切換成為 X 視窗介面囉！就是這麼簡單。

init 設定檔錯誤

前一個 root 密碼挽救的方法其實可以用在很多地方，唯一一個無法挽救的情況，那就是 /etc/inittab 這個檔案設定錯誤導致的無法開機！根據開機流程，我們知道 runlevel 0~6 都會讀取 /etc/inittab 設定檔， 因此你使用 single mode (runlevel 1) 當然也是要讀取 /etc/inittab 來進行開機的。那既然無法進入單人維護模式， 就表示這題無解囉？非也非也，既然預設的 init 無法執行，那我們就告訴核心不要執行 init ，改呼叫 bash 啊！ 可以略過 init 嗎？可以的，同樣在開機進入 grub 後，同樣在 grub edit 的情況下這樣做：

grub edit> kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/ rhgb quiet init=/bin/bash

因為我們指定了核心呼叫的第一支程式 (init) 變成 /bin/bash，因此 /sbin/init 就不會被執行。 又根據開機流程的說明，我們知道此時雖然可以利用 root 取得 bash 來工作，但此時 (1)除了根目錄外，其他的目錄都沒有被掛載； (2)根目錄被掛載成為唯讀狀態。因此我們還需要進行一些動作才行！如下所示：

圖 4.2.1、 略過 init 的程序，直接進入 bash shell

鳥哥僅下達兩個指令，『 mount -o remount,rw / 』用途是將根目錄重新掛載成為可讀寫，至於『 mount -a 』則是參考 /etc/fstab 的內容重新掛載檔案系統！ 此時你又可以開機進行救援的工作了！只是救援完畢後，你得要使用『 reboot 』重新開機一次才行！

BIOS 磁碟對應的問題 (device.map)

由於目前硬碟很便宜啊，所以很多朋友就想說：『那我能不能將 Windows 安裝在 /dev/hda 而 Linux 安裝在 /dev/hdb ， 然後調整 BIOS 的開機裝置順序，如此則兩套系統各有各的 loader 安裝在個別硬碟的 MBR 當中了！』。 這個想法非常好，如此一來兩者就不會互相干擾，因為每顆磁碟的 MBR 個別有不同作業系統的 loader 嘛！ 問題是，grub 對磁碟的裝置代號使用的是偵測到的順序啊！ 也就是說，你調整了 BIOS 磁碟開機順序後，你的 menu.lst 內的裝置代號就可能會對應到錯誤的磁碟上了！啊！真想哭！

沒關係的，我們可以透過 /boot/grub/device.map 這個檔案來寫死每個裝置對 grub 磁碟代號的對應喔！ 舉例來說，鳥哥的這個檔案內容如下：

[root@www ~]# cat /boot/grub/device.map

(fd0)   /dev/fd0

(hd0)   /dev/hda

如果你不清楚如何處理的話，也可以利用 grub-install 的功能喔！例如：

[root@www ~]# grub-install --recheck /dev/hda1

這樣 device.map 就會主動的被更新了！這樣瞭解乎？

因檔案系統錯誤而無法開機

如果因為設定錯誤導致無法開機時，要怎麼辦啊？這就更簡單了！最容易出錯的設定而導致無法順利開機的步驟，通常就是 /etc/fstab 這個檔案了，尤其是使用者在實作 Quota 時，最容易寫錯參數， 又沒有經過 mount -a 來測試掛載，就立刻直接重新開機，真要命！無法開機成功怎麼辦？ 這種情況的問題大多如下面的畫面所示：

圖 4.4.1、 檔案系統錯誤的示意圖

看到最後兩行，他說可以輸入 root 的密碼繼續加以救援喔！那請輸入 root 的密碼來取得 bash 並以 mount -o remount,rw / 將根目錄掛載成可讀寫後，繼續處理吧！其實會造成上述畫面可能的原因除了 /etc/fstab 編輯錯誤之外，如果你曾經不正常關機後，也可能導致檔案系統不一致 (Inconsistent) 的情況， 也有可能會出現相同的問題啊！如果是磁區錯亂的情況，請看到上圖中的第二行處， fsck 告知其實是 /dev/md0 出錯， 此時你就應該要利用 fsck 去檢測 /dev/md0 才是！等到系統發現錯誤，並且出現『clear [Y/N]』時，輸入『 y 』吧！

這個 fsck 的過程可能會很長，而且如果你的 partition 上面的 filesystem 有過多的資料損毀時， 即使 fsck 完成後，可能因為傷到系統槽，導致某些關鍵系統檔案資料的損毀，那麼依舊是無法進入 Linux 的。此時，就好就是將系統當中的重要資料複製出來，然後重新安裝，並且檢驗一下， 是否實體硬碟有損傷的現象才好！不過一般來說，不太可能會這樣啦∼ 通常都是 fsck 處理完畢後，就能夠順利再次進入 Linux 了。

利用 chroot 切換到另一顆硬碟工作

仔細檢查一下，你的 Linux 裡面應該會有一個名為 chroot 的指令才對！這是啥？ 這是『 change root directory 』的意思啦！意思就是說，可以暫時將根目錄移動到某個目錄下， 然後去處理某個問題，最後再離開該 root 而回到原本的系統當中。

舉例來說，補習班中心最容易有兩三個 Linux 系統在同一個主機上面，假設我的第一個 Linux 無法進入了，那麼我可以使用第二個 Linux 開機，然後在第二個 Linux 系統下將第一個 Linux 掛載起來， 最後用 chroot 變換到第一個 Linux ，就能夠進入到第一個 Linux 的環境當中去處理工作了。

你同樣也可以將你的 Linux 硬碟拔到另一個 Linux 主機上面去，然後用這個 chroot 來切換， 以處理你的硬碟問題啊！那怎麼做啊？粉簡單啦！

1. 用盡任何方法，進入一個完整的 Linux 系統 ( run level 3 或 5 )；

2. 假設有問題的 Linux 磁碟在 /dev/hdb1 上面，且他整個系統的排列是：

3.    掛載點   裝置檔名

4.    /     → /dev/hdb1

5.    /var  → /dev/hdb2

6.    /home → /dev/hdb3

/usr  → /dev/hdb5

若如此的話，那麼在我目前的這個 Linux 底下，我可以建立一個目錄，然後可以這樣做：

掛載點           裝置檔名

/chroot/      → /dev/hdb1

/chroot/var/  → /dev/hdb2

/chroot/home/ → /dev/hdb3

/chroot/usr/  → /dev/hdb5

1. 全部掛載完畢後，再輸入『 chroot /chroot 』嘿嘿！你就會發現，怎麼根目錄 (/) 變成那個 /dev/hdb1 的環境啦！這樣說明，瞭了嗎？ ^_^

重點回顧

- Linux 不可隨意關機，否則容易造成檔案系統錯亂或者是其他無法開機的問題；

- 開機流程主要是：BIOS、MBR、Loader、kernel+initrd、/sbin/init 等流程

- Loader 具有提供選單、載入核心檔案、轉交控制權給其他 loader 等功能。

- boot loader 可以安裝在 MBR 或者是每個分割槽的 boot sector 區域中

- initrd 可以提供核心在開機過程中所需要的最重要的模組，通常與磁碟及檔案系統有關的模組；

- init 的設定檔為 /etc/inittab ，此檔案內容可以設定預設 runlevel、系統初始化腳本、不同執行等級的服務啟動等；

- 額外的裝置與模組對應，可寫入 /etc/modprobe.conf 中；

- 核心模組的管理可使用 lsmod, modinfo, rmmod, insmod, modprobe 等指令；

- modprobe 主要參考 /lib/modules/$(uanem -r)/modules.dep 的設定來載入與卸載核心模組；

- grub 的設定檔與相關檔案系統定義檔大多放置於 /boot/grub 目錄中，設定檔名為 menu.lst

- grub 對磁碟的代號設定與 Linux 不同，主要透過偵測的順序來給予設定。如 (hd0) 及 (hd0,0) 等。

- menu.lst 內每個選單與 titile 有關，而直接指定核心開機時，至少需要 kernel 及 initrd 兩個項目

- menu.lst 內設定 loader 控制權移交時，最重要者為 chainloader +1 這個項目。

- 若想要重建 initrd ，可使用 mkinitrd 處理

- 重新安裝 grub 到 MBR 或 boot sector 時，可以利用 grub shell 來處理。

- 若想要進入救援模式，可於開機選單過程中，在 kernel 的項目後面加入『 single 』或『 init=/bin/bash 』等方式來進入救援模式。

- 我們可以對 grub 的個別選單給予不同的密碼。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：利用救援光碟來處理系統的錯誤導致無法開機的問題。

- 目標：瞭解救援光碟的功能；

- 前提：瞭解 grub 的原理，並且知道如何使用 chroot 功能；

- 需求：打字可以再加快一點啊！ ^_^

這個部分鳥哥就不捉圖了，請大家自行處理囉∼假設你的系統出問題而無法順利開機，此時拿出原版光碟，然後重新以光碟來啟動你的系統。 然後你應該要這樣作的：

4.  利用光碟開機時，到了看到 boot: 的階段，按下 [F5] 之後會看到可以輸入的選項，此時請輸入：

boot: linux rescue

就能夠進入救援模式的偵測了！

5.  然後請選擇語系與鍵盤對應，這個與安裝過程是一模一樣啦！所以選擇『 English 』與『 us 』即可！

6.  接下來會問你是否需要啟動網路，因為我們的系統是出問題要處理，所以不需要啟動網路啦！選擇『 No』即可；

7.  然後就進入救援光碟模式的檔案系統搜尋了！這個救援光碟會去找出目前你的主機裡面與 CentOS 5.x 相關的作業系統， 並將該作業系統彙整成為一個 chroot 的環境等待你的處置！但是他會有三個模式可以選擇，分別是『continue』繼續成為可讀寫掛載； 『Read-Only』將偵測到的作業系統變成唯讀掛載；『Skip』略過這次的救援動作。在這裡我們選擇『 Continue 』吧！

8.  然後系統會將偵測到的資訊通知你！一般來說，可能會在螢幕上顯示類似這樣的訊息：『 chroot /mnt/sysimage』此時請按下 OK 吧！

9.  按下 OK 後，系統會丟給你一個 shell 使用，先用 df 看一下掛載情況是否正確？ 若不正確請手動掛載其他未被掛載的 partition 。等到一切搞定後，利用 chroot /mnt/sysimage 來轉成你原本的作業系統環境吧！等到你將一切出問題的地方都搞定，請 reboot 系統，且取出光碟，用硬碟開機吧！

簡答題部分：

- 如何察看與修改 runlevel 呢？

察看很簡單，只要輸入『 runlevel 』就可以得知。而如果要修改目前的 runlevel ， 可以直接輸入 init [level] 例如要去到 runlevel 3 可以：『 init 3 』即可。 如果想要每次開機都設定固定的 runlevel ，那麼可以修改 /etc/inittab 這個檔案！ 將裡面這一行改成：『id:3:initdefault:』即可。

- 我有個朋友跟我說，他想要讓一個程式在 Linux 系統下一開機就啟動，但是在關機前會自動的先結束該程式，我該怎麼建議他？

由於 /etc/rc.d/rc[0-6].d 裡面有的 Sxxname 與 Kxxname 可以設定開機啟動與關機結束的事項！所以我就可以輕易的寫一個 script 放在 /etc/rc.d/init.d 裡面，並連結到我的 run-level 裡頭，就可以讓他自由自在的啟動與結束了！

- 萬一不幸，我的一些模組沒有辦法讓 Linux 的核心捉到，但是偏偏這個核心明明就有支援該模組， 我要讓該模組在開機的時候就被載入，那麼應該寫入那個檔案？

應該寫入 /etc/modprobe.conf (kernel 2.6.x) 或者是 /etc/modules.conf (kernel 2.4.x) 這個檔案，他是模組載入相關的地方呢！當然，也可以寫入 /etc/sysconfig/modules/* 裡面。

- 如何在 grub 開機過程當中，指定以『 run level 1 』來開機？

在開機進入 boot loader 之後，利用 grub shell 的功能，亦即輸入『 e 』進入編輯模式， 然後在 kernel 後面增加：

kernel (hd0,0)/boot/vmlinuz ro root=/dev/hda1 .... single

那個 single 也可以改成 1 ，就能夠進入。同樣的，若使用 lilo 時，按下 tab 按鍵後， 輸入

label_name -s

就能夠進入 run level 1 囉！

- 由於一些無心之過，導致系統開機時，只要執行 init 就會產生錯誤而無法繼續開機， 我們知道可以在開機的時候，不要以 init 載入系統，可以轉換第一支執行程式， 假設我第一支執行程式想要改為 /bin/bash ，好讓我自行維護系統(不同於 run level 1 喔！)， 該如何進行此一工作？

在開機的過程當中，進入 lilo 或 grub 的畫面後，在 kernel 的參數環境下，加入 init=/bin/bash 來取代 /sbin/init ，則可略過 init 與 /etc/inittab 的設定項目，不過，您必須相當熟悉 grub 與 lilo 的設定才行喔！ ^_^

- 在 CentOS 當中，我們如何自動可載入的模組？

可以經由設定 /etc/modprobe.conf 或者是將自行做好的設定檔寫入到 /etc/sysconfig/modules/ 目錄中， 並且將檔名取為 filename.modules ，注意喔，檔案結果務必是 .modules 才行。 相關資訊可以參考 /etc/rc.d/rc.sysinit 喔！

- 如果你不小心先安裝 Linux 再安裝 Windows 導致 boot loader 無法找到 Linux 的開機選單，該如何挽救？

方法有很多，例如：

(1)藉助第三方軟體，安裝類似 spfdisk 的軟體在 MBR 裡面，因為他同時認識 Linux 與 Windows ，所以就可以用他來進入 Linux 啦！

(2)或者使用類似 KNOPPIX 的 Live CD 以光碟開機進入 Linux 之後，再以 chroot 軟體切換根目錄 (/)，然後重新安裝 grub 等 boot loader ，同樣也可以重新讓兩個作業系統存在啦！

總之，只要你知道 MBR / Super block / boot loader 之間的相關性，怎麼切換都可能啊！ ^_^

參考資料與延伸閱讀

- 註1：BIOS 的 POST 功能解釋：http://en.wikipedia.org/wiki/Power-on_self-test

- 註2：BIOS 的 INT 13 硬體中斷解釋：http://en.wikipedia.org/wiki/INT_13

- 註3：關於 splash 的相關說明：http://ruslug.rutgers.edu/~mcgrof/grub-images/

- 註4：一些 grub 出錯時的解決之道：

http://wiki.linuxquestions.org/wiki/GRUB_boot_menu

http://forums.gentoo.org/viewtopic.php?t=122656&highlight=grub+error+collection

- info grub

- GNU 官方網站關於 grub 的說明文件：

http://www.gnu.org/software/grub/manual/html_node/

- 純文字螢幕解析度的修改方法：

http://phorum.study-area.org/viewtopic.php?t=14776

2003/02/10：第一次完成

2005/09/19：將舊的文章移動到 此處 。

2005/09/26：將 核心編譯 一文訂為進階篇，不一定要學啦！但是核心模組不可不題，所以，新增一小節！

2005/09/28：終於給他完成去！好累∼

2005/10/09：加上參考文獻資料，以及修改一些些 kernel 開機時， grub 的 vga 設定值的解說。

2005/11/09：加上了關於較大硬碟所產生的困擾！

2006/08/21：MBR 應該只有 512 bytes ，結果誤植為 512 Kbytes ，抱歉！

2007/06/27：新增 initrd 的說明，請參考這裡。

2009/04/09：將舊的基於 FC4 的文章移動到此處。

2009/04/10：取消了 LILO 的 boot loader 說明！畢竟這玩意兒已經退流行！所以不再強調！有需要請查詢此處。

2009/04/30：修訂完畢，加強 init=/bin/bash 的說明，以及 grub 的密碼管理！

2009/09/14：加入情境模擬，並根據討論區 linuxfans 兄的建議，修改了一些地方！詳情請參考討論區建議！

2003/02/10以來統計人數

第二十一章、系統設定工具(網路與印表機)與硬體偵測

切換解析度為 800x600

最近更新日期：2009/09/15

除了手動設定之外，其實系統提供了一個名為 setup 的指令給系統管理員使用喔！這個指令還能夠設定網路呢。 此外，我們也應該要知道如何在 Linux 底下連接印表機吧！否則一些資料怎麼印出來？ 另外，如果你的主機板支援 CPU 溫度偵測的話，我們還能夠利用 lm_sensors 這個軟體功能來偵測硬體的電壓、風扇轉速、 CPU 溫度等資訊呢！

1. CentOS 系統設定工具： setup

1.1 使用者身份驗證設定

1.2 網路設定項目(手動設定IP與自動取得)

1.3 防火牆設定

1.4 鍵盤形式設定

1.5 系統服務的啟動與否設定

1.6 系統時鐘的時區設定

1.7 X 視窗介面解析度設定

2. 利用 CUPS 設定 Linux 印表機

2.1 Linux 的列印元件 (列印工作、佇列、服務與印表機)

2.2 CUPS 支援的連線模式

2.3 以 Web 介面控管網路印表機

2.4 以 Web 介面控管 USB 本機印表機

2.5 將 Linux 本機印表機開放成為網路印表機

2.6 手動設定印表機： lpadmin, lpstat, lpr, lp, lpq, lprm

3. 硬體資料收集與驅動，及 lm_sensors

3.1 硬體資訊的收集與分析： lspci, lsusb, iostat...

3.2 驅動 USB 裝置

3.3 使用 lm_sensors 取得溫度、電壓等資訊： sensors-detect, sensors

3.4 udev與 hal 簡介

4. 重點回顧

5. 本章習題

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23898

CentOS 系統設定工具： setup

系統設定除了使用手動的方式編輯設定檔之外 (例如 /etc/inittab, /etc/fstab 等)，其實在 Red Hat 系統的 RHEL, CentOS 及 Fedora 還有提供一支綜合程式來管理的，那就是 setup 這個指令的功能囉！老實說， setup 其實只有在 Red Hat 的系列才有， 在其他的 Linux distributions 並不存在，因此，鳥哥並沒有很要求一定要學會這傢伙的。 只不過，setup 還是挺好用的，所以我們還是來玩玩吧！

這個 setup 的處理方法非常的簡單，就是利用 root 的身份下達這個指令，如果你已經使用遠端操作系統的話， 記得最好切換一下語系成為英文語系 (比較不會出現邊框是亂碼的情況) ，結果就會出現如下的畫面了。

圖1.0、 setup 的指令執行畫面示意圖

如上圖所示，那就是 setup 提供的各項系統設定功能。這個畫面的使用方式其實在圖中的最底下一行有說明了， 可以利用 [tab] 按鍵在三個畫面中切換，使用 Run Tool 可以開始設定該項目，使用 Quit 可以離開 setup 指令。 那麼上面的主選單部分有哪些功能呢？這些設定的基本功能是這樣的：

- Authentication configuration：

這是與使用者身份認證有關的設定，包括本機的帳號與利用遠端伺服器提供的帳號來登入本機等功能的設定；

- Firewall configuration：

簡單的設定 (1)防火牆與 (2)SELinux 的啟動模式 (Disable, Enforcing, Permissive)。 SELinux 請參考第十七章的說明， 防火牆則請參考伺服器篇的解釋了。這個地方的設定比較簡單， 有時候可能會讓你自己搞不清楚設定值的意義。所以，還是手動處理比較妥當；

- Keyboard configuration：

就是鍵盤按鍵的對應表。注意，這個設定僅與 tty 介面有關，至於 X Window 則不是以這個為設定值；

- Network configuration：

設定網路參數的地方，包括 IP, network, netmask, dns 等等，不過， 還需要看完伺服器篇關於網路基礎的介紹後， 才能夠比較瞭解設定值的意義啦！

- System services：

其實就是第十八章提到的 ntsysv 的內容喔∼亦即設定一些系統服務是否在開機時啟動的地方；

- Timezone configuration：

安裝的時候不是可以透過全世界地圖挑選時區嗎？ 這個就是在安裝完畢後重新選擇時區的地方；

- X configuration：

設定 X Window 相關的設定，例如解析度啦等等的。我們會在第二十四章再提到 X Window 方面的基礎知識。

底下我們就來約略的介紹一下這些玩意兒吧！除了網路 IP 的設定外，其餘的部分鳥哥會很快的帶過去而已。 畢竟 setup 僅是一個統整的工具，每個設定項目其實都牽涉到各自的基礎功能，那些基礎功能還得要持續摸索的...

使用者身份驗證設定

在按下了『 Authentication configuration 』項目後，會出現如下畫面：

圖 1.1.1、Setup 指令的使用者身份認證機制

我們的 Linux 除了使用自己提供的使用者密碼驗證機制之外，還能夠使用其他外部身份驗證伺服器所提供的各項驗證功能喔。 在上面圖示的左側 User Information 的地方指的是：我們系統上的使用者可以使用什麼方式對外取得帳號資訊， 也就是說，這部主機除了 /etc/passwd 的帳號之外，還能夠使用其他的帳號來登入系統的。我們支援的帳號管理伺服器主要有 LDAP, NIS, Winbind 等。

至於右側的 Authentication 則是登入時需要提供的身份驗證碼 (密碼) 所使用的機制為何。 在預設的情況下，我們身份驗證僅參考本機的 /etc/passwd, /etc/shadow 而已，而且使用 MD5 的密碼驗算機制， 因此上圖右側的部分僅會有最上方兩個而已。事實上，這個部分的設定主要是修改了 /etc/sysconfig/authconfig ，同時還加入了各個伺服器的用戶端程式設定功能哩。

你一定會問，那麼什麼時候可以用到這個機制呢？思考一下，如果你的網路環境是電腦教室， 你希望每個同學都能夠有自己的帳號來登入每部主機。此時，你會希望每部主機都幫同學建立同一個帳號嗎？ 那如果每一個同學都想要修改密碼，那就糟了！因為每部主機都得要重新修改密碼才行啊！這個時候帳號管理伺服器就很重要了。 他的功能有點像底下這樣：

圖 1.1.2、身份管理伺服器的功能示意圖

如上圖所示，我 vbird 想要登入某一部主機時，這部主機會向外要求帳號資訊，就是最上方那部伺服器。 此時，你只要在最上方的伺服器上將該帳號設定好，並且在每部主機都利用 NIS 或 LDAP 功能來指定身份查詢的方向， 那麼 vbird 就能夠使用同一組帳號密碼來登入每部主機了，這樣管理是否很方便呢？因為只要管理一部伺服器即可嘛！ 我們在伺服器篇談到 NIS 時再來實作這個環境喔！

Tips:

其實 NIS 與 LDAP 等等的，都是一種網路通訊協定，我們可以透過網路通訊協定來進行資料的傳輸。 使用者帳號資訊當然也能夠透過這個機制來管理囉！有興趣的朋友請繼續閱讀鳥哥寫的伺服器篇囉∼ ^_^

網路設定項目(手動設定IP與自動取得)

網路其實是又可愛又麻煩的玩意兒，如果你是網路管理員，那麼你必須要瞭解區域網路內的 IP, gateway, netmask 等參數，如果還想要連上 Internet ，那麼就得要理解 DNS 代表的意義為何。如果你的單位想要擁有自己的網域名稱， 那麼架設 DNS 伺服器則是不可或缺的。總之，要設定網路伺服器之前，你得要先理解網路基礎就是了！ 沒有人願意自己的伺服器老是被攻擊或者是網路問題層出不窮吧！^_^

但鳥哥這裡的網路介紹僅止於當你是一部單機的 Linux 用戶端，而非伺服器！所以你的各項網路參數只要找到網路管理員， 或者是找到你的 ISP (Internet Service Provider) ，向他詢問網路參數的取得方式以及實際的網路參數即可。 通常網路參數的取得方式在台灣常見的有底下這幾種：

1. 手動設定固定 IP ：

常見於學術網路的伺服器設定、公司行號內的特定座位等。這種方式你必須要取得底下的幾個參數才能夠讓你的 Linux 上網的：

- IP

- 子網路遮罩(netmask)

- 通訊閘(gateway)

- DNS 主機的 IP (通常會有兩個，若記不住的話，硬背 168.95.1.1 即可)

1. 網路參數可自動取得：

常見於 IP 分享器後端的主機，或者是利用電視線路的纜線上網 (cable modem)，或者是學校宿舍的網路環境等。 這種網路參數取得方式就被稱為 dhcp ，你啥事都不需要知道，只要知道設定上網方式為 dhcp 即可。

2. 透過 ADSL 寬頻撥接：

不論你的 IP 是固定的還是每次撥接都不相同 (被稱為浮動式 IP)，只要是透過寬頻數據機『撥接上網』的，就是使用這種方式。 撥接上網雖然還是使用網路卡連接到數據機上，不過，系統最終會產生一個替代數據機的網路介面 (ppp0) ， 那個 ppp0 也是一個實體網路介面啦！

瞭解了網路參數的取得方法後，你還得要知道一下我們透過啥硬體連上 Internet 的呢？其實就是網路卡嘛。 目前的主流網卡為使用乙太網路協定所開發出來的乙太網卡 (Ethernet)，因此我們 Linux 就稱呼這種網路介面為 ethN (N 為數字)。 舉例來說，鳥哥的這部測試機上面有一張乙太網卡，因此鳥哥這部主機的網路介面就是 eth0 囉 (第一張為 0 號開始)。

好了，那就讓我們透過 setup 來設定網路吧！按下『 Network Configuration 』會出現如下畫面：

圖 1.2.1 、 setup 的網路介面選擇示意圖

上圖中那個 eth1.bak 是系統捉錯的檔案，因為這個程式會跑到 /etc/sysconfig/network-scripts/ 目錄下找出檔名為 ifcfg-ethN 的檔案內容來顯示的。因為鳥哥僅有一張網卡，因此那個 eth1 不要理會他！直接點選 eth0 之後就會產生如下的畫面：

圖 1.2.2 、 網路介面的各項網路參數設定示意圖

上圖中那個 Name 與 Device 名稱最好要相同，盡量不要修改他！這裡的設定是這樣的：

1. 如果你是使用手動設定的話，『 Use DHCP 』一定不能勾選，然後將底下的 Static IP, Netmask, Default gateway IP 設定值填上去即可。這三個設定值請洽你的網路管理員喔。

2. 如果你是使用 DHCP 的自動取得 IP 方式，勾選『 Use DHCP 』後，將後面的三個設定清空，這樣就設定好網路參數了；

如果你是使用 ADSL 撥接的話，那麼上面的設定項目就不適用了。 你得要使用 (1)adsl-setup 來進行設定，然後再以 (2)adsl-start 來啟動 ADSL 撥接， 詳細的方法我們會在伺服器篇再來介紹的。上面談的都是 IP 的取得方式，並沒有談到主機名稱解析的部分 (DNS)。 只有手動設定者才需要進行 DNS IP 的設定，使用 dhcp 及 adsl-start 者都不需要進行底下的動作啦！ 假設你的 DNS IP 為中華電信的 168.95.1.1 時，那就得這樣設定：

[root@www ~]# vim /etc/resolv.conf

nameserver 168.95.1.1

重點是 nameserver 後面加上你的 DNS IP 即可！一切設定都妥當之後，你還得要進行一個任務，那就是重新啟動網路看看囉！ 重新啟動網路的方法很簡單，這樣做即可：

[root@www ~]# /etc/init.d/network restart

Shutting down interface eth0:               [  OK  ]

Shutting down loopback interface:           [  OK  ]

Bringing up loopback interface:             [  OK  ]

Bringing up interface eth0:                 [  OK  ]

由於網路涉及的範圍相當的廣泛，還包括如何進行網路除錯的工作等，鳥哥將這部份寫在伺服器篇了，所以這裡不再多費唇舌。 假設你現在已經連上 Internet 了，那麼防火牆的設定則不可不知啊！底下就來談談。

防火牆設定

防火牆的認識是非常困難的，因為你必須要有很強的網路基礎概念才行。CentOS 提供的這個簡單的設定其實有時候反而會讓我們困擾不已。基本上，這裡僅是介紹『你可以這樣做』，但並不代表『你必須這樣做』！ 所以，有興趣的還是得要再繼續鑽研網路技術喔！ ^_^。好了，在按下 Firewall configuration 後，會出現如下畫面：

圖 1.3.1 、 setup 進入防火牆設定示意圖

上圖中主要出現兩個部分，一個是關於 SELinux 的部分，一個則是防火牆的部分。SELinux 我們在第十七章介紹過了，這裡不再浪費篇幅。 請依據你的需求設定 Enforcing, Permissive 或 Disabled 吧！(當然最好還是務必要啟動 SELinux 啦！)

防火牆的部分，由於我們安裝時建議不要啟動防火牆， 因此上圖你會看到『 Disabled 』的部分被選擇了。但是由於現在你的系統已經上網了 (假設已經上網了)， 那麼你務必要啟動防火牆來管理網路才好。由於預設你的防火牆會開放遠端主機對你的登入連線， 因此最好使用 Customize (客戶設定) 來改變設定比較好喔！按下『 Customize 』會出現如下圖示：

圖 1.3.2 、 客製化防火牆抵擋機制的示意圖

這個地方不是三言兩語講的完的！包括信任裝置，以及允許進入的伺服器封包∼很是麻煩。基本上，你只要這樣想就好了：

- Trusted Devices：這是信任裝置， 如果你有兩張網路卡，一張是 eth0 對內，一張是對外，假設是 eth1 ，那麼如果你想要讓 eth0 的進出封包都是為信任，那麼這裡就可以將 eth0 勾選。不過，要非常非常注意， 接到外部網域 (Internet) 的那張網路卡，千萬不能勾選，否則大家就都能夠透過那張網卡連到你的主機上！ 在預設的情況中，這裡都不要選擇任何介面啦！

- MASQUERADE Devices：這個是『封包偽裝』的功能， 亦即是進行 IP 分享器的功能啦！如果你的 Linux 主機是作為類似 IP 分享器的功能， 那麼對外那張網路卡就得要啟動 MASQUERADE 才行！因為我們尚未談到網路伺服器，因此這裡可千萬不要隨意選擇。

- Allow incoming：這裡提到的就是各個服務的內部項目， 舉例來說，你的 Linux 有提供 WWW 服務，又希望大家都能夠來查閱， 那麼這個時候就可以在 WWW 那個項目前面勾選啦！你要注意到的是，預設 Linux 都會開放 ssh 這個服務 (如上圖)， 記得先將他取消勾選喔！因為這個 ssh 現在很容易被攻擊！所以不要開放人家使用這個服務連線到你的主機上。

基本上，這個動作僅是在建立 /etc/sysconfig/iptables 這個檔案而已。 而這個檔案預設是不存在的 (因為我們沒有啟動防火牆啊！) 。這裡你先有個概念即可，因為，我們未來會介紹以 shell script 的方式建立屬於您自己的防火牆系統，細節我們會在伺服器篇慢慢作介紹的啊！

如果你已經有網路了，記得在這個項目的設定中，於圖 1.3.1 選擇防火牆為『 Enable 』的狀態，按下『 Customize 』進入圖 1.3.2 當中取消 ssh 的勾選，最後再回到 1.3.1 當中按下『 OK 』來啟動 Linux 用戶端的防火牆設定吧！ 這樣你的系統就具有最起碼的防火牆功能囉！ ^_^

鍵盤形式設定

某些情況底下你的鍵盤可能會發生一些對應錯誤的情況，舉例來說，使用的鍵盤並非台灣常見的 104 按鍵導致很多英文對應不起來。 此時你可以使用 setup 來修改喔！按下『 Keyboard configuration 』會出現如下的畫面：

圖 1.4.1 、鍵盤形式選擇

其實這個檔案就僅會修改 /etc/sysconfig/keyboard 啦！很簡單的設定項目。

系統服務的啟動與否設定

我們在第十八章談過系統服務的啟動與關閉， 當時介紹過 ntsysv 吧？沒錯∼這個 System services 的項目就是會呼叫出 ntsysv 這支程式來處理服務的設定啦！詳細的設定請回第十八章參考吧！這裡不再浪費篇幅囉！ 因為....鳥哥實在太會碎碎唸了，再加上圖示，唔！好佔篇幅∼ @_@

系統時鐘的時區設定

我們知道地球是圓的，所以想要看王建民在紐約投球都得要三更半夜才有辦法看的到！這也就是說， 其實在同一個時間點全世界的時鐘指的時間都不相同啊！我們的 Linux 是支援多國語系的國際化作業系統， 所以你可以將這部主機拿到任何地方且不需要修改系統時鐘，因為系統會主動的依據你提供的時區來變化時間的。 當你將筆記型電腦帶到美國紐約並且想要變更成為美國時間時，可以按下『 Timezone configuration 』的項目：

圖 1.6.1 、 setup 的時區選擇

如上圖所示，你在上半部畫面中，可以使用鍵盤方向鍵來選擇正確的位置，然後再用 [tab] 移動到 [OK] 即可！ 時區的設定，其實就是找出與 /etc/sysconfig/clock 有關的設定項目而已。實際上，上面圖示出現的咚咚，就與 /usr/share/zoneinfo/ 目錄內的資料有關而已。

X 視窗介面解析度設定

X Window System 我們會在第二十四章再來詳細說明，這裡僅是告知一下， 如果你想要變更你的 X 視窗介面的解析度時，就可以使用這個項目了。不過要注意的是，這個項目的執行不可以使用類似 ssh 通訊協定連線後，在遠端主機上執行這個設定項目。因為這個項目的執行會產生一個新的 X 終端機在 tty7 或 tty8 上頭， 因此，你如果使用遠端連線機制的話，會看不到畫面的啦！理解乎？

在你點選了『 X configuration 』之後，就會出現如下的圖樣。其中以硬體及設定兩個頁面較常被變更。 先來瞧瞧圖示吧：

圖 1.7.1 、 setup 的 X 解析度設定

如上所示，由於視窗解析度的範圍與螢幕的支援有關，因此你必須要先處理螢幕的更新頻率後才能夠修改視窗解析度。 所以我們會先處理『硬體』部分，鳥哥的螢幕是舊式的 4:3 傳統螢幕，所以選擇 1024x768 ，如果你的螢幕是新型的寬螢幕， 那麼請自行挑選適當的解析度吧。處理完畢後就能夠開始設定視窗解析度了，如下所示：

圖 1.7.2 、 setup 的 X 解析度設定

如上圖所示，此時會出現可調整的解析度啦！整理整理就能夠顯示出你想要的視窗解析度。 其實這些設定都是修改 /etc/X11/xorg.conf 這個設定檔啦！等到了第二十四章時，我們再來詳細的談談這玩意吧！ 至於關於 X 方面的登錄檔則在 /var/log/Xorg.0.log 囉！

鳥哥個人認為，這個 setup 的工具是很好用的∼只是，如果能夠完全清楚整個系統架構的話， 再來玩這個小程式會比較好啦！ ^_^。另外，原本的舊版 CentOS 還有提供印表機的設定功能，不過由於新版的資料已經轉由 CUPS 負責列印， 而列印可以使用瀏覽器介面來顯示，因此就取消了這個 setup 的元件啦！底下我們就來玩玩如何簡單的設定你的印表機吧！

利用 CUPS 設定 Linux 印表機

印表機對於日常生活來說，很重要吧！呵呵∼沒錯啊！尤其我們的 Linux 主機如果未來還要作為 Printing server 的話，那麼自然就得要先建立好印表機的連線啦！在本章裡面我們僅談論一下如何讓你的 Linux 可以連接到印表機， 讓你的 Linux 可以順利的將文件資料列印出來啦！現在就來談談先！

Linux 的列印元件 (列印工作、佇列、服務與印表機)

- 硬體支援度

要談論 Linux 的列印，首先就得要知道 Linux 底下整個列印的行為是怎樣的一個流程呢？而且， 也得要瞭解一下你的硬體是否支援列印工作嘛！在硬體部分，你必須要在 BIOS 將印表機的支援啟動才行！ 不過，這大概都屬於舊式印表機才需要的動作啦！為啥呢？因為現在印表機大部分都是 USB 或者是網路印表機了， 根本不需要使用 25 針序列埠的支援！

Tips:

為什麼會談到 25 針序列埠以及 BIOS 的支援呢？這是因為鳥哥曾經發生過一件糗事。 由於鳥哥常用舊型主機的關係，所以總喜歡先在 BIOS 裡面將沒用到的裝置項目全部取消 (disable)， 所以沒有接印表機的情況下，當然連印表機的序列埠 (Parallel) 也關閉了。沒想到後來為了測試印表機的連線取得一台舊式印表機， 要命啊！連續測試兩天的時間卻無法順利的列印出正確的文件資訊！最後才想到可能是 BIOS 內部的問題。 進入 BIOS 將印表機支援啟動成為 EPP/SPP 之後，俺的 Linux 就能夠順利的捉到印表機並進行列印∼真想哭啊！ 不是感動的想哭，是氣的想哭！

除了主機本身的支援之外，你的印表機也必須要能夠支援 Linux 才行！其實並不是 Linux 的問題啦！而是印表機製造商必須要能夠提供給 Linux 用的驅動程式，這樣你的 Linux 才能夠使用該型號的印表機。 老實說，鳥哥是 HP 印表機的愛好者，因為 HP 印表機對 Linux 的支援非常好！但是另一牌的 L 開頭的印表機總是很慢或者不推出給 Linux 用的驅動程式，所以該牌的印表機很難安裝在 Linux 主機上！真困擾。

Tips:

因為鳥哥過去所待的研究室大多購買 HP 的印表機，所以測試印表機時完全沒有出現任何問題。 但是某天在家裡使用鳥嫂購買的 L 牌的事務機時，連忙了三天卻都無法連接到該印表機來順利輸出。 最終查詢 Linux 印表機支援網站，才發現該型號的事務機根本沒有推出給 Linux 用的驅動程式， 所以就無法順利使用該印表機∼最終...鳥哥就放棄該測試了∼唉！真浪費時間！

那到底你該如何確認你的印表機有支援 Linux 呢？或者是，如果你想要購買新的印表機時， 如何查詢該印表機能否在 Linux 上面安裝呢？很簡單，直接到底下的網站去查詢一下即可喔！

- http://www.linuxfoundation.org/en/OpenPrinting

舉例來說，鳥哥現在的研究室有一部 HP 的 LaserJet P2015dn 印表機，我想要知道這部印表機對 Linux 的支援度好不好， 那就先進入上述的網站連結，出現如下的畫面：

圖 2.1.1 、 印表機支援網站的主畫面

在如上畫面中請按下『 Printers 』來觀察印表機的特色吧！會出現如下畫面：

圖 2.1.2 、 選擇印表機示意圖

在上圖中填入正確的廠牌 (HP) 以及正確的印表機型號 (LaserJet P2015dn) 後，請按下『 Show 』那個按鈕， 該網站就會從資料庫內捉出支援度的情況給你看，如下圖所示：

圖 2.1.3 、 鳥哥的印表機對 Linux 的支援度

在顯示的畫面中，你最要注意的是那個企鵝數量啦！如果達到 3 隻，那就代表支援度是非常完美的。 兩支企鵝是可接受的範圍內。如果是小於一隻企鵝時，那麼該印表機對 Linux 的支援可能就是比較差的喔！ 還好，鳥哥這部含有網路功能的印表機還有兩隻企鵝的支援，等一下應該能夠順利安裝到俺的 Linux 測試機上吧！

- 列印元件

你有沒有發現，在印表機還沒有啟動電源的情況底下，其實我們還是可以透過軟體來將某個工作列印出來的， 只是該項工作就會被放入到等待的環境中 (佇列) 。為什麼會這樣呢？這是因為整個列印的行為被區分為許多部分， 每個部分都可以單獨存在的啦！我們將整個部分繪製成下圖來瞧瞧：

圖 2.1.4、 列印行為之各元件示意圖

我們大概可以將上圖區分為幾個部分來說明：

- 列印工作：

例如 Open Office 這類較大型的辦公室軟體中，可以利用內建的程式產生列印的動作。 我們也可以使用類似 lpr 這類指令列程式來直接列印某個檔案。列印軟體產生的列印動作，就是產生一個列印的工作 (job)， 這個列印工作就會進入排隊等待 (佇列, queue) 的環境中，等待列印服務來進行輸出。

- 列印佇列：

這是放置列印工作的重要項目！這個列印佇列與列印服務有關。一般來說，列印佇列會以印表機的名字來命名， 讓大家知道你的列印工作將要使用哪部印表機輸出之故。當列印工作放置到佇列後，就開始等待列印服務的取用與輸出了。

- 列印服務：

就是實際負責溝通佇列內的列印工作與印表機的服務啦！列印服務其實就是將佇列內的列印工作，將她的資料轉成印表機認識的格式後， 直接交給印表機來輸出而已。但是列印服務必須要認識與溝通印表機，因此他就得要連上印表機與驅動印表機才行。 目前常見的列印服務有 CUPS 與 LPRng ，不過以 CUPS 為主流啦！

一般我們說的印表機驅動程式，其實就是將列印工作的資料轉成印表機格式啦！ 而目前常見的印表機格式為使用 Postscript 的列印格式，Linux 預設的 CUPS 本身就支援這種列印格式，因此， 只要你購買的印表機有支援 postscript ，那麼安裝起來應該是很輕鬆的才是。我們在上面提到的印表機支援網站中， 裡面的驅動程式很多就是 postscript 印表機描述檔案 (Postscript Printer Description (註1))

那萬一沒有 PPD 檔案呢？沒關係，我們可以透過印表機製作商提供的其他定義檔 (例如 Ghostscript) 來解釋列印工作的資料， 讓印表機認識該格式後，就能夠順利列印了！這也就是說，其實印表機驅動程式就是將資料轉成印表機認識的格式後， 就能夠加以輸出了。而常見的格式為 Postscript 及 Ghostscript 囉！

那麼這些列印的 PPD 驅動程式檔放在哪裡呢？其實就放在 /usr/share/cups/model/ 底下啦！ CentOS 已經提供一些預設的驅動程式了，如果想要取得更新的 PPD 驅動程式檔，請參考上面的印表機網站， 從那上頭來下載即可呦！若想要直接下載全部的 PPD 檔案，可以參考連結： http://www.linuxprinting.org/download/PPD/

Tips:

為什麼需要列印佇列 (queue) 呢？因為印表機只能夠給單一任務進行列印，沒辦法像 CPU 可以交錯運作的！ 所以列印工作就得要排隊等待印表機的列印，而印表機得要將前一份工作列印完畢後才能夠列印下一份工作！ 否則如果是交錯列印，那印出的東西不就混雜在一起了？這樣說瞭解嗎？ ^_^

CUPS 支援的連線模式

如果你的印表機具有網路卡，那麼你當然可以使用網路連線到你的印表機上面囉！不過，這種印表機提供什麼服務呢？ 也就是說，你可以使用什麼連線協定來連上印表機呢？常見的印表機連線分享方式有底下這些：

- socket

資料透過 internet socket(埠口)來傳送，一般為 port 9100 或 35。如果想要進行資料的傳輸與列印，可以透過在瀏覽器上面輸入： socket://host-printer:9100/ 來進行。不過，這種模式不常用就是了。

- LPD (Line Pritner Daemon)

LPD 是較早之前的列印服務，剛剛上頭提到的 LPRng 就是使用這種方式的連線啦！ LPD 主要是利用序列埠來達成列印的需求，印表機名稱就是 LPT1/LPT2... 等等。 目前還是可以在比較早期的 Linux distributions 看到這種列印方式。

- IPP (Internet Printing Protocol)

這是目前比較流行的印表機列印協定，我們的 CUPS 預設也是支援這種協定啊！當啟動 IPP 時，印表機會啟動 port 631 ，列印的資料就是透過這個 port 來進行傳送的。另外，如果你的印表機或者 Linux 主機啟動了 ipp 之後， 嘿嘿！你可以直接使用瀏覽器，輸入： ipp://printer_IP/printername，或者是： http:/printer_IP:631 就能夠直接線上處理印表機的設定了！方便的很啊！

- SMB (Server Message Block)

這傢伙就是網路上的芳鄰啦！協定使用的是： smb://user:password@host/printer 。

CentOS 5.x 預設提供的就是 CUPS 的 IPP 協定喔！而且 CUPS 預設開機就啟動了， 因此，你可以隨時隨地的以 Web 介面設定自己的印表機呢！真是非常方便！ 那如果你的印表機是透過線材 (USB/序列埠) 連上主機的呢？那就得要考慮底下的連接介面囉！

- parallel ：平行序列埠啊，就是 25 針那種玩意兒！他是連接到 /dev/lp[0-2] 等裝置。 在 CUPS 裡面的裝置使用格式為： parallel:/dev/lp0；

- USB ：一般越來越常見的 USB 印表機啊！ CUPS 使用的格式為： usb:/dev/usb/lp0 。

以 Web 介面控管網路印表機

事實上，管理 Linux 的印表機是非常簡單的一件事情，因為你只要啟動 CUPS 之後，再以瀏覽器介面來管理即可。 不過，在預設的情況底下，要進行瀏覽器介面的管理動作時，你必須要：

- 必須要啟動 CUPS 這個服務 (/etc/init.d/cups start)

- 具有 root 的權限 (需要 root 的密碼來設定)；

- 預設僅能在本機 (localhost) 管理，無法使用遠端連線連到此 Linux 管理；

如果你想要在區域網路內將印表機的控制權挪出來給其他用戶管理時，就得要修改 CUPS 的設定了。 在這裡，我們先以本機的方式來處理印表機的連線喔！首先，鳥哥以具有網路卡的印表機 HP LaserJet P2015dn 這部為例 (因為鳥哥也只有這部印表機具有網卡啊！)，這部印表機的 IP 為 192.168.201.253，而鳥哥 Linux 測試機 IP 為 192.168.201.250。然後，你可以這樣做：

- 確認印表機存在且支援 CUPS 認識的相關協定

如果想要加入 CUPS 的網路印表機，那麼你的印表機當然就得要支援 CUPS 認識的通訊協定囉！如何確定呢？ 首先，你必須要依照你印表機所提供的手冊去設定好 IP ，以鳥哥上面的環境來說，我的印表機 IP 為 192.168.201.253 ， 因此我可以這樣確定該印表機是否存在喔：

# 1. 先確定 IP 是否正確：

[root@www ~]# ping -c 3 192.168.201.253

PING 192.168.201.253 (192.168.201.253) 56(84) bytes of data.

64 bytes from 192.168.201.253: icmp_seq=1 ttl=255 time=0.464 ms

64 bytes from 192.168.201.253: icmp_seq=2 ttl=255 time=0.313 ms

64 bytes from 192.168.201.253: icmp_seq=3 ttl=255 time=0.356 ms

--- 192.168.201.253 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 2000ms

rtt min/avg/max/mdev = 0.313/0.377/0.464/0.067 ms

# 重點是有沒有出現回應的時間參數，亦即是 time 那個欄位喔！

# 2. 使用 nmap 測試印表機有沒有出現列印相關的服務埠口：

[root@www ~]# nmap 192.168.201.253

Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-05-27 22:07 CST

Interesting ports on 192.168.201.253:

Not shown: 1676 closed ports

PORT     STATE SERVICE

80/tcp   open  http

139/tcp  open  netbios-ssn

515/tcp  open  printer

9100/tcp open  jetdirect

MAC Address: 00:18:FE:9E:4C:58 (Unknown)

Nmap finished: 1 IP address (1 host up) scanned in 3.875 seconds

# 鳥哥這部印表機僅支援 LPD 服務 (515) 以及 HP 獨家的服務 (9100)

這樣就確定我的印表機實際存在，且這部印表機僅支援 HP 獨家的網路服務 (port 9100) 以及舊版的 LPD 服務而已， 這個資訊很重要，因為等一下我們使用 CUPS 連線時，就得要使用這個 LPD 的服務喔！另外，請特別給他留意一下， 那個 nmap 是個可以掃瞄主機埠口的軟體 (port scan) ，這個軟體其實是駭客軟體，他預設並沒有安裝到 CentOS 上， 但是你可以使用『 yum install nmap 』來安裝他。請注意，因為這個軟體可以是惡意攻擊的，因此千萬不要用來查閱別人的主機，否則恐怕會有違法之虞喔！！

接下來，讓我們來瞭解一下，系統有沒有 CUPS 的支援吧！

- 查詢你 Linux 主機是否啟動 CUPS 服務

再來查看看你的主機是否已經啟動了 CUPS 呢？使用 netstat 這個指令看看：

[root@www ~]# netstat -tlunp | grep 631

tcp  0  0 127.0.0.1:631     0.0.0.0:*         LISTEN      4231/cupsd

udp  0  0 0.0.0.0:631       0.0.0.0:*                     4231/cupsd

確實有啟動 631 埠口以及 cupsd 的服務。接下來，我們可以直接連上 CUPS 了！請打開瀏覽器， 然後在網址列輸入『 http://localhost:631 』即可！因為瀏覽器要連接的並非正規的 WWW 服務埠口， 因此就得要加上冒號 (:) 來指定埠口連接！順利的話，應該可以出現如下畫面：

圖 2.3.1、 CUPS 進站畫面

主畫面主要可以分為上下兩個按鈕列來說明，其中又以下方的按鈕列為常見的操作項目。我們會用到的按鈕大概就是：

- Add Printer：新增印表機，就是從這個按鈕開始的！

- Manage Jobs：列印工作管理，如果有列印工作要取消的，這個就對了！

- Manage Printers：管理印表機，包括是否啟動或者是刪除印表機等。

不囉唆，趕緊來新增印表機看看！按下『 Add Printer 』項目吧：

圖 2.3.2、 CUPS 新增印表機的畫面示意圖

上面圖示中，最重要的其實是那個『 Name 』的項目，那就是你印表機的佇列名稱！未來所有列印的工作都是放在該名稱底下排隊的！ 鳥哥的這個印表機名稱比較複雜啦！你可以取個比較簡單的名字，以後比較容易使用指令列軟體來列印啦！ 至於位置 (Location) 與描述 (Description) 都是這個印表機的說明，可寫可不寫！寫完後按下『 continue 』吧！

圖 2.3.3、選擇印表機所提供的服務項目

接下來則是選擇這個印表機佇列所連線的印表機提供什麼服務的列印功能？你可以看到前一小節我們使用 nmap 的時候就發現 port 9100 就是 HP JetDirect ，因此我們可以選擇上圖的第一個項目。 由於這部印表機也提供 port 515 的 LPD 服務，因此你也可以選擇上圖的『 LPD/LPR Host or Printer 』項目。 不過，在這裡鳥哥選擇的是第一項啦！選擇完畢後再按下『 Continue 』進入印表機的實體位置項目，如下圖：

圖 2.3.4、填寫印表機的實際連線方式，要填正確！

上圖有提供很多範例，我們由於使用到 port 9100 ，因此使用的就是 socket:// 那個範例使用的狀態。 填寫正確的位置後，接下來按下『 Continue 』來繼續選擇印表機的型號吧！

圖 2.3.5、選擇印表機的實際型號(驅動程式確認)

如上圖所示，我們選擇的是 HP 的廠牌！廠牌選擇完畢後會出現如下圖的型號選擇：

圖 2.3.6、選擇印表機的實際型號(驅動程式確認)

但上圖中我們並沒有看到 P2015dn 這部印表機的型號！那怎辦？沒關係，可以連線到 http://www.linuxfoundation.org/en/OpenPrinting 網站下載適當的驅動程式後， 按下上圖中的『瀏覽』按鈕來選擇該檔案即可。不過，從該網站的介紹中，可以發現鳥哥的這部印表機似乎使用預設的 Postscript 驅動程式即可，該網站也沒有提供這部印表機的驅動程式啊！那怎辦？沒關係，在 /usr/share/cups/model/ 目錄下就有預設的驅動程式啦！所以請按下『瀏覽』來處理一下！

圖 2.3.7、選擇驅動程式檔案

如上圖所示，選擇正確的驅動程式，然後再按下『開啟』按鈕，最後按下『 Add Printer 』按鈕就可以進入管理員密碼輸入畫面：

圖 2.3.8、輸入管理員帳號密碼(預設用 root)

到此為止我們的印表機設定就 OK 了！如果你回到 CUPS 的進站畫面，並且點選 Printers 之後，就會出現如下的印表機畫面：

圖 2.3.9、印表機的控制畫面

上面畫面中的按鈕都看的懂吧？其中比較重要的是那個『 Set As Default 』項目， 那就是設定為『預設印表機』，當你產生列印工作後，該工作預設就會丟給這個 hp_lj_p2015dn 的佇列來處理的意思喔。 接下來，當然就是按下『 Print Test Page 』看看能否列印出正確的畫面囉！如果可以順利的列印，恭喜您！ 印表機設定成功！

以 Web 介面控管 USB 本機印表機

上一小節提到的是網路印表機，那如果你的印表機是一般普通的具有 USB 介面的印表機呢？ 由於印表機的裝置檔名為 /dev/usb/lp0 開始的名稱，既然已經知道印表機名稱了，那麼我們先來注意看看 USB 是否有捉到該印表機， 由於我們的 Linux 已經能夠處理隨插即用 (PnP) 的裝置，因此直接執行 ls 去查閱檔名是否存在即可：

[root@www ~]# ll /dev/usb/lp0

crw-rw---- 1 root lp 180, 0 Jun  1 22:32 /dev/usb/lp0

# 這個檔案會被自動的建立起來，你不需要手動建立這個檔案喔！

老實說，除非你的 USB 印表機是非常冷門的機種，否則，我們的 CUPS 應該已經自動的捉到並且設定好該印表機囉！ 以鳥哥為例，鳥哥辦公室的事務機為 HP Diskjet F380 ，如果使用列出 USB 裝置的 lsusb 時，可以看到：

[root@www ~]# lsusb

Bus 001 Device 001: ID 03f0:5511 Hewlett-Packard Deskjet F300 series

Bus 002 Device 001: ID 0000:0000

Bus 002 Device 002: ID 0d62:a100 Darfon Electronics Corp. Benq Mouse

接下來，同樣的我們使用 CUPS 的 Web 介面來設定一下這部印表機吧！在網址列輸入 http://localhost:631 之後再按下『Manage Printers』會出現如下畫面：

圖 2.4.1 、由 HAL 機制順利取得的 USB 印表機

由上圖我們可以發現 CUPS 已經捉到了印表機了！連驅動程式都安裝妥當！這是怎麼回事啊？ 這是因為 CentOS 提供了 HAL 的機制來處理 PnP 裝置的緣故。關於 HAL 的機制我們會在下一小節再來討論。 不過由於這個裝置使用的是 HAL 提供的裝置檔名，我們如果想要使用 /dev/usb/lp0 來作為印表機的輸出檔名的話， 那麼就自己來建立一個印表機的佇列吧！同樣的在 CUPS 畫面中按下『 Add Printer 』來新增一個印表機：

圖 2.4.2 、 輸入佇列名稱

圖 2.4.3 、指向第一個 USB 裝置處

如上圖所示，你要指定的是那個有 #1 的位置，那就是我們的第一個 USB 插槽位置喔！

圖 2.4.4 、選擇印表機的驅動程式

圖 2.4.5 、最終結果

如上圖所示，最後就會多出一個名為 deskjet_f380 的印表機名稱，接下來當然就是『 Print Test Page 』測試看看能否列印囉。 如果能夠列印得出來，那就是設定妥當了。所以說， USB 印表機的設定要簡單太多囉！ ^_^

將 Linux 本機印表機開放成為網路印表機

想像一個狀況，你僅有 USB 印表機安裝在 Linux 上頭，整個辦公室或實驗室裡面僅有這部印表機。 雖然你可以加裝列印伺服器來使 USB 印表機變成網路印表機，但總是得多花錢啊！ 有沒有辦法可以讓你的本機印表機變成網路印表機呢？有的，那就是修改 CUPS 的設定即可。如何修改呢？ 我們還是透過 CUSP 的瀏覽器介面來處理即可喔！選擇『Administration』會出現如下畫面(在畫面的最右邊)：

圖 2.5.1 、勾選可讓 CUPS 成為列印伺服器的功能

如上圖所示，在箭頭指定的地方進行勾選即可。勾選完畢後按下『 Change Settings 』就能夠讓你的 CUPS 變成列印伺服器！ 而你原本的印表機就會成為：『ipp://你的IP:631/printers/印表機佇列名稱』，舉例來說，鳥哥這部 Laserjet p2015dn 在網路上看到的就會是：『ipp://192.168.201.250/printers/hp_lj_p2015dn』的名稱啊！ 你可以在其他用戶端電腦上面以這個 URI 來進行連線哩！

手動設定印表機

事實上我們剛剛在上面所進行的各項動作大多是在修改 /etc/cups/ 裡面的幾個檔案而已啊！幾個重要的檔案為：

- /etc/cups/printers.conf：印表機的設定值，都寫在這個檔案中；

- /etc/cups/cupsd.conf：CUPS 的主要設定檔，包括做為伺服器之用途的設定。

- /etc/cups/ppd/*.ppd：就是各個印表機的驅動程式 (PPD 設定檔)；

既然只是改了這幾個設定檔，你當然也可以使用 vim 去編輯，不過，因為涉及硬體連線的問題， 因此還是建議使用 web 介面來進行修改啦。不過，某些時候如果你沒有瀏覽器介面時，那麼使用終端機介面的指令來修改也是可以的。 我們底下只以鳥哥辦公室擁有的這一部 HP P2015dn 的雷射印表機來作為範例喔！

- 1. 下載合適的 PPD 驅動程式定義檔

首先你必須要前往印表機網站下載你的印表機驅動程式定義檔。鳥哥之前已經查詢過，這部印表機使用預設的 PPD 檔案即可。 所以鳥哥這部印表機的驅動程式定義檔基本上在： /usr/share/cups/model/postscript.ppd.gz 。 如果你有自己下載自己印表機的驅動程式時，請將你下載的檔案放置到 /usr/share/cups/model/ 目錄下， 因為後續要操作的指令會到此目錄中找尋驅動程式定義檔喔！

- 2. 啟動 CUPS 以及印表機

接下來請確定你的 CUPS 是有啟動的，而且印表機也已經打開電源了。啟動 CUPS 的方法與檢查是否啟動 CUPS 的操作如下：

# 1. 重新啟動 CUPS 的方法！

[root@www ~]# /etc/init.d/cups restart

正在停止 cups:                  [  確定  ]

正在啟動 cups:                  [  確定  ]

[root@www ~]# netstat -tlunp | grep 631

tcp   0  0 0.0.0.0:631       0.0.0.0:*      LISTEN      4939/cupsd

tcp   0  0 :::631            :::*           LISTEN      4939/cupsd

udp   0  0 0.0.0.0:631       0.0.0.0:*                  4939/cupsd

# 因為 CUPS 啟動的網路服務埠口就是 port 631 ！所以確定是啟動的！

# 2. 確認印表機提供的服務為何

[root@www ~]# nmap 192.168.201.253

Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-06-03 00:43 CST

Interesting ports on 192.168.201.253:

Not shown: 1676 closed ports

PORT     STATE SERVICE

80/tcp   open  http

139/tcp  open  netbios-ssn

515/tcp  open  printer

9100/tcp open  jetdirect

# 再次強調，鳥哥這部印表機僅有提供 HP 自家的印表機協定 9100 埠口！

從上面的輸出可以很清楚的看到鳥哥的印表機與 Linux 上面的 CUPS 都有順利的運作中！其中還是要強調， 你千萬不要拿 nmap 去掃瞄別人家的系統！很可怕的！而由於上面輸出的結果，我們也知道鳥哥這部印表機在網路上的連線方式為： socket://192.168.201.253:9100 的樣式喔！這個地方也請先記錄下來。

- 3. 使用 lpadmin 進行印表機的建立與刪除

指令設定/刪除印表機的方式就是透過 lpadmin 這個指令啊！這個指令的語法是這樣的：

[root@www ~]# lpadmin [-p 自訂佇列名] [-v URI] [-m PPD] [-E] <==建立印表機

[root@www ~]# lpadmin [-d 已存在的佇列名]  <==設定成為預設印表機

[root@www ~]# lpadmin [-x 已存在的佇列名]  <==刪除此一印表機佇列

選項與參數：

-p ：後面接的就是印表機的佇列名稱，這個名稱可自訂，但還是定為有意義較佳。

-v ：後面接的就是裝置的相關位置，常見的裝置有：

序列埠      ： parallel:/dev/lp0

USB         ： usb:/dev/usb/lp0

網路印表機  ： ipp://192.168.201.253/

提供特殊插槽： socket://192.168.201.253:9100

-m ：後面接的通常就是 PPD 的定義檔，注意，要放置到 /usr/share/cups/model/ 底下！

-E ：作為可接受 (accept) 此列印工作之意！

# 1. 先列出本機上面所有已經存在的印表機吧！

[root@www ~]# lpstat -a

Deskjet_F300_series accepting requests since Tue Jun  2 00:48:59 2009

deskjet_f380 accepting requests since Mon Jun  1 23:34:21 2009

hp_lj_p2015dn accepting requests since Tue Jun  2 00:22:31 2009

# 2. 刪除所有已經存在的印表機吧！

[root@www ~]# lpadmin -x Deskjet_F300_series

[root@www ~]# lpadmin -x deskjet_f380

[root@www ~]# lpadmin -x hp_lj_p2015dn

[root@www ~]# lpstat -a

lpstat: No destinations added.

# 這樣就確定沒有任何存在的印表機囉！

# 3. 加入 hp_p2015 印表機，印表機參數如前面兩小節所示：

[root@www ~]# lpadmin -p hp_p2015 -v socket://192.168.201.253:9100 \

> -m postscript.ppd.gz -E

# 4. 因為僅有一部印表機，因此讓此印表機成為預設列印印表機

[root@www ~]# lpadmin -d hp_p2015

其實這個 lpadmin 指令只是在更新 /etc/cups/ 目錄裡面的兩個資料而已， 一個是 /etc/cups/printers.conf ，這個檔案主要是規範了印表機的相關裝置、是否接受列印工作、 印表機的佇列名稱、頁面的限制等等，反正就是整個印表機的規範就是了。 至於這個印表機相關的 PPD 檔案則是以印表機的佇列名稱連結到 /etc/cups/ppd/ 目錄下。 不相信嗎？讓我們來瞧瞧 printers.conf 的檔案內容吧！

[root@www ~]# cat /etc/cups/printers.conf

# Printer configuration file for CUPS v1.2.4

# Written by cupsd on 2009-06-03 01:06

<DefaultPrinter hp_p2015>                <==這就是印表機佇列名稱

Info hp_p2015

DeviceURI socket://192.168.201.253:9100  <==就是印表機所在的裝置位置

State Idle

StateTime 1243962326

Accepting Yes

Shared Yes

JobSheets none none

QuotaPeriod 0

PageLimit 0

KLimit 0

OpPolicy default

ErrorPolicy stop-printer

</Printer>

[root@www ~]# ll /etc/cups/ppd

-rw-r--r-- 1 root root 7714 Jun  3 01:05 hp_p2015.ppd

# 這就是剛剛捉過來的，給 hp_p2015 用的印表機定義檔！

- 4. 印表機狀態的觀察

設定完印表機後，來觀察一下目前的印表機狀態吧！底下的 lpstat 是個不錯用的觀察指令喔！

[root@www ~]# lpstat [-adprt]

選項與參數：

-a  ：列出目前可以接受列印工作的印表機佇列名稱；

-d  ：列出目前系統的預設印表機 (未指定列印佇列時，預設輸出的印表機)；

-p  ：列出每部印表機目前的工作狀態，包含工作的 ID；

-r  ：列出目前 CUPS 服務是否有在運作？

-t  ：列出目前列印系統中更為詳細的資訊說明，很適合查詢喔！

# 1. 列出目前系統上面所有的印表機佇列與接受工作與否的情形

[root@www ~]# lpstat -a

hp_p2015 accepting requests since Wed Jun  3 01:05:26 2009

# 有一部名為 hp_p2015 的印表機，從 2009/6/3 開始接受列印工作之意！

# 2. 列出目前的『列印系統』狀態，不止包括印表機而已。

[root@www ~]# lpstat -t

scheduler is running   <==CUPS 這個服務有在運作的意思

system default destination: hp_p2015  <==預設的印表機為這一部 hp_2015

device for hp_p2015: socket://192.168.201.253:9100 <==這部印表機的裝置位址

hp_p2015 accepting requests since Wed Jun  3 01:05:26 2009

printer hp_p2015 is idle.  enabled since Wed Jun  3 01:05:26 2009

# 這部印表機目前是發呆 (Idle) 的狀態，但可接受列印工作！

如果不清楚你的印表機狀態，使用 lpstat 就能夠看的清楚囉∼接下來，讓我們開始來使用列印指令產生列印工作吧！

- 5. 利用 lpr 與 lp 來產生列印工作

如果你沒有瀏覽器或者是說，你沒有圖形介面的軟體時，可以透過 lpr 或者是 lp 這兩個指令來列印某些檔案或資料流重導向的東東。底下的測試會實際列印出資料來，因此，建議你可以先將印表機電源關閉， 讓 CUPS 可以接受列印佇列的工作，卻無法輸出到印表機，這樣也方便我們後續管理指令的查詢！ 所以，請將印表機的電源關閉先。來看看這兩個指令如何操作吧！

[root@www ~]# lpr [-P printer佇列] [-#  列印份數] -U [username] file

選項與參數：

-P  ：若沒有預設印表機 (default) 或者想要由不同印表機輸出時，可用 -P 指定印表機

-#  ：如果這份文件你想要列印多個副本時，用這個 -# 加上份數就對了！

-U  ：有些印表機有限制可使用的使用者帳號，此時就得要使用這個選項；

# 1. 指定 hp_p2015 這部印表機來列印 /etc/passwd 這個檔案

[root@www ~]# lpr -P hp_p2015 /etc/passwd

# 2. 關閉印表機後，將 /root/ 底下的檔案檔名輸出到這部印表機

[root@www ~]# ll /root | lpr -P hp_p2015

要注意的是，因為鳥哥有指定預設印表機，因此上面的範例中，即使沒有加上 [-P hp_p2015] 這個項目時，依舊能夠順利的列印。但如果你沒有指定預設印表機，那麼就一定要加上這個項目， 否則 lpr 會不知到要將資料輸出到哪裡去喔！看完了 lpr ，再來聊聊 lp 這個指令的用法吧：

[root@www ~]# lp [-d printer佇列] [-n 列印份數] file

選項與參數：

-d  ：後面接的是印表機的佇列名稱。如果有多部印表機才需要指定；

-n  ：就是列印的份數啊！

# 1. 列印出 2 份 /etc/issue 資料

[root@www ~]# lp -d hp_p2015 -n 2 /etc/issue

request id is hp_p2015-11 (1 file(s))  <==以 hp_p2015 來列印，工作號碼為 11

- 6. 列印工作的觀察 (lpq) 與刪除 (lprm)

我們已經有產生三個工作，但是第一個工作有順利的列印 (印表機是開啟的)，因此還有兩個工作尚未完成才對！ 那我們如何知道還有哪些列印工作在佇列內呢？可以使用底下的指令來觀察喔！

[root@www ~]# lpq [-al] [-P 列印佇列]

選項與參數：

-a  ：列出所有印表機上面在佇列當中的工作情況；

-l  ：用其他較長格式來輸出列印的相關資訊 (擁有者與檔案大小等等)

-P  ：後面接特定的印表機，與 -a 不同。

# 1. 顯示出目前所有印表機的工作佇列狀況

[root@www ~]# lpq -a

Rank    Owner   Job     File(s)               Total Size

active  root    10      (stdin)               1024 bytes

1st     root    11      issue                 1024 bytes

# 上面的意思是，有 2 份工作，第一個工作為來自 stdin 的資料流，列印號碼為 10 ，

# 整份列印資料佔去 1024 bytes 。同理，第二份工作為檔案，檔名為 issue。

# 2. 用更詳細的資訊顯示列印工作

[root@www ~]# lpq -l -P hp_p2015

hp_p2015 is ready and printing

root: active                  [job 10 localhost]

(stdin)                       1024 bytes

root: 1st                     [job 11 localhost]

2 copies of issue             1024 bytes

# 你可以看到， issue 會被列印兩份的資料！

如果這些列印工作你想要取消呢？那就使用 lprm 吧！

[root@www ~]# lprm [-P printer佇列] job_id

選項與參數：

-P  ：後面直接指定某部印表機的某個工作號碼。注意，那個 job_id

就是剛剛我們使用 lpq 查看到的那個 Job 的號碼啦！

# 1. 將使用 lpq 看到的第 11 號列印工作取消！

[root@www ~]# lprm 11

[root@www ~]# lpq -a

Rank    Owner   Job     File(s)               Total Size

active  root    10      (stdin)               1024 bytes

# 瞧！只剩下一個工作而已囉！

整個指令模式處理印表機的任務大約到此為止，其他的，還是使用 Web 介面去管理比較方便啦！

- 7. 一個簡單的練習

假設你目前的 CentOS 主機上面接著一台 USB 介面的印表機，這台 USB 介面的印表機是 Samsung 的 ML-1210 印表機， 請問，您可以如何安裝這部印表機？

1. 先下載 PPD 定義檔，檔名為： Samsung-ML-1210-gdi.ppd 到 /usr/share/cups/model/ 當中；

2. 加入印表機，使用下列方法：

[root@www ~]# lpadmin -p samsung -v usb:/dev/usb/lp0 \

> -m Samsung-ML-1210-gdi.ppd -E

1. 開始給他測試練習一下：『 lpr -P samsung /etc/passwd 』如果有東西印出來，那就是 OK 啦！

另外，如果老是看到螢幕前面顯示：『 Printer not connected; will retry in 30 seconds...』， 很有可能是因為我們的裝置代號輸入錯誤，請使用『 lpstat -t 』查閱一下是否正確的設定好了？ 基本上，安裝一部 Linux 有支援的印表機，真的是快速啦！

硬體資料收集與驅動，及 lm_sensors

『工欲善其事，必先利其器』，這是一句大家耳熟能詳的古人名言，在我們的資訊設備上面也是一樣的啊！ 如同前面小節談到的，如果你的印表機本身就沒有提供給 Linux 系統用的驅動程式，那麼我們就不要浪費時間在該印表機設備上了。 同理可證，如果我們想要好好的使用 Linux 安裝在自己的主機上面，那麼主機上面的硬體資訊最好還是能夠瞭解一下的好。 現在一般主機板也都有提供 CPU 電壓與溫度的偵測，那我們也能夠透過 lm_sensors 這個軟體來取得該數據喔！ 底下就讓我們來玩玩吧！

硬體資訊的收集與分析

現在我們知道系統硬體是由作業系統核心所管理的，由第二十章的開機流程分析中，我們也知道 Linux kernel 在開機時就能夠偵測主機硬體並載入適當的模組來驅動硬體了。 而核心所偵測到的各項硬體裝置，後來就會被記錄在 /proc 與 /sys 當中了。 包括 /proc/cpuinfo, /proc/partitions, /proc/interrupts 等等。 更多的 /proc 內容介紹，先回到第十七章的程序管理瞧一瞧先！

Tips:

其實核心所偵測到的硬體可能並非完全正確喔！因為他僅是『使用最適當的模組來驅動這個硬體』而已， 所以有時候難免會誤判啦 (雖然機率非常之低)！那你可能想要以最新最正確的模組來驅動你的硬體， 此時，重新編譯核心是一條可以達成的道路。不過，現在的 Linux 系統並沒有很建議你一定要重新編譯核心就是了。

那除了直接呼叫出 /proc 底下的檔案內容之外，其實 Linux 有提供幾個簡單的指令來將核心所偵測到的硬體叫出來的∼ 常見的指令有底下這些：

- fdisk：第八章曾經談過，可以使用 fdisk -l 將分割表列出；

- hdparm：第八章談過的，可觀察硬碟的資訊與測試讀寫速度；

- dmesg：第十七章談過， 觀察核心運作過程當中所顯示的各項訊息記錄；

- vmstat：第十七章談過，可分析系統 (CPU/RAM/IO) 目前的狀態；

- lspci：列出整個 PC 系統的 PCI 介面裝置！很有用的指令；

- lsusb：列出目前系統上面各個 USB 埠口的狀態，與連接的 USB 裝置；

- iostat：與 vmstat 類似，可即時列出整個 CPU 與周邊設備的 Input/Output 狀態。

lspci, lsusb, iostat 是本章新談到的指令，尤其如果你想要知道主機板與各周邊相關設備時，那個 lspci 真是不可多得的好工具！而如果你想要知道目前 USB 插槽的使用情況以及偵測到的 USB 裝置， 那個 lsusb 則好用到爆！至於 iostat 則是一個即時分析軟體，與 vmstat 有異曲同工之妙！ 既然本節是想要使用 lm_sensors 分析各元件的溫度與電壓，那麼這幾個指令得要來使用看看才行啊！ ^_^

基本上，想要知道你 Linux 主機的硬體配備，最好的方法還是直接拆開機殼去察看上面的資訊 (這也是為何第零章會談計概啊)！ 如果環境因素導致您無法直接拆開主機的話，那麼直接 lspci 是很棒的一的方法：

- lspci

[root@www ~]# lspci [-vvn]

選項與參數：

-v  ：顯示更多的 PCI 介面裝置的詳細資訊；

-vv ：比 -v 還要更詳細的細部資訊；

-n  ：直接觀察 PCI 的 ID 而不是廠商名稱

範例一：查閱您系統內的 PCI 裝置：

[root@www ~]# lspci

00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 30)

00:00.1 IDE interface: Silicon Integrated Systems [SiS] 5513 [IDE] (rev d0)

00:01.0 ISA bridge: Silicon Integrated Systems [SiS] SiS85C503/5513 (LPC Bridge)

00:01.2 USB Controller: Silicon Integrated Systems [SiS] USB 1.1 Controller (rev 07)

00:01.3 USB Controller: Silicon Integrated Systems [SiS] USB 1.1 Controller (rev 07)

00:01.4 Multimedia audio controller: Silicon Integrated Systems [SiS] SiS PCI Audio

Accelerator (rev 02)

00:02.0 PCI bridge: Silicon Integrated Systems [SiS] Virtual PCI-to-PCI bridge (AGP)

00:0e.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (rev 10)

01:00.0 VGA compatible controller: Silicon Integrated Systems [SiS] 630/730 PCI/AGP

VGA Display Adapter (rev 21)

# 不必加任何的參數，就能夠顯示出目前主機上面的各個 PCI 介面的裝置呢！

不必加上任何選項，就能夠顯示出目前的硬體配備為何。上面就是鳥哥的測試機所使用的主機配備。 包括使用 SIS 這家公司推出的 630 主機板晶片組，使用 USB 驅動為 1.1 版的控制器， 內建 SIS 的音效卡，使用內建整合的 SIS 的 AGP 顯示卡，以及網路卡為螃蟹卡 (型號為 RTL-8139)。 您瞧瞧！很清楚，不是嘛。

由於目前的主機配備實在太高檔了，因此很多朋友學習 Linux 時，習慣以類似 Virtualbox 或 VMWare 等虛擬機器進行模擬，此時你得要特別注意，你的硬體配備將是 Virtualbox 或 VMWare 模擬出來的，並不是原本的主機配備喔！實在是由於討論區太多網友發問類似『我的螃蟹卡為何捉不到』等問題， 詢問後，才發現他使用 VMWare 模擬硬體。此時你就得要使用 lspci 去列出 Linux 核心捉到的硬體， 而不是你原本的硬體啦！注意注意！

如果你還想要瞭解某個設備的詳細資訊時，可以加上 -v 或 -vv 來顯示更多的資訊喔！ 舉例來說，鳥哥想要知道那個乙太網路卡更詳細的資訊時，可以使用如下的選項來處理：

[root@www ~]# lspci -s 00:0e.0 -vv

-s 後面接的那個怪東西每個設備的匯流排、插槽與相關函數功能啦！那個是我們硬體偵測所得到的數據囉！ 你可以對照底下這個檔案來瞭解該串數據的意義：

- /usr/share/hwdata/pci.ids

其實那個就是 PCI 的標準 ID 與廠牌名稱的對應表啦！ 此外，剛剛我們使用 lspci 時，其實所有的資料都是由 /proc/bus/pci/ 目錄下的資料所取出的呢！瞭解了吧！ ^_^

- lsusb

剛剛談到的是 PCI 介面裝置，如果是想要知道系統接了多少個 USB 裝置呢？那就使用 lsusb 吧！ 這個指令也是很簡單的！

[root@www ~]# lsusb [-t]

選項與參數：

-t  ：使用類似樹狀目錄來顯示各個 USB 埠口的相關性

範例一：列出目前鳥哥的測試用主機 USB 各埠口狀態

[root@www ~]# lsusb

Bus 001 Device 001: ID 0000:0000

Bus 002 Device 001: ID 0000:0000

Bus 002 Device 002: ID 0d62:a100 Darfon Electronics Corp. Benq Mouse

# 如上所示，鳥哥的主機有兩個 USB 控制器 (bus)，而 Bus 002 有接了一個設備，

# 該設備的 ID 是 0d62:a100，對應的廠商與產品為 Benq 的滑鼠。

確實非常清楚吧！其中比較有趣的就屬那個 ID 號碼與廠商型號對照了！那也是寫入在 /usr/share/hwdata/pci.ids 的東西，你也可以自行去查詢一下喔！更多資訊我們留待下一小節再來討論吧！

- iostat

剛剛那個 lspci 找到的是目前主機上面的硬體配備，那麼整部機器的儲存設備， 主要是硬碟對吧！請問，您硬碟由開機到現在，已經存取多少資料呢？這個時候就得要 iostat 這個指令的幫忙了！ 不過，預設 CentOS 並沒有安裝這個軟體，因此你必須要先安裝他才行！如果你已經有網路了， 那麼使用『 yum install sysstat 』先來安裝此軟體吧！否則無法進行如下的測試喔！

[root@www ~]# iostat [-c|-d] [-k|-m] [-t] [間隔秒數] [偵測次數]

選項與參數：

-c  ：僅顯示 CPU 的狀態；

-d  ：僅顯示儲存設備的狀態，不可與 -c 一起用；

-k  ：預設顯示的是 block ，這裡可以改成 K bytes 的大小來顯示；

-m  ：與 -k 類似，只是以 MB 的單位來顯示結果。

-t  ：顯示日期出來；

範例一：顯示一下目前整個系統的 CPU 與儲存設備的狀態

[root@www ~]# iostat

Linux 2.6.18-92.el5 (www.vbird.tsai)    06/03/2009

avg-cpu:  %user   %nice %system %iowait  %steal   %idle

0.35    0.31    0.25    0.03    0.00   99.06

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

hda               0.29         3.46         4.01    1116645    1295796

# 瞧！上面數據總共分為上下兩部分，上半部顯示的是 CPU 的當下資訊；

# 下面數據則是顯示儲存裝置 /dev/hda 的相關數據，他的數據意義：

# tps       ：平均每秒鐘的傳送次數！與資料傳輸『次數』有關，非容量！

# kB_read/s ：開機到現在平均的讀取單位；

# kB_wrtn/s ：開機到現在平均的寫入單位；

# kB_read   ：開機到現在，總共讀出來的檔案單位；

# kB_wrtn   ：開機到現在，總共寫入的檔案單位；

範例二：每兩秒鐘偵測一次，並且共偵測三次儲存裝置

[root@www ~]# iostat -d 2 3

Linux 2.6.18-92.el5 (www.vbird.tsai)    06/03/2009

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

hda               0.29         3.46         4.01    1116645    1296276

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

hda               0.00         0.00         0.00          0          0

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn

hda               0.00         0.00         0.00          0          0

# 仔細看一下，如果是有偵測次數的情況，那麼第一次顯示的是『從開機到現在的數據』，

# 第二次以後所顯示的資料則代表兩次偵測之間的系統傳輸值！舉例來說，上面的資訊中，

# 第二次顯示的資料，則是兩秒鐘內(本案例)系統的總傳輸量與平均值。

透過 lspci 及 iostat 可以約略的瞭解到目前系統的狀態啊！ 還有目前的主機硬體資料呢！知道這些資訊後，我們就可以來玩一些比較不一樣的東西囉！ ^_^

驅動 USB 裝置

在現在的電腦裡面，你或許真的無法想像沒有 USB 介面裝置的主機∼ 因為不論我們的鍵盤、滑鼠、印表機、掃描器、隨身碟等等，幾乎都是使用到 USB 來作為傳輸的介面的。 所謂這 USB (Universal Serial Bus) 最早是在 1994 年被發展出來，到 1996 年前後發展出 version 1.0 ，當時的速度大約在 12Mbit/second，到了 2000 年發展出 version 2.0 ，這一版的速度則提高到 480Mbit/second， 這也是目前使用最廣泛的一個速度。2008 年則釋出 USB 3.0，這一版的速度比 2.0 要快十倍喔！ 不過目前市面上的產品還是非常的少見。(註2)

USB 有很多的優點啦，包括他是可以延伸的，每個 USB port 都可以最多接到 127 個裝置！ 速度又快，又具有 Plug and Play (隨插即用) 的優點，所以近期以來被用來作為攜帶式裝置的主要資料傳輸介面呢！

- 關於 USB 的晶片版本

目前 USB 1.1版本的控制器主要有兩種規格，分別是：

- OHCI (Open Host Controller Interface)：主要由 Compaq 所發展，包括 Compaq, SiS, ALi 等等廠商發展的晶片都是用這個模組；

- UHCI (Universal Host Controller Interface)：主要由 Intel 所發展， 包括 Intel, VIA 等等廠商發展的晶片都是使用這個模組。

由於我們的 Linux 會將這兩種 USB 的驅動程式載入，因此不論你的 USB 是使用哪種晶片，我們的 Linux 都可以順利的偵測到並且正確的驅動的啦！至於 USB 2.0 在 Linux 上都以 Enhanced Host Controller Interface (EHCI) 來驅動的。我們使用 lsmod 來找一下 hci 這個關鍵字看看，鳥哥的測試主機驅動了多少 USB 模組了呢？

[root@www ~]# lsmod | grep hci

Module                  Size  Used by

uhci_hcd               25421  0

ohci_hcd               23261  0

ehci_hcd               33357  0

# 三個模組都有載入，再來找一下 ehci_hcd 的說明看看：

[root@www ~]# modinfo ehci_hcd

filename:       /lib/modules/2.6.18-92.el5/kernel/drivers/usb/host/ehci-hcd.ko

license:        GPL

author:         David Brownell

description:    10 Dec 2004 USB 2.0 'Enhanced' Host Controller (EHCI) Driver

srcversion:     006DD5CF82C35E943696BE7

....(底下省略)....

- 啟動 USB 的隨身碟或快閃碟

我們之前談過 USB 的磁碟代號是： /dev/sd[a-p] 之類的，類似 SCSI 硬碟的代號， 這是因為 USB 的磁碟裝置使用 SCSI 相關的裝置代號，因此，如果您要使用 USB 隨身碟的話，嘿嘿！那麼您的 Linux 主機就得要支援 SCSI 裝置才行∼

此外，為了讓 USB 磁碟裝置順利的被使用，因此，有時候還得要啟動 usb-storage 模組才行∼ 所以囉，光是有 USB 的 uhci 模組還不行，還得要配合 usb-storage 啦∼ 而一般 USB 的裝置都會被主動的偵測，核心也會主動的載入 USB 裝置的驅動模組， 所以你應該不需要手動載入 usb-storage 才是。不過，如果老是無法驅動時，那麼不妨手動載入 usb-storage 試看看。

順利載入各個需要的模組之後，直接下達 fdisk -l 應該就可以看到您的 USB 隨身碟的裝置代號才是！一般來說，如果是第一個 USB 磁碟裝置的話， 應該可以看到一個名為 /dev/sda1 的裝置，使用 mount 將他掛載起來即可啊！

在這裡要強調的是，如果你是使用類似筆記型電腦的 2.5 吋硬碟作為隨身硬碟的話，由於他就是硬碟的規格， 因此你可以看到一個完整的 /dev/sda 之類的磁碟資訊，你也可以進行額外的分割。但如果是快閃碟的話， 快閃碟並不是傳統的硬碟，他並不是使用磁碟讀取頭與磁碟盤來記錄資料，因此你只能使用 /dev/sda1 之類的檔名來掛載， 理論上是無法進行額外分割的喔！這部份要特別強調一下。

- 啟動 USB 印表機

要驅動 USB 印表機也很簡單啊！只要做好 USB 印表機的裝置代號即可！反正我們的 usb 模組已經載入了嘛！ 目前的 CentOS 5.x 會主動的幫我們建立印表機的裝置檔名，所以底下的動作我們根本不需要進行。 不過如果你的 Linux 是較老式的系統，那可能得要使用 mknod 來建立起 USB 印表機才行。 透過核心裝置代碼(註3)的查詢，我們知道 USB 印表機的主要/次要裝置代碼為 180 /0~15， 所以，建立的方法為：

# 假設你已經有 /dev/usb/lp0 ，那我們來嘗試建立 /dev/usb/lp1 看看

[root@www ~]# mkdir -p /dev/usb

[root@www ~]# mknod /dev/usb/lp1 c 180 1

[root@www ~]# chown root:lp /dev/usb/lp1

[root@www ~]# chmod 660 /dev/usb/lp1

[root@www ~]# ls -l /dev/usb/lp1

crw-rw---- 1 root lp 180, 1 Jun  3 14:27 /dev/usb/lp1

[root@www ~]# echo "testing" > /dev/usb/lp1

在我們一般的生活當中，最常見的兩種 USB 裝置就是隨身碟與印表機了， 所以鳥哥在這裡僅就這兩種裝置來介紹啟動的方法，如果您還有其他的 USB 裝置要驅動的話， 請參考底下這一篇的內容啊！

- http://www.linux-usb.org/USB-guide/book1.html

使用 lm_sensors 取得溫度、電壓等資訊

玩電腦硬體的朋友們一定都聽過所謂的『超頻』這玩意兒，所謂的『超頻』就是讓系統原有的運作時脈增加， 讓 CPU/PCI/VGA 前端匯流排速度提升到非正規的頻率，以取得較高的電腦效能。 這在早期對於單價還是很貴的電腦來說，可以讓我們花比較少的錢去獲得比較高效能的電腦哩！ 不過，超頻要注意的地方可不少，包括電壓不可高出 CPU 的負荷、CPU 風扇必須要強有力， 避免因為溫度過高導致系統當機等等。

不過現今的電腦速度已經夠快了，我們的 Linux 主機也實在不建議您超頻，因為整體效能可能增加不了多少， 但是卻會讓您的主機壽命減少、系統不穩定呢！而由早期超頻的『技術培養』過程當中，我們知道『CPU 的溫度、系統的相關電壓』 是影響主機是否穩定的一項重要指標喔！所以囉，如果能夠隨時掌握溫度、電壓， 其實對於系統還是有一定程度的監控啦。

其實各大主要主機板商與晶片組，都會有溫度、電壓的偵測器在主機內，這個我們可以在主機板操作手冊或者是在 BIOS 內的『 Monitor 』項目找到相關的溫度、電壓資料。在 Windows 系統當中，廠商有推出相關的軟體來偵測，那麼在 Linux 當中呢？呵呵！也是有啊！那就是 lm_sensors 這套好用的東西了！

目前較新的 Linux distributions 都預設會幫忙安裝這套軟體，但如果你的 Linux 是比較早期的版本，那麼就只好請您自行前往 http://www.lm-sensors.org/ 官方網站直接下載 tarball 並且安裝他囉∼

- 偵測主機板的型號

由於 lm_sensors 主要是依據『主機板晶片組的型號，帶入相關的模組後，再偵測其溫度、電壓』的， 如果該主機板晶片組並不是 lm_sensors 所支援的模組，那自然就無法找出該晶片組的溫壓囉∼ 所以啦，我們在使用 lm_sensors 之前，必須要確定主機板是有提供溫度、電壓的， 再來，必須要載入主機板的驅動模組，然後才有辦法使用 lm_sensors 來進行偵測。

好消息是， lm_sensors 本來就提供我們一個不錯的主機板晶片組偵測程式， 那就是 sensors-detect 這個指令。偵測到主機板晶片組後，將該資訊寫入設定檔當中， 就可以使用 sensors 指令直接讀取目前的 CPU、機殼、電源、風扇等等的資訊了！ 直接來作看看吧！

[root@www ~]# sensors-detect

# sensors-detect revision 1.413 (2006/01/19 20:28:00)

....(中間省略)....

It is generally safe and recommended to accept the default answers to all

questions, unless you know what you're doing. <==就一直接受就對了！

We can start with probing for (PCI) I2C or SMBus adapters.

You do not need any special privileges for this.

Do you want to probe now? (YES/no): y

Probing for PCI bus adapters...

Use driver `i2c-sis630' for device 00:00.0: Silicon Integrated Systems SIS630

Probe succesfully concluded.

# 接下來的行為當中，反正你就一直按 Enter 就可以了！讓他自動去偵測！

To make the sensors modules behave correctly, add these lines to

/etc/modprobe.conf:

#----cut here----

# I2C module options

alias char-major-89 i2c-dev

#----cut here----

To load everything that is needed, add this to some /etc/rc* file:

#----cut here----

# I2C adapter drivers

modprobe i2c-sis630

modprobe i2c-isa

# I2C chip drivers

modprobe eeprom

modprobe it87

# sleep 2 # optional

/usr/bin/sensors -s # recommended

#----cut here----

Do you want to generate /etc/sysconfig/lm_sensors? (YES/no):

Copy prog/init/lm_sensors.init to /etc/rc.d/init.d/lm_sensors

for initialization at boot time.

上面就進行好型號的偵測，並且主動的建立了 /etc/sysconfig/lm_sensors 的參數設定檔。不過我們依舊需要進行一些額外的處理！ 包括讓系統開機主動載入模組的功能！這樣我們就能夠直接使用 lm_sensors 來偵測而不需要手動載入偵測模組啊！ 你可以這樣做：

[root@www ~]# vi /etc/modprobe.conf

alias char-major-89 i2c-dev

# 將剛剛偵測到的模組給他寫入到這個檔案當中！

[root@www ~]# vi /etc/rc.d/rc.local

# I2C adapter drivers

modprobe i2c-sis630

modprobe i2c-isa

# I2C chip drivers

modprobe eeprom

modprobe it87

sleep 2s

/usr/bin/sensors -s

[root@www ~]# chkconfig --list  lm_sensors

lm_sensors      0:off   1:off   2:on    3:on    4:on    5:on    6:off

# 確定 lm_sensors 預設開機會啟動即可！此時你可以重新 reboot ，

# 或者執行上述的 modprobe 之後，在進行底下的偵測囉！

- 利用 sensors 偵測溫度、電壓等硬體參數

偵測的指令就是 sensors 啊！直接動作吧！

[root@www ~]# sensors

it87-isa-0290  <==使用到的模組功能！

Adapter: ISA adapter

VCore 1:   +1.55 V  (min =  +1.42 V, max =  +1.57 V)

VCore 2:   +1.09 V  (min =  +2.40 V, max =  +2.61 V)   ALARM

+3.3V:     +1.25 V  (min =  +3.14 V, max =  +3.47 V)   ALARM

+5V:       +2.69 V  (min =  +4.76 V, max =  +5.24 V)   ALARM

+12V:      +5.82 V  (min = +11.39 V, max = +12.61 V)   ALARM

-12V:     -17.05 V  (min = -12.63 V, max = -11.41 V)   ALARM

-5V:       -7.40 V  (min =  -5.26 V, max =  -4.77 V)   ALARM

Stdby:     +2.07 V  (min =  +4.76 V, max =  +5.24 V)   ALARM

VBat:      +0.40 V

fan1:        0 RPM  (min =    0 RPM, div = 2)

fan2:        0 RPM  (min = 3000 RPM, div = 2)          ALARM

fan3:     2689 RPM  (min = 3000 RPM, div = 2)

M/B Temp:    +33°C  (low  =   +15°C, high =   +40°C)   sensor = diode

CPU Temp:    +37°C  (low  =   +15°C, high =   +45°C)   sensor = thermistor

Temp3:        -5°C  (low  =   +15°C, high =   +45°C)   sensor = disabled

# 你可以發現一大堆的錯誤訊息！沒關係的！這是因為鳥哥的主機板太舊，

# 導致 lm_sensors 誤判，所以輸出的結果就會有點差異！至少轉速與溫度是正常的啦！

基本上，只要這樣的步驟，您的主機就可以主動的偵測溫度與電壓，還有風扇轉速等等資訊。 不過，事實上，由於主機板設計的不同，所以偵測的結果很有可能是有誤差的。以鳥哥的情況來說， 我所使用的主機板型號是太舊了，lm_sensors 確實捉到錯誤的資訊啊！此時或許就需要進行調校了。 調校的步驟很簡單，先確定使用 sensors 顯示的結果每個項目代表的意義 (可以參考 BIOS 硬體偵測結果的順序來排列) ，然後進入 /etc/sensors.conf 進行修改即可。

如果想要以圖表輸出的話，那麼不妨搭配 MRTG 來進行網頁繪圖∼ 這部分網路上面文章就比較多一點，也可以先參考鳥哥的一篇舊文章：

- http://linux.vbird.org/linux_security/old/04mrtg.php

udev 與 hal 簡介

從上面的介紹中，我們不難發現目前新的 Linux distributions 大多能夠類似視窗作業系統，就是能夠即時的偵測隨插即用硬體！ 例如 USB 介面的各項硬體設備等等。那我們也知道其實所有的硬體都是檔案，這些裝置檔案必須要使用 mknod 才能建立的！ 那到底 (1)硬體如何偵測與 (2)裝置檔案如何主動建立呢？這就與 udev 及 HAL 這兩個東西有關了。

事實上，系統所有的硬體應該都是給核心管理的，但我們知道作業系統在記憶體內是受保護的，使用者根本無權使用作業系統核心。 為了解決這個問題於是有 udev 的產生。這個 udev 是個使用者層級軟體，他可以讓使用者自行處理 /dev 底下的裝置！ 如此一來就能夠解決一般用戶在使用類似 USB 時，需要額外硬體的問題。(註4)

但我們如何知道系統上面多了個硬體呢？這時候就得要硬體抽象層 (Hardware Abstraction Layer, HAL) 的輔助了。 HAL 可以將系統目前的所有硬體進行快照，並持續檢視這個快照的內容(註5)。如果有新的 PnP 硬體插入時， HAL 就會發現目前的硬體與快照不同，此時就會通知 udev 進行新的裝置的建置了！如此一來，兩者的配合就能夠讓你的裝置 PnP 囉！

目前這兩個咚咚在 CentOS 上面都會是啟動的，其中 udev 是在 /etc/rc.d/rc.sysinit 就啟動了， 而 hal 則是在 /etc/init.d/haldaemon 這個服務才啟動。讓我們檢查看看是否真的有啟動啊！

[root@www ~]# pstree -p | egrep '(udevd|hal)'

|-hald(4814)---hald-runner(4815)-+-hald-addon-acpi(4822)

|                                |-hald-addon-keyb(4827)

|                                `-hald-addon-stor(4837)

|-udevd(401)

# 確實有啟動喔！一個是 udevd 一個是 hald 啦！

老實說，如果你已經啟動了這兩個傢伙，那麼其他的事不需要進行，交給這兩個小玩意兒自己處理即可。 但如果你想要多瞭解 udev 是如何進行裝置的建立時，那麼我們可以來玩玩底下的咚咚。

- 自訂裝置名稱進行裝置建立

假設你想要將你的隨身碟取名為較有趣的裝置，不想再使用類似 /dev/sda1 之類的名稱時，可以怎麼作呢？ 我們可以透過更改 udev 的規則 (rule) 來使用 mknod 建立不同名稱的裝置檔案。舉例來說， 鳥哥這部測試機的硬碟使用為 /dev/hda ，因此第一個 USB 快閃碟裝置應該是 /dev/sda1 才對！ 如果你的系統使用 SATA 磁碟，那麼你的快閃碟可能就得要由 /dev/sdb1 開始編號起來了。

udev 建立裝置檔案的規則放置到 /etc/udev/rules.d/ 目錄下，在該目錄下的檔案可以依序進行處理的。 以最簡單的語法來看，在該目錄下可以使用的變數與對應可以是：

KERNEL=="核心能夠分析到的檔名", NAME="你要使用的裝置檔名"

當然還有很多語法，不過這裡我們先不介紹，有興趣的查一下本文最後的連結去看看吧！ 假設鳥哥的 /dev/sda1 要取名字成為 /dev/vbirdusb ，你可以這樣做：

# 1. 先在規則目錄下新增一個檔案，檔名設定為 99-vbirdusb.rules 好了

[root@www ~]# cd /etc/udev/rules.d/

[root@www rules.d]# vi 99-vbirdusb.rules

KERNEL=="sda1", NAME="vbirdusb"

# 上面這一行就足夠啦！注意，檔名前的 /dev 不需要寫入！

# 2. 插入一支隨身碟，然後檢查看看：

[root@www rules.d]# ll /dev/sda* /dev/vbirdusb

brw-r----- 1 root disk 8, 0 Jun  3 16:43 /dev/sda

brw-r----- 1 root disk 8, 1 Jun  3 16:43 /dev/vbirdusb

# 唔！ /dev/sda1 不見了！取而代之的是 /dev/vbirdusb 啦！

[root@www rules.d]# mount /dev/vbirdusb /mnt

[root@www rules.d]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

....(中間省略)....

/dev/vbirdusb           976064    192784    783280  20% /mnt

# 很有趣吧！裝置名稱被鳥哥改過了！

雖然這樣很具有個性化的需求，不過總是不太可靠∼萬一哪天忘記自己有進行這些動作，偏偏用核心預設的檔名去處理時， 會發生很多不明的錯誤啊！所以將剛剛建立的資料反向刪除回來吧！

# 1. 先卸載系統吧！

[root@www ~]# umount /dev/vbirdusb

# 2. 拔除隨身碟，並將規則檔刪除！

[root@www ~]# rm /etc/udev/rules.d/99-vbirdusb.rules

# 3. 再插入隨身碟，測試一下檔名有沒有恢復正常？

[root@www ~]# ll /dev/sda*

brw-r----- 1 root disk 8, 0 Jun  3 16:50 /dev/sda

brw-r----- 1 root disk 8, 1 Jun  3 16:50 /dev/sda1

# 看起來，檔名確實恢復正常囉！

重點回顧

- CentOS 提供了好用的 setup 功能，可以幫忙設定 (1)認證方式 (2)防火牆設定 (3)鍵盤格式設定 (4)網路設定 (5)系統預設啟動的服務設定 (6)時區設定 (7)X 解析度與硬體設定 等功能；

- 網際網路 (Internet) 就是 TCP/IP ，而 IP 的取得需與 ISP 要求。一般常見的取得 IP 的方法有：(1)手動直接設定 (2)自動取得 (dhcp) (3)撥接取得 (4)cable寬頻 等方式。

- 主機的網路設定要成功，必須要有底下的資料：(1)IP (2)Netmask (3)gateway (4)DNS 伺服器 等項目；

- DNS 伺服器 IP 的指定，需寫入 /etc/resolv.conf 這個檔案中；

- 預設 Linux 的列印服務使用 CUPS ，更早之前則是使用 lpd 這個服務；

- Linux 支援的印表機網站查詢： http://www.linuxfoundation.org/en/OpenPrinting

- 列印元件主要有：列印指令、列印工作、列印佇列、列印服務、印表機

- 網路印表機的格式主要有： ipp, smb 等類別；

- CUPS 可使用 http://localhost:631 來連接，然後使用瀏覽器介面來管理！

- PPD 指的是 postscript 列印定義檔，可視為印表機的驅動程式；

- 指令列管理印表機的方式主要透過： lpadmin, lpstat, lpq, lprm 等指令。至於產生列印工作的指令則為 lpr, lp

- 本章新增硬體資訊的收集指令有： lspci, lsusb, iostat 等；

- USB 的驅動模組主要有 OHCI 與 UHCI，至於 USB 2.0 則使用 EHCI。

- lm_sensors 可用來偵測主機板的溫度、電壓、風扇轉速等功能；

- 動態管理硬體，透過使用者層級的管理方式，主要透過 udev 與 HAL 的管理！

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

簡答題部分：

- 如果你硬是要建立一個不存在的印表機裝置檔案，例如： /dev/usb/lp8，該如何處置？

首先，必須要查閱得該裝置的主要裝置代號，亦即 180，至於次要代號則是 8 ， 再使用 mknod 來建立，因此，需要這樣做：

mknod /dev/usb/lp8 c 180 8

chown root:lp /dev/usb/lp8

chmod 660 /dev/usb/lp8

- 如果你想要知道整個系統的周邊硬體裝置，可以使用哪個指令查詢？

lspci 可以查詢到，更可使用 lspci -v 來查詢更詳細資訊。

- 承上題，那麼如果單純只想要知道 USB 裝置呢？又該如何查詢？

lsusb就可以查詢的到！

- 試說明 (1)列印工作 (2)列印佇列 (3)列印指令 (4)列印服務 (5)印表機之間的相關性。

列印指令可以產生列印工作，列印工作會在列印佇列裡面排隊等待被列印。在佇列內的資料於列印服務有啟動的環境下， 該資料可以被轉成印表機可讀的格式，最終列印服務會將佇列工作轉成適合的資料交給印表機列印出來。 詳細資料可參考圖 2.1.4 的說明。

- 說出三種以上目前常見的網路列印通訊協定。

例如 IPP, LPD, SMB 等均是列印的通訊協定。

- 如何使用 lm_sensors 偵測主機內的溫度，詳細說明整個步驟？

- 先確定您的主機板具有溫度與電壓等偵測晶片，可使用 lspci 檢查晶片組；

- 開機進入 BIOS 後，查詢一下是否具有硬體偵測溫度、電壓的項目，將輸出的項目順序記一下；

- 確定 Linux 已經安裝了 lm_sensors，再使用 sensors-detect 檢查所需要的設定項目；

- 依據上個步驟，設定 /etc/modprobe.conf 及 /etc/rc.d/rc.local 兩個檔案；

- 使用 chkconfig 讓 lm_sensors 開機啟動，並且重新開機 (reboot)；

- 開始使用 sensors 進行偵測，也可以嘗試修改 /etc/sensors.conf 的內容，以符合實際狀況。

- (挑戰題)如果你的網路設定妥當了，但是卻老是發現網路不通，你覺得應該如何進行測試？

(1)先檢查硬體，每個環節 (網卡、hub/switch、路由器等) 的燈號是否有亮？有亮再進行下個動作；

(2)使用 ifconfig 檢查 IP 與 netmask 的資料是否正確，若正確才可進行下一步；

(3)使用 route 看看 default gateway 是否正確，若正確再進行下一步；

(4)使用 ping -c 3 [gateway IP] ，若有回應才進行下一步；

(5)使用 ping -c 3 [外部IP，例如 168.95.1.1] ，若有回應則 IP 正常，若無回應，請檢查 gateway 的設定

(6)使用 dig www.google.com 看看能否找到 IP ，找不到則請檢查 /etc/resolv.conf 的設定。

參考資料與延伸閱讀

- 註1：PPD 的解釋：http://en.wikipedia.org/wiki/PostScript_Printer_Description

- 註2：USB 的相關解釋與書籍

維基百科的解釋：http://en.wikipedia.org/wiki/Universal_Serial_Bus

USB 的線上書籍：http://www.linux-usb.org/USB-guide/book1.html

Linux USB ：http://www.linux-usb.org/

- 註3：核心代碼的相關網頁：http://www.kernel.org/pub/linux/docs/device-list/devices.txt

- 註4：關於 udev 的簡單說明：

核心網站的說明：http://kernel.org/pub/linux/utils/kernel/hotplug/udev.html

linuxjournal 的說明：http://www.linuxjournal.com/article/7316

- 註5：hal 的官網 http://www.freedesktop.org/wiki/Software/hal

- LM_sensors 官方網站：http://www.lm-sensors.org/

2005/10/25：準備準備∼寫一些跟硬體比較有關係的資料！

2005/11/08：準備完畢 USB 與 lm_sensors 的部分了∼啊！拖了真久∼還有 RAID 的說明也差不多哩！

2005/11/09：加入了 FC4 的 setup 指令，尤其是印表機的部分，可以參考參考！

2005/11/10：終於將 iSCSI 的裝置寫好了∼這部份真的是很有趣！不過，一般使用者可能碰不到就是了。

2005/11/13：終於將 CUPS 架構設定好自己的 Printer 部分了！

2005/11/14：連同 LVM 也大致的給他寫完了！那個 resize2fs 指令確實有趣！

2005/11/25：加入一個簡單的練習題∼利用 dd 配合 resize2fs 來製作備份的資料！

2009/04/30：將 LVM 移動到 第十五章 ，且拿掉 iSCSI 的說明了。

2009/04/30：將舊的基於 FC4 撰寫的版本移動到 此處 。

2009/06/03：加入 udev 與 hal 的簡單說明！

2009/09/15：簡單修訂一些語句，修改章節的習題，並沒有改到什麼重要的資訊。

2005/11/14以來統計人數

第二十二章、軟體安裝：原始碼與 Tarball

切換解析度為 800x600

最近更新日期：2009/09/15

我們在第一章、Linux是什麼當中提到了 GNU 計畫與 GPL 授權所產生的自由軟體與開放源碼等咚咚。不過，前面的章節都還沒有提到真正的開放源碼是什麼的訊息！在這一章當中，我們將藉由 Linux 作業系統裡面的執行檔，來理解什麼是可執行的程式，以及瞭解什麼是編譯器。另外，與程式息息相關的函式庫 (library) 的資訊也需要瞭解一番！不過，在這個章節當中，鳥哥並不是要你成為一個開放源碼的程式設計師， 而是希望你可以瞭解如何將開放源碼的程式設計、加入函式庫的原理、透過編譯而成為可以執行 的 binary program，最後該執行檔可被我們所使用的一連串過程！

瞭解上面的咚咚有什麼好處呢？因為在 Linux 的世界裡面，由於客製化的關係，有時候我們需要自行安裝軟體在自己的 Linux 系統上面，所以如果你有簡單的程式編譯概念，那麼將很容易進行軟體的安裝。 甚至在發生軟體編譯過程中的錯誤時，你也可以自行作一些簡易的修訂呢！而最傳統的軟體安裝過程， 自然就是由原始碼編譯而來的囉！所以，在這裡我們將介紹最原始的軟體管理方式：使用 Tarball 來安裝與升級管理我們的軟體喔！

1. 開放源碼的軟體安裝與升級簡介

1.1 什麼是開放源碼、編譯器與可執行檔

1.2 什麼是函式庫

1.3 什麼是 make 與 configure

1.4 什麼是 Tarball 的軟體

1.5 如何安裝與升級軟體

2. 使用傳統程式語言進行編譯的簡單範例

2.1 單一程式：印出 Hello World

2.2 主、副程式連結：副程式的編譯

2.3 呼叫外部函式庫：加入連結的函式庫

2.4 gcc 的簡易用法 (編譯、參數與鏈結)

3. 用 make 進行巨集編譯

3.1 為什麼要用 make

3.2 makefile 的基本語法與變數

4. Tarball 的管理與建議

4.1 使用原始碼管理軟體所需要的基礎軟體

4.2 Tarball 安裝的基本步驟

4.3 一般 Tarball 軟體安裝的建議事項 (如何移除？升級？)

4.4 一個簡單的範例、利用 ntp 來示範

4.5 利用 patch 更新原始碼

5. 函式庫管理

5.1 動態與靜態函式庫

5.2 ldconfig 與 /etc/ld.so.conf

5.3 程式的動態函式庫解析： ldd

6. 檢驗軟體的正確性

6.1 md5sum / sha1sum

7. 重點回顧

8. 課後練習

9. 參考資料與延伸閱讀

10. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23892

開放源碼的軟體安裝與升級簡介

如果鳥哥想要在我的 Linux 伺服器上面跑網頁伺服器 (WWW server) 這項服務，那麼我應該要做些什麼事呢？當然就一定需要『安裝網頁伺服器的軟體』囉！如果鳥哥的伺服器上面沒有這個軟體的話，那當然也就無法啟用 WWW 的服務啦！所以啦，想要在你的 Linux 上面進行一些有的沒的功能，學會『如何安裝軟體』是很重要的一個課題！

咦！安裝軟體有什麼難的？在 W 牌的作業系統上面安裝軟體時，不是只要一直給他按 『下一步』就可以安裝妥當了嗎？話是這樣說沒錯啦，不過，也由於如此，所以在 Windows 系統上面的軟體都是一模一樣的，也就是說，你『無法修改該軟體的原始程式碼』，因此， 萬一你想要增加或者減少該軟體的某些功能時，大概只能求助於當初發行該軟體的廠商了！(這就是所謂的商機嗎？)

或許你會說：『唉呦！我不過是一般人，不會用到多餘的功能，所以不太可能會更動到程式碼的部分吧？』 如果你這麼想的話，很抱歉∼是有問題的！怎麼說呢？像目前網路上面的病毒、黑客軟體、臭蟲程式等等， 都可能對你的主機上面的某些軟體造成影響，導致主機的當機或者是其他資料損毀等等的傷害。 如果你可以藉由安全資訊單位所提供的修訂方式進行修改， 那麼你將可以很快速的自行修補好該軟體的漏洞，而不必一定要等到軟體開發商提供修補的程式包哩！要知道，提早補洞是很重要的一件事。

Tips:

並不是軟體開發商故意要搞出一個有問題的軟體，而是某些程式碼當初設計時可能沒有考量周全， 或者是程式碼與作業系統的權限設定並不相同，所導致的一些漏洞。當然，也有可能是 cracker 透過某些攻擊程式測試到程式的不周全所致。 無論如何，只要有網路存在的一天，可以想像的到，程式的漏洞永遠補不完！但能補多少就補多少吧！

這樣說可以瞭解 Linux 的優點了嗎？沒錯！因為 Linux 上面的軟體幾乎都是經過 GPL 的授權，所以每個軟體幾乎均提供原始程式碼， 並且你可以自行修改該程式碼，以符合你個人的需求呢！很棒吧！這就是開放源碼的優點囉！不過，到底什麼是開放源碼？ 這些程式碼是什麼咚咚？又 Linux 上面可以執行的相關軟體檔案與開放源碼之間是如何轉換的？不同版本的 Linux 之間能不能使用同一個執行檔？或者是該執行檔需要由原始程式碼的部分重新進行轉換？ 這些都是需要釐清觀念的。底下我們先就原始程式碼與可執行檔來進行說明。

什麼是開放源碼、編譯器與可執行檔

在討論程式碼是什麼之前，我們先來談論一下什麼是可執行檔？我們說過，在 Linux 系統上面，一個檔案能不能被執行看的是有沒有可執行的那個權限 (具有 x permission)，不過，Linux 系統上真正認識的可執行檔其實是二進位檔案 ( binary program)，例如 /usr/bin/passwd, /bin/touch 這些個檔案即為二進位程式碼。

或許你會說 shell scripts 不是也可以執行嗎？其實 shell scripts 只是利用 shell (例如 bash) 這支程式的功能進行一些判斷式，而最終執行的除了 bash 提供的功能外，仍是呼叫一些已經編譯好的二進位程式來執行的呢！ 當然啦， bash 本身也是一支二進位程式啊！那麼我怎麼知道一個檔案是否為 binary 呢？還記得我們在第七章裡面提到的 file 這個指令的功能嗎？對啦！用他就是了！我們現在來測試一下：

# 先以系統的檔案測試看看：

[root@www ~]# file /bin/bash

/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/

Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped

# 如果是系統提供的 /etc/init.d/syslog 呢？

[root@www ~]# file /etc/init.d/syslog

/etc/init.d/syslog: Bourne-Again shell script text executable

看到了吧！如果是 binary 而且是可以執行的時候，他就會顯示執行檔類別 (ELF 32-bit LSB executable)， 同時會說明是否使用動態函式庫 (shared libs)，而如果是一般的 script ，那他就會顯示出 text executables 之類的字樣！

Tips:

事實上，syslog 的資料顯示出 Bourne-Again ... 那一行，是因為你的 scripts 上面第一行有宣告 #!/bin/bash 的緣故，如果你將 script 的第一行拿掉，那麼不管 /etc/init.d/syslog 的權限為何，他其實顯示的是 ASCII 文字檔的資訊喔！

既然 Linux 作業系統真正認識的其實是 binary program，那麼我們是如何做出這樣的一支 binary 的程式呢？首先，我們必須要寫程式，用什麼東西寫程式？就是一般的文書處理器啊！鳥哥都喜歡使用 vim 來進行程式的撰寫，寫完的程式就是所謂的原始程式碼囉！ 這個程式碼檔案其實就是一般的純文字檔。 在完成這個原始碼檔案的編寫之後，再來就是要將這個檔案『編譯』成為作業系統看的懂得 binary program 囉！而要編譯自然就需要『編譯器』來動作， 經過編譯器的編譯與連結之後，就會產生一支可以執行的 binary program 囉。

舉個例子來說，在 Linux 上面最標準的程式語言為 C ，所以我使用 C 的語法進行原始程式碼的書寫，寫完之後，以 Linux 上標準的 C 語言編譯器 gcc 這支程式來編譯，就可以製作一支可以執行的 binary program 囉。整個的流程有點像這樣：

圖 1.1.1、利用 gcc 編譯器進行程式的編譯流程示意圖"

事實上，在編譯的過程當中還會產生所謂的目標檔 (Object file)，這些檔案是以 *.o 的副檔名樣式存在的！至於 C 語言的原始碼檔案通常以 *.c 作為副檔名。此外，有的時候，我們會在程式當中『引用、呼叫』 其他的外部副程式，或者是利用其他軟體提供的『函數功能』，這個時候，我們就必須要在編譯的過程當中， 將該函式庫給他加進去，如此一來，編譯器就可以將所有的程式碼與函式庫作一個連結 (Link) 以產生正確的執行檔囉。

總之，我們可以這麼說：

- 開放源碼：就是程式碼，寫給人類看的程式語言，但機器並不認識，所以無法執行；

- 編譯器：將程式碼轉譯成為機器看的懂得語言，就類似翻譯者的角色；

- 可執行檔：經過編譯器變成二進位程式後，機器看的懂所以可以執行的檔案。

什麼是函式庫

在前一小節的圖1.1.1示意圖中，在編譯的過程裡面有提到函式庫這東西。 什麼是函式庫呢？先舉個例子來說：我們的 Linux 系統上通常已經提供一個可以進行身份驗證的模組， 就是在第十四章提到的 PAM 模組。這個 PAM 提供的功能可以讓很多的程式在被執行的時候，除了可以驗證使用者登入的資訊外， 還可以將身份確認的資料記錄在登錄檔裡面，以方便系統管理員的追蹤！

既然有這麼好用的功能，那如果我要編寫具有身份認證功能的程式時，直接引用該 PAM 的功能就好啦，如此一來，我就不需要重新設計認證機制囉！也就是說，只要在我寫的程式碼裡面，設定去呼叫 PAM 的函式功能，我的程式就可以利用 Linux 原本就有的身份認證的程序咯！除此之外，其實我們的 Linux 核心也提供了相當多的函式庫來給硬體開發者利用喔。

函式庫又分為動態與靜態函式庫，這兩個咚咚的分別我們在後面的小節再加以說明。 這裡我們以一個簡單的流程圖，來示意一支有呼叫外部函式庫的程式的執行情況。

圖 1.2.1、程式執行時引用外部動態函式庫的示意圖

很簡單的示意圖啊！^_^！而如果要在程式裡面加入引用的函式庫，就需要如圖 1.1.1 所示， 亦即在編譯的過程當中，就需要加入函式庫的相關設定囉。 事實上， Linux 的核心提供很多的核心相關函式庫與外部參數， 這些核心功能在設計硬體的驅動程式的時候是相當有用的資訊，這些核心相關資訊大多放置在 /usr/include, /lib, /usr/lib 裡面哩！我們在本章的後續小節再來探討。反正我們可以簡單的這麼想：

- 函式庫：就類似副程式的角色，可以被呼叫來執行的一段功能函數。

什麼是 make 與 configure

事實上，使用類似 gcc 的編譯器來進行編譯的過程並不簡單，因為一套軟體並不會僅有一支程式， 而是有一堆程式碼檔案。所以除了每個主程式與副程式均需要寫上一筆編譯過程的指令外，還需要寫上最終的連結程序。 程式碼小的時候還好，如果是類似 WWW 伺服器軟體 (例如 Apache) ，或者是類似核心的原始碼，動則數百 MBytes 的資料量，編譯指令會寫到瘋掉∼這個時候，我們就可以使用 make 這個指令的相關功能來進行編譯過程的指令簡化了！

當執行 make 時，make 會在當時的目錄下搜尋 Makefile (or makefile) 這個文字檔，而 Makefile 裡面則記錄了原始碼如何編譯的詳細資訊！ make 會自動的判別原始碼是否經過變動了，而自動更新執行檔，是軟體工程師相當好用的一個輔助工具呢！

咦！make 是一支程式，會去找 Makefile ，那 Makefile 怎麼寫？ 通常軟體開發商都會寫一支偵測程式來偵測使用者的作業環境， 以及該作業環境是否有軟體開發商所需要的其他功能，該偵測程式偵測完畢後，就會主動的建立這個 Makefile 的規則檔案啦！通常這支偵測程式的檔名為 configure 或者是 config 。

咦！那為什麼要偵測作業環境呢？在第一章當中， 不是曾經提過其實每個 Linux distribution 都使用同樣的核心嗎？但妳得要注意， 不同版本的核心所使用的系統呼叫可能不相同，而且每個軟體所需要的相依的函式庫也不相同， 同時，軟體開發商不會僅針對 Linux 開發，而是會針對整個 Unix-Like 做開發啊！ 所以他也必須要偵測該作業系統平台有沒有提供合適的編譯器才行！所以當然要偵測環境啊！ 一般來說，偵測程式會偵測的資料大約有底下這些：

- 是否有適合的編譯器可以編譯本軟體的程式碼；

- 是否已經存在本軟體所需要的函式庫，或其他需要的相依軟體；

- 作業系統平台是否適合本軟體，包括 Linux 的核心版本；

- 核心的表頭定義檔 (header include) 是否存在 (驅動程式必須要的偵測)。

至於 make 與 configure 運作流程的相關性，我們可以使用底下的圖示來示意一下啊！ 下圖中，妳要進行的任務其實只有兩個，一個是執行 configure 來建立 Makefile ， 這個步驟一定要成功！成功之後再以 make 來呼叫所需要的資料來編譯即可！非常簡單！

圖 1.3.1、透過 configure 與 make 進行編譯示意圖

由於不同的 Linux distribution 的函式庫檔案所放置的路徑，或者是函式庫的檔名訂定， 或者是預設安裝的編譯器，以及核心的版本都不相同，因此理論上，妳無法在 CentOS 5.x 上面編譯出 binary program 後，還將他拿到 SuSE 上面執行，這個動作通常是不可能成功的！ 因為呼叫的目標函式庫位置可能不同 (參考圖1.2.1) ， 核心版本更不可能相同！所以能夠執行的情況是微乎其微！所以同一套軟體要在不同的平台上面執行時， 必須要重複編譯！所以才需要原始碼嘛！瞭解乎！

詳細的 make 用法與 Makefile 規則，在後續的小節裡面再探討囉！

什麼是 Tarball 的軟體

從前面幾個小節的說明來看，我們知道所謂的原始程式碼，其實就是一些寫滿了程式碼的純文字檔案。 那我們在第九章壓縮指令的介紹當中， 也瞭解了純文字檔在網路上其實是很浪費頻寬的一種檔案格式！ 所以啦，如果能夠將這些原始碼透過檔案的打包與壓縮技術來將檔案的數量與容量減小， 不但讓使用者容易下載，軟體開發商的網站頻寬也能夠節省很多很多啊！這就是 Tarball 檔案的由來囉！

Tips:

想一想，一個核心的原始碼檔案大約要 300~500 MB 以上，如果每個人都去下載這樣的一個核心檔案， 呵呵！那麼網路頻寬不被吃的死翹翹才怪呢！

所謂的 Tarball 檔案，其實就是將軟體的所有原始碼檔案先以 tar 打包，然後再以壓縮技術來壓縮，通常最常見的就是以 gzip 來壓縮了。因為利用了 tar 與 gzip 的功能，所以 tarball 檔案一般的副檔名就會寫成 *.tar.gz 或者是簡寫為 *.tgz 囉！不過，近來由於 bzip2 的壓縮率較佳，所以 Tarball 漸漸的以 bzip2 的壓縮技術來取代 gzip 囉！因此檔名也會變成 *.tar.bz2 之類的哩。所以說， Tarball 是一個軟體包， 妳將他解壓縮之後，裡面的檔案通常就會有：

- 原始程式碼檔案；

- 偵測程式檔案 (可能是 configure 或 config 等檔名)；

- 本軟體的簡易說明與安裝說明 (INSTALL 或 README)。

其中最重要的是那個 INSTALL 或者是 README 這兩個檔案，通常你只要能夠參考這兩個檔案， Tarball 軟體的安裝是很簡單的啦！我們在後面的章節會再繼續介紹 Tarball 這個玩意兒。

如何安裝與升級軟體

將原始碼作了一個簡單的介紹，也知道了系統其實認識的可執行檔是 binary program 之後，好了，得要聊一聊，那麼怎麼安裝與升級一個 Tarball 的軟體？為什麼要安裝一個新的軟體呢？當然是因為我們的主機上面沒有該軟體囉！那麼， 為何要升級呢？原因可能有底下這些：

- 需要新的功能，但舊有主機的舊版軟體並沒有，所以需要升級到新版的軟體；

- 舊版本的軟體上面可能有資安上的顧慮，所以需要更新到新版的軟體；

- 舊版的軟體執行效能不彰，或者執行的能力不能讓管理者滿足。

在上面的需求當中，尤其需要注意的是第二點，當一個軟體有安全上的顧慮時，千萬不要懷疑， 趕緊更新軟體吧！否則造成網路危機，那可不是鬧著玩的！那麼更新的方法有哪些呢？ 基本上更新的方法可以分為兩大類，分別是：

- 直接以原始碼透過編譯來安裝與升級；

- 直接以編譯好的 binary program 來安裝與升級。

上面第一點很簡單，就是直接以 Tarball 在自己的機器上面進行偵測、編譯、 安裝與設定等等動作來升級就是了。不過，這樣的動作雖然讓使用者在安裝過程當中具有很高的彈性， 但畢竟是比較麻煩一點，如果 Linux distribution 廠商能夠針對自己的作業平台先進行編譯等過程，再將編譯好的 binary program 釋出的話，那由於我的系統與該 Linux distribution 的環境是相同的，所以他所釋出的 binary program 就可以在我的機器上面直接安裝啦！省略了偵測與編譯等等繁雜的過程呢！

這個預先編譯好程式的機制存在於很多 distribution 喔，包括有 Red Hat 系統 (含 Fedora/CentOS 系列) 發展的 RPM 軟體管理機制與 yum 線上更新模式； Debian 使用的 dpkg 軟體管理機制與 APT 線上更新模式等等。

由於 CentOS 系統是依循標準的 Linux distribution，所以可以使用 Tarball 直接進行編譯的安裝與升級， 當然也可以使用 RPM 相關的機制來進行安裝與升級囉！本章節主要針對 Tarball ，至於 RPM 則留待下個章節再來介紹呢！

好了，那麼一個軟體的 Tarball 是如何安裝的呢？基本流程是這樣的啦：

1. 將 Tarball 由廠商的網頁下載下來；

2. 將 Tarball 解開，產生很多的原始碼檔案；

3. 開始以 gcc 進行原始碼的編譯 (會產生目標檔 object files)；

4. 然後以 gcc 進行函式庫、主、副程式的連結，以形成主要的 binary file；

5. 將上述的 binary file 以及相關的設定檔安裝至自己的主機上面。

上面第 3, 4 步驟當中，我們可以透過 make 這個指令的功能來簡化他， 所以整個步驟其實是很簡單的啦！只不過你就得需要至少有 gcc 以及 make 這兩個軟體在你的 Linux 系統裡面才行喔！ 詳細的過程以及需要的軟體我們在後面的章節繼續來介紹的啦！

使用傳統程式語言進行編譯的簡單範例

經過上面的介紹之後，你應該比較清楚的知道原始碼、編譯器、函式庫與執行檔之間的相關性了。 不過，詳細的流程可能還是不很清楚，所以，在這裡我們以一個簡單的程式範例來說明整個編譯的過程喔！趕緊進入 Linux 系統，實地的操作一下底下的範例呢！

單一程式：印出 Hello World

我們以 Linux 上面最常見的 C 語言來撰寫第一支程式！第一支程式最常作的就是..... 在螢幕上面印出『Hello World！』的字樣∼當然， 這裡我們是以簡單的 C 語言來撰寫，如果你對於 C 有興趣的話，那麼請自行購買相關的書籍喔！ ^_^ 好了，不囉唆，立刻編輯第一支程式吧！

Tips:

請先確認你的 Linux 系統裡面已經安裝了 gcc 了喔！如果尚未安裝 gcc 的話，請先參考下一節的 RPM 安裝法，先安裝好 gcc 之後，再回來閱讀本章。 如果你已經有網路了，那麼直接使用『 yum groupinstall "Development Tools" 』 預先安裝好所需的所有軟體即可。 rpm 與 yum 均會在下一章介紹。

- 編輯程式碼，亦即原始碼

[root@www ~]# vim hello.c   <==用 C 語言寫的程式副檔名建議用 .c

#include <stdio.h>

int main(void)

{

printf("Hello World\n");

}

上面是用 C 語言的語法寫成的一個程式檔案。第一行的那個『 # 』並不是註解喔！如果你擔心輸入錯誤， 請到底下的連結下載這個檔案：

- http://linux.vbird.org/linux_basic/0520source/hello.c

- 開始編譯與測試執行

[root@www ~]# gcc hello.c

[root@www ~]# ll hello.c a.out

-rwxr-xr-x 1 root root 4725 Jun  5 02:41 a.out   <==此時會產生這個檔名

-rw-r--r-- 1 root root   72 Jun  5 02:40 hello.c

[root@www ~]# ./a.out

Hello World  <==呵呵！成果出現了！

在預設的狀態下，如果我們直接以 gcc 編譯原始碼，並且沒有加上任何參數，則執行檔的檔名會被自動設定為 a.out 這個檔案名稱！ 所以妳就能夠直接執行 ./a.out 這個執行檔啦！上面的例子很簡單吧！那個 hello.c 就是原始碼，而 gcc 就是編譯器，至於 a.out 就是編譯成功的可執行 binary program 囉！ 咦！那如果我想要產生目標檔 (object file) 來進行其他的動作，而且執行檔的檔名也不要用預設的 a.out ，那該如何是好？其實妳可以將上面的第 2 個步驟改成這樣：

[root@www ~]# gcc -c hello.c

[root@www ~]# ll hello*

-rw-r--r-- 1 root root  72 Jun  5 02:40 hello.c

-rw-r--r-- 1 root root 868 Jun  5 02:44 hello.o  <==就是被產生的目標檔

[root@www ~]# gcc -o hello hello.o

[root@www ~]# ll hello*

-rwxr-xr-x 1 root root 4725 Jun  5 02:47 hello  <==這就是可執行檔！ -o 的結果

-rw-r--r-- 1 root root   72 Jun  5 02:40 hello.c

-rw-r--r-- 1 root root  868 Jun  5 02:44 hello.o

[root@www ~]# ./hello

Hello World

這個步驟主要是利用 hello.o 這個目標檔製作出一個名為 hello 的執行檔，詳細的 gcc 語法我們會在後續章節中繼續介紹！透過這個動作後，我們可以得到 hello 及 hello.o 兩個檔案， 真正可以執行的是 hello 這個 binary program 喔！ 或許你會覺得，咦！只要一個動作作出 a.out 就好了，幹嘛還要先製作目標檔再做成執行檔呢？ 呵呵！透過下個範例，你就可以知道為什麼啦！

主、副程式連結：副程式的編譯

如果我們在一個主程式裡面又呼叫了另一個副程式呢？這是很常見的一個程式寫法， 因為可以簡化整個程式的易讀性！在底下的例子當中，我們以 thanks.c 這個主程式去呼叫 thanks_2.c 這個副程式，寫法很簡單：

- 撰寫所需要的主、副程式

# 1. 編輯主程式：

[root@www ~]# vim thanks.c

#include <stdio.h>

int main(void)

{

printf("Hello World\n");

thanks_2();

}

# 上面的 thanks_2(); 那一行就是呼叫副程式啦！

[root@www ~]# vim thanks_2.c

#include <stdio.h>

void thanks_2(void)

{

printf("Thank you!\n");

}

上面這兩個檔案你可以到底下下載：

- http://linux.vbird.org/linux_basic/0520source/thanks.c

- http://linux.vbird.org/linux_basic/0520source/thanks_2.c

- 進行程式的編譯與連結 (Link)

# 2. 開始將原始碼編譯成為可執行的 binary file ：

[root@www ~]# gcc -c thanks.c thanks_2.c

[root@www ~]# ll thanks*

-rw-r--r-- 1 root root  76 Jun  5 16:13 thanks_2.c

-rw-r--r-- 1 root root 856 Jun  5 16:13 thanks_2.o  <==編譯產生的！

-rw-r--r-- 1 root root  92 Jun  5 16:11 thanks.c

-rw-r--r-- 1 root root 908 Jun  5 16:13 thanks.o    <==編譯產生的！

[root@www ~]# gcc -o thanks thanks.o thanks_2.o

[root@www ~]# ll thanks*

-rwxr-xr-x 1 root root 4870 Jun  5 16:17 thanks     <==最終結果會產生這玩意兒

# 3. 執行一下這個檔案：

[root@www ~]# ./thanks

Hello World

Thank you!

知道為什麼要製作出目標檔了嗎？由於我們的原始碼檔案有時並非僅只有一個檔案，所以我們無法直接進行編譯。 這個時候就需要先產生目標檔，然後再以連結製作成為 binary 可執行檔。另外，如果有一天，你更新了 thanks_2.c 這個檔案的內容，則你只要重新編譯 thanks_2.c 來產生新的 thanks_2.o ，然後再以連結製作出新的 binary 可執行檔即可！而不必重新編譯其他沒有更動過的原始碼檔案。 這對於軟體開發者來說，是一個很重要的功能，因為有時候要將偌大的原始碼全部編譯完成，會花很長的一段時間呢！

此外，如果你想要讓程式在執行的時候具有比較好的效能，或者是其他的除錯功能時， 可以在編譯的過程裡面加入適當的參數，例如底下的例子：

[root@www ~]# gcc -O -c thanks.c thanks_2.c  <== -O 為產生最佳化的參數

[root@www ~]# gcc -Wall -c thanks.c thanks_2.c

thanks.c: In function 'main':

thanks.c:5: warning: implicit declaration of function 'thanks_2'

thanks.c:6: warning: control reaches end of non-void function

# -Wall 為產生更詳細的編譯過程資訊。上面的訊息為警告訊息 (warning)

# 所以不用理會也沒有關係！

至於更多的 gcc 額外參數功能，就得要 man gcc 囉∼呵呵！可多的跟天書一樣∼

呼叫外部函式庫：加入連結的函式庫

剛剛我們都僅只是在螢幕上面印出一些字眼而已，如果說要計算數學公式呢？例如我們想要計算出三角函數裡面的 sin (90度角)。要注意的是，大多數的程式語言都是使用徑度而不是一般我們在計算的『角度』， 180 度角約等於 3.14 徑度！嗯！那我們就來寫一下這個程式吧！

[root@www ~]# vim sin.c

#include <stdio.h>

int main(void)

{

float value;

value = sin ( 3.14 / 2 );

printf("%f\n",value);

}

上面這個檔案的內容可以在底下取得！

- http://linux.vbird.org/linux_basic/0520source/sin.c

那要如何編譯這支程式呢？我們先直接編譯看看：

[root@www ~]# gcc sin.c

sin.c: In function 'main':

sin.c:5: warning: incompatible implicit declaration of built-in function 'sin'

/tmp/ccsfvijY.o: In function `main':

sin.c:(.text+0x1b): undefined reference to `sin'

collect2: ld returned 1 exit status

# 注意看到上面最後一行，會有個錯誤訊息，代表沒有成功！

特別注意上面的錯誤訊息，唉啊！怎麼沒有編譯成功？它說的是『undefined reference to sin』，說的是『沒有 sin 的相關定義參考值！』，為什麼會這樣呢？這是因為 C 語言裡面的 sin 函示是寫在 libm.so 這個函式庫中，而我們並沒有在原始碼裡面將這個函式庫功能加進去， 所以當然就需要在編譯與連結的時候將這個函式庫給他連結進執行檔裡面啊！我們可以這樣做：

- 編譯時加入額外函式庫連結的方式：

[root@www ~]# gcc sin.c -lm -L/lib -L/usr/lib  <==重點在 -lm

[root@www ~]# ./a.out                          <==嘗試執行新檔案！

1.000000

特別注意，使用 gcc 編譯時所加入的那個 -lm 是有意義的，他可以拆開成兩部份來看：

- -l ：是『加入某個函式庫(library)』的意思，

- m ：則是 libm.so 這個函式庫，其中， lib 與副檔名(.a 或 .so)不需要寫

所以 -lm 表示使用 libm.so (或 libm.a) 這個函式庫的意思∼至於那個 -L 後面接的路徑呢？這表示： 『我要的函式庫 libm.so 請到 /lib 或 /usr/lib 裡面搜尋！』

上面的說明很清楚了吧！不過，要注意的是，由於 Linux 預設是將函式庫放置在 /lib 與 /usr/lib 當中，所以你沒有寫 -L/lib 與 -L/usr/lib 也沒有關係的！不過，萬一哪天你使用的函式庫並非放置在這兩個目錄下，那麼 -L/path 就很重要了！否則會找不到函式庫喔！

除了連結的函式庫之外，你或許已經發現一個奇怪的地方，那就是在我們的 sin.c 當中第一行『 #include <stdio.h>』，這行說的是要將一些定義資料由 stdio.h 這個檔案讀入，這包括 printf 的相關設定。這個檔案其實是放置在 /usr/include/stdio.h 的！那麼萬一這個檔案並非放置在這裡呢？那麼我們就可以使用底下的方式來定義出要讀取的 include 檔案放置的目錄：

[root@www ~]# gcc sin.c -lm -I/usr/include

-I/path 後面接的路徑( Path )就是設定要去搜尋相關的 include 檔案的目錄啦！不過，同樣的，預設值是放置在 /usr/include 底下，除非你的 include 檔案放置在其他路徑，否則也可以略過這個項目！

透過上面的幾個小範例，你應該對於 gcc 以及原始碼有一定程度的認識了，再接下來，我們來稍微整理一下 gcc 的簡易使用方法吧！

gcc 的簡易用法 (編譯、參數與鏈結)

前面說過， gcc 為 Linux 上面最標準的編譯器，這個 gcc 是由 GNU 計畫所維護的，有興趣的朋友請自行前往參考。既然 gcc 對於 Linux 上的 Open source 是這麼樣的重要，所以底下我們就列舉幾個 gcc 常見的參數，如此一來大家應該更容易瞭解原始碼的各項功能吧！

# 僅將原始碼編譯成為目標檔，並不製作連結等功能：

[root@www ~]# gcc -c hello.c

# 會自動的產生 hello.o 這個檔案，但是並不會產生 binary 執行檔。

# 在編譯的時候，依據作業環境給予最佳化執行速度

[root@www ~]# gcc -O hello.c -c

# 會自動的產生 hello.o 這個檔案，並且進行最佳化喔！

# 在進行 binary file 製作時，將連結的函式庫與相關的路徑填入

[root@www ~]# gcc sin.c -lm -L/usr/lib -I/usr/include

# 這個指令較常下達在最終連結成 binary file 的時候，

# -lm 指的是 libm.so 或 libm.a 這個函式庫檔案；

# -L 後面接的路徑是剛剛上面那個函式庫的搜尋目錄；

# -I 後面接的是原始碼內的 include 檔案之所在目錄。

# 將編譯的結果輸出成某個特定檔名

[root@www ~]# gcc -o hello hello.c

# -o 後面接的是要輸出的 binary file 檔名

# 在編譯的時候，輸出較多的訊息說明

[root@www ~]# gcc -o hello hello.c -Wall

# 加入 -Wall 之後，程式的編譯會變的較為嚴謹一點，

# 所以警告訊息也會顯示出來！

比較重要的大概就是這一些。另外，我們通常稱 -Wall 或者 -O 這些非必要的參數為旗標 (FLAGS)，因為我們使用的是 C 程式語言，所以有時候也會簡稱這些旗標為 CFLAGS ，這些變數偶爾會被使用的喔！尤其是在後頭會介紹的 make 相關的用法時，更是重要的很吶！ ^_^

用 make 進行巨集編譯

在本章一開始我們提到過 make 的功能是可以簡化編譯過程裡面所下達的指令，同時還具有很多很方便的功能！那麼底下咱們就來試看看使用 make 簡化下達編譯指令的流程吧！

為什麼要用 make

先來想像一個案例，假設我的執行檔裡面包含了四個原始碼檔案，分別是 main.c haha.c sin_value.c cos_value.c 這四個檔案，這四個檔案的目的是：

- main.c ：主要的目的是讓使用者輸入角度資料與呼叫其他三支副程式；

- haha.c ：輸出一堆有的沒有的訊息而已；

- sin_value.c ：計算使用者輸入的角度(360) sin 數值；

- cos_value.c ：計算使用者輸入的角度(360) cos 數值。

這四個檔案你可以到 http://linux.vbird.org/linux_basic/0520source/main.tgz 來下載。由於這四個檔案裡面包含了相關性，並且還用到數學函式在裡面，所以如果你想要讓這個程式可以跑， 那麼就需要這樣編譯：

# 1. 先進行目標檔的編譯，最終會有四個 *.o 的檔名出現：

[root@www ~]# gcc -c main.c

[root@www ~]# gcc -c haha.c

[root@www ~]# gcc -c sin_value.c

[root@www ~]# gcc -c cos_value.c

# 2. 再進行連結成為執行檔，並加入 libm 的數學函式，以產生 main 執行檔：

[root@www ~]# gcc -o main main.o haha.o sin_value.o cos_value.o \

> -lm -L/usr/lib -L/lib

# 3. 本程式的執行結果，必須輸入姓名、360 度角的角度值來計算：

[root@www ~]# ./main

Please input your name: VBird  <==這裡先輸入名字

Please enter the degree angle (ex> 90): 30   <==輸入以 360 度角為主的角度

Hi, Dear VBird, nice to meet you.    <==這三行為輸出的結果喔！

The Sin is:  0.50

The Cos is:  0.87

編譯的過程需要進行好多動作啊！而且如果要重新編譯，則上述的流程得要重新來一遍，光是找出這些指令就夠煩人的了！ 如果可以的話，能不能一個步驟就給他完成上面所有的動作呢？那就利用 make 這個工具吧！ 先試看看在這個目錄下建立一個名為 makefile 的檔案，內容如下：

# 1. 先編輯 makefile 這個規則檔，內容只要作出 main 這個執行檔

[root@www ~]# vim makefile

main: main.o haha.o sin_value.o cos_value.o

gcc -o main main.o haha.o sin_value.o cos_value.o -lm

# 注意：第二行的 gcc 之前是 <tab> 按鍵產生的空格喔！

# 2. 嘗試使用 makefile 制訂的規則進行編譯的行為：

[root@www ~]# rm -f main *.o   <==先將之前的目標檔去除

[root@www ~]# make

cc    -c -o main.o main.c

cc    -c -o haha.o haha.c

cc    -c -o sin_value.o sin_value.c

cc    -c -o cos_value.o cos_value.c

gcc -o main main.o haha.o sin_value.o cos_value.o -lm

# 此時 make 會去讀取 makefile 的內容，並根據內容直接去給他編譯相關的檔案囉！

# 3. 在不刪除任何檔案的情況下，重新執行一次編譯的動作：

[root@www ~]# make

make: `main' is up to date.

# 看到了吧！是否很方便呢！只會進行更新 (update) 的動作而已。

或許你會說：『如果我建立一個 shell script 來將上面的所有動作都集結在一起，不是具有同樣的效果嗎？』呵呵！ 效果當然不一樣，以上面的測試為例，我們僅寫出 main 需要的目標檔，結果 make 會主動的去判斷每個目標檔相關的原始碼檔案，並直接予以編譯，最後再直接進行連結的動作！ 真的是很方便啊！此外，如果我們更動過某些原始碼檔案，則 make 也可以主動的判斷哪一個原始碼與相關的目標檔檔案有更新過， 並僅更新該檔案，如此一來，將可大大的節省很多編譯的時間呢！要知道，某些程式在進行編譯的行為時，會消耗很多的 CPU 資源呢！所以說， make 有這些好處：

- 簡化編譯時所需要下達的指令；

- 若在編譯完成之後，修改了某個原始碼檔案，則 make 僅會針對被修改了的檔案進行編譯，其他的 object file 不會被更動；

- 最後可以依照相依性來更新 (update) 執行檔。

既然 make 有這麼多的優點，那麼我們當然就得好好的瞭解一下 make 這個令人關心的傢伙啦！而 make 裡面最需要注意的大概就是那個規則檔案，也就是 makefile 這個檔案的語法啦！所以底下我們就針對 makefile 的語法來加以介紹囉。

makefile 的基本語法與變數

make 的語法可是相當的多而複雜的，有興趣的話可以到 GNU (註1) 去查閱相關的說明，鳥哥這裡僅列出一些基本的規則，重點在於讓讀者們未來在接觸原始碼時，不會太緊張啊！ 好了，基本的 makefile 規則是這樣的：

標的(target): 目標檔1 目標檔2

<tab>   gcc -o 欲建立的執行檔 目標檔1 目標檔2

那個標的 (target) 就是我們想要建立的資訊，而目標檔就是具有相關性的 object files ，那建立執行檔的語法就是以 <tab> 按鍵開頭的那一行！特別給他留意喔，『命令列必須要以 tab 按鍵作為開頭』才行！他的規則基本上是這樣的：

- 在 makefile 當中的 # 代表註解；

- <tab> 需要在命令行 (例如 gcc 這個編譯器指令) 的第一個字元；

- 標的 (target) 與相依檔案(就是目標檔)之間需以『:』隔開。

同樣的，我們以剛剛上一個小節的範例進一步說明，如果我想要有兩個以上的執行動作時， 例如下達一個指令就直接清除掉所有的目標檔與執行檔，該如何製作呢？

# 1. 先編輯 makefile 來建立新的規則，此規則的標的名稱為 clean ：

[root@www ~]# vi makefile

main: main.o haha.o sin_value.o cos_value.o

gcc -o main main.o haha.o sin_value.o cos_value.o -lm

clean:

rm -f main main.o haha.o sin_value.o cos_value.o

# 2. 以新的標的 (clean) 測試看看執行 make 的結果：

[root@www ~]# make clean  <==就是這裡！透過 make 以 clean 為標的

rm -rf main main.o haha.o sin_value.o cos_value.o

如此一來，我們的 makefile 裡面就具有至少兩個標的，分別是 main 與 clean ，如果我們想要建立 main 的話，輸入『make main』，如果想要清除有的沒的，輸入『make clean』即可啊！而如果想要先清除目標檔再編譯 main 這個程式的話，就可以這樣輸入：『make clean main』，如下所示：

[root@www ~]# make clean main

rm -rf main main.o haha.o sin_value.o cos_value.o

cc    -c -o main.o main.c

cc    -c -o haha.o haha.c

cc    -c -o sin_value.o sin_value.c

cc    -c -o cos_value.o cos_value.c

gcc -o main main.o haha.o sin_value.o cos_value.o -lm

這樣就很清楚了吧！但是，你是否會覺得，咦！ makefile 裡面怎麼重複的資料這麼多啊！沒錯！所以我們可以再藉由 shell script 那時學到的『變數』來更簡化 makefile 喔：

[root@www ~]# vi makefile

LIBS = -lm

OBJS = main.o haha.o sin_value.o cos_value.o

main: ${OBJS}

gcc -o main ${OBJS} ${LIBS}

clean:

rm -f main ${OBJS}

與 bash shell script 的語法有點不太相同，變數的基本語法為：

1. 變數與變數內容以『=』隔開，同時兩邊可以具有空格；

2. 變數左邊不可以有 <tab> ，例如上面範例的第一行 LIBS 左邊不可以是 <tab>；

3. 變數與變數內容在『=』兩邊不能具有『:』；

4. 在習慣上，變數最好是以『大寫字母』為主；

5. 運用變數時，以 ${變數} 或 $(變數) 使用；

6. 在該 shell 的環境變數是可以被套用的，例如提到的 CFLAGS 這個變數！

7. 在指令列模式也可以給予變數。

由於 gcc 在進行編譯的行為時，會主動的去讀取 CFLAGS 這個環境變數，所以，你可以直接在 shell 定義出這個環境變數，也可以在 makefile 檔案裡面去定義，更可以在指令列當中給予這個咚咚呢！例如：

[root@www ~]# CFLAGS="-Wall" make clean main

# 這個動作在上 make 進行編譯時，會去取用 CFLAGS 的變數內容！

也可以這樣：

[root@www ~]# vi makefile

LIBS = -lm

OBJS = main.o haha.o sin_value.o cos_value.o

CFLAGS = -Wall

main: ${OBJS}

gcc -o main ${OBJS} ${LIBS}

clean:

rm -f main ${OBJS}

咦！我可以利用指令列進行環境變數的輸入，也可以在檔案內直接指定環境變數，那萬一這個 CFLAGS 的內容在指令列與 makefile 裡面並不相同時，以那個方式輸入的為主？呵呵！問了個好問題啊！ 環境變數取用的規則是這樣的：

1. make 指令列後面加上的環境變數為優先；

2. makefile 裡面指定的環境變數第二；

3. shell 原本具有的環境變數第三。

此外，還有一些特殊的變數需要瞭解的喔：

- $@：代表目前的標的(target)

所以我也可以將 makefile 改成：

[root@www ~]# vi makefile

LIBS = -lm

OBJS = main.o haha.o sin_value.o cos_value.o

CFLAGS = -Wall

main: ${OBJS}

gcc -o $@ ${OBJS} ${LIBS}   <==那個 $@ 就是 main ！

clean:

rm -f main ${OBJS}

這樣是否稍微瞭解了 makefile (也可能是 Makefile) 的基本語法？這對於你未來自行修改原始碼的編譯規則時，是很有幫助的喔！^_^！

Tarball 的管理與建議

在我們知道了原始碼的相關資訊之後，再來要瞭解的自然就是如何使用具有原始碼的 Tarball 來建立一個屬於自己的軟體囉！從前面幾個小節的說明當中，我們曉得其實 Tarball 的安裝是可以跨平台的，因為 C 語言的程式碼在各個平台上面是可以共通的， 只是需要的編譯器可能並不相同而已。例如 Linux 上面用 gcc 而 Windows 上面也有相關的 C 編譯器啊∼所以呢，同樣的一組原始碼，既可以在 CentOS Linux 上面編譯，也可以在 SuSE Linux 上面編譯，當然，也可以在大部分的 Unix 平台上面編譯成功的！

如果萬一沒有編譯成功怎麼辦？很簡單啊，透過修改小部分的程式碼 (通常是因為很小部分的異動而已) 就可以進行跨平台的移植了！也就是說，剛剛我們在 Linux 底下寫的程式『理論上，是可以在 Windows 上面編譯的！』這就是原始碼的好處啦！所以說，如果朋友們想要學習程式語言的話， 鳥哥個人是比較建議學習『具有跨平台能力的程式語言』，例如 C 就是很不錯的一個！

唉啊！又扯遠了∼趕緊拉回來繼續說明我們的 Tarball 啦！

使用原始碼管理軟體所需要的基礎軟體

從原始碼的說明我們曉得要製作一個 binary program 需要很多咚咚的呢！這包括底下這些基礎的軟體：

- gcc 或 cc 等 C 語言編譯器 (compiler)：

沒有編譯器怎麼進行編譯的動作？所以 C compiler 是一定要有的。不過 Linux 上面有眾多的編譯器，其中當然以 GNU 的 gcc 是首選的自由軟體編譯器囉！事實上很多在 Linux 平台上面發展的軟體的原始碼，原本就是以 gcc 為底來設計的呢。

- make 及 autoconfig 等軟體：

一般來說，以 Tarball 方式釋出的軟體當中，為了簡化編譯的流程，通常都是配合前幾個小節提到的 make 這個指令來依據目標檔案的相依性而進行編譯。但是我們也知道說 make 需要 makefile 這個檔案的規則，那由於不同的系統裡面可能具有的基礎軟體環境並不相同， 所以就需要偵測使用者的作業環境，好自行建立一個 makefile 檔案。這個自行偵測的小程式也必須要藉由 autoconfig 這個相關的軟體來輔助才行。

- 需要 Kernel 提供的 Library 以及相關的 Include 檔案：

從前面的原始碼編譯過程，我們曉得函式庫 (library) 的重要性，同時也曉得有 include 檔案的存在。很多的軟體在發展的時候都是直接取用系統核心提供的函式庫與 include 檔案的，這樣才可以與這個作業系統相容啊！尤其是在『驅動程式方面的模組 』，例如網路卡、音效卡、USB 等驅動程式在安裝的時候，常常是需要核心提供的相關資訊的。在 Red Hat 的系統當中 (包含 Fedora/CentOS 等系列) ，這個核心相關的功能通常都是被包含在 kernel-source 或 kernel-header 這些軟體名稱當中，所以記得要安裝這些軟體喔！

雖然 Tarball 的安裝上面相當的簡單，如同我們前面幾個小節的例子，只要順著開發商提供的 README 與 INSTALL 檔案所載明的步驟來進行，安裝是很容易的。但是我們卻還是常常會在 BBS 或者是新聞群組當中發現這些留言：『我在執行某個程式的偵測檔案時，他都會告訴我沒有 gcc 這個軟體，這是怎麼回事？』還有：『我沒有辦法使用 make 耶！這是什麼問題？』呵呵！ 這就是沒有安裝上面提到的那些基礎軟體啦！

咦！為什麼使用者不安裝這些軟體啊？這是因為目前的 Linux distribution 大多已經偏向於桌上型電腦的使用 (非伺服器端)，他們希望使用者能夠按照廠商自己的希望來安裝相關的軟體即可， 所以通常『預設』是沒有安裝 gcc 或者是 make 等軟體的。所以啦，如果你希望未來可以自行安裝一些以 Tarball 方式釋出的軟體時，記得請自行挑選想要安裝的軟體名稱喔！例如在 CentOS 或者是 Red Hat 當中記得選擇 Development Tools 以及 Kernel Source Development 等相關字眼的軟體群集呢。

那萬一我已經安裝好一部 Linux 主機，但是使用的是預設值所安裝的軟體，所以沒有 make, gcc 等咚咚，該如何是好？呵呵！問題其實不大啦，目前使用最廣泛的 CentOS/Fedora 或者是 Red Hat 大多是以 RPM (下一章會介紹) 來安裝軟體的，所以，你只要拿出當初安裝 Linux 時的原版光碟，然後以下一章介紹的 RPM 來一個一個的加入到你的 Linux 主機裡面就好啦！很簡單的啦！ 尤其現在又有 yum 這玩意兒，更方便吶！

在 CentOS 當中，如果你已經有網路可以連上 Internet 的話，那麼就可以使用下一章會談到的 yum 囉！ 透過 yum 的軟體群組安裝功能，你可以這樣做：

- 如果是要安裝 gcc 等軟體發展工具，請使用『 yum groupinstall "Development Tools" 』

- 若待安裝的軟體需要圖形介面支援，一般還需要『 yum groupinstall "X Software Development" 』

- 若安裝的軟體較舊，可能需要『 yum groupinstall "Legacy Software Development" 』

大概就是這樣，更多的資訊請參考下一章的介紹喔。

Tarball 安裝的基本步驟

我們提過以 Tarball 方式釋出的軟體是需要重新編譯可執行的 binary program 的。而 Tarball 是以 tar 這個指令來打包與壓縮的檔案，所以啦，當然就需要先將 Tarball 解壓縮，然後到原始碼所在的目錄下進行 makefile 的建立，再以 make 來進行編譯與安裝的動作啊！所以整個安裝的基礎動作大多是這樣的：

1. 取得原始檔：將 tarball 檔案在 /usr/local/src 目錄下解壓縮；

2. 取得步驟流程：進入新建立的目錄底下，去查閱 INSTALL 與 README 等相關檔案內容 (很重要的步驟！)；

3. 相依屬性軟體安裝：根據 INSTALL/README 的內容察看並安裝好一些相依的軟體 (非必要)；

4. 建立 makefile：以自動偵測程式 (configure 或 config) 偵測作業環境，並建立 Makefile 這個檔案；

5. 編譯：以 make 這個程式並使用該目錄下的 Makefile 做為他的參數設定檔，來進行 make (編譯或其他) 的動作；

6. 安裝：以 make 這個程式，並以 Makefile 這個參數設定檔，依據 install 這個標的 (target) 的指定來安裝到正確的路徑！

注意到上面的第二個步驟，通常在每個軟體在釋出的時候，都會附上 INSTALL 或者是 README 這種檔名的說明檔，這些說明檔請『確實詳細的』 閱讀過一遍，通常這些檔案會記錄這個軟體的安裝要求、軟體的工作項目、 與軟體的安裝參數設定及技巧等，只要仔細的讀完這些檔案，基本上，要安裝好 tarball 的檔案，都不會有什麼大問題囉。

至於 makefile 在製作出來之後，裡頭會有相當多的標的 (target)，最常見的就是 install 與 clean 囉！通常『make clean』代表著將目標檔 (object file) 清除掉，『make』則是將原始碼進行編譯而已。 注意喔！編譯完成的可執行檔與相關的設定檔還在原始碼所在的目錄當中喔！因此，最後要進行『make install』來將編譯完成的所有咚咚都給他安裝到正確的路徑去，這樣就可以使用該軟體啦！

OK！我們底下約略提一下大部分的 tarball 軟體之安裝的指令下達方式：

1. ./configure

這個步驟就是在建立 Makefile 這個檔案囉！通常程式開發者會寫一支 scripts 來檢查你的 Linux 系統、相關的軟體屬性等等，這個步驟相當的重要， 因為未來你的安裝資訊都是這一步驟內完成的！另外，這個步驟的相關資訊應該要參考一下該目錄下的 README 或 INSTALL 相關的檔案！

2. make clean

make 會讀取 Makefile 中關於 clean 的工作。這個步驟不一定會有，但是希望執行一下，因為他可以去除目標檔案！因為誰也不確定原始碼裡面到底有沒有包含上次編譯過的目標檔案 (*.o) 存在，所以當然還是清除一下比較妥當的。 至少等一下新編譯出來的執行檔我們可以確定是使用自己的機器所編譯完成的嘛！

3. make

make 會依據 Makefile 當中的預設工作進行編譯的行為！編譯的工作主要是進行 gcc 來將原始碼編譯成為可以被執行的 object files ，但是這些 object files 通常還需要一些函式庫之類的 link 後，才能產生一個完整的執行檔！使用 make 就是要將原始碼編譯成為可以被執行的可執行檔，而這個可執行檔會放置在目前所在的目錄之下， 尚未被安裝到預定安裝的目錄中；

4. make install

通常這就是最後的安裝步驟了，make 會依據 Makefile 這個檔案裡面關於 install 的項目，將上一個步驟所編譯完成的資料給他安裝到預定的目錄中，就完成安裝啦！

請注意，上面的步驟是一步一步來進行的，而其中只要一個步驟無法成功，那麼後續的步驟就完全沒有辦法進行的！ 因此，要確定每一的步驟都是成功的才可以！舉個例子來說，萬一今天你在 ./configure 就不成功了，那麼就表示 Makefile 無法被建立起來，要知道，後面的步驟都是根據 Makefile 來進行的，既然無法建立 Makefile，後續的步驟當然無法成功囉！

另外，如果在 make 無法成功的話，那就表示原始檔案無法被編譯成可執行檔，那麼 make install 主要是將編譯完成的檔案給他放置到檔案系統中的，既然都沒有可用的執行檔了，怎麼進行安裝？ 所以囉，要每一個步驟都正確無誤才能往下繼續做！此外，如果安裝成功， 並且是安裝在獨立的一個目錄中，例如 /usr/local/packages 這個目錄中好了，那麼你就必需手動的將這個軟體的 man page 給他寫入 /etc/man.config 裡面去。

一般 Tarball 軟體安裝的建議事項 (如何移除？升級？)

或許你已經發現了也說不定，那就是為什麼前一個小節裡面， Tarball 要在 /usr/local/src 裡面解壓縮呢？基本上，在預設的情況下，原本的 Linux distribution 釋出安裝的軟體大多是在 /usr 裡面的，而使用者自行安裝的軟體則建議放置在 /usr/local 裡面。這是考量到管理使用者所安裝軟體的便利性。

怎麼說呢？我們曉得幾乎每個軟體都會提供線上說明的服務，那就是 info 與 man 的功能。在預設的情況下， man 會去搜尋 /usr/local/man 裡面的說明文件， 因此，如果我們將軟體安裝在 /usr/local 底下的話，那麼自然安裝完成之後， 該軟體的說明文件就可以被找到了。此外，如果你所管理的主機其實是由多人共同管理的， 或者是如同學校裡面，一部主機是由學生管理的，但是學生總會畢業吧？ 所以需要進行交接，如果大家都將軟體安裝在 /usr/local 底下，那麼管理上不就顯的特別的容易嗎！

所以囉，通常我們會建議大家將自己安裝的軟體放置在 /usr/local 下，至於原始碼 (Tarball)則建議放置在 /usr/local/src (src 為 source 的縮寫)底下啊。

再來，讓我們先來看一看 Linux distribution 預設的安裝軟體的路徑會用到哪些？我們以 apache 這個軟體來說明的話 (apache 是 WWW 伺服器軟體，詳細的資料請參考伺服器架設篇。你的系統不見得有裝這個軟體)：

- /etc/httpd

- /usr/lib

- /usr/bin

- /usr/share/man

我們會發現軟體的內容大致上是擺在 etc, lib, bin, man 等目錄當中，分別代表『設定檔、函式庫、執行檔、線上說明檔』。 好了，那麼你是以 tarball 來安裝時呢？如果是放在預設的 /usr/local 裡面，由於 /usr/local 原本就預設這幾個目錄了，所以你的資料就會被放在：

- /usr/local/etc

- /usr/local/bin

- /usr/local/lib

- /usr/local/man

但是如果你每個軟體都選擇在這個預設的路徑下安裝的話， 那麼所有的軟體的檔案都將放置在這四個目錄當中，因此，如果你都安裝在這個目錄下的話， 那麼未來再想要升級或移除的時候，就會比較難以追查檔案的來源囉！ 而如果你在安裝的時候選擇的是單獨的目錄，例如我將 apache 安裝在 /usr/local/apache 當中，那麼你的檔案目錄就會變成：

- /usr/local/apache/etc

- /usr/local/apache/bin

- /usr/local/apache/lib

- /usr/local/apache/man

呵呵！單一軟體的檔案都在同一個目錄之下，那麼要移除該軟體就簡單的多了！ 只要將該目錄移除即可視為該軟體已經被移除囉！以上面為例，我想要移除 apache 只要下達『rm -rf /usr/local/apache』 就算移除這個軟體啦！當然囉，實際安裝的時候還是得視該軟體的 Makefile 裡頭的 install 資訊才能知道到底他的安裝情況為何的。因為例如 sendmail 的安裝就很麻煩......

這個方式雖然有利於軟體的移除，但不曉得你有沒有發現，我們在執行某些指令的時候，與該指令是否在 PATH 這個環境變數所記錄的路徑有關，以上面為例，我的 /usr/local/apache/bin 肯定是不在 PATH 裡面的，所以執行 apache 的指令就得要利用絕對路徑了，否則就得將這個 /usr/local/apache/bin 加入 PATH 裡面。另外，那個 /usr/local/apache/man 也需要加入 man page 搜尋的路徑當中啊！

除此之外， Tarball 在升級的時候也是挺困擾的，怎麼說呢？我們還是以 apache 來說明好了。WWW 伺服器為了考慮互動性，所以通常會將 PHP+MySQL+Apache 一起安裝起來 (詳細的資訊請參考伺服器架設篇) ，果真如此的話，那麼每個軟體在安裝的時候『都有一定的順序與程序！』 因為他們三者之間具有相關性，所以安裝時必需要三者同時考慮到他們的函式庫與相關的編譯參數。

假設今天我只要升級 PHP 呢？有的時候因為只有涉及動態函式庫的升級，那麼我只要升級 PHP 即可！其他的部分或許影響不大。但是如果今天 PHP 需要重新編譯的模組比較多，那麼可能會連帶的，連 Apache 這個程式也需要重新編譯過才行！真是有點給他頭痛的！沒辦法啦！使用 tarball 確實有他的優點啦，但是在這方面，確實也有他一定的傷腦筋程度。

由於 Tarball 在升級與安裝上面具有這些特色，亦即 Tarball 在反安裝上面具有比較高的難度 (如果你沒有好好規劃的話∼)，所以，為了方便 Tarball 的管理，通常鳥哥會這樣建議使用者：

1. 最好將 tarball 的原始資料解壓縮到 /usr/local/src 當中；

2. 安裝時，最好安裝到 /usr/local 這個預設路徑下；

3. 考慮未來的反安裝步驟，最好可以將每個軟體單獨的安裝在 /usr/local 底下；

4. 為安裝到單獨目錄的軟體之 man page 加入 man path 搜尋：

如果你安裝的軟體放置到 /usr/local/software/ ，那麼 man page 搜尋的設定中，可能就得要在 /etc/man.config 內的 40~50 行左右處，寫入如下的一行：

MANPATH /usr/local/software/man

這樣才可以使用 man 來查詢該軟體的線上文件囉！

一個簡單的範例、利用 ntp 來示範

讀萬卷書不如行萬里路啊！所以當然我們就來給他測試看看，看你是否真的瞭解了如何利用 Tarball 來安裝軟體呢？我們利用時間伺服器 (network time protocol) ntp 這個軟體來測試安裝看看。先請到 http://www.ntp.org/downloads.html 這個目錄去下載檔案，請下載最新版本的檔案即可。或者直接到鳥哥的網站下載 2009/05 公告釋出的穩定版本：

http://linux.vbird.org/linux_basic/0520source/ntp-4.2.4p7.tar.gz

假設我對這個軟體的要求是這樣的：

- 假設 ntp-4.2.4p7.tar.gz 這個檔案放置在 /root 這個目錄下；

- 原始碼請解開在 /usr/local/src 底下；

- 我要安裝到 /usr/local/ntp 這個目錄中；

那麼你可以依照底下的步驟來安裝測試看看 (如果可以的話，請你不要參考底下的文件資料， 先自行安裝過一遍這個軟體，然後再來對照一下鳥哥的步驟喔！)。

- 解壓縮下載的 tarball ，並參閱 README/INSTALL 檔案

[root@www ~]# cd /usr/local/src   <==切換目錄

[root@www src]# tar -zxvf /root/ntp-4.2.4p7.tar.gz  <==解壓縮到此目錄

ntp-4.2.4p7/         <==會建立這個目錄喔！

ntp-4.2.4p7/libopts/

....(底下省略)....

[root@www src]# cd ntp-4.2.4p7/

[root@www ntp-4.2.4p7]# vi INSTALL  <==記得 README 也要看一下！

# 特別看一下 28 行到 54 行之間的安裝簡介！可以瞭解如何安裝的流程喔！

- 檢查 configure 支援參數，並實際建置 makefile 規則檔

[root@www ntp*]# ./configure --help | more  <==查詢可用的參數有哪些

--prefix=PREFIX         install architecture-independent files in PREFIX

--enable-all-clocks     + include all suitable non-PARSE clocks:

--enable-parse-clocks   - include all suitable PARSE clocks:

# 上面列出的是比較重要的，或者是你可能需要的參數功能！

[root@www ntp*]# ./configure --prefix=/usr/local/ntp \

>  --enable-all-clocks --enable-parse-clocks  <==開始建立makefile

checking for a BSD-compatible install... /usr/bin/install -c

checking whether build environment is sane... yes

....(中間省略)....

checking for gcc... gcc           <==也有找到 gcc 編譯器了！

....(中間省略)....

config.status: creating Makefile  <==現在知道這個重要性了吧？

config.status: creating config.h

config.status: executing depfiles commands

一般來說 configure 設定參數較重要的就是那個 --prefix=/path 了，--prefix 後面接的路徑就是『這個軟體未來要安裝到那個目錄去？』如果你沒有指定 --prefix=/path 這個參數，通常預設參數就是 /usr/local 至於其他的參數意義就得要參考 ./configure --help 了！ 這個動作完成之後會產生 makefile 或 Makefile 這個檔案。當然啦，這個偵測檢查的過程會顯示在螢幕上， 特別留意關於 gcc 的檢查，還有最重要的是最後需要成功的建立起 Makefile 才行！

- 最後開始編譯與安裝嚕！

[root@www ntp*]# make clean; make

[root@www ntp*]# make check

[root@www ntp*]# make install

# 將資料給他安裝在 /usr/local/ntp 底下

整個動作就這麼簡單，你完成了嗎？完成之後到 /usr/local/ntp 你發現了什麼？

利用 patch 更新原始碼

我們在本章一開始介紹了為何需要進行軟體的升級，這是很重要的喔！那假如我是以 Tarball 來進行某個軟體的安裝，那麼是否當我要升級這個軟體時，就得要下載這個軟體的完整全新的 Tarball 呢？舉個例子來說，鳥哥幫崑山資傳系架了個討論區在 http://www.dic.ksu.edu.tw/phpbb3 這個網址，這個討論區是以 phpBB 這個軟體來架設的，而鳥哥的討論區版本為 phpbb3.0.4.tar.gz ，目前 (2009/06) 最新釋出的版本則是 phpbb3.0.5.tar.gz 。那我是否需要下載全新的 phpbb3.0.5.tar.gz 這個檔案來更新原本的舊程式呢？

事實上，當我們發現一些軟體的漏洞，通常是某一段程式碼寫的不好所致。因此， 所謂的『更新原始碼』常常是只有更改部分檔案的小部分內容而已。既然如此的話， 那麼我們是否可以就那些被更動的檔案來進行修改就可以咯？也就是說， 舊版本到新版本間沒有更動過的檔案就不要理他，僅將有修訂過的檔案部分來處理即可。

這有什麼好處呢？首先，沒有更動過的檔案的目標檔 (object file) 根本就不需要重新編譯，而且有更動過的檔案又可以利用 make 來自動 update (更新)，如此一來，我們原先的設定 (makefile 檔案裡面的規則) 將不需要重新改寫或偵測！可以節省很多寶貴的時間呢 (例如後續章節會提到的核心的編譯！)

從上面的說明當中，我們可以發現，如果可以將舊版的原始碼資料改寫成新版的版本， 那麼就能直接編譯了，而不需要將全部的新版 Tarball 重新下載一次呢！可以節省頻寬與時間說！那麼如何改寫原始碼？ 難道要我們一個檔案一個檔案去參考然後修訂嗎？當然沒有這麼沒人性！

我們在第十二章、正規表示法的時候有提到一個比對檔案的指令，那就是 diff，這個指令可以將『兩個檔案之間的差異性列出來』呢！那我們也知道新舊版本的檔案之間， 其實只有修改一些程式碼而已，那麼我們可以透過 diff 比對出新舊版本之間的文字差異，然後再以相關的指令來將舊版的檔案更新嗎？ 呵呵！當然可以啦！那就是 patch 這個指令啦！很多的軟體開發商在更新了原始碼之後，幾乎都會釋出所謂的 patch file，也就是直接將原始碼 update 而已的一個方式喔！我們底下以一個簡單的範例來說明給你瞭解喔！

關於 diff 與 patch 的基本用法我們在第十二章都談過了，所以這裡不再就這兩個指令的語法進行介紹， 請回去參閱第十二章的內容。這裡我們來舉個案例解釋一下好了。假設我們剛剛計算三角函數的程式 (main) 歷經多次改版， 0.1 版僅會簡單的輸出， 0.2 版的輸出就會含有角度值，因此這兩個版本的內容不相同。如下所示，兩個檔案的意義為：

- http://linux.vbird.org/linux_basic/0520source/main-0.1.tgz ：main 的 0.1 版；

- http://linux.vbird.org/linux_basic/0520source/main_0.1_to_0.2.patch ：main 由 0.1 升級到 0.2 的 patch file；

請您先下載這兩個檔案，並且解壓縮到你的 /root 底下。你會發現系統產生一個名為 main-0.1 的目錄。 該目錄內含有五個檔案，就是剛剛的程式加上一個 Makefile 的規則檔案。你可以到該目錄下去看看 Makefile 的內容， 在這一版當中含有 main 與 clean 兩個標的功能而已。至於 0.2 版則加入了 install 與 uninstall 的規則設定。 接下來，請看一下我們的作法囉：

- 測試舊版程式的功能

[root@www ~]# tar -zxvf main-0.1.tgz

[root@www ~]# cd main-0.1

[root@www main-0.1]# make clean main

[root@www main-0.1]# ./main

version 0.1

Please input your name: VBird

Please enter the degree angle (ex> 90): 45

Hi, Dear VBird, nice to meet you.

The Sin is:  0.71

The Cos is:  0.71

與之前的結果非常類似，只是鳥哥將 Makefile 直接給您了！但如果你下達 make install 時，系統會告知沒有 install 的 target 啊！而且版本是 0.1 也告知了。那麼如何更新到 0.2 版呢？透過這個 patch 檔案吧！這個檔案的內容有點像這樣：

- 查閱 patch file 內容

[root@www main-0.1]# vim ~/main_0.1_to_0.2.patch

diff -Naur main-0.1/cos_value.c main-0.2/cos_value.c

--- main-0.1/cos_value.c        2009-06-09 22:52:33.000000000 +0800

+++ main-0.2/cos_value.c        2009-06-12 00:45:10.000000000 +0800

@@ -6,5 +6,5 @@

{

float value;

....(底下省略)....

上面表格內有個底線的部分，那代表使用 diff 去比較時，被比較的兩個檔案所在路徑，這個路徑非常的重要喔！ 因為 patch 的基本語法如下：

patch -p數字 < patch_file

特別留意那個『 -p數字』，那是與 patch_file 裡面列出的檔名有關的資訊。假如在 patch_file 第一行寫的是這樣：

*** /home/guest/example/expatch.old

那麼當我下達『 patch -p0 < patch_file 』時，則更新的檔案是『 /home/guest/example/expatch.old 』，如果『 patch -p1 < patch_file』，則更新的檔案為『home/guest/example/expatch.old』，如果『patch -p4 < patch_file』則更新『expatch.old』，也就是說， -pxx 那個 xx 代表『拿掉幾個斜線(/)』的意思！這樣可以理解了嗎？ 好了，根據剛剛上頭的資料，我們可以發現比較的檔案是在 main-0.1/xxx 與 main-0.2/xxx ， 所以說，如果你是在 main-0.1 底下，並且想要處理更新時，就得要拿掉一個目錄 (因為並沒有 main-0.2 的目錄存在， 我們是在當前的目錄進行更新的！)，因此使用的是 -p1 才對喔！所以：

- 更新原始碼，並且重新編譯程式！

[root@www main-0.1]# patch -p1 < ../main_0.1_to_0.2.patch

patching file cos_value.c

patching file main.c

patching file Makefile

patching file sin_value.c

# 請注意，鳥哥目前所在目錄是在 main-0.1 底下喔！注意與 patch 檔案的相對路徑！

# 雖然有五個檔案，但其實只有四個檔案有修改過喔！上面顯示有改過的檔案！

[root@www main-0.1]# make clean main

[root@www main-0.1]# ./main

version 0.2

Please input your name: VBird

Please enter the degree angle (ex> 90): 45

Hi, Dear VBird, nice to meet you.

The sin(45.000000) is:  0.71

The cos(45.000000) is:  0.71

# 你可以發現，輸出的結果中版本變了，輸出資訊多了括號 () 喔！

[root@www main-0.1]# make install   <==將他安裝到 /usr/local/bin 給大家用

cp -a main /usr/local/bin

[root@www main-0.1]# main           <==直接輸入指令可執行！

[root@www main-0.1]# make uninstall <==移除此軟體！

rm -f /usr/local/bin/main

很有趣的練習吧！所以你只要下載 patch file 就能夠對你的軟體原始碼更新了！只不過更新了原始碼並非軟體就更新！你還是得要將該軟體進行編譯後，才會是最終正確的軟體喔！ 因為 patch 的功能主要僅只是更新原始碼檔案而已！切記切記！此外，如果你 patch 錯誤呢？沒關係的！我們的 patch 是可以還原的啊！透過『 patch -R < ../main_0.1_to_0.2.patch 』就可以還原啦！很有趣吧！

例題：

如果我有一個很舊版的軟體，這個軟體已經更新到很新的版本，例如核心，那麼我可以使用 patch file 來更新嗎？

答：

這個問題挺有趣的，首先，你必須要確定舊版本與新版本之間『確實有釋出 patch file 』才行，以 kernel 2.2.xx 及 2.4.xx 來說，這兩者基本上的架構已經不同了，所以兩者間是無法以 patch file 來更新的。不過， 2.4.xx 與 2.4.yy 就可以更新了。不過，因為 kernel 每次推出的 patch 檔案都僅針對前一個版本而已，所以假設要由 kernel 2.4.20 升級到 2.4.26 ，就必須要使用 patch 2.4.21, 2.4.22, 2.4.23, 2.4.24, 2.4.25, 2.4.26 六個檔案來『依序更新』才行喔！當然，如果有朋友幫你比對過 2.4.20 與 2.4.26 ，那你自然就可以使用該 patch file 來直接一次更新囉！

函式庫管理

在我們的 Linux 作業系統當中，函式庫是很重要的一個項目。 因為很多的軟體之間都會互相取用彼此提供的函式庫來進行特殊功能的運作， 例如很多需要驗證身份的程式都習慣利用 PAM 這個模組提供的驗證機制來實作，而很多網路連線機制則習慣利用 SSL 函式庫來進行連線加密的機制。所以說，函式庫的利用是很重要的。不過， 函式庫又依照是否被編譯到程式內部而分為動態與靜態函式庫，這兩者之間有何差異？哪一種函式庫比較好？ 底下我們就來談一談先！

動態與靜態函式庫

首先我們要知道的是，函式庫的類型有哪些？依據函式庫被使用的類型而分為兩大類，分別是靜態 (Static) 與動態 (Dynamic) 函式庫兩類。底下我們來談一談這兩種類行的函式庫吧！

- 靜態函式庫的特色：

- 副檔名：(副檔名為 .a)

這類的函式庫通常副檔名為 libxxx.a 的類型；

- 編譯行為：

這類函式庫在編譯的時候會直接整合到執行程式當中，所以利用靜態函式庫編譯成的檔案會比較大一些喔；

- 獨立執行的狀態：

這類函式庫最大的優點，就是編譯成功的可執行檔可以獨立執行，而不需要再向外部要求讀取函式庫的內容 (請參照動態函式庫的說明)。

- 升級難易度：

雖然執行檔可以獨立執行，但因為函式庫是直接整合到執行檔中， 因此若函式庫升級時，整個執行檔必須要重新編譯才能將新版的函式庫整合到程式當中。 也就是說，在升級方面，只要函式庫升級了，所有將此函式庫納入的程式都需要重新編譯！

- 動態函式庫的特色：

- 副檔名：(副檔名為 .so)

這類函式庫通常副檔名為 libxxx.so 的類型；

- 編譯行為：

動態函式庫與靜態函式庫的編譯行為差異挺大的。 與靜態函式庫被整個捉到程式中不同的，動態函式庫在編譯的時候，在程式裡面只有一個『指向 (Pointer)』的位置而已。也就是說，動態函式庫的內容並沒有被整合到執行檔當中，而是當執行檔要使用到函式庫的機制時， 程式才會去讀取函式庫來使用。由於執行檔當中僅具有指向動態函式庫所在的指標而已， 並不包含函式庫的內容，所以他的檔案會比較小一點。

- 獨立執行的狀態：

這類型的函式庫所編譯出來的程式不能被獨立執行， 因為當我們使用到函式庫的機制時，程式才會去讀取函式庫，所以函式庫檔案『必須要存在』才行，而且，函式庫的『所在目錄也不能改變』，因為我們的可執行檔裡面僅有『指標』亦即當要取用該動態函式庫時， 程式會主動去某個路徑下讀取，呵呵！所以動態函式庫可不能隨意移動或刪除，會影響很多相依的程式軟體喔！

- 升級難易度：

雖然這類型的執行檔無法獨立運作，然而由於是具有指向的功能， 所以，當函式庫升級後，執行檔根本不需要進行重新編譯的行為，因為執行檔會直接指向新的函式庫檔案 (前提是函式庫新舊版本的檔名相同喔！)。

目前的 Linux distribution 比較傾向於使用動態函式庫，因為如同上面提到的最重要的一點， 就是函式庫的升級方便！由於 Linux 系統裡面的軟體相依性太複雜了，如果使用太多的靜態函式庫，那麼升級某一個函式庫時， 都會對整個系統造成很大的衝擊！因為其他相依的執行檔也要同時重新編譯啊！ 這個時候動態函式庫可就有用多了，因為只要動態函式庫升級就好，其他的軟體根本無須變動。

那麼這些函式庫放置在哪裡呢？絕大多數的函式庫都放置在：/usr/lib, /lib 目錄下！ 此外，Linux 系統裡面很多的函式庫其實 kernel 就提供了，那麼 kernel 的函式庫放在哪裡？呵呵！就是在 /lib/modules 裡面啦！裡面的資料可多著呢！不過要注意的是， 不同版本的核心提供的函式庫差異性是挺大的，所以 kernel 2.4.xx 版本的系統不要想將核心換成 2.6.xx 喔！ 很容易由於函式庫的不同而導致很多原本可以執行的軟體無法順利運作呢！

ldconfig 與 /etc/ld.so.conf

在瞭解了動態與靜態函式庫，也知道我們目前的 Linux 大多是將函式庫做成動態函式庫之後，再來要知道的就是，那有沒有辦法增加函式庫的讀取效能？ 我們知道記憶體的存取速度是硬碟的好幾倍，所以，如果我們將常用到的動態函式庫先載入記憶體當中 (快取, cache)，如此一來，當軟體要取用動態函式庫時，就不需要從頭由硬碟裡面讀出囉！ 這樣不就可以增進動態函式庫的讀取速度？沒錯，是這樣的！這個時候就需要 ldconfig 與 /etc/ld.so.conf 的協助了。

如何將動態函式庫載入快取記憶體當中呢？

1. 首先，我們必須要在 /etc/ld.so.conf 裡面寫下『 想要讀入快取記憶體當中的動態函式庫所在的目錄』，注意喔， 是目錄而不是檔案；

2. 接下來則是利用 ldconfig 這個執行檔將 /etc/ld.so.conf 的資料讀入快取當中；

3. 同時也將資料記錄一份在 /etc/ld.so.cache 這個檔案當中吶！

圖 5.2.1、使用 ldconfig 預載入動態函式庫到記憶體中

事實上， ldconfig 還可以用來判斷動態函式庫的連結資訊呢！趕緊利用 CentOS 來測試看看。假設妳想要將目前你系統下的 MySQL 函式庫加入到快取當中時，可以這樣做：

[root@www ~]# ldconfig [-f conf] [ -C cache]

[root@www ~]# ldconfig [-p]

選項與參數：

-f conf ：那個 conf 指的是某個檔案名稱，也就是說，使用 conf 作為 libarary

函式庫的取得路徑，而不以 /etc/ld.so.conf 為預設值

-C cache：那個 cache 指的是某個檔案名稱，也就是說，使用 cache 作為快取暫存

的函式庫資料，而不以 /etc/ld.so.cache 為預設值

-p      ：列出目前有的所有函式庫資料內容 (在 /etc/ld.so.cache 內的資料！)

範例一：假設我的 MySQL 資料庫函式庫在 /usr/lib/mysql 當中，如何讀進 cache ？

[root@www ~]# vi /etc/ld.so.conf

include ld.so.conf.d/*.conf

/usr/lib/mysql   <==這一行新增的啦！

[root@www ~]# ldconfig  <==畫面上不會顯示任何的資訊，不要太緊張！正常的！

[root@www ~]# ldconfig -p

530 libs found in cache `/etc/ld.so.cache'

libz.so.1 (libc6) => /usr/lib/libz.so.1

libxslt.so.1 (libc6) => /usr/lib/libxslt.so.1

....(底下省略)....

#       函式庫名稱 => 該函式庫實際路徑

透過上面的動作，我們可以將 MySQL 的相關函式庫給他讀入快取當中，這樣可以加快函式庫讀取的效率呢！ 在某些時候，你可能會自行加入某些 Tarball 安裝的動態函式庫，而你想要讓這些動態函式庫的相關連結可以被讀入到快取當中， 這個時候你可以將動態函式庫所在的目錄名稱寫入 /etc/ld.so.conf 當中，然後執行 ldconfig 就可以啦！

程式的動態函式庫解析： ldd

說了這麼多，那麼我如何判斷某個可執行的 binary 檔案含有什麼動態函式庫呢？很簡單，利用 ldd 就可以曉得了！例如我想要知道 /usr/bin/passwd 這個程式含有的動態函式庫有哪些，可以這樣做：

[root@www ~]# ldd [-vdr] [filename]

選項與參數：

-v ：列出所有內容資訊；

-d ：重新將資料有遺失的 link 點秀出來！

-r ：將 ELF 有關的錯誤內容秀出來！

範例一：找出 /usr/bin/passwd 這個檔案的函式庫資料

[root@www ~]# ldd /usr/bin/passwd

....(前面省略)....

libaudit.so.0 => /lib/libaudit.so.0 (0x00494000)     <==SELinux

libselinux.so.1 => /lib/libselinux.so.1 (0x00101000) <==SELinux

libc.so.6 => /lib/libc.so.6 (0x00b99000)

libpam.so.0 => /lib/libpam.so.0 (0x004ab000)         <==PAM 模組

....(底下省略)....

# 我們前言的部分不是一直提到 passwd 有使用到 pam 的模組嗎！怎麼知道？

# 利用 ldd 察看一下這個檔案，看到 libpam.so 了吧？這就是 pam 提供的函式庫

範例二：找出 /lib/libc.so.6 這個函式的相關其他函式庫！

[root@www ~]# ldd -v /lib/libc.so.6

/lib/ld-linux.so.2 (0x00ab3000)

linux-gate.so.1 =>  (0x00636000)

Version information:  <==使用 -v 選項，增加顯示其他版本資訊！

/lib/libc.so.6:

ld-linux.so.2 (GLIBC_PRIVATE) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2

ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2

未來如果你常常升級安裝 RPM 的軟體時 (下一章節會介紹)，應該常常會發現那個『 相依屬性』的問題吧！沒錯！我們可以先以 ldd 來視察『相依函式庫』之間的相關性！以先取得瞭解！ 例如上面的例子中，我們檢查了 libc.so.6 這個在 /lib 當中的函式庫，結果發現他其實還跟 ld-linux.so.2 有關！所以我們就需要來瞭解一下，那個檔案到底是什麼軟體的函式庫呀？使用 -v 這個參數還可以得知該函式庫來自於哪一個軟體！像上面的資料中，就可以得到該 libc.so.6 其實可以支援 GLIBC_2.1 等的版本！

檢驗軟體正確性

前面提到很多升級與安裝需要注意的事項，因為我們需要克服很多的程式漏洞，所以需要前往 Linux distribution 或者是某些軟體開發商的網站，下載最新並且較安全的軟體檔案來安裝才行。 好了，那麼『有沒有可能我們下載的檔案本身就有問題？』 是可能的！因為 cracker 無所不在，很多的軟體開發商已經公布過他們的網頁所放置的檔案曾經被竄改過！ 那怎麼辦？連下載原版的資料都可能有問題了？難道沒有辦法判斷檔案的正確性嗎？

這個時候我們就要透過每個檔案獨特的指紋驗證資料了！因為每個檔案的內容與檔案大小都不相同， 所以如果一個檔案被修改之後，必然會有部分的資訊不一樣！利用這個咚咚，我們可以使用 MD5 這個指紋驗證機制來判斷該檔案有沒有被更動過！ 舉個例子來說，台灣高速網路中心所提供的 CentOS 5.3 原版光碟下載點：

http://ftp.twaren.net/Linux/CentOS/5.3/isos/i386/

同時提供了 CentOS 5.3 所有光碟/DVD 的 ISO 檔案 MD5 編碼，透過這個編碼的比對， 我們就可以曉得下載的檔案是否有問題。那麼萬一 CentOS 提供的光碟映象檔被下載之後，讓有心人士偷偷修改過，再轉到 Internet 上面流傳，那麼你下載的這個檔案偏偏不是原廠提供的，呵呵！ 你能保證該檔案的內容完全沒有問題嗎？當然不能對不對！是的，這個時候就有 md5sum 與 sha1sum 這個檔案指紋的咚咚出現啦！說說他的用法吧！

md5sum / sha1sum

目前有多種機制可以計算檔案的指紋碼，我們選擇使用較為廣泛的 MD5 與 SHA1 加密機制來處理。 同樣的，我們以高速電腦中心談到的 CentOS 5.3 的網路安裝映像檔來處理試看看好了。 在上面的連結網址上面，妳會看到幾個檔案：

- CentOS-5.3-i386-netinstall.iso：CentOS 5.3 的網路安裝映像檔；

- md5sum.txt： MD5 指紋編碼

- sha1sum.txt： SHA1 指紋編碼

如果妳下載了 CentOS-5.3-i386-netinstall.iso 後，再以 md5sum 與 sha1sum 去檢驗這個檔案時， 檔案所回傳的指紋碼應該要與網站上面提供的檔案指紋碼相同才對！我們由網站上面提供的指紋碼知道這個映像檔的指紋為：

- MD5 : 6ae4077a9fc2dcedca96013701bd2a43

- SHA1: a0c640ae0c68cc0d9558cf4f8855f24671b3dadb

[root@www ~]# md5sum/sha1sum [-bct] filename

[root@www ~]# md5sum/sha1sum [--status|--warn] --check filename

選項與參數：

-b ：使用 binary 的讀檔方式，預設為 Windows/DOS 檔案型態的讀取方式；

-c ：檢驗檔案指紋；

-t ：以文字型態來讀取檔案指紋。

範例一：將剛剛的檔案下載後，測試看看指紋碼

[root@www ~]# wget \

> http://ftp.twaren.net/Linux/CentOS/5.3/isos/i386/CentOS-5.3-i386-netinstall.iso

[root@www ~]# md5sum CentOS-5.3-i386-netinstall.iso

6ae4077a9fc2dcedca96013701bd2a43  CentOS-5.3-i386-netinstall.iso

[root@www ~]# sha1sum CentOS-5.3-i386-netinstall.iso

a0c640ae0c68cc0d9558cf4f8855f24671b3dadb  CentOS-5.3-i386-netinstall.iso

# 看！顯示的編碼是否與上面相同呢？趕緊測試看看！

一般而言，每個系統裡面的檔案內容大概都不相同，例如你的系統中的 /etc/passwd 這個登入資訊檔與我的一定不一樣，因為我們的使用者與密碼、 Shell 及家目錄等大概都不相同，所以由 md5sum 這個檔案指紋分析程式所自行計算出來的指紋表當然就不相同囉！

好了，那麼如何應用這個東西呢？基本上，你必須要在你的 Linux 系統上為你的這些重要的檔案進行指紋資料庫的建立 (好像在做戶口調查！)，將底下這些檔案建立資料庫：

- /etc/passwd

- /etc/shadow( 假如你不讓使用者改密碼了 )

- /etc/group

- /usr/bin/passwd

- /sbin/portmap

- /bin/login ( 這個也很容易被駭！ )

- /bin/ls

- /bin/ps

- /usr/bin/top

這幾個檔案最容易被修改了！因為很多木馬程式執行的時候，還是會有所謂的『執行序, PID』為了怕被 root 追查出來，所以他們都會修改這些檢查排程的檔案，如果你可以替這些檔案建立指紋資料庫 (就是使用 md5sum 檢查一次，將該檔案指紋記錄下來，然後常常以 shell script 的方式由程式自行來檢查指紋表是否不同了！)，那麼對於檔案系統會比較安全啦！

重點回顧

- 原始碼其實大多是純文字檔，需要透過編譯器的編譯動作後，才能夠製作出 Linux 系統能夠認識的可執行的 binary file ；

- 開放原始碼可以加速軟體的更新速度，讓軟體效能更快、漏洞修補更即時；

- 在 Linux 系統當中，最標準的 C 語言編譯器為 gcc ；

- 在編譯的過程當中，可以藉由其他軟體提供的函式庫來使用該軟體的相關機制與功能；

- 為了簡化編譯過程當中的複雜的指令輸入，可以藉由 make 與 makefile 規則定義，來簡化程式的更新、編譯與連結等動作；

- Tarball 為使用 tar 與 gzip/bzip2 壓縮功能所打包與壓縮的，具有原始碼的檔案；

- 一般而言，要使用 Tarball 管理 Linux 系統上的軟體，最好需要 gcc, make, autoconfig, kernel source, kernel header 等前驅軟體才行，所以在安裝 Linux 之初，最好就能夠選擇 Software development 以及 kernel development 之類的群組；

- 函式庫有動態函式庫與靜態函式庫，動態函式庫在升級上具有較佳的優勢。動態函式庫的副檔名為 *.so 而靜態則是 *.a ；

- patch 的主要功能在更新原始碼，所以更新原始碼之後，還需要進行重新編譯的動作才行；

- 可以利用 ldconfig 與 /etc/ld.so.conf 來製作動態函式庫的連結與快取！

- 透過 MD5 的編碼可以判斷下載的檔案是否為原本廠商所釋出的檔案。

本章習題

實作題部分：

- 請前往企鵝遊戲網站 http://xpenguins.seul.org/ 下載 xpenguins-2.2.tar.gz 原始碼檔案，並安裝該軟體。安裝完畢之後，請在 GNOME 圖形介面執行 xpenguins ， 看看有沒有出現如同官網上面出現的小企鵝？

情境模擬題部分：

- 請依照底下的方式來建置你的系統的重要檔案指紋碼，並每日比對此重要工作。

1. 將 /etc/{passwd,shadow,group} 以及系統上面所有的 SUID/SGID 檔案建立檔案列表，該列表檔名為『 important.file 』；

[root@www ~]# ls /etc/{passwd,shadow,group} > important.file

[root@www ~]# find /bin /sbin /usr/sbin /usr/bin -perm +6000 \

> >> important.file

1. 透過這個檔名列表，以名為 md5.checkfile.sh 的檔名去建立指紋碼，並將該指紋碼檔案『 finger1.file 』設定成為不可修改的屬性；

[root@www ~]# vim md5.checkfile.sh

#!/bin/bash

for filename in $(cat important.file)

do

md5sum $filename >> finger1.file

done

[root@www ~]# sh md5.checkfile.sh

[root@www ~]# chattr +i finger1.file

1. 透過相同的機制去建立後續的分析資料為 finger_new.file ，並將兩者進行比對，若有問題則提供 email 給 root 查閱：

[root@www ~]# vim md5.checkfile.sh

#!/bin/bash

if [ "$1" == "new" ]; then

for filename in $(cat important.file)

do

md5sum $filename >> finger1.file

done

echo "New file finger1.file is created."

exit 0

fi

if [ ! -f finger1.file ]; then

echo "file: finger1.file NOT exist."

exit 1

fi

[ -f finger_new.file ] && rm finger_new.file

for filename in $(cat important.file)

do

md5sum $filename >> finger_new.file

done

testing=$(diff finger1.file finger_new.file)

if [ "$testing" != "" ]; then

diff finger1.file finger_new.file | mail -s 'finger trouble..' root

fi

[root@www ~]# vim /etc/crontab

30 2 * * * root cd /root; sh md5.checkfile.sh

如此一來，每天系統會主動的去分析你認為重要的檔案之指紋資料，然後再加以分析，看看有沒有被更動過。 不過，如果該變動是正常的，例如 CentOS 自動的升級時，那麼你就得要刪除 finger1.file ， 再重新建置一個新的指紋資料庫才行！否則你會每天收到有問題信件的回報喔！

參考資料與延伸閱讀

- 註1：GNU 的 make 網頁：http://www.gnu.org/software/make/manual/make.html

- 幾種常見加密機制的全名：

md5 (Message-Digest algorithm 5) http://en.wikipedia.org/wiki/MD5

sha (Secure Hash Algorithm) http://en.wikipedia.org/wiki/SHA_hash_functions

des (Data Encryption Standard) http://en.wikipedia.org/wiki/Data_Encryption_Standard

- 洪朝貴老師的 C 程式語言：http://www.cyut.edu.tw/~ckhung/b/c/

2002/08/21：第一次完成

2003/02/11：重新編排與加入 FAQ

2004/03/25：原本是 Tarball 與 RPM ，本日開始將 Tarball 與 RPM  分開說明與講解(後續會花好幾天喔！)，

最重要的是 Source code 的說明，並提到相關的 gcc compile 功能等等！

2004/04/10：經歷了當兵中的無奈生活，終於將這篇給他完工了∼(當時的鳥哥在將軍漁港與青山港∼)

2005/09/30：舊版文章 (Tarball 與 RPM 的簡單說明) 移動到 此處 。

2005/10/01：將風格作個轉變之外，也將一些測試移轉到 FC4 上面進行！

2008/01/10：感謝網友 ayttk 的說明，原本的 make 語法網頁已經移動到其他地方了，請參考 這裡。

2009/06/04：將基於 FC4 撰寫的文章移動到 此處

2009/06/20：增加一個小練習，需要使用到 X software development 的軟體群組喔！

2009/09/15：加入一個情境模擬，其實有點功力練功練功而已的習題囉！

2002/05/08以來統計人數

第二十三章、軟體安裝： RPM, SRPM 與 YUM 功能

切換解析度為 800x600

最近更新日期：2009/09/18

雖然使用原始碼進行軟體編譯可以具有客製化的設定，但對於 Linux distribution 的發佈商來說，則有軟體管理不易的問題， 畢竟不是每個人都會進行原始碼編譯的。如果能夠將軟體預先在相同的硬體與作業系統上面編譯好才發佈的話， 不就能夠讓相同的 distribution 具有完全一致的軟體版本嗎？如果再加上簡易的安裝/移除/管理等機制的話， 對於軟體控管就會簡易的多。有這種東西嗎？有的，那就是 RPM 與 YUM 這兩個好用的咚咚。 既然這麼好用，我們當然不能錯過學習機會囉！趕緊來參詳參詳！

1. 軟體管理員簡介

1.1 Linux 界的兩大主流: RPM 與 DPKG

1.2 什麼是 RPM 與 SRPM

1.3 什麼是 i386, i586, i686, noarch, x86_64

1.4 RPM 的優點

1.5 RPM 屬性相依的克服方式： YUM 線上升級

2. RPM 軟體管理程式： rpm

2.1 RPM 預設安裝的路徑

2.2 RPM 安裝 (install)

2.3 RPM 升級與更新 (upgrade/freshen)

2.4 RPM 查詢 (query)

2.5 RPM 驗證與數位簽章 (Verify/signature)

2.6 RPM 反安裝與重建資料庫 (erase/rebuilddb)

3. SRPM 的使用： rpmbuild

3.1 利用預設值安裝 SRPM 檔案 (--rebuid/--recompile)

3.2 SRPM 使用的路徑與需要的軟體

3.3 設定檔的主要內容 (*.spec)

3.4 SRPM 的編譯指令 (-ba/-bb)

3.5 一個打包自己軟體的範例

4. YUM 線上升級機制

4.1 利用 yum 進行查詢、安裝、升級與移除功能

4.2 yum 的設定檔

4.3 yum 的軟體群組功能

4.4 全系統自動升級

5. 管理的抉擇：RPM 還是 Tarball

6. 重點回顧

7. 本章習題

8. 參考資料與延伸閱讀

9. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23893

軟體管理員簡介

在前一章我們提到以原始碼的方式來安裝軟體，也就是利用廠商釋出的 Tarball 來進行軟體的安裝。不過，你應該很容易發現，那就是每次安裝軟體都需要偵測作業系統與環境、設定編譯參數、實際的編譯、 最後還要依據個人喜好的方式來安裝軟體到定位。這過程是真的很麻煩的，而且對於不熟整個系統的朋友來說，還真是累人啊！

那有沒有想過，如果我的 Linux 系統與廠商的系統一模一樣，那麼在廠商的系統上面編譯出來的執行檔， 自然也就可以在我的系統上面跑囉！也就是說，廠商先在他們的系統上面編譯好了我們使用者所需要的軟體， 然後將這個編譯好的可執行的軟體直接釋出給使用者來安裝，如此一來，由於我們本來就使用廠商的 Linux distribution ，所以當然系統 (硬體與作業系統) 是一樣的，那麼使用廠商提供的編譯過的可執行檔就沒有問題啦！ 說的比較白話一些，那就是利用類似 Windows 的安裝方式，由程式開發者直接在已知的系統上面編譯好，再將該程式直接給使用者來安裝，如此而已。

那麼如果在安裝的時候還可以加上一些與這些程式相關的資訊，將他建立成為資料庫，那不就可以進行安裝、反安裝、 升級與驗證等等的相關功能囉 (類似 Windows 底下的『新增移除程式』)？確實如此，在 Linux 上面至少就有兩種常見的這方面的軟體管理員，分別是 RPM 與 Debian 的 dpkg 。我們的 CentOS 主要是以 RPM 為主，但也不能不知道 dpkg 啦！所以底下就來約略介紹一下這兩個玩意兒。

Linux 界的兩大主流: RPM 與 DPKG

由於自由軟體的蓬勃發展，加上大型 Unix-Like 主機的強大效能，讓很多軟體開發者將他們的軟體使用 Tarball 來釋出。 後來 Linux 發展起來後，由一些企業或社群將這些軟體收集起來製作成為 distributions 以發佈這好用的 Linux 作業系統。但後來發現到，這些 distribution 的軟體管理實在傷腦筋， 如果軟體有漏洞時，又該如何修補呢？使用 tarball 的方式來管理嗎？又常常不曉得到底我們安裝過了哪些程式？ 因此，一些社群與企業就開始思考 Linux 的軟體管理方式。

如同剛剛談過的方式，Linux 開發商先在固定的硬體平台與作業系統平台上面將需要安裝或升級的軟體編譯好， 然後將這個軟體的所有相關檔案打包成為一個特殊格式的檔案，在這個軟體檔案內還包含了預先偵測系統與相依軟體的腳本， 並提供記載該軟體提供的所有檔案資訊等。最終將這個軟體檔案釋出。用戶端取得這個檔案後，只要透過特定的指令來安裝， 那麼該軟體檔案就會依照內部的腳本來偵測相依的前驅軟體是否存在，若安裝的環境符合需求，那就會開始安裝， 安裝完成後還會將該軟體的資訊寫入軟體管理機制中，以達成未來可以進行升級、移除等動作呢。

目前在 Linux 界軟體安裝方式最常見的有兩種，分別是：

- dpkg：

這個機制最早是由 Debian Linux 社群所開發出來的，透過 dpkg 的機制， Debian 提供的軟體就能夠簡單的安裝起來，同時還能提供安裝後的軟體資訊，實在非常不錯。 只要是衍生於 Debian 的其他 Linux distributions 大多使用 dpkg 這個機制來管理軟體的， 包括 B2D, Ubuntu 等等。

- RPM：

這個機制最早是由 Red Hat 這家公司開發出來的，後來實在很好用，因此很多 distributions 就使用這個機制來作為軟體安裝的管理方式。包括 Fedora, CentOS, SuSE 等等知名的開發商都是用這咚咚。

如前所述，不論 dpkg/rpm 這些機制或多或少都會有軟體屬性相依的問題，那該如何解決呢？ 其實前面不是談到過每個軟體檔案都有提供相依屬性的檢查嗎？那麼如果我們將相依屬性的資料做成列表， 等到實際軟體安裝時，若發生有相依屬性的軟體狀況時，例如安裝 A 需要先安裝 B 與 C ，而安裝 B 則需要安裝 D 與 E 時，那麼當妳要安裝 A ，透過相依屬性列表，管理機制自動去取得 B, C, D, E 來同時安裝， 不就解決了屬性相依的問題嗎？

沒錯！您真聰明！目前新的 Linux 開發商都有提供這樣的『線上升級』機制，透過這個機制， 原版光碟就只有第一次安裝時需要用到而已，其他時候只要有網路，妳就能夠取得原本開發商所提供的任何軟體了呢！ 在 dpkg 管理機制上就開發出 APT 的線上升級機制，RPM 則依開發商的不同，有 Red Hat 系統的 yum ， SuSE 系統的 Yast Online Update (YOU)， Mandriva 的 urpmi 軟體等。

distribution 代表

軟體管理機制

使用指令

線上升級機制(指令)

Red Hat/Fedora

RPM

rpm, rpmbuild

YUM (yum)

Debian/Ubuntu

DPKG

dpkg

APT (apt-get)

我們這裡使用的是 CentOS 系統嘛！所以說：使用的軟體管理機制為 RPM 機制，而用來作為線上升級的方式則為 yum ！底下就讓我們來談談 RPM 與 YUM 的相關說明吧！

什麼是 RPM 與 SRPM

RPM 全名是『 RedHat Package Manager 』簡稱則為 RPM 啦！顧名思義，當初這個軟體管理的機制是由 Red Hat 這家公司發展出來的。 RPM 是以一種資料庫記錄的方式來將你所需要的軟體安裝到你的 Linux 系統的一套管理機制。

他最大的特點就是將你要安裝的軟體先編譯過， 並且打包成為 RPM 機制的包裝檔案，透過包裝好的軟體裡頭預設的資料庫記錄， 記錄這個軟體要安裝的時候必須具備的相依屬性軟體，當安裝在你的 Linux 主機時， RPM 會先依照軟體裡頭的資料查詢 Linux 主機的相依屬性軟體是否滿足， 若滿足則予以安裝，若不滿足則不予安裝。那麼安裝的時候就將該軟體的資訊整個寫入 RPM 的資料庫中，以便未來的查詢、驗證與反安裝！這樣一來的優點是：

1. 由於已經編譯完成並且打包完畢，所以軟體傳輸與安裝上很方便 (不需要再重新編譯)；

2. 由於軟體的資訊都已經記錄在 Linux 主機的資料庫上，很方便查詢、升級與反安裝

但是這也造成些許的困擾。由於 RPM 檔案是已經包裝好的資料，也就是說， 裡面的資料已經都『編譯完成』了！所以，該軟體檔案幾乎只能安裝在原本預設的硬體與作業系統版本中。 也就是說，妳的主機系統環境必須要與當初建立這個軟體檔案的主機環境相同才行！ 舉例來說，rp-pppoe 這個 ADSL 撥接軟體，他必須要在 ppp 這個軟體存在的環境下才能進行安裝！如果你的主機並沒有 ppp 這個軟體，那麼很抱歉，除非你先安裝 ppp 否則 rp-pppoe 就是不讓你安裝的 (當然你可以強制安裝，但是通常都會有點問題發生就是了！)。

所以，通常不同的 distribution 所釋出的 RPM 檔案，並不能用在其他的 distributions 上。舉例來說，Red Hat 釋出的 RPM 檔案，通常無法直接在 SuSE 上面進行安裝的。更有甚者，相同 distribution 的不同版本之間也無法互通，例如 CentOS 4.x 的 RPM 檔案就無法直接套用在 CentOS 5.x ！因此，這樣可以發現這些軟體管理機制的問題是：

1. 軟體檔案安裝的環境必須與打包時的環境需求一致或相當；

2. 需要滿足軟體的相依屬性需求；

3. 反安裝時需要特別小心，最底層的軟體不可先移除，否則可能造成整個系統的問題！

那怎麼辦？如果我真的想要安裝其他 distributions 提供的好用的 RPM 軟體檔案時？ 呵呵！還好，還有 SRPM 這個東西！SRPM 是什麼呢？顧名思義，他是 Source RPM 的意思，也就是這個 RPM 檔案裡面含有原始碼哩！特別注意的是，這個 SRPM 所提供的軟體內容『並沒有經過編譯』， 他提供的是原始碼喔！

通常 SRPM 的副檔名是以 ***.src.rpm 這種格式來命名的。不過，既然 SRPM 提供的是原始碼，那麼為什麼我們不使用 Tarball 直接來安裝就好了？這是因為 SRPM 雖然內容是原始碼， 但是他仍然含有該軟體所需要的相依性軟體說明、以及所有 RPM 檔案所提供的資料。同時，他與 RPM 不同的是，他也提供了參數設定檔 (就是 configure 與 makefile)。所以，如果我們下載的是 SRPM ，那麼要安裝該軟體時，你就必須要：

- 先將該軟體以 RPM 管理的方式編譯，此時 SRPM 會被編譯成為 RPM 檔案；

- 然後將編譯完成的 RPM 檔案安裝到 Linux 系統當中

怪了，怎麼 SRPM 這麼麻煩吶！還要重新編譯一次，那麼我們直接使用 RPM 來安裝不就好了？通常一個軟體在釋出的時候，都會同時釋出該軟體的 RPM 與 SRPM 。我們現在知道 RPM 檔案必須要在相同的 Linux 環境下才能夠安裝，而 SRPM 既然是原始碼的格式，自然我們就可以透過修改 SRPM 內的參數設定檔，然後重新編譯產生能適合我們 Linux 環境的 RPM 檔案，如此一來，不就可以將該軟體安裝到我們的系統當中，而不必與原作者打包的 Linux 環境相同了？這就是 SRPM 的用處了！

檔案格式

檔名格式

直接安裝與否

內含程式類型

可否修改參數並編譯

RPM

xxx.rpm

可

已編譯

不可

SRPM

xxx.src.rpm

不可

未編譯之原始碼

可

Tips:

為何說 CentOS 是『社群維護的企業版』呢？ Red Hat 公司的 RHEL 釋出後，連帶會將 SRPM 釋出。 社群的朋友就將這些 SRPM 收集起來並重新編譯成為所需要的軟體，再重複釋出成為 CentOS，所以才能號稱與 Red Hat 的 RHEL 企業版同步啊！真要感謝 SRPM 哩！如果妳想要理解 CentOS 是如何編譯一支程式的， 也能夠透過學習 SRPM 內含的編譯參數，來學習的啊！

什麼是 i386, i586, i686, noarch, x86_64

從上面的說明，現在我們知道 RPM 與 SRPM 的格式分別為：

xxxxxxxxx.rpm   <==RPM 的格式，已經經過編譯且包裝完成的 rpm 檔案；

xxxxx.src.rpm   <==SRPM的格式，包含未編譯的原始碼資訊。

那麼我們怎麼知道這個軟體的版本、適用的平台、編譯釋出的次數呢？只要透過檔名就可以知道了！例如 rp-pppoe-3.1-5.i386.rpm 這的檔案的意義為：

rp-pppoe -        3.1    -     5        .i386        .rpm

軟體名稱   軟體的版本資訊 釋出的次數 適合的硬體平台 副檔名

除了後面適合的硬體平台與副檔名外，主要是以『-』來隔開各個部分，這樣子可以很清楚的發現該軟體的名稱、 版本資訊、打包次數與操作的硬體平台！好了，來談一談每個不同的地方吧：

- 軟體名稱：

當然就是每一個軟體的名稱了！上面的範例就是 rp-pppoe 。

- 版本資訊：

每一次更新版本就需要有一個版本的資訊，否則如何知道這一版是新是舊？這裡通常又分為主版本跟次版本。以上面為例，主版本為 3 ，在主版本的架構下更動部分原始碼內容，而釋出一個新的版本，就是次版本啦！以上面為例，就是 1 囉！

- 釋出版本次數：

通常就是編譯的次數啦！那麼為何需要重複的編譯呢？這是由於同一版的軟體中，可能由於有某些 bug 或者是安全上的顧慮，所以必須要進行小幅度的 patch 或重設一些編譯參數。 設定完成之後重新編譯並打包成 RPM 檔案！因此就有不同的打包數出現了！

- 操作硬體平台：

這是個很好玩的地方，由於 RPM 可以適用在不同的操作平台上，但是不同的平台設定的參數還是有所差異性！ 並且，我們可以針對比較高階的 CPU 來進行最佳化參數的設定，這樣才能夠使用高階 CPU 所帶來的硬體加速功能。 所以就有所謂的 i386, i586, i686, x86_64 與 noarch 等的檔案名稱出現了！

平台名稱

適合平台說明

i386

幾乎適用於所有的 x86 平台，不論是舊的 pentum 或者是新的 Intel Core 2 與 K8 系列的 CPU 等等，都可以正常的工作！那個 i 指的是 Intel 相容的 CPU 的意思，至於 386 不用說，就是 CPU 的等級啦！

i586

就是針對 586 等級的電腦進行最佳化編譯。那是哪些 CPU 呢？包括 pentum 第一代 MMX CPU， AMD 的 K5, K6 系列 CPU (socket 7 插腳) 等等的 CPU 都算是這個等級；

i686

在 pentun II 以後的 Intel 系列 CPU ，及 K7 以後等級的 CPU 都屬於這個 686 等級！ 由於目前市面上幾乎僅剩 P-II 以後等級的硬體平台，因此很多 distributions 都直接釋出這種等級的 RPM 檔案。

x86_64

針對 64 位元的 CPU 進行最佳化編譯設定，包括 Intel 的 Core 2 以上等級 CPU ，以及 AMD 的 Athlon64 以後等級的 CPU ，都屬於這一類型的硬體平台。

noarch

就是沒有任何硬體等級上的限制。一般來說，這種類型的 RPM 檔案，裡面應該沒有 binary program 存在， 較常出現的就是屬於 shell script 方面的軟體。

- 受惠於目前 x86 系統的支援方面，新的 CPU 都能夠執行舊型 CPU 所支援的軟體，也就是說硬體方面都可以向下相容的， 因此最低等級的 i386 軟體可以安裝在所有的 x86 硬體平台上面，不論是 32 位元還是 64 位元。但是反過來說就不行了。舉例來說，目前硬體大多是 64 位元的等級，因此妳可以在該硬體上面安裝 x86_64 或 i386 等級的 RPM 軟體。但在你的舊型主機，例如 P-III/P-4 32 位元機器上面，就不能夠安裝 x86_64 的軟體！

根據上面的說明，其實我們只要選擇 i386 版本來安裝在你的 x86 硬體上面就肯定沒問題。但是如果強調效能的話， 還是選擇搭配你的硬體的 RPM 檔案吧！畢竟該軟體才有針對你的 CPU 硬體平台進行過參數最佳化的編譯嘛！

RPM 的優點

由於 RPM 是透過預先編譯並打包成為 RPM 檔案格式後，再加以安裝的一種方式，並且還能夠進行資料庫的記載。 所以 RPM 有以下的優點：

- RPM 內含已經編譯過的程式與設定檔等資料，可以讓使用者免除重新編譯的困擾；

- RPM 在被安裝之前，會先檢查系統的硬碟容量、作業系統版本等，可避免檔案被錯誤安裝；

- RPM 檔案本身提供軟體版本資訊、相依屬性軟體名稱、軟體用途說明、軟體所含檔案等資訊，便於瞭解軟體；

- RPM 管理的方式使用資料庫記錄 RPM 檔案的相關參數，便於升級、移除、查詢與驗證。

為什麼 RPM 在使用上很方便呢？我們前面提過， RPM 這個軟體管理員所處理的軟體，是由軟體提供者在特定的 Linux 作業平台上面將該軟體編譯完成並且打包好。那使用者只要拿到這個打包好的軟體， 然後將裡頭的檔案放置到應該要擺放的目錄，不就完成安裝囉？對啦！就是這樣！

但是有沒有想過，我們在前一章裡面提過的，有些軟體是有相關性的，例如要安裝網路卡驅動程式，就得要有 kernel source 與 gcc 及 make 等軟體。那麼我們的 RPM 軟體是否一定可以安裝完成呢？如果該軟體安裝之後，卻找不到他相關的前驅軟體， 那不是挺麻煩的嗎？因為安裝好的軟體也無法使用啊！

為了解決這種具有相關性的軟體之間的問題 (就是所謂的軟體相依屬性)，RPM 就在提供打包的軟體時，同時加入一些訊息登錄的功能，這些訊息包括軟體的版本、 打包軟體者、相依屬性的其他軟體、本軟體的功能說明、本軟體的所有檔案記錄等等，然後在 Linux 系統上面亦建立一個 RPM 軟體資料庫，如此一來，當你要安裝某個以 RPM 型態提供的軟體時，在安裝的過程中， RPM 會去檢驗一下資料庫裡面是否已經存在相關的軟體了， 如果資料庫顯示不存在，那麼這個 RPM 檔案『預設』就不能安裝。呵呵！沒有錯，這個就是 RPM 類型的檔案最為人所詬病的『軟體的屬性相依』問題啦！

RPM 屬性相依的克服方式： YUM 線上升級

為了重複利用既有的軟體功能，因此很多軟體都會以函式庫的方式釋出部分功能，以方便其他軟體的呼叫應用， 例如 PAM 模組的驗證功能。此外，為了節省使用者的資料量，目前的 distributions 在釋出軟體時， 都會將軟體的內容分為一般使用與開發使用 (development) 兩大類。所以妳才會常常看到有類似 pam-x.x.rpm 與 pam-devel-x.x.rpm 之類的檔名啊！而預設情況下，大部分的 software-devel-x.x.rpm 都不會安裝，因為終端用戶大部分不會去開發軟體嘛！

因為有上述的現象，因此 RPM 軟體檔案就會有所謂的屬性相依的問題產生 (其實所有的軟體管理幾乎都有這方面的情況存在)。 那有沒有辦法解決啊？前面不是談到 RPM 軟體檔案內部會記錄相依屬性的資料嗎？那想一想，要是我將這些相依屬性的軟體先列表， 在有要安裝軟體需求的時候，先到這個列表去找，同時與系統內已安裝的軟體相比較，沒安裝到的相依軟體就一口氣同時安裝起來， 那不就解決了相依屬性的問題了嗎？有沒有這種機制啊？有啊！那就是 YUM 機制的由來！

CentOS 先將釋出的軟體放置到 YUM 伺服器內，然後分析這些軟體的相依屬性問題，將軟體內的記錄資訊寫下來 (header)。 然後再將這些資訊分析後記錄成軟體相關性的清單列表。這些列表資料與軟體所在的位置可以稱呼為容器 (repository)。 當用戶端有軟體安裝的需求時，用戶端主機會主動的向網路上面的 yum 伺服器的容器網址下載清單列表， 然後透過清單列表的資料與本機 RPM 資料庫已存在的軟體資料相比較，就能夠一口氣安裝所有需要的具有相依屬性的軟體了。 整個流程可以簡單的如下圖說明：

圖 1.5.1、YUM 使用的流程示意圖

當用戶端有升級、安裝的需求時， yum 會向容器要求清單的更新，等到清單更新到本機的 /var/cache/yum 裡面後， 等一下更新時就會用這個本機清單與本機的 RPM 資料庫進行比較，這樣就知道該下載什麼軟體。接下來 yum 會跑到容器伺服器 (yum server) 下載所需要的軟體，然後再透過 RPM 的機制開始安裝軟體啦！這就是整個流程！ 談到最後，還是需要動到 RPM 的啦！所以下個小節就讓我們來談談 RPM 這咚咚吧！

Tips:

為什麼要做出『容器』呢？由於 yum 伺服器提供的 RPM 檔案內容可能有所差異，舉例來說，原廠釋出的資料有 (1)原版資料； (2)更新資料 (update)； (3)特殊資料 (例如第三方協力軟體，或某些特殊功能的軟體)。 這些軟體檔案基本上不會放置到一起，那如何分辨這些軟體功能呢？就用『容器』的概念來處理的啦！ 不同的『容器』網址，可以放置不同的軟體功能之意！

RPM 軟體管理程式： rpm

RPM 的使用其實不難，只要使用 rpm 這個指令即可！鳥哥最喜歡的就是 rpm 指令的查詢功能了，可以讓我很輕易的就知道某個系統有沒有安裝鳥哥要的軟體呢！此外， 我們最好還是得要知道一下，到底 RPM 類型的檔案他們是將軟體的相關檔案放置在哪裡呢？還有，我們說的那個 RPM 的資料庫又是放置在哪裡呢？

RPM 預設安裝的路徑

一般來說，RPM 類型的檔案在安裝的時候，會先去讀取檔案內記載的設定參數內容，然後將該資料用來比對 Linux 系統的環境，以找出是否有屬性相依的軟體尚未安裝的問題。例如 Openssh 這個連線軟體需要透過 Openssl 這個加密軟體的幫忙，所以得先安裝 openssl 才能裝 openssh 的意思。那你的環境如果沒有 openssl ， 妳就無法安裝 openssh 的意思啦。

若環境檢查合格了，那麼 RPM 檔案就開始被安裝到你的 Linux 系統上。安裝完畢後，該軟體相關的資訊就會被寫入 /var/lib/rpm/ 目錄下的資料庫檔案中了。 上面這個目錄內的資料很重要喔！因為未來如果我們有任何軟體升級的需求，版本之間的比較就是來自於這個資料庫， 而如果妳想要查詢系統已經安裝的軟體，也是從這裡查詢的！同時，目前的 RPM 也提供數位簽章資訊， 這些數位簽章也是在這個目錄內記錄的呢！所以說，這個目錄得要注意不要被刪除了啊！

那麼軟體內的檔案到底是放置到哪裡去啊？當然與檔案系統有關對吧！我們在第六章的目錄配置談過每個目錄的意義， 這裡再次的強調囉：

/etc

一些設定檔放置的目錄，例如 /etc/crontab

/usr/bin

一些可執行檔案

/usr/lib

一些程式使用的動態函式庫

/usr/share/doc

一些基本的軟體使用手冊與說明檔

/usr/share/man

一些 man page 檔案

好了，底下我們就來針對每個 RPM 的相關指令來進行說明囉！

RPM 安裝 (install)

因為安裝軟體是 root 的工作，因此妳得要是 root 的身份才能夠操作 rpm 這指令的。 用 rpm 來安裝很簡單啦！假設我要安裝一個檔名為 rp-pppoe-3.5-32.1.i386.rpm 的檔案，那麼我可以這樣：

[root@www ~]# rpm -i rp-pppoe-3.5-32.1.i386.rpm

不過，這樣的參數其實無法顯示安裝的進度，所以，通常我們會這樣下達安裝指令：

[root@www ~]# rpm -ivh package_name

選項與參數：

-i ：install 的意思

-v ：察看更細部的安裝資訊畫面

-h ：以安裝資訊列顯示安裝進度

範例一：安裝 rp-pppoe-3.5-32.1.i386.rpm

[root@www ~]# rpm -ivh rp-pppoe-3.5-32.1.i386.rpm

Preparing...     ####################################### [100%]

1:rp-pppoe    ####################################### [100%]

範例二、一口氣安裝兩個以上的軟體時：

[root@www ~]# rpm -ivh a.i386.rpm b.i386.rpm *.rpm

# 後面直接接上許多的軟體檔案！

範例三、直接由網路上面的某個檔案安裝，以網址來安裝：

[root@www ~]# rpm -ivh http://website.name/path/pkgname.rpm

另外，如果我們在安裝的過程當中發現問題，或者已經知道會發生的問題， 而還是『執意』要安裝這個軟體時，可以使用如下的參數『強制』安裝上去：

rpm 安裝時常用的選項與參數說明

可下達的選項

代表意義

--nodeps

使用時機：當發生軟體屬性相依問題而無法安裝，但你執意安裝時

危險性： 軟體會有相依性的原因是因為彼此會使用到對方的機制或功能，如果強制安裝而不考慮軟體的屬性相依， 則可能會造成該軟體的無法正常使用！

--replacefiles

使用時機： 如果在安裝的過程當中出現了『某個檔案已經被安裝在你的系統上面』的資訊，又或許出現版本不合的訊息 (confilcting files) 時，可以使用這個參數來直接覆蓋檔案。

危險性： 覆蓋的動作是無法復原的！所以，你必須要很清楚的知道被覆蓋的檔案是真的可以被覆蓋喔！否則會欲哭無淚！

--replacepkgs

使用時機： 重新安裝某個已經安裝過的軟體！如果妳要安裝一堆 RPM 軟體檔案時，可以使用 rpm -ivh *.rpm ，但若某些軟體已經安裝過了， 此時系統會出現『某軟體已安裝』的資訊，導致無法繼續安裝。此時可使用這個選項來重複安裝喔！

--force

使用時機：這個參數其實就是 --replacefiles 與 --replacepkgs 的綜合體！

--test

使用時機： 想要測試一下該軟體是否可以被安裝到使用者的 Linux 環境當中，可找出是否有屬性相依的問題。範例為：

rpm -ivh pkgname.i386.rpm --test

--justdb

使用時機： 由於 RPM 資料庫破損或者是某些緣故產生錯誤時，可使用這個選項來更新軟體在資料庫內的相關資訊。

--nosignature

使用時機： 想要略過數位簽章的檢查時，可以使用這個選項。

--prefix 新路徑

使用時機： 要將軟體安裝到其他非正規目錄時。舉例來說，妳想要將某軟體安裝到 /usr/local 而非正規的 /bin, /etc 等目錄， 就可以使用『 --prefix /usr/local 』來處理了。

--noscripts

使用時機：不想讓該軟體在安裝過程中自行執行某些系統指令。

說明： RPM 的優點除了可以將檔案放置到定位之外，還可以自動執行一些前置作業的指令，例如資料庫的初始化。 如果你不想要讓 RPM 幫你自動執行這一類型的指令，就加上他吧！

一般來說，rpm 的安裝選項與參數大約就是這些了。通常鳥哥建議直接使用 -ivh 就好了， 如果安裝的過程中發現問題，一個一個去將問題找出來，盡量不要使用『 暴力安裝法 』，就是透過 --force 去強制安裝！ 因為可能會發生很多不可預期的問題呢！除非你很清楚的知道使用上面的參數後，安裝的結果是你預期的！

例題：

在沒有網路的前提下，妳想要安裝一個名為 pam-devel 的軟體，妳手邊只有原版光碟，該如何是好？

答：

妳可以透過掛載原版光碟來進行資料的查詢與安裝。請將原版光碟放入光碟機，底下我們嘗試將光碟掛載到 /media 當中， 並據以處理軟體的下載囉：

- 掛載光碟，使用： mount /dev/cdrom /media

- 找出檔案的實際路徑：find /media -name 'pam-devel*'

- 測試此軟體是否具有相依性： rpm -ivh pam-devel... --test

- 直接安裝： rpm -ivh pam-devel...

- 卸載光碟： umount /dev/cdrom

在鳥哥的系統中，剛好這個軟體並沒有屬性相依的問題，因此最後一個步驟可以順利的進行下去呢！

RPM 升級與更新 (upgrade/freshen)

使用 RPM 來升級真是太簡單了！就以 -Uvh 或 -Fvh 來升級即可，而 -Uvh 與 -Fvh 可以用的選項與參數，跟 install 是一樣的。不過， -U 與 -F 的意義還是不太一樣的，基本的差別是這樣的：

-Uvh

後面接的軟體即使沒有安裝過，則系統將予以直接安裝； 若後面接的軟體有安裝過舊版，則系統自動更新至新版；

-Fvh

如果後面接的軟體並未安裝到你的 Linux 系統上，則該軟體不會被安裝；亦即只有已安裝至你 Linux 系統內的軟體會被『升級』！

由上面的說明來看，如果你想要大量的升級系統舊版本的軟體時，使用 -Fvh 則是比較好的作法，因為沒有安裝的軟體才不會被不小心安裝進系統中。但是需要注意的是，如果你使用的是 -Fvh ，偏偏你的機器上尚無這一個軟體，那麼很抱歉，該軟體並不會被安裝在你的 Linux 主機上面，所以請重新以 ivh 來安裝吧！

通常有的朋友在進行整個作業系統的舊版軟體修補時，喜歡這麼進行：

1. 先到各發展商的 errata 網站或者是國內的 FTP 映像站捉下來最新的 RPM 檔案；

2. 使用 -Fvh 來將你的系統內曾安裝過的軟體進行修補與升級！(真是方便呀！)

所以，在不曉得 yum 功能的情況下，妳依舊可以到 CentOS 的映設站台下載 updates 資料，然後利用上述的方法來一口氣升級！ 當然囉，升級也是可以利用 --nodeps/--force 等等的參數啦！

RPM 查詢 (query)

RPM 在查詢的時候，其實查詢的地方是在 /var/lib/rpm/ 這個目錄下的資料庫檔案啦！另外， RPM 也可以查詢未安裝的 RPM 檔案內的資訊喔！那如何去查詢呢？ 我們先來談談可用的選項有哪些？

[root@www ~]# rpm -qa                              <==已安裝軟體

[root@www ~]# rpm -q[licdR] 已安裝的軟體名稱       <==已安裝軟體

[root@www ~]# rpm -qf 存在於系統上面的某個檔名     <==已安裝軟體

[root@www ~]# rpm -qp[licdR] 未安裝的某個檔案名稱  <==查閱RPM檔案

選項與參數：

查詢已安裝軟體的資訊：

-q  ：僅查詢，後面接的軟體名稱是否有安裝；

-qa ：列出所有的，已經安裝在本機 Linux 系統上面的所有軟體名稱；

-qi ：列出該軟體的詳細資訊 (information)，包含開發商、版本與說明等；

-ql ：列出該軟體所有的檔案與目錄所在完整檔名 (list)；

-qc ：列出該軟體的所有設定檔 (找出在 /etc/ 底下的檔名而已)

-qd ：列出該軟體的所有說明檔 (找出與 man 有關的檔案而已)

-qR ：列出與該軟體有關的相依軟體所含的檔案 (Required 的意思)

-qf ：由後面接的檔案名稱，找出該檔案屬於哪一個已安裝的軟體；

查詢某個 RPM 檔案內含有的資訊：

-qp[icdlR]：注意 -qp 後面接的所有參數以上面的說明一致。但用途僅在於找出

某個 RPM 檔案內的資訊，而非已安裝的軟體資訊！注意！

在查詢的部分，所有的參數之前都需要加上 -q 才是所謂的查詢！查詢主要分為兩部分， 一個是查已安裝到系統上面的的軟體資訊，這部份的資訊都是由 /var/lib/rpm/ 所提供。另一個則是查某個 rpm 檔案內容， 等於是由 RPM 檔案內找出一些要寫入資料庫內的資訊就是了，這部份就得要使用 -qp (p 是 package 的意思)。 那就來看看幾個簡單的範例吧！

範例一：找出你的 Linux 是否有安裝 logrotate 這個軟體？

[root@www ~]# rpm -q logrotate

logrotate-3.7.4-8

[root@www ~]# rpm -q logrotating

package logrotating is not installed

# 注意到，系統會去找是否有安裝後面接的軟體名稱。注意，

# 不必要加上版本喔！至於顯示的結果，一看就知道有沒有安裝啦！

範例二：列出上題當中，屬於該軟體所提供的所有目錄與檔案：

[root@www ~]# rpm -ql logrotate

/etc/cron.daily/logrotate

/etc/logrotate.conf

....(以下省略)....

# 可以看出該軟體到底提供了多少的檔案與目錄，也可以追蹤軟體的資料。

範例三：列出 logrotate 這個軟體的相關說明資料：

[root@www ~]# rpm -qi logrotate

Name        : logrotate             Relocations: (not relocatable)

Version     : 3.7.4                      Vendor: CentOS

Release     : 8                      Build Date: Sun 02 Dec 2007 08:38:06 AM CST

Install Date: Sat 09 May 2009 11:59:05 PM CST    Build Host: builder6

Group       : System Environment/Base  Source RPM: logrotate-3.7.4-8.src.rpm

Size        : 53618                     License: GPL

Signature   : DSA/SHA1, Sun 02 Dec 2007 09:10:01 AM CST, Key ID a8a447dce8562897

Summary     : Rotates, compresses, removes and mails system log files.

Description :

The logrotate utility is designed to simplify the administration of

log files on a system which generates a lot of log files.  Logrotate

allows for the automatic rotation compression, removal and mailing of

log files.  Logrotate can be set to handle a log file daily, weekly,

monthly or when the log file gets to a certain size.  Normally,

logrotate runs as a daily cron job.

Install the logrotate package if you need a utility to deal with the

log files on your system.

# 列出該軟體的 information (資訊)，裡面的資訊可多著呢，包括了軟體名稱、

# 版本、開發商、SRPM檔案名稱、打包次數、簡單說明資訊、軟體打包者、

# 安裝日期等等！如果想要詳細的知道該軟體的資料，用這個參數來瞭解一下

範例四：分別僅找出 logrotate 的設定檔與說明檔

[root@www ~]# rpm -qc logrotate

[root@www ~]# rpm -qd logrotate

範例五：若要成功安裝 logrotate ，他還需要什麼檔案的幫忙？

[root@www ~]# rpm -qR logrotate

/bin/sh

config(logrotate) = 3.7.4-8

libc.so.6

....(以下省略)....

# 由這裡看起來，呵呵∼還需要很多檔案的支援才行喔！

範例六：由上面的範例五，找出 /bin/sh 是那個軟體提供的？

[root@www ~]# rpm -qf /bin/sh

bash-3.2-21.el5

# 這個參數後面接的可是『檔案』吶！不像前面都是接軟體喔！

# 這個功能在查詢系統的某個檔案屬於哪一個軟體所有的。

範例七：假設我有下載一個 RPM 檔案，想要知道該檔案的需求檔案，該如何？

[root@www ~]# rpm -qpR filename.i386.rpm

# 加上 -qpR ，找出該檔案需求的資料！

常見的查詢就是這些了！要特別說明的是，在查詢本機上面的 RPM 軟體相關資訊時， 不需要加上版本的名稱，只要加上軟體名稱即可！因為他會由 /var/lib/rpm 這個資料庫裡面去查詢， 所以我們可以不需要加上版本名稱。但是查詢某個 RPM 檔案就不同了，我們必須要列出整個檔案的完整檔名才行∼ 這一點朋友們常常會搞錯。底下我們就來做幾個簡單的練習吧！

例題：

1. 我想要知道我的系統當中，以 c 開頭的軟體有幾個，如何實做？

2. 我的 WWW 伺服器為 Apache ，我知道他使用的 RPM 軟體檔名為 httpd 。現在，我想要知道這個軟體的所有設定檔放置在何處，可以怎麼作？

3. 承上題，如果查出來的設定檔案已經被我改過，但是我忘記了曾經修改過哪些地方，所以想要直接重新安裝一次該軟體，該如何作？

4. 如果我誤砍了某個重要檔案，例如 /etc/crontab，偏偏不曉得他屬於哪一個軟體，該怎麼辦？

答：

2. rpm -qa | grep ^c | wc -l

3. rpm -qc httpd

4. 假設該軟體在網路上的網址為：

http://web.site.name/path/httpd-x.x.xx.i386.rpm

則我可以這樣做：

rpm -ivh http://web.site.name/path/httpd-x.x.xx.i386.rpm --replacepkgs

5. 雖然已經沒有這個檔案了，不過沒有關係，因為 RPM 有記錄在 /var/lib/rpm 當中的資料庫啊！所以直接下達：

rpm -qf /etc/crontab

就可以知道是那個軟體囉！重新安裝一次該軟體即可！

RPM 驗證與數位簽章 (Verify/signature)

驗證 (Verify) 的功能主要在於提供系統管理員一個有用的管理機制！作用的方式是『使用 /var/lib/rpm 底下的資料庫內容來比對目前 Linux 系統的環境下的所有軟體檔案 』也就是說，當你有資料不小心遺失， 或者是因為你誤殺了某個軟體的檔案，或者是不小心不知道修改到某一個軟體的檔案內容， 就用這個簡單的方法來驗證一下原本的檔案系統吧！好讓你瞭解這一陣子到底是修改到哪些檔案資料了！驗證的方式很簡單：

[root@www ~]# rpm -Va

[root@www ~]# rpm -V  已安裝的軟體名稱

[root@www ~]# rpm -Vp 某個 RPM 檔案的檔名

[root@www ~]# rpm -Vf 在系統上面的某個檔案

選項與參數：

-V  ：後面加的是軟體名稱，若該軟體所含的檔案被更動過，才會列出來；

-Va ：列出目前系統上面所有可能被更動過的檔案；

-Vp ：後面加的是檔案名稱，列出該軟體內可能被更動過的檔案；

-Vf ：列出某個檔案是否被更動過∼

範例一：列出你的 Linux 內的 logrotate 這個軟體是否被更動過？

[root@www ~]# rpm -V logrotate

# 如果沒有出現任何訊息，恭喜你，該軟體所提供的檔案沒有被更動過。

# 如果有出現任何訊息，才是有出現狀況啊！

範例二：查詢一下，你的 /etc/crontab 是否有被更動過？

[root@www ~]# rpm -Vf /etc/crontab

S.5....T  c /etc/crontab

# 瞧！因為有被更動過，所以會列出被更動過的資訊類型！

好了，那麼我怎麼知道到底我的檔案被更動過的內容是什麼？例如上面的範例二。呵呵！簡單的說明一下吧！ 例如，我們檢查一下 logrotate 這個軟體：

[root@www ~]# rpm -ql logrotate

/etc/cron.daily/logrotate

/etc/logrotate.conf

/etc/logrotate.d

/usr/sbin/logrotate

/usr/share/doc/logrotate-3.7.4

/usr/share/doc/logrotate-3.7.4/CHANGES

/usr/share/man/man8/logrotate.8.gz

/var/lib/logrotate.status

# 呵呵！共有八個檔案啊！請修改 /etc/logrotate.conf 內的 rotate 變成 5

[root@www ~]# rpm -V logrotate

..5....T  c /etc/logrotate.conf

妳會發現在檔名之前有個 c ，然後就是一堆奇怪的文字了。那個 c 代表的是 configuration ， 就是設定檔的意思。至於最前面的八個資訊是：

- S ：(file Size differs) 檔案的容量大小是否被改變

- M ：(Mode differs) 檔案的類型或檔案的屬性 (rwx) 是否被改變？如是否可執行等參數已被改變

- 5 ：(MD5 sum differs) MD5 這一種指紋碼的內容已經不同

- D ：(Device major/minor number mis-match) 裝置的主/次代碼已經改變

- L ：(readLink(2) path mis-match) Link 路徑已被改變

- U ：(User ownership differs) 檔案的所屬人已被改變

- G ：(Group ownership differs) 檔案的所屬群組已被改變

- T ：(mTime differs) 檔案的建立時間已被改變

所以，如果當一個設定檔所有的資訊都被更動過，那麼他的顯示就會是：

SM5DLUGT c filename

至於那個 c 代表的是『 Config file 』的意思，也就是檔案的類型，檔案類型有底下這幾類：

- c ：設定檔 (config file)

- d ：文件資料檔 (documentation)

- g ：鬼檔案∼通常是該檔案不被某個軟體所包含，較少發生！(ghost file)

- l ：授權檔案 (license file)

- r ：讀我檔案 (read me)

經過驗證的功能，你就可以知道那個檔案被更動過。那麼如果該檔案的變更是『預期中的』， 那麼就沒有什麼大問題，但是如果該檔案是『非預期的』，那麼是否被入侵了呢？呵呵！得注意注意囉！ 一般來說，設定檔 (configure) 被更動過是很正常的，萬一你的 binary program 被更動過呢？ 那就得要特別特別小心啊！

Tips:

雖說家醜不可外揚，不過有件事情還是跟大家分享一下的好。鳥哥之前的主機曾經由於安裝一套軟體，導致被攻擊成為跳板。 會發現的原因是系統中只要出現 *.patch 的副檔名時，使用 ls -l 就是顯示不出來該檔名 (該檔名確實存在)。 找了好久，用了好多工具都找不出問題，最終利用 rpm -Va 找出來，原來好多 binary program 被更動過，連 init 都被惡搞！此時，趕緊重新安裝 Linux 並移除那套軟體，之後就比較正常了。所以說，這個 rpm -Va 是個好功能喔！

- 數位簽章 (digital signature)

談完了軟體的驗證後，不知道你有沒有發現一個問題，那就是，驗證只能驗證軟體內的資訊與 /var/lib/rpm/ 裡面的資料庫資訊而已，如果該軟體檔案所提供的資料本身就有問題，那你使用驗證的手段也無法確定該軟體的正確性啊！ 那如何解決呢？在 Tarball 與檔案的驗證方面，我們可以使用前一章談到的 md5 指紋碼來檢查， 不過，連指紋碼也可能會被竄改的嘛！那怎辦？沒關係，我們可以透過數位簽章來檢驗軟體的來源的！

就像你自己的簽名一樣，我們的軟體開發商原廠所推出的軟體也會有一個廠商自己的簽章系統！ 只是這個簽章被數位化了而已。廠商可以數位簽章系統產生一個專屬於該軟體的簽章，並將該簽章的公鑰 (public key) 釋出。 當你要安裝一個 RPM 檔案時：

1. 首先你必須要先安裝原廠釋出的公鑰檔案；

2. 實際安裝原廠的 RPM 軟體時， rpm 指令會去讀取 RPM 檔案的簽章資訊，與本機系統內的簽章資訊比對，

3. 若簽章相同則予以安裝，若找不到相關的簽章資訊時，則給予警告並且停止安裝喔。

我們 CentOS 使用的數位簽章系統為 GNU 計畫的 GnuPG (GNU Privacy Guard, GPG)(註1)。 GPG 可以透過雜湊運算，算出獨一無二的專屬金鑰系統或者是數位簽章系統，有興趣的朋友可以參考文末的延伸閱讀， 去瞭解一下 GPG 加密的機制喔！這裡我們僅簡單的說明數位簽章在 RPM 檔案上的應用而已。 而根據上面的說明，我們也會知道首先必須要安裝原廠釋出的 GPG 數位簽章的公鑰檔案啊！CentOS 的數位簽章位於：

[root@www ~]# ll /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

-rw-r--r-- 1 root root 1504  6月 19  2008 /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

[root@www ~]# cat /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

-----BEGIN PGP PUBLIC KEY BLOCK-----

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfB6MRBACrnYW6yKMT+MwJlCIhoyTxGf3mAxmnAiDEy6HcYN8rivssVTJk

....(中間省略)....

-----END PGP PUBLIC KEY BLOCK-----

從上面的輸出，你會知道該數位簽章碼其實僅是一個亂數而已，這個亂數對於數位簽章有意義而已， 我們看不懂啦！那麼這個檔案如何安裝呢？透過底下的方式來安裝即可喔！

[root@www ~]# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

由於不同版本 GPG 金鑰檔案放置的位置可能不同，不過檔名大多是以 GPG-KEY 來說明的， 因此你可以簡單的使用 locate 或 find 來找尋，如以下的方式來搜尋即可：

[root@www ~]# locate GPG-KEY

[root@www ~]# find /etc -name '*GPG-KEY*'

那安裝完成之後，這個金鑰的內容會以什麼方式呈現呢？基本上都是使用 pubkey 作為軟體的名稱的！ 那我們先列出金鑰軟體名稱後，再以 -qi 的方式來查詢看看該軟體的資訊為何：

[root@www ~]# rpm -qa | grep pubkey

gpg-pubkey-e8562897-459f07a4

[root@www ~]# rpm -qi gpg-pubkey-e8562897-459f07a4

Name        : gpg-pubkey        Relocations: (not relocatable)

Version     : e8562897               Vendor: (none)

Release     : 459f07a4           Build Date: Wed 27 May 2009 10:07:26 PM CST

Install Date: Wed 27 May 2009 10:07:26 PM CST   Build Host: localhost

Group       : Public Keys        Source RPM: (none)

Size        : 0                     License: pubkey

Signature   : (none)

Summary     : gpg(CentOS-5 Key <centos-5-key@centos.org>)

Description :

-----BEGIN PGP PUBLIC KEY BLOCK-----

Version: rpm-4.4.2 (beecrypt-4.1.2)

....(底下省略)....

重點就是最後面出現的那一串亂碼啦！那可是作為數位簽章非常重要的一環哩！ 如果你忘記加上數位簽章，很可能很多原版軟體就不能讓你安裝囉∼除非你利用 rpm 時選擇略過數位簽章的選項。

RPM 反安裝與重建資料庫 (erase/rebuilddb)

反安裝就是將軟體解除安裝啦！要注意的是，『解安裝的過程一定要由最上層往下解除』，以 rp-pppoe 為例，這一個軟體主要是依據 ppp 這個軟體來安裝的，所以當你要解除 ppp 的時候，就必須要先解除 rp-pppoe 才行！否則就會發生結構上的問題啦！這個可以由建築物來說明， 如果你要拆除五、六樓，那麼當然要由六樓拆起，否則先拆的是第五樓時，那麼上面的樓層難道會懸空？

移除的選項很簡單，就透過 -e 即可移除。不過，很常發生軟體屬性相依導致無法移除某些軟體的問題！ 我們以底下的例子來說明：

# 1. 找出與 pam 有關的軟體名稱，並嘗試移除 pam 這個軟體：

[root@www ~]# rpm -qa | grep pam

pam-devel-0.99.6.2-3.27.el5

pam_passwdqc-1.0.2-1.2.2

pam_pkcs11-0.5.3-23

pam_smb-1.1.7-7.2.1

pam-0.99.6.2-3.27.el5

pam_ccreds-3-5

pam_krb5-2.2.14-1

[root@www ~]# rpm -e pam

error: Failed dependencies:  <==這裡提到的是相依性的問題

libpam.so.0 is needed by (installed) coreutils-5.97-14.el5.i386

libpam.so.0 is needed by (installed) libuser-0.54.7-2.el5.5.i386

....(以下省略)....

# 2. 若僅移除 pam-devel 這個之前範例安裝上的軟體呢？

[root@www ~]# rpm -e pam-devel  <==不會出現任何訊息！

[root@www ~]# rpm -q pam-devel

package pam-devel is not installed

從範例一我們知道 pam 所提供的函式庫是讓非常多其他軟體使用的，因此你不能移除 pam ，除非將其他相依軟體一口氣也全部移除！你當然也能加 --nodeps 來強制移除， 不過，如此一來所有會用到 pam 函式庫的軟體，都將成為無法運作的程式，我想，你的主機也只好準備停機休假了吧！ 至於範例二中，由於 pam-devel 是依附於 pam 的開發工具，你可以單獨安裝與單獨移除啦！

由於 RPM 檔案常常會安裝/移除/升級等，某些動作或許可能會導致 RPM 資料庫 /var/lib/rpm/ 內的檔案破損。果真如此的話，那你該如何是好？別擔心，我們可以使用 --rebuilddb 這個選項來重建一下資料庫喔！ 作法如下：

[root@www ~]# rpm --rebuilddb   <==重建資料庫

SRPM 的使用 ： rpmbuild

談完了 RPM 類型的軟體之後，再來我們談一談包含了 Source code 的 SRPM 該如何使用呢？假如今天我們由網路上面下載了一個 SRPM 的檔案，該如何安裝他？又，如果我想要修改這個 SRPM 裡面原始碼的相關設定值，又該如何訂正與重新編譯呢？ 此外，最需要注意的是，新版的 rpm 已經將 RPM 與 SRPM 的指令分開了，SRPM 使用的是 rpmbuild 這個指令，而不是 rpm 喔！如果你是 Red Hat 7.3 以前的用戶，那麼請使用 rpm 來替代 rpmbuild 啦！

利用預設值安裝 SRPM 檔案 (--rebuid/--recompile)

假設我下載了一個 SRPM 的檔案，又不想要修訂這個檔案內的原始碼與相關的設定值， 那麼我可以直接編譯並安裝嗎？當然可以！利用 rpmbuild 配合選項即可。選項主要有底下兩個：

--rebuild

這個選項會將後面的 SRPM 進行『編譯』與『打包』的動作，最後會產生 RPM 的檔案，但是產生的 RPM 檔案並沒有安裝到系統上。當你使用 --rebuild 的時候，最後通常會發現一行字體：

Wrote: /usr/src/redhat/RPMS/i386/pkgname.i386.rpm

這個就是編譯完成的 RPM 檔案囉！這個檔案就可以用來安裝啦！安裝的時候請加絕對路徑來安裝即可！

--recompile

這個動作會直接的『編譯』『打包』並且『安裝』囉！請注意， rebuild 僅『編譯並打包』而已，而 recompile 不但進行編譯跟打包，還同時進行『安裝』了！

不過，要注意的是，這兩個選項都沒有修改過 SRPM 內的設定值，僅是透過再次編譯來產生 RPM 可安裝軟體檔案而已。 一般來說，如果編譯的動作順利的話，那麼編譯過程所產生的中間暫存檔都會被自動刪除，如果發生任何錯誤， 則該中間檔案會被保留在系統上，等待使用者的除錯動作！那麼，該如何除錯呢？如果想要自行除錯， 或者是想要修改 SRPM 內的設定值時，就得要知道利用 SRPM 的時候，系統會動用到哪些重要的目錄了！ 底下我們就來談一談當處理 SRPM 時，系統會使用到的目錄。

SRPM 使用的路徑與需要的軟體

SRPM 既然含有 source code ，那麼其中必定有設定檔囉，所以首先我們必需要知道，這個 SRPM 在進行編譯的時候會使用到哪些目錄呢？這樣一來才能夠來修改嘛！你可以到你的 /usr/src 這個目錄裡面去查看一下，通常每個 distribution 提供的目錄都不太相同，以 CentOS 5.x 為例，他是以 /usr/src/redhat/ 為工作目錄， Openlinux 則是以 /usr/src/openlinux 為工作目錄！無論如何，反正就是在 /usr/src 這個目錄下就對了！好了，既然我們是 CentOS ， 請到 /usr/src/redhat 裡頭去看一看呦：

/usr/src/redhat/SPECS

這個目錄當中放置的是該軟體的設定檔，例如這個軟體的資訊參數、設定項目等等都放置在這裡；

/usr/src/redhat/SOURCES

這個目錄當中放置的是該軟體的原始檔 (*.tar.gz 的檔案) 以及 config 這個設定檔；

/usr/src/redhat/BUILD

在編譯的過程中，有些暫存的資料都會放置在這個目錄當中；

/usr/src/redhat/RPMS

經過編譯之後，並且順利的編譯成功之後，將打包完成的檔案放置在這個目錄當中。裡頭有包含了 i386, i586, i686, noarch.... 等等的次目錄。

/usr/src/redhat/SRPMS

與 RPMS 內相似的，這裡放置的就是 SRPM 封裝的檔案囉！有時候你想要將你的軟體用 SRPM 的方式釋出時， 你的 SRPM 檔案就會放置在這個目錄中了。

此外，在編譯的過程當中，可能會發生不明的錯誤，或者是設定的錯誤，這個時候就會在 /tmp 底下產生一個相對應的錯誤檔，你可以根據該錯誤檔進行除錯的工作呢！ 等到所有的問題都解決之後，也編譯成功了，那麼剛剛解壓縮之後的檔案，就是在 /usr/src/redhat/SPECS, SOURCES, BUILD 等等的檔案都會被殺掉，而只剩下放置在 /usr/src/redhat/RPMS 底下的檔案了！

由於 SRPM 需要重新編譯，而編譯的過程當中，我們至少需要有 make 與其相關的程式，及 gcc, c, c++ 等其他的編譯用的程式語言來進行編譯，更多說明請參考第二十二章原始碼所需基礎軟體吧。 所以，如果你在安裝的過程當中沒有選取軟體開發工具之類的軟體， 呵呵！得重新拿出你的光碟，然後再安裝喔！哈哈！只是得要克服一大堆的屬性相依的問題就是了∼ 這問題待會兒可以使用 yum 來處理，妳當然也可以先使用『 yum groupinstall "Development Tools" 』來安裝開發軟體。 鳥哥這裡假設妳已經安裝了該軟體群組囉。

例題：

嘗試使用 --rebuild 選項製作出一個 RPM 軟體檔案，可以到國家高速網路中心下載 rp-pppoe 這個 SRPM 軟體檔案， 妳可以到 http://ftp.twaren.net/Linux/CentOS/5/os/SRPMS/ 找到這個軟體來下載。 鳥哥這裡使用 CentOS 5.3 的 rp-pppoe-3.5-32.1.src.rpm 為例喔。

答：

假設你已經將 rp-pppoe 軟體下載到 /root 底下，那接下來可以簡單的使用底下的方式來重新編譯：

[root@www ~]# rpmbuild --rebuild rp-pppoe-3.5-32.1.src.rpm

正在安裝 rp-pppoe-3.5-32.1.src.rpm

警告：使用者 mockbuild 不存在 - 現使用 root 代替

....(中間省略)....

已寫入：/usr/src/redhat/RPMS/i386/rp-pppoe-3.5-32.1.i386.rpm

已寫入：/usr/src/redhat/RPMS/i386/rp-pppoe-debuginfo-3.5-32.1.i386.rpm

正在執行 (%clean)：/bin/sh -e /var/tmp/rpm-tmp.69789

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd rp-pppoe-3.5

+ rm -rf /var/tmp/rp-pppoe-3.5-32.1-root

+ exit 0

正在執行 (--clean)：/bin/sh -e /var/tmp/rpm-tmp.69789

+ umask 022

+ cd /usr/src/redhat/BUILD

+ rm -rf rp-pppoe-3.5

+ exit 0

[root@www ~]# ll /usr/src/redhat/RPMS/i386/

-rw-r--r-- 1 root root 105443  6月 27 02:51 rp-pppoe-3.5-32.1.i386.rpm

-rw-r--r-- 1 root root  18756  6月 27 02:51 rp-pppoe-debuginfo-3.5-32.1.i386.rpm

其實整個過程與 Tarball 的方式差不多，也是編譯後變成 binary program，接著再以 RPM 的機制封裝起來啦。 重點在上面特殊字體的部分，記得要察看一下喔！若一切正常，則會看到 exit 0 的字樣，且會主動的刪除 (rm) 很多中間暫存檔哩。

設定檔的主要內容 (*.spec)

除了使用 SRPM 內預設的參數來進行編譯之外，我們還可以修改這些參數後再重新編譯喔！那該如何處理呢？ 首先我們必須要將 SRPM 內的檔案安置到 /usr/src/redhat/ 內的相關目錄，然後再去修改設定檔即可啊！ 我們就拿剛剛上頭那個 rp-pppoe 來說明好了，假設我們已經將該檔案放置到 /root 中啦，然後：

[root@www ~]# rpm -i rp-pppoe-3.5-32.1.src.rpm

# 過程不會顯示任何東西，他只會將 SRPM 的檔案解開後，放置到 /usr/src/redhat/

[root@www ~]# find /usr/src/redhat/ -type f

/usr/src/redhat/SOURCES/rp-pppoe-3.5-firewall.patch  <==補丁檔

/usr/src/redhat/SOURCES/adsl-stop                    <==CentOS 提供的腳本

/usr/src/redhat/SOURCES/rp-pppoe-3.5.tar.gz          <==原始碼啦！

/usr/src/redhat/SOURCES/rp-pppoe-3.5-buildroot.patch <==補丁檔

/usr/src/redhat/SOURCES/adsl-start                   <==CentOS 提供的腳本

/usr/src/redhat/SOURCES/adsl-connect

/usr/src/redhat/SOURCES/adsl-setup

/usr/src/redhat/SOURCES/adsl-status

/usr/src/redhat/SOURCES/rp-pppoe-3.4-redhat.patch    <==補丁檔

/usr/src/redhat/SPECS/rp-pppoe.spec                  <==重要設定檔！

# 主要含有原始碼與一個重要的設定檔啊！ rp-pppoe.spec ！

好了，來看看我們的設定參數檔，亦即是在 /usr/src/redhat/SPECS 內的 *.spec 檔案囉！

[root@www ~]# cd /usr/src/redhat/SPECS

[root@www SPECS]# vi rp-pppoe.spec

# 1. 首先，這個部分在介紹整個軟體的基本相關資訊！不論是版本還是釋出次數等。

Summary: A PPP over Ethernet client (for xDSL support).

Name: rp-pppoe

Version: 3.5

Release: 32.1

License: GPL

Group: System Environment/Daemons

Url: http://www.roaringpenguin.com/pppoe/

Source: http://www.roaringpenguin.com/rp-pppoe-%{version}.tar.gz

Source1: adsl-connect

Source2: adsl-setup

....(中間省略)....

# 2. 這部分則是在設定相依屬性需求的地方！

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

Prereq: /sbin/chkconfig  <==需要的前驅程式有哪些！

Prereq: /sbin/service

Prereq: fileutils

Requires: ppp >= 2.4.2         <==需要的軟體又有哪些！

Requires: initscripts >= 5.92

Requires: iproute >= 2.6

BuildRequires: libtool   <==還需要哪些工具軟體？

BuildRequires: autoconf

BuildRequires: automake

%description             <==此軟體的描述啦！

PPPoE (Point-to-Point Protocol over Ethernet) is a protocol used by

many ADSL Internet Service Providers. This package contains the

Roaring Penguin PPPoE client, a user-mode program that does not

require any kernel modifications. It is fully compliant with RFC 2516,

the official PPPoE specification.

# 3. 編譯前的預處理，以及編譯過程當中所需要進行的指令，都寫在這裡

#    尤其 %build 底下的資料，幾乎就是 makefile 裡面的資訊啊！

%prep  <==這部份在預先 (pre) 進行處理，大致就是 patch 軟體啊！

%setup -q

%patch0 -p1 -b .config

%patch1 -p1 -b .buildroot

%patch2 -p1 -b .ipchains

%build <==這部分就是在實際編譯囉！

cd src

autoconf

CFLAGS="-D_GNU_SOURCE" %configure

make

install -m 0755 %{SOURCE1} scripts

install -m 0755 %{SOURCE2} scripts

install -m 0755 %{SOURCE3} scripts

install -m 0755 %{SOURCE4} scripts

install -m 0755 %{SOURCE5} scripts

%install  <==這就是安裝過程！

rm -rf %{buildroot}

mkdir -p %{buildroot}/sbin

make -C src install RPM_INSTALL_ROOT=%{buildroot}

....(中間省略)....

# 4. 這裡列出，這個軟體釋出的檔案有哪些的意思！

%files   <==這個軟體提供的檔案有哪些？需要記錄在資料庫內！

%defattr(-,root,root)

%doc doc/LICENSE scripts/adsl-connect scripts/adsl-setup scripts/adsl-init

%doc scripts/adsl-start scripts/adsl-status scripts/adsl-stop

%doc configs

%config(noreplace) %{_sysconfdir}/ppp/pppoe-server-options

%config(noreplace) %{_sysconfdir}/ppp/firewall*

/sbin/*

%{_sbindir}/*

%{_mandir}/man?/*

# 5. 列出這個軟體的更改歷史紀錄檔！

%changelog

* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 3.5-32.1

- rebuild

....(中間省略)....

* Wed May 31 2000 Than Ngo <than@redhat.de>

- adopted for Winston.

要注意到的是 rp-pppoe.sepc 這個檔案，這是主要的將 SRPM 編譯成 RPM 的設定檔，他的基本規則可以這樣看：

1. 整個檔案的開頭以Summary為開始，這部份的設定都是最基礎的說明內容；

2. 然後每個不同的段落之間，都以%來做為開頭，例如%prep與%install等；

我們來談一談幾個常見的 SRPM 設定段落：

- 系統整體資訊方面：

剛剛你看到的就有底下這些重要的咚咚囉：

參數

參數意義

Summary

本軟體的主要說明，例如上表中說明了本軟體是針對 xDSL 的撥接用途啦！

Name

本軟體的軟體名稱 (最終會是 RPM 檔案的檔名構成之一)

Version

本軟體的版本 (也會是 RPM 檔名的構成之一)

Release

這個是該版本打包的次數說明 (也會是 RPM 檔名的構成之一)。由於我們想要動點手腳，所以上頭的檔案中， 這個部分請修改為 32.2.vbird 看看

License

這個軟體的授權模式，我們是使用 GPL 啦！

Group

這個軟體的發展團體名稱；

Url

這個原始碼的主要官方網站；

Source

這個軟體的來源，如果是網路上下載的軟體，通常一定會有這個資訊來告訴大家這個原始檔的來源！ 此外，還有來自開發商自己提供的原始檔資料喔！例如上面的 adsl-start 等程式。

Patch

就是作為補丁的 patch file 囉！

BuildRoot

設定作為編譯時，該使用哪個目錄來暫存中間檔案 (如編譯過程的目標檔案/連結檔案等檔)。

ExclusiveArch

這個是說明這個軟體的適合安裝的硬體，通常預設為 i386，當然，你也可以調整為 i586 啦等等的！ 由於我們的系統是新的 CPU 架構，這裡我們修改內容成為『ExclusiveArch: i686』來玩玩看。

上述為必須要存在的項目，底下為可使用的額外設定值

Requires

如果你這個軟體還需要其他的軟體的支援，那麼這裡就必需寫上來，則當你製作成 RPM 之後，系統就會自動的去檢查啦！這就是『相依屬性』的主要來源囉！

Prereq

這個軟體需要的前驅程式為何！這裡指的是『程式』而 Requires 指的是『軟體』！

BuildRequires

編譯過程中所需要的軟體。Requires 指的是『安裝時需要檢查』的，因為與實際運作有關，這個 BuildRequires 指的是『編譯時』所需要的軟體，只有在 SRPM 編譯成為 RPM 時才會檢查的項目。

Packager

這個軟體是經由誰來打包的呢？

Vender

發展的廠商哪；

上面幾個資料通常都必需要寫啦！但是如果你的軟體沒有相依屬性的關係時，那麼就可以不需要那個 Requires 囉！ 根據上面的設定，最終的檔名就會是『{Name}-{Version}-{Release}.{ExclusiveArch}.rpm』的樣式， 以我們上面的設定來說，檔名應該會是『rp-pppoe-3.5-32.2.vbird.i686.rpm』的樣子囉！

- %description：

將你的軟體做一個簡短的說明！這個也是必需要的。還記得使用『 rpm -qi 軟體名稱 』會出現一些基礎的說明嗎？ 上面這些東西包括 Description 就是在顯示這些重要資訊的啦！所以，這裡記得要詳加解釋喔！

- %prep：

pre 這個關鍵字原本就有『在...之前』的意思，因此這個項目在這裡指的就是『尚未進行設定或安裝之前，你要編譯完成的 RPM 幫你事先做的事情』，就是 prepare 的簡寫囉！那麼他的工作事項主要有：

1. 進行軟體的補丁 (patch) 等相關工作；

2. 尋找軟體所需要的目錄是否已經存在？確認用的！

3. 事先建立你的軟體所需要的目錄，或者事先需要進行的任務；

4. 如果待安裝的Linux系統內已經有安裝的時候可能會被覆蓋掉的檔案時，那麼就必需要進行備份(backup)的工作了！

在本案例中，你會發現程式會使用 patch 去進行補丁的動作啦！

- %setup：

這個項目就是在進行類似解壓縮之類的工作！這個項目一定要寫喔！不然你的 tarball 原始碼是無法被解壓縮的哩！切記切記！

- %build：

build 就是建立啊！所以當然囉，這個段落就是在談怎麼 make 編譯成為可執行的程式囉！ 你會發現在此部分的程式碼方面，就是 ./configure, make 等項目哩！

- %install：

編譯完成 (build) 之後，就是要安裝啦！安裝就是寫在這裡，也就是類似 Tarball 裡面的 make install 的意思囉！

- %clean：

編譯與安裝完畢後，必須要將一些暫存在 BuildRoot 內的資料刪除才好， 因此這個時候這個 clean 的項目就重要啦！這有點像是 make clean 的感覺∼保持系統的乾爽嘛！

- %files：

這個軟體安裝的檔案都需要寫到這裡來，當然包括了『目錄』喔！所以連同目錄請一起寫到這個段落當中！以備查驗呢！^_^ ！此外，你也可以指定每個檔案的類型，包括文件檔 (%doc 後面接的) 與設定檔 (%config 後面接的) 等等。

- %changelog：

這個項目主要則是在記錄這個軟體曾經的更新紀錄囉！星號 (*) 後面應該要以時間，修改者， email 與軟體版本來作為說明， 減號 (-) 後面則是你要作的詳細說明囉！在這部份鳥哥就新增了兩行，內容如下：

%changelog

* Wed Jul 01 2009 VBird Tsai <vbird@mail.vbird.idv.tw> - 3.5-32.2.vbird

- only rebuild this SRPM to RPM

* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 3.5-32.1

....(底下省略)....

修改到這裡也差不多了，您也應該要瞭解到這個 rp-pppoe.spec 有多麼重要！我們用 rpm -q 去查詢一堆資訊時， 其實都是在這裡寫入的！這樣瞭解否？接下來，就讓我們來瞭解一下如何將 SRPM 給他編譯出 RPM 來吧！

SRPM 的編譯指令 (-ba/-bb)

要將在 /usr/src/redhat 底下的資料編譯或者是單純的打包成為 RPM 或 SRPM 時，就需要 rpmbuild 指令與相關選項的幫忙了！我們只介紹兩個常用的選項給您瞭解一下：

[root@www ~]# rpmbuild -ba rp-pppoe.spec  <==編譯並同時產生 RPM 與 SRPM 檔案

[root@www ~]# rpmbuild -bb rp-pppoe.spec  <==僅編譯成 RPM 檔案

這個時候系統就會這樣做：

1. 先進入到 BUILD 這個目錄中，亦即是： /usr/src/redhat/BUILD 這個目錄；

2. 依照 *.spec 檔案內的 Name 與 Version 定義出工作的目錄名稱，以我們上面的例子為例，那麼系統就會在 BUILD 目錄中先刪除 rp-pppoe-3.5 的目錄，再重新建立一個 rp-pppoe-3.5 的目錄，並進入該目錄；

3. 在新建的目錄裡面，針對 SOURCES 目錄下的來源檔案，也就是 *.spec 裡面的 Source 設定的那個檔案，以 tar 進行解壓縮，以我們這個例子來說，則會在 /usr/src/redhat/BUILD/rp-pppoe-3.5 當中，將 /usr/src/redhat/SOURCES/rp-pppoe-3.5.tar.gz 進行解壓縮啦！

4. 再來開始 %build 及 %install 的設定與編譯！

5. 最後將完成打包的檔案給他放置到該放置的地方去，如果你的規定的硬體是在 i386 的系統，那麼最後編譯成功的 *.i386.rpm檔案就會被放置在 /usr/src/redhat/RPMS/i386 裡面囉！如果是 i686 那麼自然就是 /usr/src/redhat/RPMS/i686 目錄下囉！

整個步驟大概就是這樣子！最後的結果資料會放置在 RPMS 那個目錄底下就對啦！我們這個案例中想要同時打包 RPM 與 SRPM ， 因此請您自行處理一下『 rpmbuild -ba rp-pppoe.spec 』吧！

[root@www ~]# cd /usr/src/redhat/SPECS

[root@www SPECS]# rpmbuild -ba rp-pppoe.spec

....(以上省略)....

正在處理檔案：rp-pppoe-debuginfo-3.5-32.2.vbird

已寫入：/usr/src/redhat/SRPMS/rp-pppoe-3.5-32.2.vbird.src.rpm

已寫入：/usr/src/redhat/RPMS/i386/rp-pppoe-3.5-32.2.vbird.i386.rpm

已寫入：/usr/src/redhat/RPMS/i386/rp-pppoe-debuginfo-3.5-32.2.vbird.i386.rpm

正在執行 (%clean)：/bin/sh -e /var/tmp/rpm-tmp.10628

+ umask 022

+ cd /usr/src/redhat/BUILD

+ cd rp-pppoe-3.5

+ rm -rf /var/tmp/rp-pppoe-3.5-32.2.vbird-root

+ exit 0

[root@www SPECS]# find /usr/src/redhat -name 'rp-pppoe*rpm'

/usr/src/redhat/RPMS/i386/rp-pppoe-3.5-32.2.vbird.i386.rpm

/usr/src/redhat/RPMS/i386/rp-pppoe-debuginfo-3.5-32.2.vbird.i386.rpm

/usr/src/redhat/SRPMS/rp-pppoe-3.5-32.2.vbird.src.rpm

# 上面分別是 RPM 與 SRPM 的檔案檔名！

老實說，應該會出現 i686 的檔名才對！不過，可能是原始碼本身沒有支援 i686 之類的語法吧！ 所以僅出現 i386 的檔名而已。另外，你可以看到檔名確實是如同我們之前談到的喔！ 那你可以自行製作出有你特殊名稱的檔名囉 (例如上面的 vbird 囉)。

一個打包自己軟體的範例

這個就有趣了！我們自己來編輯一下自己製作的 RPM 怎麼樣？會很難嗎？完全不會！ 我們這裡就舉個例子來玩玩吧！還記得我們在前一章談到 Tarball 與 make 時，曾經談到的 main 這個程式嗎？現在我們將這個程式加上 Makefile 後， 將他製作成為 main-0.1.i386.rpm 好嗎？那該如何進行呢？底下就讓我們來處理處理吧！

- 製作原始碼檔案 tarball 產生：

請將前一章你曾經處理過的 main.tgz 再次的捉下來一次，我們將這個檔案放置到 /root 底下， 並且在 /usr/local/src 底下建立一個名為 main-0.1 的目錄來解壓縮喔！

[root@www ~]# mkdir /usr/local/src/main-0.1

[root@www ~]# tar -zxvf main.tgz -C /usr/local/src/main-0.1

[root@www ~]# cd /usr/local/src/main-0.1

[root@www main-0.1]# vim Makefile  <==建立原始碼所需 make 規則

LIBS = -lm

OBJS = main.o haha.o sin_value.o cos_value.o

main: ${OBJS}

gcc -o main ${OBJS} ${LIBS}

clean:

rm -f main ${OBJS}

install:

install -m 755 main $(RPM_INSTALL_ROOT)/usr/local/bin/main

# 記得 gcc 與 rm 之前是使用 <tab> 按鍵作出來的空白喔！

[root@www main-0.1]# cd ..

[root@www src]# tar -zcvf main-0.1.tar.gz main-0.1

# 此時會產生 main-0.1.tar.gz ，將他挪到 /usr/src/redhat/SOURCES 底下：

[root@www src]# cp main-0.1.tar.gz /usr/src/redhat/SOURCES

這個時候在 /usr/src/redhat 底下的原始碼就建立成功了！接下來就是 spec 檔案的建立囉！

- 建立 *.spec 的設定檔

這個檔案的建置是所有 RPM 製作裡面最重要的課題！你必須要仔細的設定他，不要隨便處理！仔細看看吧！

[root@www ~]# cd /usr/src/redhat/SPECS

[root@www SPECS]# vim main.spec

Summary:   calculate sin and cos value.

Name:      main

Version:   0.1

Release:   1

License:   GPL

Group:     VBird's Home

Source:    main-0.1.tar.gz   <==記得要寫正確的 Tarball 檔名喔！

Url:       http://linux.vbird.org

Packager:  VBird

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description

This package will let you input your name and calculate sin cos value.

%prep

%setup -q

%build

make

%install

rm -rf %{buildroot}

mkdir -p %{buildroot}/usr/local/bin

make install RPM_INSTALL_ROOT=%{buildroot}   <==這項目也很重要！

%files

/usr/local/bin/main

%changelog

* Wed Jul 01 2009 VBird Tsai <vbird@mail.vbird.idv.tw> 0.1

- build the program

- 編譯成為 RPM 與 SRPM

老實說，那個 spec 檔案建置妥當後，後續的動作就簡單的要命了！開始來編譯吧！

[root@www SPECS]# rpmbuild -ba main.spec

....(前面省略)....

已寫入：/usr/src/redhat/SRPMS/main-0.1-1.src.rpm

已寫入：/usr/src/redhat/RPMS/i386/main-0.1-1.i386.rpm

已寫入：/usr/src/redhat/RPMS/i386/main-debuginfo-0.1-1.i386.rpm

很快的，我們就已經建立了幾個 RPM 檔案囉！接下來讓我們好好測試一下打包起來的成果吧！

- 安裝/測試/實際查詢

[root@www ~]# rpm -ivh /usr/src/redhat/RPMS/i386/main-0.1-1.i386.rpm

正在準備…             ########################################### [100%]

1:main                   ########################################### [100%]

[root@www ~]# rpm -ql main

/usr/local/bin/main   <==自己嘗試執行 main 看看！

[root@www ~]# rpm -qi main

Name        : main              Relocations: (not relocatable)

Version     : 0.1                    Vendor: (none)

Release     : 1                  Build Date: 西元2009年07月02日 (週四)

Install Date: 西元2009年07月02日 Build Host: www.vbird.tsai

Group       : VBird's Home       Source RPM: main-0.1-1.src.rpm

Size        : 3360                  License: GPL

Signature   : (none)

Packager    : VBird

URL         : http://linux.vbird.org

Summary     : calculate sin and cos value.

Description :

This package will let you input your name and calculate sin cos value.

# 看到沒？屬於你自己的軟體喔！真是很愉快的啦！

用很簡單的方式，就可以將自己的軟體或者程式給他修改與設定妥當！以後你就可以自行設定你的 RPM 囉！當然，也可以手動修改你的 SRPM 的來源檔內容囉！

YUM 線上升級機制

我們在本章一開始的地方談到過 yum 這玩意兒，這個 yum 是透過分析 RPM 的標頭資料後， 根據各軟體的相關性製作出屬性相依時的解決方案，然後可以自動處理軟體的相依屬性問題，以解決軟體安裝或移除與升級的問題。 詳細的 yum 伺服器與用戶端之間的溝通，可以再回到前面的部分查閱一下圖 1.5.1 的說明。

由於 distribution 必須要先釋出軟體，然後將軟體放置於 yum 伺服器上面，以提供用戶端來要求安裝與升級之用的。 因此我們想要使用 yum 的功能時，必須要先找到適合的 yum server 才行啊！而每個 yum server 可能都會提供許多不同的軟體功能，那就是我們之前談到的『容器』啦！因此，你必須要前往 yum server 查詢到相關的容器網址後，再繼續處理後續的設定事宜。

事實上 CentOS 在釋出軟體時已經製作出多部映射站台 (mirror site) 提供全世界的軟體更新之用。 所以，理論上我們不需要處理任何設定值，只要能夠連上 Internet ，就可以使用 yum 囉！底下就讓我們來玩玩看吧！

利用 yum 進行查詢、安裝、升級與移除功能

yum 的使用真是非常簡單，就是透過 yum 這個指令啊！那麼這個指令怎麼用呢？ 用法很簡單，就讓我們來簡單的談談：

- 查詢功能：yum [list|info|search|provides|whatprovides] 參數

如果想要查詢利用 yum 來查詢原版 distribution 所提供的軟體，或已知某軟體的名稱，想知道該軟體的功能， 可以利用 yum 相關的參數為：

[root@www ~]# yum [option] [查詢工作項目] [相關參數]

選項與參數：

[option]：主要的選項，包括有：

-y ：當 yum 要等待使用者輸入時，這個選項可以自動提供 yes 的回應；

--installroot=/some/path ：將該軟體安裝在 /some/path 而不使用預設路徑

[查詢工作項目] [相關參數]：這方面的參數有：

search  ：搜尋某個軟體名稱或者是描述 (description) 的重要關鍵字；

list    ：列出目前 yum 所管理的所有的軟體名稱與版本，有點類似 rpm -qa；

info    ：同上，不過有點類似 rpm -qai 的執行結果；

provides：從檔案去搜尋軟體！類似 rpm -qf 的功能！

範例一：搜尋磁碟陣列 (raid) 相關的軟體有哪些？

[root@www ~]# yum search raid

....(前面省略)....

mdadm.i386 : mdadm controls Linux md devices (software RAID arrays)

lvm2.i386 : Userland logical volume management tools

....(後面省略)....

# 在冒號 (:)  左邊的是軟體名稱，右邊的則是在 RPM 內的 name 設定 (軟體名)

# 瞧！上面的結果，這不就是與 RAID 有關的軟體嗎？如果想瞭解 mdadm 的軟體內容呢？

範例二：找出 mdadm 這個軟體的功能為何

[root@www ~]# yum info mdadm

Installed Packages      <==這說明該軟體是已經安裝的了

Name   : mdadm          <==這個軟體的名稱

Arch   : i386           <==這個軟體的編譯架構

Version: 2.6.4          <==此軟體的版本

Release: 1.el5          <==釋出的版本

Size   : 1.7 M          <==此軟體的檔案總容量

Repo   : installed      <==容器回報說已安裝的

Summary: mdadm controls Linux md devices (software RAID arrays)

Description:            <==看到否？這就是 rpm -qi 嘛！

mdadm is used to create, manage, and monitor Linux MD (software RAID)

devices.  As such, it provides similar functionality to the raidtools

package.  However, mdadm is a single program, and it can perform

almost all functions without a configuration file, though a configuration

file can be used to help with some common tasks.

# 不要跟我說，上面說些啥？自己找字典翻一翻吧！拜託拜託！

範例三：列出 yum 伺服器上面提供的所有軟體名稱

[root@www ~]# yum list

Installed Packages <==已安裝軟體

Deployment_Guide-en-US.noarch            5.2-9.el5.centos       installed

Deployment_Guide-zh-CN.noarch            5.2-9.el5.centos       installed

Deployment_Guide-zh-TW.noarch            5.2-9.el5.centos       installed

....(中間省略)....

Available Packages <==還可以安裝的其他軟體

Cluster_Administration-as-IN.noarch      5.2-1.el5.centos       base

Cluster_Administration-bn-IN.noarch      5.2-1.el5.centos       base

....(底下省略)....

# 上面提供的意義為：『 軟體名稱   版本   在那個容器內 』

範例四：列出目前伺服器上可供本機進行升級的軟體有哪些？

[root@www ~]# yum list updates  <==一定要是 updates 喔！

Updated Packages

Deployment_Guide-en-US.noarch            5.2-11.el5.centos      base

Deployment_Guide-zh-CN.noarch            5.2-11.el5.centos      base

Deployment_Guide-zh-TW.noarch            5.2-11.el5.centos      base

....(底下省略)....

# 上面就列出在那個容器內可以提供升級的軟體與版本！

範例五：列出提供 passwd 這個檔案的軟體有哪些

[root@www ~]# yum provides passwd

passwd.i386 : The passwd utility for setting/changing passwords using PAM

passwd.i386 : The passwd utility for setting/changing passwords using PAM

# 找到啦！就是上面的這個軟體提供了 passwd 這個程式！

透過上面的查詢，你應該大致知道 yum 如何用在查詢上面了吧？那麼實際來應用一下：

例題：

利用 yum 的功能，找出以 pam 為開頭的軟體名稱有哪些？而其中尚未安裝的又有哪些？

答：

可以透過如下的方法來查詢：

[root@www ~]# yum list pam*

Installed Packages

pam.i386                  0.99.6.2-3.27.el5      installed

pam_ccreds.i386           3-5                    installed

pam_krb5.i386             2.2.14-1               installed

pam_passwdqc.i386         1.0.2-1.2.2            installed

pam_pkcs11.i386           0.5.3-23               installed

pam_smb.i386              1.1.7-7.2.1            installed

Available Packages <==底下則是『可升級』的或『未安裝』的

pam.i386                  0.99.6.2-4.el5         base

pam-devel.i386            0.99.6.2-4.el5         base

pam_krb5.i386             2.2.14-10              base

如上所示，所以可升級者有 pam, pam_krb5 這兩個軟體，完全沒有安裝的則是 pam-devel 這個軟體囉！

- 安裝/升級功能：yum [install|update] 軟體

既然可以查詢，那麼安裝與升級呢？很簡單啦！就利用 install 與 update 這兩項工作來處理即可喔！

[root@www ~]# yum [option] [查詢工作項目] [相關參數]

選項與參數：

install ：後面接要安裝的軟體！

update  ：後面接要升級的軟體，若要整個系統都升級，就直接 update 即可

範例一：將前一個練習找到的未安裝的 pam-devel 安裝起來

[root@www ~]# yum install pam-devel

Setting up Install Process

Parsing package install arguments

Resolving Dependencies  <==先檢查軟體的屬性相依問題

--> Running transaction check

---> Package pam-devel.i386 0:0.99.6.2-4.el5 set to be updated

--> Processing Dependency: pam = 0.99.6.2-4.el5 for package: pam-devel

--> Running transaction check

---> Package pam.i386 0:0.99.6.2-4.el5 set to be updated

filelists.xml.gz          100% |=========================| 1.6 MB    00:05

filelists.xml.gz          100% |=========================| 138 kB    00:00

-> Finished Dependency Resolution

Dependencies Resolved

=============================================================================

Package                 Arch       Version          Repository        Size

=============================================================================

Installing:

pam-devel               i386       0.99.6.2-4.el5   base              186 k

Updating:

pam                     i386       0.99.6.2-4.el5   base              965 k

Transaction Summary

=============================================================================

Install      1 Package(s)  <==結果發現要安裝此軟體需要升級另一個相依的軟體

Update       1 Package(s)

Remove       0 Package(s)

Total download size: 1.1 M

Is this ok [y/N]: y  <==確定要安裝！

Downloading Packages: <==先下載！

(1/2): pam-0.99.6.2-4.el5 100% |=========================| 965 kB    00:05

(2/2): pam-devel-0.99.6.2 100% |=========================| 186 kB    00:01

Running rpm_check_debug

Running Transaction Test

Finished Transaction Test

Transaction Test Succeeded

Running Transaction <==開始安裝！

Updating  : pam                          ######################### [1/3]

Installing: pam-devel                    ######################### [2/3]

Cleanup   : pam                          ######################### [3/3]

Installed: pam-devel.i386 0:0.99.6.2-4.el5

Updated: pam.i386 0:0.99.6.2-4.el5

Complete!

有沒有很高興啊！你不必知道軟體在哪裡，你不必手動下載軟體，你也不必拿出原版光碟出來 mount 之後查詢再安裝！全部不需要，只要有了 yum 這個傢伙，你的安裝、升級再也不是什麼難事！ 而且還能主動的進行軟體的屬性相依處理流程，如上所示，一口氣幫我們處理好了所有事情！ 是不是很過癮啊！而且整個動作完全免費！夠酷吧！

- 移除功能：yum [remove] 軟體

那能不能用 yum 移除軟體呢？將剛剛的軟體移除看看，會出現啥狀況啊？

[root@www ~]# yum remove pam-devel

Setting up Remove Process

Resolving Dependencies  <==同樣的，先解決屬性相依的問題

--> Running transaction check

---> Package pam-devel.i386 0:0.99.6.2-4.el5 set to be erased

--> Finished Dependency Resolution

Dependencies Resolved

=============================================================================

Package                 Arch       Version          Repository        Size

=============================================================================

Removing:

pam-devel               i386       0.99.6.2-4.el5   installed         495 k

Transaction Summary

=============================================================================

Install      0 Package(s)

Update       0 Package(s)

Remove       1 Package(s)  <==還好，並沒有屬性相依的問題，單純移除一個軟體

Is this ok [y/N]: y

Downloading Packages:

Running rpm_check_debug

Running Transaction Test

Finished Transaction Test

Transaction Test Succeeded

Running Transaction

Erasing   : pam-devel                    ######################### [1/1]

Removed: pam-devel.i386 0:0.99.6.2-4.el5

Complete!

連移除也這麼簡單！看來，似乎不需要 rpm 這個指令也能夠快樂的安裝所有的軟體了！ 雖然是如此，但是 yum 畢竟是架構在 rpm 上面所發展起來的，所以，鳥哥認為你還是得需要瞭解 rpm 才行！不要學了 yum 之後就將 rpm 的功能忘記了呢！切記切記！

yum 的設定檔

雖然 yum 是你的主機能夠連線上 Internet 就可以直接使用的，不過，由於 CentOS 的映射站台可能會選錯， 舉例來說，我們在台灣，但是 CentOS 的映射站台卻選擇到了大陸北京或者是日本去，有沒有可能發生啊！ 有啊！鳥哥教學方面就常常發生這樣的問題，要知道，我們連線到大陸或日本的速度是非常慢的呢！那怎辦？ 當然就是手動的修改一下 yum 的設定檔就好囉！

在台灣，CentOS 的映射站台主要有高速網路中心與義首大學，鳥哥近來比較偏好高速網路中心， 似乎更新的速度比較快，而且連接台灣學術網路也非常快速哩！因此，鳥哥底下建議台灣的朋友使用高速網路中心的 ftp 主機資源來作為 yum 伺服器來源喔！目前高速網路中心對於 CentOS 所提供的相關網址如下：

- http://ftp.twaren.net/Linux/CentOS/5/

如果你連接到上述的網址後，就會發現裡面有一堆連結，那些連結就是這個 yum 伺服器所提供的容器了！ 所以高速網路中心也提供了 addons, centosplus, extras, fasttrack, os, updates 等容器，最好認的容器就是 os (系統預設的軟體) 與 updates (軟體升級版本) 囉！由於鳥哥在我的測試用主機是利用 i386 的版本， 因此那個 os 再點進去就會得到如下的可提供安裝的網址：

- http://ftp.twaren.net/Linux/CentOS/5/os/i386/

為什麼在上述的網址內呢？有什麼特色！最重要的特色就是那個『 repodata 』的目錄！該目錄就是分析 RPM 軟體後所產生的軟體屬性相依資料放置處！因此，當你要找容器所在網址時， 最重要的就是該網址底下一定要有個名為 repodata 的目錄存在！那就是容器的網址了！ 其他的容器正確網址，就請各位看倌自行尋找一下喔！現在讓我們修改設定檔吧！

[root@www ~]# vi /etc/yum.repos.d/CentOS-Base.repo

[base]

name=CentOS-$releasever - Base

mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os

#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/

gpgcheck=1

gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5

如上所示，鳥哥僅列出 base 這個容器內容而已，其他的容器內容請自行查閱囉！上面的資料需要注意的是：

- [base]：代表容器的名字！中刮號一定要存在，裡面的名稱則可以隨意取。但是不能有兩個相同的容器名稱， 否則 yum 會不曉得該到哪裡去找容器相關軟體清單檔案。

- name：只是說明一下這個容器的意義而已，重要性不高！

- mirrorlist=：列出這個容器可以使用的映射站台，如果不想使用，可以註解到這行；

- baseurl=：這個最重要，因為後面接的就是容器的實際網址！ mirrorlist 是由 yum 程式自行去捉映射站台， baseurl 則是指定固定的一個容器網址！我們剛剛找到的網址放到這裡來啦！

- enable=1：就是讓這個容器被啟動。如果不想啟動可以使用 enable=0 喔！

- gpgcheck=1：還記得 RPM 的數位簽章嗎？這就是指定是否需要查閱 RPM 檔案內的數位簽章！

- gpgkey=：就是數位簽章的公鑰檔所在位置！使用預設值即可

瞭解這個設定檔之後，接下來讓我們修改整個檔案的內容，讓我們這部主機可以直接使用高速網路中心的資源吧！ 修改的方式鳥哥僅列出 base 這個容器項目而已，其他的項目請您自行依照上述的作法來處理即可！

[root@www ~]# vi /etc/yum.repos.d/CentOS-Base.repo

[base]

name=CentOS-$releasever - Base

baseurl=http://ftp.twaren.net/Linux/CentOS/5/os/i386/

gpgcheck=1

gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5

# 底下其他的容器項目，請自行到高速網路中心去查詢後自己處理！

接下來當然就是給他測試一下囉！如何測試呢？再次使用 yum 即可啊！

範例一：列出目前 yum server 所使用的容器有哪些？

[root@www ~]# yum repolist all

repo id         repo name                  status

addons          CentOS-5 - Addons          enabled

base            CentOS-5 - Base            enabled

c5-media        CentOS-5 - Media           disabled

centosplus      CentOS-5 - Plus            disabled

extras          CentOS-5 - Extras          enabled

updates         CentOS-5 - Updates         enabled

# 上面最右邊有寫 enabled 才是有啟動的！由於 /etc/yum.repos.d/

# 有多個設定檔，所以你會發現還有其他的容器存在。

- 修改容器產生的問題與解決之道

由於我們是修改系統預設的設定檔，事實上，我們應該要在 /etc/yum.repos.d/ 底下新建一個檔案， 該副檔名必須是 .repo 才行！但因為我們使用的是指定特定的映射站台，而不是其他軟體開發生提供的容器， 因此才修改系統預設設定檔。但是可能由於使用的容器版本有新舊之分，你得要知道， yum 會先下載容器的清單到本機的 /var/cache/yum 裡面去！那我們修改了網址卻沒有修改容器名稱 (中刮號內的文字)， 可能就會造成本機的清單與 yum 伺服器的清單不同步，此時就會出現無法更新的問題了！

那怎麼辦啊？很簡單，就清除掉本機上面的舊資料即可！需要手動處理嗎？不需要的， 透過 yum 的 clean 項目來處理即可！

[root@www ~]# yum clean [packages|headers|all]

選項與參數：

packages：將已下載的軟體檔案刪除

headers ：將下載的軟體檔頭刪除

all     ：將所有容器資料都刪除！

範例一：刪除已下載過的所有容器的相關資料 (含軟體本身與清單)

[root@www ~]# yum clean all

yum 的軟體群組功能

透過 yum 來線上安裝一個軟體是非常的簡單，但是，如果要安裝的是一個大型專案呢？ 舉例來說，鳥哥使用預設安裝的方式安裝了測試機，這部主機就只有 GNOME 這個視窗管理員， 那我如果想要安裝 KDE 呢？難道需要重新安裝？當然不需要，透過 yum的軟體群組功能即可！ 來看看指令先：

[root@www ~]# yum [群組功能] [軟體群組]

選項與參數：

grouplist   ：列出所有可使用的『套件組』，例如 Development Tools 之類的；

groupinfo   ：後面接 group_name，則可瞭解該 group 內含的所有套件名；

groupinstall：這個好用！可以安裝一整組的套件群組，相當的不錯用！

groupremove ：移除某個套件群組；

範例一：查閱目前容器與本機上面的可用與安裝過的軟體群組有哪些？

[root@www ~]# yum grouplist

Installed Groups:

Office/Productivity

Editors

System Tools

....(中間省略)....

Available Groups:

Tomboy

Cluster Storage

Engineering and Scientific

....(以下省略)....

你會發現系統上面的軟體大多是群組的方式一口氣來提供安裝的！還記全新安裝 CentOS 時， 不是可以選擇所需要的軟體嗎？而那些軟體不是利用 GNOME/KDE/X Window ... 之類的名稱存在嗎？ 其實那就是軟體群組囉！如果你執行上述的指令後，在『Available Groups』底下應該會看到一個 『XFCE-4.4』的軟體群組，想知道那是啥嗎？就這樣做：

[root@www ~]# yum groupinfo XFCE-4.4

Setting up Group Process

Group: XFCE-4.4

Description: This group contains the XFCE desktop environment.

Mandatory Packages:

xfce4-session

....(中間省略)....

Default Packages:

xfce4-websearch-plugin

....(中間省略)....

Optional Packages:

xfce-mcs-manager-devel

xfce4-panel-devel

....(以下省略)....

你會發現那就是一個桌面環境 (desktop environment) ，也就是一個視窗管理員啦！ 至於底下就列出主要的與選擇性 (optional) 的軟體名稱囉！讓我們直接安裝看看：

[root@www ~]# yum groupinstall XFCE-4.4

你會發現系統進行了一大堆軟體的安裝！那就是啦！整個安裝 XFCE 這個視窗介面所需的所有軟體！ 這個咚咚真是非常的方便呢！這個功能請一定要記下來，對你未來安裝軟體是非常有幫助的喔！ ^_^

全系統自動升級

我們可以手動選擇是否需要升級，那能不能讓系統自動升級，讓我們的系統隨時保持在最新的狀態呢？ 當然可以啊！透過『 yum -y update 』來自動升級，那個 -y 很重要，因為可以自動回答 yes 來開始下載與安裝！ 然後再透過 crontab 的功能來處理即可！假設我每天在台灣時間 3:00am 網路頻寬比較輕鬆的時候進行升級， 你可以這樣做的：

[root@www ~]# vim /etc/crontab

....(前面省略並保留設定值)....

0  3 * * * root /usr/bin/yum -y update

從此你的系統就會自動升級啦！很棒吧！此外，你還是得要分析登錄檔與收集 root 的信件的， 因為如果升級的是核心軟體 (kernel)，那麼你還是得要重新開機才會讓安裝的軟體順利運作的！ 所以還是得分析登錄檔，若有新核心安裝，就重新開機，否則就讓系統自動維持在最新較安全的環境吧！ 真是輕鬆愉快的管理啊！

管理的抉擇：RPM 還是 Tarball

這一直是個有趣的問題：『如果我要升級的話，或者是全新安裝一個新的軟體， 那麼該選擇 RPM 還是 Tarball 來安裝呢？』，事實上考慮的因素很多，不過鳥哥通常是這樣建議的：

1. 優先選擇原廠的 RPM 功能：

由於原廠釋出的軟體通常具有一段時間的維護期，舉例來說， RHEL 與 CentOS 每一個版本至少提供五年以上的更新期限。這對於我們的系統安全性來說，實在是非常好的選項！ 何解？既然 yum 可以自動升級，加上原廠會持續維護軟體更新，那麼我們的系統就能夠自己保持在軟體最新的狀態， 對於資安來說當然會比較好一些的！ 此外，由於 RPM 與 yum 具有容易安裝/移除/升級等特點，且還提供查詢與驗證的功能，安裝時更有數位簽章的保護， 讓你的軟體管理變的更輕鬆自在！因此，當然首選就是利用 RPM 來處理啦！

2. 選擇軟體官網釋出的 RPM 或者是提供的容器網址：

不過，原廠並不會包山包海，因此某些特殊軟體你的原版廠商並不會提供的！舉例來說 CentOS 就沒有提供 NTFS 的相關模組。此時你可以自行到官網去查閱，看看有沒有提供相對到你的系統的 RPM 檔案， 如果有提供容器網址，那就更好啦！可以修改 yum 設定檔來加入該容器，就能夠自動安裝與升級該軟體！ 你說方不方便啊！

3. 利用 Tarball 安裝特殊軟體：

某些特殊用途的軟體並不會特別幫你製作 RPM 檔案的，此時建議你也不要妄想自行製作 SRPM 來轉成 RPM 啦！ 因為你只有區區一部主機而已，若是你要管理相同的 100 部主機，那麼將原始碼轉製作成 RPM 就有價值！ 單機版的特殊軟體，例如學術網路常會用到的 MPICH/PVM 等平行運算函式庫，這種軟體建議使用 tarball 來安裝即可， 不需要特別去搜尋 RPM 囉！

4. 用 Tarball 測試新版軟體：

某些時刻你可能需要使用到新版的某個軟體，但是原版廠商僅提供舊版軟體，舉例來說，我們的 CentOS 主要是定位於企業版，因此很多軟體的要求是『穩』而不是『新』，但你就是需要新軟體啊！ 然後又擔心新軟體裝好後產生問題，回不到舊軟體，那就慘了！此時你可以用 tarball 安裝新軟體到 /usr/local 底下， 那麼該軟體就能夠同時安裝兩個版本在系統上面了！而且大多數軟體安裝數種版本時還不會互相干擾的！ 嘿嘿！用來作為測試新軟體是很不錯的呦！只是你就得要知道你使用的指令是新版軟體還是舊版軟體了！

所以說，RPM 與 Tarball 各有其優缺點，不過，如果有 RPM 的話，那麼優先權還是在於 RPM 安裝上面，畢竟管理上比較便利，但是如果軟體的架構差異性太大， 或者是無法解決相依屬性的問題，那麼與其花大把的時間與精力在解決屬性相依的問題上，還不如直接以 tarball 來安裝，輕鬆又愜意！

重點回顧

- 為了避免使用者自行編譯的困擾，開發商自行在特定的硬體與作業系統平台上面預先編譯好軟體， 並將軟體以特殊格式封包成檔案，提供終端用戶直接安裝到固定的作業系統上，並提供簡單的查詢/安裝/移除等流程。 此稱為軟體管理員。常見的軟體管理員有 RPM 與 DPKG 兩大主流。

- RPM 的全名是 RedHat Package Manager，原本是由 Red Hat 公司所發展的，流傳甚廣；

- RPM 類型的軟體中，所含有的軟體是經過編譯後的 binary program ，所以可以直接安裝在使用者端的系統上， 不過，也由於如此，所以 RPM 對於安裝者的環境要求相當嚴格；

- RPM 除了將軟體安裝至使用者的系統上之外，還會將該軟體的版本、名稱、檔案與目錄配置、系統需求等等均記錄於資料庫 (/var/lib/rpm) 當中，方便未來的查詢與升級、移除；

- RPM 可針對不同的硬體等級來加以編譯，製作出來的檔案可於副檔名 (i386, i586, i686, x86_64) 來分辨；

- RPM 最大的問題為軟體之間的相依性問題；

- SRPM 為 Source RPM ，內含的檔案為 Source code 而非為 binary file ，所以安裝 SRPM 時還需要經過 compile ，不過，SRPM 最大的優點就是可以讓使用者自行修改設定參數 (makefile/configure 的參數) ，以符合使用者自己的 Linux 環境；

- RPM 軟體的屬性相依問題，已經可以藉由 yum 或者是 APT 等方式加以克服。 CentOS 使用的就是 yum 機制。

- yum 伺服器提供多個不同的容器放置個別的軟體，以提供用戶端分別管理軟體類別。

本章習題

- 情境模擬題一：實際安裝 php, php-mysql, php-devel, httpd-devel 等軟體的方式

- 目標：利用 rpm 查詢軟體是否已安裝，利用 yum 進行線上查詢；

- 目標：你的 Linux 必須要已經接上 Internet 才行；

- 需求：最好瞭解磁碟容量是否夠用，以及如何啟動服務等。

這個模擬題的目的是想要安裝一套較為完整的 WWW 伺服器，便且此伺服器可以支援外掛的其他網頁伺服器模組。 所以需要安裝的就會有網頁程式語言 php 與資料庫軟體 MySQL ，以及未來開發用的 php-devel, httpd-devel 等軟體。 整個流程會有點像這樣：

- 檢查所需要的軟體是否存在？最好直接使用 rpm ，因為可以直接取得 RPM 的資料庫內容：

[root@www ~]# rpm -q httpd httpd-devel php php-devel php-mysql

httpd-2.2.3-22.el5.centos

package httpd-devel is not installed  <==沒有安裝的軟體！

php-5.1.6-23.el5

package php-devel is not installed    <==沒有安裝的軟體！

package php-mysql is not installed    <==沒有安裝的軟體！

經過上面的分析，我們知道 httpd-devel, php-devel, php-mysql 等軟體並沒有安裝！那麼該如何安裝 可以使用 yum 直接線上安裝。不過我們必須要先有網路才行！

- 確認網路的可行性：

[root@www ~]# ifconfig eth0

eth0      Link encap:Ethernet  HWaddr 08:00:27:11:3B:75

inet addr:192.168.201.201  Bcast:192.168.201.255  Mask:255.255.255.0

....(底下省略)....

# 你可以看到我們的主機是有 IP 存在的！再來看看有沒有路由設定存在？

[root@www ~]# route -n

Kernel IP routing table

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

192.168.201.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0

0.0.0.0         192.168.201.254 0.0.0.0         UG    0      0        0 eth0

# 確實是有路由器 (Gateway) 存在的！那麼該路由器是否設定正確呢？

[root@www ~]# ping -c 2 192.168.201.254

PING 192.168.201.254 (192.168.201.254) 56(84) bytes of data.

64 bytes from 192.168.201.254: icmp_seq=1 ttl=64 time=0.325 ms

64 bytes from 192.168.201.254: icmp_seq=2 ttl=64 time=0.281 ms

# 路由器有回應！表示可以連接到路由器！那麼 TCP/IP 設好了，

# 但是主機名稱解析器統 (DNS) 該如何處理？

[root@www ~]# dig www.google.com

; <<>> DiG 9.3.4-P1 <<>> www.google.com

;; global options:  printcmd

....(中間省略)....

;; QUESTION SECTION:

;www.google.com.                        IN      A

....(中間省略)....

;; ANSWER SECTION:

www.google.com.         522933  IN      CNAME   www.l.google.com.

www.l.google.com.       107     IN      A       72.14.203.103

....(中間省略)....

;; Query time: 5 msec

;; SERVER: 120.114.150.1#53(120.114.150.1)

;; WHEN: Fri Sep 18 13:14:45 2009

;; MSG SIZE  rcvd: 340

# 確實有查到 Google 的 IP ，且是由 120.114.150.1 那部 DNS 主機幫忙解析的！

- 網路設定妥當之後，那我們就能夠直接使用 yum 囉！可以這樣直接進行安裝的：

[root@www ~]# yum install httpd httpd-devel php php-devel php-mysql

然後接著一步一步進行安裝即可。

簡答題部分：

- 如果你曾經修改過 yum 設定檔內的容器設定 (/etc/yum.repos.d/*.repo) ，導致下次使用 yum 進行安裝時老是發現錯誤， 此時你該如何是好？

先確認你的設定檔確實是正確的，如果沒問題，可以將 yum 的快取清除，使用『yum clean all』即可。 事實上， yum 的所有快取、下載軟體、下載軟體的表頭資料，都放置於 /var/cache/yum/ 目錄下。

- 簡單說明 RPM 與 SRPM 的異同？

RPM 檔案是由程式打包者 (通常是由 distribution 的開發商) 藉由程式的原始碼，在特定的平台上面所編譯成功的 binary program 的資料，並將該資料製作成為 RPM 的格式，以方便相同軟、硬體平台的使用者之安裝使用。 在安裝時顯的很簡單，因為程式打包者的平台與使用者所使用的平台預設為相同。

至於 SRPM 則是藉由與 RPM 相同的設定檔資料，不過將原始碼直接包在 SRPM 檔案當中，而不經過編譯。 因為 SRPM 所內含的資料為原始碼，所以安裝時必須要再經過編譯的行為才能成為 RPM 並提供使用者安裝。

- 假設我想要安裝一個軟體，例如 pkgname.i386.rpm ，但卻老是發生無法安裝的問題，請問我可以加入哪些參數來強制安裝他？

可以加入 --nodeps 等參數。例如 rpm -ivh --nodeps pkgname.i386.rpm

- 承上題，你認為強制安裝之後，該軟體是否可以正常執行？為什麼？

一般來說，應該是『不能執行』的，因為該軟體具有相依屬性的問題， 某些時刻該軟體的程式可能需要呼叫外部的函式庫，但函式庫可能未安裝，因此當然無法執行成功。

- 有些人使用 OpenLinux 3.1 Server 安裝在自己的 P-166 MMX ，卻發現無法安裝，在查詢了該原版光碟的內容，發現裡面的檔案名稱為 ***.i686.rpm 。請問，無法安裝的可能原因為何？

因為 P-166MMX 為 i586 的硬體平台，而 OpenLinux 為針對 i686 的硬體平台進行最佳化， 因此很可能由於下達的參數無法支援的問題，導致無法安裝成功。

- 請問我使用 rpm -Fvh *.rpm 及 rpm -Uvh *.rpm 來升級時，兩者有何不同？

-Uvh 後面接的軟體，如果原本未安裝，則直接安裝，原本已安裝時，則直接升級；

-Fvh 後面接的軟體，如果原本未安裝，則不安裝，原本已安裝時，則直接升級；

- 假設有一個廠商推出軟體時，自行處理了數位簽章，你想要安裝他們的軟體所以需要使用數位簽章，假設數位簽章的檔名為 signe， 那你該如何安裝？

rpm --import signe

- 承上，假設該軟體廠商提供了 yum 的安裝網址為： http://their.server.name/path/ ，那你該如何處理 yum 的設定檔？

可以自行取個檔名，在此例中我們使用『 vim /etc/yum.repos.d/their.repo 』，副檔名要正確！ 內容有點像這樣即可：

[their]

name=their server name

baseurl=http://their.server.name/path/

enable=1

gpgcheck=0

然後使用 yum 去安裝該軟體看看。

參考資料與延伸閱讀

- 註1：GNU Privacy Guard (GPG) 官方網站的介紹：http://www.gnupg.org/

- RPM 包裝檔案管理程式：http://www.study-area.org/tips/rpm.htm

- 中文 RPM HOW-TO：http://www.linux.org.tw/CLDP/RPM-HOWTO.html

- RPM 的使用：http://linux.tnc.edu.tw/techdoc/rpm-howto.htm

- 大家來作 RPM ：http://freebsd.ntu.edu.tw/bsd/4/3/2/29.html

- 一本 RPM 的原文書：http://linux.tnc.edu.tw/techdoc/maximum-rpm/rpmbook/

- 台灣網路危機處理小組：http://www.cert.org.tw/

2002/08/21：第一次完成

2003/02/11：重新編排與加入 FAQ

2004/04/11：已經完成了 Source code 與 Tarball ，開始進行 RPM 與 SRPM 的介紹！(需要耗時多日啊！因為又要進兵營去了！)

2004/04/20：終於給他熬出來啦！又是過了兩個休假期間∼啊！給我退伍令、其餘免談！

2005/10/02：舊版的 SRPM 資料已經移動到 此處 。

2005/10/03：舊版的針對 Red Hat 與 Mandriva 的版本移動到 此處 。

2005/10/03：將原本去年的版本改為 FC4 為範例的模樣！

2009/06/20：原本的針對 FC4 寫的舊版文章移動到此處。

2009/09/18：加入了簡單的情境模擬，也加入了一些關於 yum 的習題喔！

2002/12/04以來統計人數

第二十四章、 X Window 設定介紹

切換解析度為 800x600

最近更新日期：2009/08/07

在 Linux 上頭的圖形介面我們稱之為 X Window System，簡稱為 X 或 X11 囉！ 為何稱之為系統呢？這是因為 X 視窗系統又分為 X server 與 X client ，既然是 Server/Client (主從架構) 這就表示其實 X 視窗系統是可以跨網路且跨平台的！X 視窗系統對於 Linux 來說僅是一個軟體， 只是這個軟體日趨重要喔！因為 Linux 是否能夠在桌上型電腦上面流行，與這個 X 視窗系統有關啦！ 好在，目前的 X 視窗系統整合到 Linux 已經非常優秀了，而且也能夠具有 3D 加速的功能， 只是，我們還是得要瞭解一下 X 視窗系統才好，這樣如果出問題，我們才有辦法處理啊！

1. 什麼是 X Window System

1.1 X Window 的發展簡史

1.2 主要元件： X Server/X Client/Window Manager/Display Manager

1.3 X Window 的啟動流程：startx, xinit

1.4 X 啟動流程測試

1.5 我是否需要啟用 X Window System

2. X Server 設定檔解析與設定

2.1 解析 xorg.conf 設定

2.2 X Font Server (XFS) 與加入額外中文字形：chkfontpath, fc-cache

2.3 設定檔重建與顯示器參數微調：透過 gtf 調整解析度

3. 顯示卡驅動程式安裝範例

3.1 NVidia

3.2 ATI (AMd)

3.3 Intel

4. 重點回顧

5. 本章習題

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23897

什麼是 X Window System

Unix Like 作業系統不是只能進行伺服器的架設而已，在美編、排版、製圖、多媒體應用上也是有其需要的。 這些需求都需要用到圖形介面 (Graphical User Interface, GUI) 的操作的， 所以後來才有所謂的 X Window System 這玩意兒。那麼為啥圖形視窗介面要稱為 X 呢？因為就英文字母來看 X 是在 W(indow) 後面，因此，人們就戲稱這一版的視窗介面為 X 囉 (有下一版的新視窗之意)！

事實上， X Window System 是個非常大的架構，他還用到網路功能呢！也就是說，其實 X 視窗系統是能夠跨網路與跨作業系統平台的！ 而鳥哥這個基礎篇是還沒有談到伺服器與網路主從式架構，因此 X 在這裡並不容易理解的。不過，沒關係！ 我們還是談談 X 怎麼來的，然後再來談談這 X 視窗系統的元件有哪些，慢慢來，應該還是能夠理解 X 的啦！

X Window 的發展簡史

X Window 系統最早是由 MIT (Massachusetts Institute of Technology, 麻省理工學院) 在 1984 年發展出來的， 當初 X 就是在 Unix 的 System V 這個作業系統版本上面開發出來的。在開發 X 時，開發者就希望這個視窗介面不要與硬體有強烈的相關性，這是因為如果與硬體的相關性高，那就等於是一個作業系統了， 如此一來的應用性會比較侷限。因此 X 在當初就是以應用程式的概念來開發的，而非以作業系統來開發。

由於這個 X 希望能夠透過網路進行圖形介面的存取，因此發展出許多的 X 通訊協定，這些網路架構非常的有趣， 所以吸引了很多廠商加入研發，因此 X 的功能一直持續在加強！一直到 1987 年更改 X 版本到 X11 ，這一版 X 取得了明顯的進步， 後來的視窗介面改良都是架構於此一版本，因此後來 X 視窗也被稱為 X11 。這個版本持續在進步當中，到了 1994 年發佈了新版的 X11R6 ，後來的架構都是沿用此一釋出版本，所以後來的版本定義就變成了類似 1995 年的 X11R6.3 之類的樣式。 (註1)

1992 年 XFree86 (http://www.xfree86.org/) 計畫順利展開， 該計畫持續在維護 X11R6 的功能性，包括對新硬體的支援以及更多新增的功能等等。當初定名為 XFree86 其實是根據『 X + Free software + x86 硬體 』而來的呢。早期 Linux 所使用的 X Window 的主要核心都是由 XFree86 這個計畫所提供的，因此，我們常常將 X 系統與 XFree86 掛上等號的說。

不過由於一些授權的問題導致 XFree86 無法繼續提供類似 GPL 的自由軟體，後來 Xorg 基金會就接手 X11R6 的維護！ Xorg (http://www.x.org/) 利用當初 MIT 發佈的類似自由軟體的授權， 將 X11R6 拿來進行維護，並且在 2004 年發佈了 X11R6.8 版本，更在 2005 年後發表了 X11R7.x 版。 現在我們 CentOS 5.x 使用的 X 就是 Xorg 提供的 X11R7 喔！ 而這個 X11R6/X11R7 的版本是自由軟體，因此很多組織都利用這個架構去設計他們的圖形介面喔！包括 Mac OS X v10.3 也曾利用過這個架構來設計他們的視窗呢！我們的 CentOS 也是利用 Xorg 提供的 X11 啦！

從上面的說明，我們可以知道的是：

- 在 Unix Like 上面的圖形使用者介面 (GUI) 被稱為 X 或 X11；

- X11 是一個『軟體』而不是一個作業系統；

- X11 是利用網路架構來進行圖形介面的執行與繪製；

- 較著名的 X 版本為 X11R6 這一版，目前大部分的 X 都是這一版演化出來的 (包括 X11R7)；

- 現在大部分的 distribution 使用的 X 都是由 Xorg 基金會所提供的 X11 軟體；

- X11 使用的是 MIT 授權，為類似 GPL 的自由軟體授權方式。

主要元件： X Server/X Client/Window Manager/Display Manager

如同前面談到的，X Window system 是個利用網路架構的圖形使用者介面軟體，那到底這個架構可以分成多少個元件呢？ 基本上是分成 X Server 與 X Client 兩個元件而已喔！其中 X Server 在管理硬體，而 X Client 則是應用程式。 在運作上，X Client 應用程式會將所想要呈現的畫面告知 X Server ，最終由 X server 來將結果透過他所管理的硬體繪製出來！ 整體的架構我們大約可以使用如下的圖示來作個介紹：(註2)

圖 1.2.1、 X Window System 的架構 (註2)

上面的圖示非常有趣喔！我們在用戶端想要取得來自伺服器的圖形資料時，我們用戶端使用的當然是用戶端的硬體設備啊， 所以，X Server 的重點就是在管理用戶端的硬體，包括接受鍵盤/滑鼠等設備的輸入資訊， 並且將圖形繪製到螢幕上 (請注意上圖的所有元件之間的箭頭指示)。但是到底要繪製個啥東西呢？ 繪圖總是需要一些數據才能繪製吧？此時 X Client (就是 X 應用程式) 就很重要啦！他主要提供的就是告知 X Server 要繪製啥東西。那照這樣的想法來思考，我們是想要取得遠端伺服器的繪圖數據來我們的電腦上面顯示嘛！ 所以囉，遠端伺服器提供的是 X client 軟體啊！

底下就讓我們來更深入的聊一聊這兩個元件吧！

- X Server：硬體管理、螢幕繪製與提供字型功能：

既然 X Window System 是要顯示圖形介面，因此理所當然的需要一個元件來管理我主機上面的所有硬體設備才行！ 這個任務就是 X Server 所負責的。而我們在 X 發展簡史當中提到的 XFree86 計畫及 Xorg 基金會，主要提供的就是這個 X Server 啦！那麼 X Server 管理的設備主要有哪些呢？其實與輸入/輸出有關喔！包括鍵盤、滑鼠、手寫板、顯示器 (monitor) 、螢幕解析度與色彩深度、顯示卡 (包含驅動程式) 與顯示的字型等等，都是 X Server 管理的。

咦！顯示卡、螢幕以及鍵盤滑鼠的設定，不是在開機的時候 Linux 系統以 /etc/sysconfig 目錄下的 keyboard/mouse 等設定檔就設好了嗎？為何 X Server 還要重新設定啊？這是因為 X Window 在 Linux 裡面僅能算是『一套很棒的軟體』， 所以 X Window 有自己的設定檔，你必須要針對他的設定檔設定妥當才行。也就是說， Linux 的設定與 X Server 的設定不一定要相同的！因此，你在 Linux 的 run level 3 想要玩圖形介面時，就得要載入 X Window 需要的驅動程式才行∼總之， X Server 的主要功能就是在管理『主機』上面的顯示硬體與驅動程式。

既然 X Window System 是以透過網路取得圖形介面的一個架構，那麼用戶端是如何取得伺服器端提供的圖形畫面呢？ 由於伺服器與用戶端的硬體不可能完全相同，因此我們用戶端當然不可能使用到伺服器端的硬體顯示功能！ 舉例來說，你的用戶端電腦並沒有 3D 影像加速功能，那麼你的畫面可能呈現出伺服器端提供的 3D 加速嗎？ 當然不可能吧！所以囉 X Server 的目的在管理用戶端的硬體設備！也就是說：『每部用戶端主機都需要安裝 X Server，而伺服器端則是提供 X Client 軟體， 以提供用戶端繪圖所需要的數據資料』。

X Server / X Client 的互動並非僅有 client --> server，兩者其實有互動的！從上圖 1.2.1 我們也可以發現， X Server 還有一個重要的工作，那就是將來自輸入裝置 (如鍵盤、滑鼠等) 的動作告知 X Client， 你曉得， X Server 既然是管理這些周邊硬體，所以，周邊硬體的動作當然是由 X Server 來管理的， 但是 X Server 本身並不知道周邊設備這些動作會造成什麼顯示上的效果， 因此 X Server 會將周邊設備的這些動作行為告知 X Client ，讓 X Client 去傷腦筋。

- X Client：負責 X Server 要求的『事件』之處理：

前面提到的 X Server 主要是管理顯示介面與在螢幕上繪圖，同時將輸入裝置的行為告知 X Client， 此時 X Client 就會依據這個輸入裝置的行為來開始處理，最後 X Client 會得到『 嗯！這個輸入裝置的行為會產生某個圖示』，然後將這個圖示的顯示資料回傳給 X Server ， X server 再根據 X Client 傳來的繪圖資料將他描圖在自己的螢幕上，來得到顯示的結果。

也就是說， X Client 最重要的工作就是處理來自 X Server 的動作，將該動作處理成為繪圖資料， 再將這些繪圖資料傳回給 X Server 囉！由於 X Client 的目的在產生繪圖的數據，因此我們也稱呼 X Client 為 X Application (X 應用程式)。而且，每個 X Client 並不知道其他 X Client 的存在， 意思是說，如果有兩個以上的 X client 同時存在時，兩者並不知道對方到底傳了什麼數據給 X Server ， 因此 X Client 的繪圖常常會互相重疊而產生困擾喔！

舉個例子來說，當我們在 X Window 的畫面中，將滑鼠向右移動，那他是怎麼告知 X Server 與 X Client 的呢？ 首先， X server 會偵測到滑鼠的移動，但是他不知道應該怎麼繪圖啊！此時，他將滑鼠的這個動作告知 X Client， X Client 就會去運算，結果得到，嘿嘿！其實要將滑鼠指標向右移動幾個位素，然後將這個結果告知 X server ， 接下來，您就會看到 X Server 將滑鼠指標向右移動囉∼

這樣做有什麼好處啊？最大的好處是， X Client 不需要知道 X Server 的硬體配備與作業系統！因為 X Client 單純就是在處理繪圖的資料而已，本身是不繪圖的。所以，在用戶端的 X Server 用的是什麼硬體？用的是哪套作業系統？伺服器端的 X Client 根本不需要知道∼相當的先進與優秀∼對吧！ ^_^ 整個運作流程可以參考下圖：用戶端用的是什麼作業系統在 Linux 主機端是不在乎的！

圖 1.2.2、 X Server 用戶端的作業系統與 X client 的溝通示意

- X Window Manager：特殊的 X Client ，負責管理所有的 X client 軟體

剛剛前面提到，X Client 的主要工作是將來自 X Server 的資料處理成為繪圖數據，再回傳給 X server 而已， 所以 X client 本身是不知道他在 X Server 當中的位置、大小以及其他相關資訊的。這也是上面我們談到的， X client 彼此不知道對方在螢幕的哪個位置啊！為了克服這個問題，因此就有 Window Manager (WM, 視窗管理員) 的產生了。 視窗管理員也是 X client ，只是他主要在負責全部 X client 的控管，還包括提供某些特殊的功能，例如：

- 提供許多的控制元素，包括工作列、背景桌面的設定等等；

- 管理虛擬桌面 (virtual desktop)；

- 提供視窗控制參數，這包括視窗的大小、視窗的重疊顯示、視窗的移動、視窗的最小化等等。

我們常常聽到的 KDE, GNOME, XFCE 還有陽春到爆的 twm 等等，都是一些視窗管理員的專案計畫啦！ 這些專案計畫中，每種視窗管理員所用以開發的顯示引擎都不太相同，所著重的方向也不一樣， 因此我們才會說，在 Linux 底下，每套 Window Manager 都是獨特存在的，不是換了桌面與顯示效果而已， 而是連顯示的引擎都不會一樣喔！底下是這些常見的視窗管理員全名與連結：

- GNOME (GNU Network Object Model Environment)：http://www.gnome.org/

- KDE (K Desktop Enviroment)：http://kde.org/

- twm (Tab Window Manager)：http://xwinman.org/vtwm.php

- XFCE (XForms Common Environment)：http://www.xfce.org/

由於 Linux 越來越朝向 Desktop 桌上型電腦使用方向走，因此視窗管理員的角色會越來越重要！ 目前我們 CentOS 預設提供的有 GNOME 與 KDE ，這兩個視窗管理員上面還有提供非常多的 X client 軟體， 包括辦公室生產力軟體 (Open Office) 以及常用的網路功能 (firefox 瀏覽器、 Thunderbird 收發信件軟體) 等。 現在使用者想要接觸 Linux 其實真的越來越簡單了，如果不要架設伺服器，那麼 Linux 桌面的使用與 Windows 系統可以說是一模一樣的！不需要學習也能夠入門哩！ ^_^

那麼你知道 X Server / X client / window manager 的關係了嗎？我們舉 CentOS 預設的 GNOME 為例好了， 由於我們要在本機端啟動 X Window system ，因此，在我們的 CentOS 主機上面必須要有 Xorg 的 X server 核心， 這樣才能夠提供螢幕的繪製啊∼然後為了讓視窗管理更方便，於是就加裝了 GNOME 這個計畫的 window manager ， 然後為了讓自己的使用更方便，於是就在 GNOME 上面加上更多的視窗應用軟體，包括輸入法等等的， 最後就建構出我們的 X Window System 囉∼ ^_^！所以你也會知道，X server/X client/Window Manager 是同時存在於我們一部 Linux 主機上頭的啦！

- Display Manager：提供登入需求

談完了上述的資料後，我們得要瞭解一下，那麼我如何取得 X Window 的控制？在本機的文字介面底下你可以輸入 startx 來啟動 X 系統，此時由於你已經登入系統了，因此不需要重新登入即可取得 X 環境。但如果是 runlevel 5 的環境呢？你會發現在 tty7 的地方有個可以讓你使用圖形介面登入 (輸入帳號密碼) 的咚咚，那個是啥？ 是 X Server/X client 還是什麼的？其實那是個 Display Manager 啦！這個 display manager 最大的任務就是提供登入的環境， 並且載入使用者選擇的 Window Manager 與語系等資料喔！

幾乎所有的大型視窗管理員專案計畫都會提供 display manager 的，在 CentOS 上面我們主要利用的是 GNOME 的 GNOME Display Manager (gdm) 這支程式來提供 tty7 的圖形介面登入喔！至於登入後取得的視窗管理員， 則可以在 gdm 上面進行選擇的！我們在第五章介紹的登入環境， 那個環境其實就是 gdm 提供的啦！再回去參考看看圖示吧！ ^_^！所以說，並非 gdm 只能提供 GNOME 的登入而已喔！

X Window 的啟動流程

現在我們知道要啟動 X Window System 時，必須要先啟動管理硬體與繪圖的 X Server ，然後才載入 X Client 。 基本上，目前都是使用 Window Manager 來管理視窗介面風格的。那麼如何取得這樣的視窗系統呢？ 你可以透過登入本機的文字介面後，輸入 startx 來啟動 X 視窗；也能夠透過 display manager (如果有啟動 runlevel 5) 提供的登入畫面，輸入你的帳號密碼來登入與取得 X 視窗的！

問題是，你的 X server 設定檔為何？如何修改解析度與顯示器？你能不能自己設定預設啟動的視窗管理員？ 如何設定預設的使用者環境 (與 X client 有關) 等等的，這些資料都需要透過瞭解 X 的啟動流程才能得知！ 所以，底下我們就來談談如何啟動 X 的流程吧！ ^_^

- 在文字介面啟動 X ：透過 startx 指令

我們都知道 Linux 是個多人多工的作業系統，所以啦，X 視窗也是可以根據不同的使用者而有不同的設定！ 這也就是說，每個用戶啟動 X 時， X server 的解析度、啟動 X client 的相關軟體及 Window Manager 的選擇可能都不一樣！ 但是，如果你是首次登入 X 呢？也就是說，你自己還沒有建立自己的專屬 X 畫面時，系統又是從哪裡給你這個 X 預設畫面呢？而如果你已經設定好相關的資訊，這些資訊又是存放於何處呢？

事實上，當你在純文字介面且並沒有啟動 X 視窗的情況下來輸入 startx 時，這個 startx 的作用就是在幫你設定好上頭提到的這些動作囉！ startx 其實是一個 shell script ，他是一個比較親和的程式，會主動的幫忙使用者建立起他們的 X 所需要引用的設定檔而已。你可以自行研究一下 startx 這個 script 的內容，鳥哥在這裡僅就 startx 的作用作個介紹。

startx 最重要的任務就是找出使用者或者是系統預設的 X server 與 X client 的設定檔，而使用者也能夠使用 startx 外接參數來取代設定檔的內容。這個意思是說：startx 可以直接啟動，也能夠外接參數，例如底下格式的啟動方式：

[root@www ~]# startx [X client 參數] -- [X server 參數]

# 範例：以色彩深度為 16 bit 啟動 X

[root@www ~]# startx  --  -depth 16

startx 後面接的參數以兩個減號『--』隔開，前面的是 X Client 的設定，後面的是 X Server 的設定。 上面的範例是讓 X server 以色彩深度 16 bit 色 (亦即每一像素佔用 16 bit ，也就是 65536 色) 顯示， 因為色彩深度是與 X Server 有關的，所以參數當然是寫在 -- 後面囉，於是就成了上面的模樣！

你會發現，鳥哥上面談到的 startx 都是提到如何找出 X server / X client 的設定值而已！ 沒錯，事實上啟動 X 的是 xinit 這支程式， startx 僅是在幫忙找出設定值而已！那麼 startx 找到的設定值可用順序為何呢？基本上是這樣的：

- X server 的參數方面：

1. 使用 startx 後面接的參數；

2. 若無參數，則找尋使用者家目錄的檔案，亦即 ~/.xserverrc

3. 若無上述兩者，則以 /etc/X11/xinit/xserverrc

4. 若無上述三者，則單純執行 /usr/bin/X (此即 X server 執行檔)

- X client 的參數方面：

1. 使用 startx 後面接的參數；

2. 若無參數，則找尋使用者家目錄的檔案，亦即 ~/.xinitrc

3. 若無上述兩者，則以 /etc/X11/xinit/xinitrc

4. 若無上述三者，則單純執行 xterm (此為 X 底下的終端機軟體)

根據上述的流程找到啟動 X 時所需要的 X server / X client 的參數，接下來 startx 會去呼叫 xinit 這支程式來啟動我們所需要的 X 視窗系統整體喔！接下來當然就是要談談 xinit 囉∼

- 由 startx 呼叫執行的 xinit

事實上，當 startx 找到需要的設定值後，就呼叫 xinit 實際啟動 X 的。他的語法是：

[root@www ~]# xinit [client option] -- [server or display option]

那個 client option 與 server option 如何下達呢？其實那兩個咚咚就是由剛剛 startx 去找出來的啦！ 在我們透過 startx 找到適當的 xinitrc 與 xserverrc 後，就交給 xinit 來執行。 在預設的情況下 (使用者尚未有 ~/.xinitrc 等檔案時)，你輸入 startx ， 就等於進行 xinit /etc/X11/xinit/xinitrc -- /etc/X11/xinit/xserverrc 這個指令一般！但由於 xserverrc 也不存在，參考上一小節的參數搜尋順序， 因此實際上的指令是：xinit /etc/X11/xinit/xinitrc -- /usr/bin/X，這樣瞭了嗎？

那為什麼不要直接執行 xinit 而是使用 startx 來呼叫 xinit 呢？這是因為我們必須要取得一些參數嘛！ startx 可以幫我們快速的找到這些參數而不必手動輸入的。因為單純只是執行 xinit 的時候，系統的預設 X Client 與 X Server 的內容是這樣的：(註3)

xinit xterm  -geometry  +1+1  -n  login  -display  :0 --  X  :0

在 X client 方面：那個 xterm 是 X 視窗底下的虛擬終端機，後面接的參數則是這個終端機的位置與登入與否。 最後面會接一個『 -display :0 』表示這個虛擬終端機是啟動在『第 :0 號的 X 顯示介面』的意思。至於 X Server 方面， 而我們啟動的 X server 程式就是 X 啦！其實 X 就是 Xorg 的連結檔，亦即是 X Server 的主程式囉！ 所以我們啟動 X 還挺簡單的∼直接執行 X 而已，同時還指定 X 啟動在第 :0 個 X 顯示介面。 如果單純以上面的內容來啟動你的 X 系統時，你就會發現 tty7 有畫面了！只是.....很醜∼因為我們還沒有啟動 window manager 啊！

從上面的說明我們可以知道， xinit 主要在啟動 X server 與載入 X client ，但這個 xinit 所需要的參數則是由 startx 去幫忙找尋的。因此，最重要的當然就是 startx 找到的那些參數啦！ 所以呢，重點當然就是 /etc/X11/xinit/ 目錄下的 xinitrc 與 xserverrc 這兩個檔案的內容是啥囉∼ 雖然 xserverrc 預設是不存在的。底下我們就分別來談一談這兩個檔案的主要內容與啟動的方式∼

- 啟動 X server 的檔案： xserverrc

X 視窗最先需要啟動的就是 X server 啊，那 X server 啟動的腳本與參數是透過 /etc/X11/xinit/ 裡面的 xserverrc 。不過我們的 CentOS 5.x 根本就沒有 xserverrc 這個檔案啊！ 那使用者家目錄目前也沒有 ~/.xserverrc ，這個時候系統會怎麼做呢？其實就是執行 /usr/bin/X 這個指令啊！ 這個指令也是系統最原始的 X server 執行檔囉。

在啟動 X Server 時，Xorg 會去讀取 /etc/X11/xorg.conf 這個設定檔。針對這個設定檔的內容， 我們會在下個小節介紹。如果一切順利，那麼 X 就會順利的在 tty7 的環境中啟動了 X 。 單純的 X 啟動時，你只會看到畫面一片漆黑，然後中心有個滑鼠的游標而已∼

由前一小節的說明中，你可以發現到其實 X 啟動的時候還可以指定啟動的介面喔！那就是 :0 這個參數，這是啥？ 事實上我們的 Linux 可以『同時啟動多個 X』喔！第一個 X 的畫面會在 :0 亦即是 tty7 ，第二個 X 則是 :1 亦即是 tty8 。 後續還可以有其他的 X 存在的。因此，上一小節我們也有發現， xterm 在載入時，也必須要使用 -display 來說明， 這個 X 應用程式是需要在哪個 X 載入的才行呢！其中比較有趣的是， X server 未註明載入的介面時，預設是使用 :0 ∼ 但是 X client 未註明時，則無法執行喔！

啟動了 X server 後，接下來就是載入 X client 到這個 X server 上面啦！

- 啟動 X Client 的檔案： xinitrc

假設你的家目錄並沒有 ~/.xinitrc ，則此時 X Client 會以 /etc/X11/xinit/xinitrc 來作為啟動 X Client 的預設腳本。xinitrc 這個檔案會將很多其他的檔案參數引進來， 包括 /etc/X11/xinit/xinitrc-common 與 /etc/X11/xinit/Xclients 還有 /etc/sysconfig/desktop 。你可以參考 xinitrc 後去搜尋各個檔案來瞭解彼此的關係。

不過分析到最後，其實最終就是載入 KDE 或者是 GNOME 而已。你也可以發現最終在 XClient 檔案當中會有兩個指令的搜尋， 包括 startkde 與 gnome-session 這兩個，這也是 CentOS 預設會提供的兩個主要的 Window Manager 囉。 而你也可以透過修改 /etc/sysconfig/desktop 內的 DESKTOP=GNOME 或 DESKTOP=KDE 來決定預設使用哪個視窗管理員的。 如果你並沒有安裝這兩個大傢伙，那麼 X 就會去使用陽春的 twm 這個視窗管理員來管理你的環境囉。

Tips:

不論怎麼說，鳥哥還是希望大家可以透過解析 startx 這個 script 的內容去找到每個檔案， 再根據分析每個檔案來找到您 distributions 上面的 X 相關檔案∼ 畢竟每個版本的 Linux 還是有所差異的∼

另外，如果有特殊需求，你當然可以自訂 X client 的參數！這就得要修改你家目錄下的 ~/.xinitrc 這個檔案囉。 不過要注意的是，如果你的 .xinitrc 設定檔裡面有啟動的 x client 很多的時候，千萬注意將除了最後一個 window manager 或 X Client 之外，都放到背景裡面去執行啊！舉例來說，像底下這樣：

xclock -geometry 100x100-5+5 &

xterm -geometry 80x50-50+150 &

exec /usr/bin/twm

意思就是說，我啟動了 X ，並且同時啟動 xclock / xterm / twm 這三個 X clients 喔！ 如此一來，你的 X 就有這三個咚咚可以使用了！如果忘記加上 & 的符號，那就..... 會讓系統等待啊，而無法一次就登入 X 呢！

- X 啟動的埠口

好了，根據上面的說明，我們知道要在文字介面底下啟動 X 時，直接使用 startx 來找到 X server 與 X client 的參數或設定檔， 然後再呼叫 xinit 來啟動 X 視窗系統。xinit 先載入 X server 到預設的 :0 這個顯示介面 (預設在 tty7)，然後再載入 X client 到這個 X 顯示介面上。而 X client 通常就是 GNOME 或 KDE ，這兩個設定也能夠在 /etc/sysconfig/desktop 裡面作好設定。最後我們想要瞭解的是，既然 X 是可以跨網路的，那 X 啟動的埠口是幾號？

其實，CentOS 由於考慮 X 視窗是在本機上面運作，因此將埠口改為插槽檔 (socket) 了，因此你無法觀察到 X 啟動的埠口的。事實上， X server 應該是要啟動一個 port 6000 來與 X client 進行溝通的！ 由於系統上面也可能有多個 X 存在，因此我們就會有 port 6001, port 6002... 等等。這也就是說：

X 視窗系統

顯示介面號碼

預設終端機

網路監聽埠口

第一個 X

hostname:0

tty7

port 6000

第二個 X

hostname:1

tty8

port 6001

在 X Window System 的環境下，我們稱 port 6000 為第 0 個顯示介面，亦即為 hostname:0 ， 那個主機名稱通常可以不寫，所以就成了 :0 即可。在預設的情況下，第一個啟動的 X (不論是啟動在第幾個 port number) 是在 tty7 ，亦即按下 [ctrl]+[Alt]+[F7] 那個畫面。 而起動的第二個 X (注意到了吧！可以有多個 X 同時啟動在您的系統上呢) 則預設在 tty8 亦即 [ctrl]+[Alt]+[F8] 那個畫面呢！很神奇吧！ ^_^

如前所述，因為主機上的 X 可能有多個同時存在，因此，當我們在啟動 X Server / Client 時， 應該都要註明該 X Server / Client 主要是提供或接受來自哪個 display 的 port number 才行。

X 啟動流程測試

好了，我們可以針對 X Server 與 X client 的架構來做個簡單的測試喔！ 由於鳥哥不知道你到底有沒有啟動過 X ，因此底下鳥哥將這個練習指定於第二個 X ，亦即是 :1 這個顯示位置來顯示喔！ 而且，底下的指令都是在 tty1 的地方執行的，至於底下的畫面則是在 tty8 的地方展現。 因此，請自行切換 tty1 下達指令與 tty8 查閱結果囉！(如果是 CentOS 之類的 Red Hat 系統，請務必要啟動 xfs 這個服務喔！)

1. 先來啟動第一個 X 在 :1 畫面中：

[root@www ~]# X :1 &

圖 1.4.1 、 單純啟動 X server的情況

上述的 X 是大寫，那個 :1 是寫在一起的，至於 & 則是放到背景去執行。此時系統會主動的跳到第二個圖形介面終端機，亦即 tty8 上喔！所以如果一切順利的話，你應該可以看到一個 X 的滑鼠游標可以讓你移動了(如上圖所示)。 該畫面就是 X Server 啟動的畫面囉！醜醜的，而且沒有什麼 client 可以用啊！ 接下來，請按下 [ctrl]+[alt]+[F1] 回到剛剛下達指令的終端機：

2. 輸入數個可以在 X 當中執行的虛擬終端機

[root@www ~]# xterm -display :1  &

[root@www ~]# xterm -display :1  &

圖 1.4.2 、 在 X 上面啟動 xterm 終端機顯示的結果

那個 xterm 是必須要在 X 底下才能夠執行的終端機介面。加入的參數 -display 則是指出這個 xterm 要在那個 display 使用的。這兩個指令請不要一次下完！先執行一次，然後按下 [ctrl]+[alt]+[F8] 去到 X 畫面中，你會發現多了一個終端機囉∼ 不過，可惜的是，你無法看到終端機的標題、也無法移動終端機，當然也無法調整終端機的大小啊！我們回到剛剛的 tty1 然後再次下達 xterm 指令，理論上應該多一個終端機，去到 tty8 查閱一下。唉∼沒有多出一個終端機啊？ 這是因為兩個終端機重疊了∼我們又無法移動終端機，所以只看到一個。 接下來，請再次回到 tty1 去下達指令吧！

3. 在輸入不同的 X client 觀察觀察，分別去到 tty8 觀察喔！

[root@www ~]# xclock -display :1  &

[root@www ~]# xeyes -display :1  &

圖 1.4.3 、 分別啟動 xclock 時鐘與 xeyes 眼睛的結果

跟前面一樣的，我們又多執行了兩個 X client ，其中 xclock 會顯示時鐘，而 xeyes 則是會出現一雙大眼睛來盯著游標！ 你可以移動一下游標就可以發現眼睛的焦聚會跑啊 ^_^！不過，目前的四個 X client 通通不能夠移動與放大縮小！ 如此一來，你怎麼在 xterm 底下下達指令啊？當然就很困擾∼所以讓我們來載入最陽春的視窗管理員吧！

4. 輸入可以管理的 window manager

[root@www ~]# twm -display :1  &

圖 1.4.4 、 視窗管理員 twm 的功能顯示

回到 tty1 後，用最簡單的 twm 這個視窗管理員來管理我們的 X 吧！輸入之後，去到 tty8 看看，用滑鼠移動一下終端機看看？可以移動了吧？也可以縮小放大視窗囉∼同時也出現了標題提示囉∼也看到兩個終端機啦！ 現在終於知道視窗管理員的重要性了吧？ ^_^！在黑螢幕地方按下滑鼠右鍵，就會出現類似上面畫面最右邊的選單， 你就可以進行額外的管理囉∼玩玩看先！

5. 將所有剛剛建立的 X 相關工作全部殺掉！

[root@www ~]# kill %6

[root@www ~]# kill %5

[root@www ~]# kill %4

[root@www ~]# kill %3

[root@www ~]# kill %2

[root@www ~]# kill %1

很有趣的一個小實驗吧∼透過這個實驗，你應該會對 X server 與 Window manager 及 tty7 以後的終端介面使用方式有比較清楚的瞭解∼加油！

我是否需要啟用 X Window System

談了這麼多 X 視窗系統方面的資訊後，再來聊聊，那麼你的 Linux 主機是否需要預設就啟動 X 視窗呢？ 一般來說，如果你的 Linux 主機定位為網路伺服器的話，那麼由於 Linux 裡面的主要服務的設定檔都是純文字的格式檔案， 相當的容易設定的，所以啊，根本就是不需要 X Window 存在呢！因為 X Window 僅是 Linux 系統內的一個軟體而已啊！

但是萬一你的 Linux 主機是用來作為你的桌上電腦用的，那麼 X Window 對你而言，就是相當重要的一個咚咚了！因為我們日常使用的辦公室軟體，都需要使用到 X Window 圖形的功能呢！此外，以鳥哥的例子來說，俺之前接觸到的數值分析模式，需要利用圖形處理軟體來將資料讀取出來， 所以在那部 Linux 主機上面，我一定需要 X Window 的。

回歸到主題上面，除了主機的用途決定你是否需要啟用 X Window 之外， 主機的『配備』也是你必須要考慮的一項決定性因素。因為 X Window 如果要美觀，可能需要功能較為強大的 KDE 或 GNOME 等視窗管理員的協助，但是這兩個龐然大物對於系統的要求又很高，除了 CPU 等級要夠，RAM 要足之外，顯示卡的等級也不能太差∼所以，早期的主機可能對於 X Window 就沒有辦法具有很好的執行效率了。

也就是說，你如果想要玩 X Window 的話，特別需要考慮到這兩點：

- 穩定性：

X Window 僅是 Linux 上面的一個軟體，雖然目前的 X window 已經整合得相當好了，但任何程式的設計都或多或少會有些臭蟲， X 當然也不例外。此外，在你的 Linux 伺服器上面啟用 X 系統的話，自然多一組程序的啟用 (X Window 會啟動多個程序來執行各項任務) ，系統的不確定性當然可能會增加一些。 因此，鳥哥不是很建議對 Internet 開放的伺服器啟動 X Window 的啦！

- 效能：

無論怎麼說，程式在跑總是需要系統資源的，所以，多啟用了 X 就會造成一些系統資源的損耗。 此外，上面也稍稍提到，某些 X 的軟體是相當耗費系統資源的呢！所以，啟動 X 可能會讓你的可用系統資源 (尤其是記憶體) 降低很多，可能會造成系統效能較低落的問題。

Tips:

鳥哥剛開始接觸 Linux (大約是在 1999 年左右)時，由於不熟，通常都是預設給他啟用 X Window 在我的主機上面的。 不過，那個時候的圖形介面與 Linux kernel 的整合度比較差， 老是掛點去，是常常造成主機上面的網路服務無法順暢的原因之一呢！

就鳥哥的使用經驗來看， GNOME 速度稍微快一點， KDE 的介面感覺比較具有親和力！不過，總體而言， 這個 X Window System 的速度其實並不是那麼棒！如果你有其他圖形介面的需求時，可以使用 yum 去安裝一下 XFCE 這一套，XFCE 是比較輕量級的視窗管理員，據說使用上速度比 GNOME 還快些。 最近很火紅的 Ubuntu 的分支之一 Xubuntu 據說就是使用這套視窗管理員喔！試看看吧！ ^_^

X Server 設定檔解析與設定

從前面的說明來看，我們知道一個 X 視窗系統能不能成功啟動，其實與 X Server 有很大的關係的。因為 X Server 負責的是整個畫面的描繪，所以沒有成功啟動 X Server 的話，即使有啟動 X Client 也無法將圖樣顯示出來啊。所以，底下我們就針對 X Server 的設定檔來做個簡單的說明，好讓大家可以成功的啟動 X Window System 啊。

基本上， X Server 管理的是顯示卡、螢幕解析度、滑鼠按鍵對應等等，尤其是顯示卡晶片的認識，真是重要啊。 此外，還有顯示的字體也是 X Server 管理的一環。基本上，X server 的設定檔都是預設放置在 /etc/X11 目錄下，而相關的顯示模組或上面提到的總總模組，則主要放置在 /usr/lib/xorg/modules 底下。比較重要的是字型檔與晶片組，她們主要放置在:

- 提供的螢幕字型: /usr/share/X11/fonts/

- 顯示卡的晶片組: /usr/lib/xorg/modules/drivers/

在 CentOS 底下，我們可以透過 chkfontpath 這個指令來取得目前系統有的字型檔案目錄。 這些都要透過一個統一的設定檔來規範，那就是 X server 的設定檔啦。這個設定檔的檔名就是 /etc/X11/xorg.conf 喔！

解析 xorg.conf 設定

如同前幾個小節談到的，在 Xorg 基金會裡面的 X11 版本為 X11R7.xx ，那如果你想要知道到底你用的 X Server 版本是第幾版，可以使用 X 指令來檢查喔！(你必須以 root 的身分執行下列指令)

[root@www ~]# X -version

X Window System Version 7.1.1

Release Date: 12 May 2006

X Protocol Version 11, Revision 0, Release 7.1.1

Build Operating System: Linux 2.6.18-53.1.14.el5PAE i686 Red Hat, Inc.

Current Operating System: Linux localhost.localdomain 2.6.18-128.1.14.el5 #1

SMP Wed Jun 17 06:40:54 EDT 2009 i686

Build Date: 21 January 2009

Build ID: xorg-x11-server 1.1.1-48.52.el5

Before reporting problems, check http://wiki.x.org

to make sure that you have the latest version.

Module Loader present

由上面的幾個關鍵字我們可以知道，目前鳥哥的這部測試機使用的 X server 是 Xorg 計畫所提供的 X11R7 版， 若有問題則可以到 http://wiki.x.org 去查詢∼因為是 Xorg 這個 X server ，因此我們的設定檔檔名為 /etc/X11/xorg.conf 這一個哩。所以，理解這個檔案的內容對於 X server 的功能來說，是很重要的。

注意一下，在修改這個檔案之前，務必將這個檔案給她備份下來，免的改錯了甚麼東西導致連 X server 都無法啟動的問題啊。這個檔案的內容是分成數個段落的，每個段落以 Section 開始，以 EndSection 結束， 裡面含有該 Section (段落) 的相關設定值，例如:

Section  "section name"

…… <== 與這個 section name 有關的設定項目

……

EndSection

至於常見的 section name 主要有:

1. Module: 被載入到 X Server 當中的模組 (某些功能的驅動程式)；

2. InputDevice: 包括輸入的 1. 鍵盤的格式 2. 滑鼠的格式，以及其他相關輸入設備；

3. Files: 設定字型所在的目錄位置等；

4. Monitor: 監視器的格式， 主要是設定水平、垂直的更新頻率，與硬體有關；

5. Device: 這個重要，就是顯示卡晶片組的相關設定了；

6. Screen: 這個是在螢幕上顯示的相關解析度與色彩深度的設定項目，與顯示的行為有關；

7. ServerLayout: 上述的每個項目都可以重覆設定，這裡則是此一 X server 要取用的哪個項目值的設定囉。

好了，直接來看看這個檔案的內容吧！這個檔案預設的情況是取消很多設定值的，所以你的設定檔可能不會看到這麼多的設定項目。 不要緊的，後續的章節會交代如何設定這些項目的喔！

[root@www ~]# cd /etc/X11

[root@www X11]# cp -a xorg.conf xorg.conf.20090713  <== 有備份有保佑

[root@www X11]# vim xorg.conf

Section "Module"

Load  "dbe"

Load  "extmod"

Load  "record"

Load  "dri"

Load  "xtrap"

Load  "glx"

Load  "vnc"

EndSection

# 上面這些模組是 X Server 啟動時，希望能夠額外獲得的相關支援的模組。

# 關於更多模組可以搜尋一下 /usr/lib/xorg/modules/extensions/ 這個目錄

Section "InputDevice"

Identifier  "Keyboard0"

Driver      "kbd"

Option      "XkbModel" "pc105"

Option      "XkbLayout" "us"  <==注意，是 us 美式鍵盤對應

EndSection

# 這個玩意兒是鍵盤的對應設定資料，重點在於 XkbLayout 那一項，

# 如果沒有問題的話，我們台灣地區應該都是使用美式鍵盤對應按鈕的。

# 特別注意到 Identifier (定義) 那一項，那個是在說明，我這個鍵盤的設定檔，

# 被定義為名稱是 Keyboard0 的意思，這個名稱最後會被用於 ServerLayout 中

Section "InputDevice"

Identifier  "Mouse0"

Driver      "mouse"

Option      "Protocol" "auto"

Option      "Device" "/dev/input/mice"

Option      "ZAxisMapping" "4 5 6 7" <==滾輪支援

EndSection

# 這個則主要在設定滑鼠功能，重點在那個 Protocol 項目，

# 那個是可以指定滑鼠介面的設定值，我這裡使用的是自動偵測！不論是 USB/PS2。

Section "Files"

RgbPath      "/usr/share/X11/rgb"

ModulePath   "/usr/lib/xorg/modules"

FontPath     "unix/:7100"  <==使用另外的服務來提供字型定義

FontPath     "built-ins"

EndSection

# 我們的 X Server 很重要的一點就是必須要提供字型，這個 Files

# 的項目就是在設定字型，當然啦，你的主機必須要有字型檔才行。一般字型檔案在：

# /usr/share/X11/fonts/ 目錄中。至於那個 Rgb 是與色彩有關的項目。

# 相關的字型說明我們會在下一小節的 xfs 在跟大家報告。

Section "Monitor"

Identifier   "Monitor0"

VendorName   "Monitor Vendor"

ModelName    "Monitor Model"

HorizSync    30.0 - 80.0

VertRefresh  50.0 - 100.0

EndSection

# 螢幕監視器的設定僅有一個地方要注意，那就是垂直與水平的更新頻率。

# 在上面的 HorizSync 與 VerRefresh 的設定上，要注意，不要設定太高，

# 這個玩意兒與實際的監視器功能有關，請查詢你的監視器手冊說明來設定吧！

# 傳統 CRT 螢幕設定太高的話，據說會讓 monitor 燒毀呢，要很注意啊。

Section "Device"   <==顯示卡的驅動程式項目

Identifier  "Card0"

Driver      "vesa"  <==實際的驅動程式喔！

VendorName  "Unknown Vendor"

BoardName   "Unknown Board"

BusID       "PCI:0:2:0"

EndSection

# 這地方重要了，這就是顯示卡的晶片模組載入的設定區域。由於鳥哥使用 Virtualbox

# 模擬器模擬這個測試機，因此這個地方顯示的驅動程式為通用的 vesa 模組。

# 更多的顯示晶片模組可以參考 /usr/lib/xorg/modules/drivers/

Section "Screen"    <==與顯示的畫面有關，解析度與色彩深度

Identifier "Screen0"

Device     "Card0"     <==使用哪個顯示卡來提供顯示

Monitor    "Monitor0"  <==使用哪個監視器

SubSection "Display"   <==此階段的附屬設定項目

Viewport   0 0

Depth     16   <==就是色彩深度

Modes    "1024x768" "800x600" "640x480" <==解析度

EndSubSection

SubSection "Display"

Viewport   0 0

Depth     24

Modes    "1024x768" "800x600"

EndSubSection

EndSection

# Monitor 與實際的顯示器有關，而 Screen 則是與顯示的畫面解析度、色彩深度有關。

# 我們可以設定多個解析度，實際應用時可以讓使用者自行選擇想要的解析度來呈現。

# 不過，為了避免困擾，鳥哥通常只指定一到兩個解析度而已。

Section "ServerLayout"   <==實際選用的設定值

Identifier     "X.org Configured"

Screen      0  "Screen0" 0 0              <==解析度等

InputDevice    "Mouse0" "CorePointer"     <==滑鼠

InputDevice    "Keyboard0" "CoreKeyboard" <==鍵盤

EndSection

# 我們上面設定了這麼多的項目之後，最後整個 X Server 要用的項目，

# 就通通一骨腦的給他寫入這裡就是了，包括鍵盤、滑鼠以及顯示介面啊。

# 其中 screen 的部分還牽涉到顯示卡、監視器螢幕等設定值呢！

上面設定完畢之後，就等於將整個 X Server 設定妥當了，很簡單吧。 如果你想要更新其他的例如顯示晶片的模組的話，就得要去硬體開發商的網站下載原始檔來編譯才行。 設定完畢之後，你就可以啟動 X Server 試看看囉。基本上，如果你的 Files 那個項目用的是直接寫入字型的路徑， 那就不需要啟動 XFS (X Font Server)，如果是使用 font server 時，就要先啟動 xfs ：

# 1. 啟動 xfs 服務：

[root@www ~]# /etc/init.d/xfs start

# 2. 測試 X server 的設定檔是否正常：

[root@www ~]# startx  <==直接在 runlevel 3 啟動 X 看看

[root@www ~]# X :1    <==在 tty8 單獨啟動 X server 看看

當然，你也可以利用 init 5 這個指令直接切換到圖形介面的登入來試看看囉。

Tips:

經由討論區網友的說明，如果你發現明明有捉到顯示卡驅動程式卻老是無法順利啟動 X 的話，可以嘗試去官網取得驅動程式來安裝， 也能夠將『Device』階段的『Driver』修改成預設的『Driver "vesa"』，使用該驅動程式來暫時啟動 X 內的顯示卡喔！

X Font Server (XFS) 與加入額外中文字形

與 X 有關的設定檔主要是 /etc/X11/xorg.conf 這個主設定檔，但是剛剛上頭解析這個檔案時，在 Files 的部分我們還提到了 X Font Server (XFS) 這個服務喔！這個是啥咚咚？這個服務的目的在提供 X server 字型庫啦！ 也就是說， X server 所使用的字型其實是 XFS 這個服務所提供的，因此沒有啟動 XFS 服務時，你的 X server 是無法順利啟動的喔！所以，我們當然就來瞧瞧這玩意兒的功能囉！

這個 XFS 的主設定檔在 /etc/X11/fs/config ，而字型檔則在 /usr/share/X11/fonts/ ，這裡再次給他強調一下。 至於啟動的腳本則在 /etc/init.d/xfs 囉！好，那我們就先來瞧瞧主設定檔的內容是怎樣的設定吧！

[root@www ~]# vi /etc/X11/fs/config

client-limit = 10  <==最多允許幾個 X server 向我要求字型(因為跨網路)

clone-self = on    <==與效能有關，若 xfs 達到限制值，啟動新的 xfs

catalogue = /usr/share/X11/fonts/misc:unscaled,

/usr/share/X11/fonts/75dpi:unscaled,

/usr/share/X11/fonts/100dpi:unscaled,

/usr/share/X11/fonts/Type1,

/usr/share/X11/fonts/TTF,

/usr/share/fonts/default/Type1,

# 上面這些咚咚，就是字型檔案的所在！如果你有新字型，可以放置在該目錄。

default-point-size = 120            <==預設字型大小，單位為 1/10 點字 (point)

default-resolutions = 75,75,100,100 <==這個則是顯示的字型像素 (pixel)

deferglyphs = 16                    <==延遲顯示的字型，此為 16 bits 字型

use-syslog = on                     <==啟動支援錯誤登錄

no-listen = tcp                     <==啟動 xfs 於 socket 而非 TCP

上面這個檔案的設定重點在 catalogue 那個設定項目當中。你可以使用 chkfontpath 這個指令來列出目前支援的字型檔案，也可以直接修改呢！

另外，雖然目前的 CentOS 已經是支援多國語系了，因此你可以直接在安裝完畢後就看到中文， 不過預設的中文字形可能讓你不太滿意∼此時，你可以選擇額外的中文字形顯示喔。比較有名的中文字形除了預設提供的文鼎字型外， 還有一種台北字型 (taipeifonts)，不過這種字形是 Big5 編碼的，因此預設並沒有在你的字型支援之中 (因為目前大多使用萬國碼來顯示中文了)。如果你想要測試一下這種字形，除了自行下載字型檔之外， 我們可以使用 CentOS 提供的軟體來處理喔！看看底下的作法吧：

# 1. 先安裝中文字形軟體，亦即 fonts-chinese 這個軟體名

[root@www ~]# yum install fonts-chinese

# 2. 查閱 taipei 字型的所在目錄位置：

[root@www ~]# rpm -ql fonts-chinese | grep taipei

/usr/share/fonts/chinese/misc/taipei16.pcf.gz  <==重點在目錄！

/usr/share/fonts/chinese/misc/taipei20.pcf.gz

/usr/share/fonts/chinese/misc/taipei24.pcf.gz

# 3. 建立字型檔的目錄架構

[root@www ~]# cd /usr/share/fonts/chinese/misc

[root@www ~]# mkfontdir

# 這個指令在建置 fonts.dir 這個檔案，提供字型檔案目錄的說明。

# 4. 將上述的目錄加入 xfs 的支援之中：

[root@www ~]# chkfontpath -a /usr/share/fonts/chinese/misc/

[root@www ~]# chkfontpath

....(前面省略)....

/usr/share/fonts/chinese/misc:unscaled

/usr/share/fonts/chinese/misc  <==這兩行會被新增出來！

[root@www ~]# /etc/init.d/xfs restart

# 5. 在 X window 底下啟動終端機，測試一下有沒有捉到該字型？

[root@www ~]# xlsofnts | grep taipei

# 如果順利的話，你會看到有幾個 taipeiXX 的字樣在螢幕上出現！

這個時候的 X server 已經有新支援的中文字形了，很簡單吧！不過如果你想要讓 X client 可以使用額外的字型的話，還得要使用 fontconfig 的軟體提供的 fc-cache 來建立字型快取檔才行 (註4)！

- 讓視窗管理員可以使用額外的字型

如果想要使用額外的字型的話，你可以自行取得某些字型來處理的。鳥哥這邊從 Windows 取得三個檔案來作為測試，這邊得註明一下是純粹的測試，測試完畢後檔案就給她拿掉了， 並沒有持續使用喔！並沒有想要違法的意思啦∼大家參考看看就好了。這三個檔案分別是 kaiu.ttf mingliu.ttc times.ttf，代表的是中楷體、明體、times and Romans 三種字體。 那就來看看如何增加字型吧！(假設上述的三個字體檔是放置在 /root 中)

# 1. 將上述的三個檔案放置到系統設定目錄，亦即底下的目錄中：

[root@www ~]# cd /usr/share/fonts/

[root@www ~]# mkdir windows

[root@www ~]# cp /root/*.tt[fc] /usr/share/fonts/windows

# 2. 使用 fc-cache 將上述的檔案加入字型的支援中：

[root@www ~]# fc-cache -f -v

....(前面省略)....

/usr/share/fonts/windows: caching, 4 fonts, 0 dirs

....(中間省略)....

fc-cache: succeeded

# -v 僅是列出目前的字型資料， -f 則是強制重新建立字型快取！

# 3. 透過 fc-list 列出已經被使用的檔案看看：

[root@www ~]# fc-list : file  <==找出被快取住的檔名

....(前面省略)....

/usr/share/fonts/windows/kaiu.ttf:

/usr/share/fonts/windows/times.ttf:

/usr/share/fonts/windows/mingliu.ttc:

....(後面省略)....

透過 fc-cache 以及 fc-list 去確認過字型確實存在後，就能夠使用視窗管理員的功能去檢查字型檔了。 以 GNOME 為例，在『系統』-->『偏好設定』-->『字型』點選後，就會出現可以調整的字型， 接下來你就會發現多出了『標楷體、細明體、新細明體』等字體可以選擇囉！試看看吧！鳥哥調整成為『Times and Roman』 出現如下圖的結果呢！參考看看：

圖 2.2.1、中文字形的調整結果

設定檔重建與顯示器參數微調

如果你修改 xorg.conf 結果改錯了，導致無法順利的啟動 X server 時，偏偏又忘記製作備份檔！該如何是好？ 沒關係，我們的 Xorg 有提供不錯的工具可以處理。同時 CentOS 也有提供相關的設定指令， 那就是在第二十一章提到的 setup 這個指令啦！ 詳細的設定請自行前往參考，在這裡我們要介紹的是使用 Xorg 重新製作出設定檔啦！你可以使用 root 的身份這樣執行：

[root@www ~]# Xorg -configure :1

此時 X 會主動的以內建的模組進行系統硬體的探索，並將硬體與字型的偵測結果寫入 /root/xorg.conf.new 這個檔案裡面去，這就是 xorg.conf 的重製結果。不過，這個新建的檔案不見得真的能夠啟動 X server ， 所以我們必須要使用底下的指令來測試一下這個新的設定檔是否能夠順利的運作：

[root@www ~]# X -config /root/xorg.conf.new :1

因為鳥哥不知道你到底是在 runlevel 幾號，因此上述的測試通通是在 tty8 的終端機上面顯示 (display 1)， 這樣就能夠避免切換到不同的 runlevel 囉∼如果一切順利的話，你就可以將 /root/xorg.conf.new 複製成為 /etc/X11/xorg.conf 覆蓋掉修改錯誤的檔案，然後重新啟動 X ，嘿嘿！應該就能夠順利的救回來你的 X Window System 囉！

- 關於螢幕解析度與更新率

有些朋友偶而會這樣問：『我的顯示器明明還不錯，但是螢幕解析度卻永遠只能達到 800x600 而已， 這該如何處理？』，螢幕的解析度應該與顯示卡相關性不高，而是與顯示器的更新頻率有關！ 所謂的更新頻率，指的是在一段時間內螢幕重新繪製畫面的速度。舉例來說， 60Hz 的更新頻率， 指的是每秒鐘畫面更新 60 次的意思。那麼關於顯示器的更新頻率該如何調整呢？ 你得先去找到你的顯示器的使用說明書 (或者是網站會有規格介紹)，取得最高的更新率後，接下來選擇你想要的解析度， 然後透過這個 gtf 的指令功能來調整：

[root@www ~]# gtf 水平像素 垂直像素 更新頻率 [-xv]

選項與參數：

水平像素：就是解析度的 X 軸

垂直像素：就是解析度的 Y 軸

更新頻率：與顯示器有關，一般可以選擇 60, 75, 80, 85 等頻率

-x      ：使用 Xorg 設定檔的模式輸出，這是預設值

-v      ：顯示偵測的過程

# 1. 使用 1024x768 的解析度，75 Hz 的更新頻率來取得顯示器內容

[root@www ~]# gtf 1024 768 75 -x

# 1024x768 @ 75.00 Hz (GTF) hsync: 60.15 kHz; pclk: 81.80 MHz

Modeline "1024x768_75.00"  81.80  1024 1080 1192 1360  768 769 772 802  -HSync +Vsync

# 重點是 Modeline 那一行！那行給他抄下來

# 2. 將上述的資料輸入 xorg.conf 內的 Monitor 項目中：

[root@www ~]# vim /etc/X11/xorg.conf

Section "Monitor"

Identifier   "Monitor0"

VendorName   "Monitor Vendor"

ModelName    "Monitor Model"

Modeline "1024x768_75.00"  81.80  1024 1080 1192 1360  768 769 772 802  -HSync +Vsync

EndSection

# 就是新增上述的那行特殊字體部分到 Monitor 的項目中即可。

然後重新啟動你的 X ，這樣就能夠選擇新的解析度囉！那如何重新啟動 X 呢？兩個方法， 一個是『 init 3 ; init 5 』從文字模式與圖形模式的執行等級去切換，另一個比較簡單， 如果原本就是 runlevel 5 的話，那麼在 X 的畫面中按下『 [alt] + [crtl] + [backspace] 』三個組合按鍵， 就能夠重新啟動 X 視窗囉！

顯示卡驅動程式安裝範例

雖然你的 X 視窗系統已經順利的啟動了，也調整到你想要的解析度了，不過在某些場合底下，你想要使用顯示卡提供的 3D 加速功能時，卻發現 X 提供的預設的驅動程式並不支援！此時真是欲哭無淚啊∼那該如何是好？沒關係，安裝官方網站提供的驅動程式即可！ 目前 (2009) 世界上針對 x86 提供顯示卡的廠商最大的應該是 Nvidia / AMD (ATI) / Intel 這三家 (沒有照市佔率排列)， 所以底下鳥哥就針對這三家的顯示卡驅動程式安裝，作個簡單的介紹吧！

由於硬體驅動程式與核心有關，因此你想要安裝這個驅動程式之前，請務必先參考第二十二章與第二十三章的介紹，才能夠順利的編譯出顯示卡驅動程式喔！ 建議可以直接使用 yum 去安裝『 Development Tools 』這個軟體群組以及 kernel-devel 這個軟體即可。

NVidia

雖然 Xorg 已經針對 NVidia 公司的顯示卡驅動程式提供了 nv 這個模組，不過這個模組無法提供很多額外的功能。 因此，如果你想要使用新的顯示卡功能時，就得要額外安裝 NVidia 提供的給 Linux 的驅動程式才行。 你可以這樣作的：

- 下載驅動程式

建議你可以到 NVidia 的官網 (http://www.nvidia.com.tw) 自行去下載最新的驅動程式，你也可以到底下的連結直接查閱給 Linux 用的驅動程式：

- http://www.nvidia.com.tw/object/unix_tw.html

請自行選擇與你的系統相關的環境。鳥哥選擇自己的測試機是 Intel Core2 架構，因此選擇 Linux AMD64/EM64T 的驅動程式版本，這個版本的驅動程式檔名為： NVIDIA-Linux-x86_64-xxx.yy.zz-pkg2.run ，其中的 xxx.yy.z 就是驅動程式的版本號碼。我將這個檔案放置到 /root家目錄中。

- 開始安裝驅動程式

安裝過程有點像這樣 (檔名依照你的環境去下載與執行)：

[root@www ~]# sh NVIDIA-Linux-x86_64-185.18.14-pkg2.run

圖 3.1.1、NVidia 驅動程式安裝示意

上面說的是授權，你必須要接受 (Accept) 才能繼續。

圖 3.1.2、NVidia 驅動程式安裝示意

我們不預期 NVidia 會幫我們編譯好核心模組，因此這裡選擇 No ，讓我們自己編譯模組吧！

圖 3.1.3、NVidia 驅動程式安裝示意

直接按下 OK 來繼續下一步即可。

圖 3.1.4、NVidia 驅動程式安裝示意

開始進行核心模組的編譯！這個過程不會太久∼

圖 3.1.5、NVidia 驅動程式安裝示意

是否要安裝額外的 OpenGL 函式庫？要啊！就選擇 Yes 吧！

圖 3.1.6、NVidia 驅動程式安裝示意

這個時候開始安裝顯示卡的驅動程式，會花費一段時間喔！然後出現下圖：

圖 3.1.7、NVidia 驅動程式安裝示意

讓這支安裝程式主動的去修改 xorg.conf 吧！比較輕鬆愉快！就按下 Yes 即可。

圖 3.1.8、NVidia 驅動程式安裝示意

最後按下 OK 就結束安裝囉！這個時候如果你去查閱一下 /etc/X11/xorg.conf 的內容，會發現 Device 的 Driver 設定會成為 nvidia 而不是原本的 nv 喔！這樣就搞定囉！很簡單吧！ 而且這個時候你的 /usr/lib64/xorg/modules/drivers 目錄內，會多出一個 nvidia_drv.so 的驅動程式檔案囉！ 同時這個軟體還提供了一支很有用的程式來幫助我們進行驅動程式升級喔！

[root@www ~]# nvidia-installer --update

# 可以進行驅動程式的升級檢查喔！

好囉，那你就趕緊試看看新的顯示卡晶片的功能吧。而如果有什麼疑問的話，查閱一下 /var/log/nvidia 開頭的登錄檔看看吧！ ^_^

ATI (AMD)

ATI 已經被 AMD 收購了，而 AMD 在近期已經宣布了 ATI 的顯示卡驅動程式要開放成為 Open source ， 這代表未來你可以很輕鬆的就取得 ATI 的顯示卡驅動程式而不必要重新安裝的。不過，就如同前面提到的， 若你需要某些特殊功能，建議還是手動安裝一下官方提供的驅動程式吧！你必須要到 AMD 的網站去下載 ATI 顯示卡驅動程式哩！ 你可以到 http://www.amdtaiwan.com.tw/ 選擇『ATI 驅動程式』的連結去選擇你的顯示卡驅動程式版本，也可以點選底下的連結：

- http://ati.amd.com/support/driver.html

然後去選擇你的作業系統與顯示卡的型號來下載。鳥哥使用另一部含有 ATI 顯示卡的主機來安裝驅動程式， 該主機使用的是 Randon HD 3200 的顯示卡晶片，最後下載的檔案是： ati-driver-installer-9-6-x86.x86_64.run。 要安裝這個驅動程式的方法與 NVidia 的方式很像的，同樣的直接執行該檔案即可：

[root@www ~]# sh ati-driver-installer-9-6-x86.x86_64.run

圖 3.2.1、ATI 顯示卡驅動程式安裝示意

選擇安裝吧！

圖 3.2.2、ATI 顯示卡驅動程式安裝示意

這裡的目的是讓我們確定一下，是否真的是安裝在 x86_64 的硬體上面而已！按下 OK 去！

圖 3.2.3、ATI 顯示卡驅動程式安裝示意

看完授權之後，直接給他 Exit 離開授權說明，然後會出現接受與否的字樣：

圖 3.2.4、ATI 顯示卡驅動程式安裝示意

要安裝啊！所以當然就是 Yes 下去喔！

圖 3.2.5、ATI 顯示卡驅動程式安裝示意

最後選擇預設安裝即可！不需要使用專家安裝啦！這樣就安裝完畢了！也是非常快速吧！最後就會在 /usr/lib64/xorg/modules/drivers/ 裡面出現 fglrx_drv.so 這個新的驅動程式啦！ 與 Nvidia 相同的， ATI 也提供一支名為 aticonfig 的指令來幫忙設定 xorg.conf ，你可以直接輸入『 aticonfig -v 』來看看處理的方式即可。然後你就可以重新啟動 X 來看看新的驅動程式功能囉！非常簡單吧！

Intel

老實說，由於 Intel 針對 Linux 的圖形介面驅動程式已經開放成為 Open source 了，所以理論上你不需要重新安裝 Intel 的顯示卡驅動程式的。除非你想要使用比預設的更新的驅動程式，那麼才需要重新安裝底下的驅動程式。 Intel 對 Linux 的顯示卡驅動程式已經有獨立的網站在運作，如下的連結就是安裝的說明網頁：

- http://intellinuxgraphics.org/install.html

其實 Intel 的顯示卡用的地方非常的多喔！因為只要是整合型主機板晶片組，用的是 Intel 的晶片時， 通常都整合了 Intel 的顯示卡囉∼鳥哥使用的一組 cluster 用的就是 Intel 的晶片，所以囉∼ 這傢伙也是用的到的啦！

一般來說， Intel 的顯示卡都常常會使用 i810 等驅動程式，而不是這個較新的 intel 驅動程式！ 你可以察看一下你系統是否有存在這些檔案：

[root@www ~]# locate libdrm

/usr/lib/libdrm.so.2        <==32位元的函式庫

/usr/lib/libdrm.so.2.0.0

/usr/lib64/libdrm.so.2      <==64位元放置位置不同！

/usr/lib64/libdrm.so.2.0.0

/usr/lib64/xorg/modules/linux/libdrm.so

[root@www ~]# locate intel | grep xorg

/usr/lib64/xorg/modules/drivers/intel_drv.so

# 上面這個就是 Intel 的顯示卡驅動程式了！

呼呼！我們的 CentOS 有提供新的 Intel 顯示卡驅動程式啦！所以不需要重新安裝說∼ 只是可能需要修改 xorg.conf 這個設定檔的內容。基本上，要修改的地方有：

[root@www ~]# vi /etc/X11/xorg.conf

Section "Device"

Identifier  "Videocard0"

Driver      "intel"  <==原本可能會是使用 i810 喔

EndSection

Section "Module"

....(中間省略)....

Load  "glx"    <==這兩個很重要！務必要載入！

Load  "dri"

....(中間省略)....

EndSection

Section "DRI"          <==這三行是新增的！讓大家都能使用 DRI

Mode 0666       <==基本上，就是權限的設定

EndSection

如果一切順利的話，接下來就是重新啟動 X 囉∼使用新的 Intel 驅動程式吧！加油囉！

重點回顧

- Unix Like 作業系統上面的 GUI 使用的是最初由 MIT 所開發的 X window system，在 1987 釋出 X11 版，並於 1994 更改為 X11R6 ，故此 GUI 介面也被稱為 X 或 X11

- X window system 的 X server 最初由 XFree86 計畫所開發，後來則由 Xorg 基金會所持續開發；

- X window system 主要分為 X server 與 X client ，其中 X Server 在管理硬體，而 X Client 則是應用程式。

- 在運作上，X Client 應用程式會將所想要呈現的畫面告知 X Server ，最終由 X server 來將結果透過他所管理的硬體繪製出來！

- 每一支 X client 都不知道對方的存在，必須要透過特殊的 X client ，稱為 Window Manager 的， 來管理各視窗的重疊、移動、最小化等工作。

- startx 可以偵測 X server / X client 的啟動腳本，並呼叫 xinit 來分別執行；

- X 可以啟動多個，各個 X 顯示的位置使用 -display 來處理，顯示位置為 :0, :1...

- Xorg 是一個 X server ，設定檔位於 /etc/X11/xorg.conf ，裡面含有 Module, Files, Monitor, Device 等設定階段

- 字型管理為 X server 的重點，目前字型管理可由 xfs 及 fontconfig 來處理

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 在 X 設定沒問題的情況下，你在 Linux 主機如何取得視窗介面？

如果是在 run level 3 ，可以使用 startx 進入，至於 run level 5 ，則直接進入 tty7 即可使用 display manager 登入 X Window 系統。

- 利用 startx 可以在 run level 3 的環境下進入 X Window 系統。請問 startx 的主要功能？

整個 X 視窗系統的重點在啟動 X server 並載入 X client ，而執行 X server/X client 呼叫的任務為 xinit ，startx 只是一個較為親和的腳本程式，可以搜尋系統上面的 X server / X client 設定值， 以提供 xinit 來執行而已。

- 如何知道你系統當中 X 系統的版本與計畫？

最簡單可以利用 root 的身份下達 X -version 即可知道！

- 要瞭解為何 X 系統可以允許不同硬體、主機、作業系統之間的溝通，需要知道 X server / X client 的相關知識。 請問 X Server / X client / Window manager 的主要用途功能？

X Server 主要負責螢幕的繪製，以及周邊輸入裝置如滑鼠、鍵盤等資料的收集，並回報給 X Client ； X Client 主要負責資料的運算，收到來自 X Server 的資料後，加以運算得到圖形的數據，並回傳給 X Server， 讓 X server 自行繪製圖形。至於 Window manager 是一個比較特殊的 X Client ，他可以管理更多控制元素， 最重要的地方還是在於視窗的大小、重疊、移動等等的功能。

- 如何重新啟動 X

最簡單在 X Window System 下，直接按下 [alt]+[ctrl]+[backspace<--] 即可， 也可以 init 3 再 init 5，也可以關閉 X 後，再 startx 啟動等等。

- 試說明 ~/.xinitrc 這個檔案的用途？

當我們要啟動 X 時，必須要啟動 X Client 軟體端。這個 ~/.xinitrc 即是在客制化自己的 X Client ， 你可以在這個檔案內輸入你自己的 X Client 。若無此檔案，則預設以 /etc/X11/xinit/xinitrc 替代。

- 我在 CentOS 的系統中，預設使用 GNOME 登入 X 。但我想要改以 KDE 登入，該怎麼辦？

首先你必須要已經安裝 KDE 環境 (參考前一章的 yum grouplist 功能)，然後可以藉由修改 /etc/sysconfig/desktop 內的設定值即可。但如果你不是 root 無法修訂該檔案時， 亦可以在自己的家目錄參考 /etc/X11/xinit/xinitrc 的內容自行製作 ~/.xinitrc 檔案來修改！

- X Server 的 port 預設開放在？

X port 預設開放在 port 6000 ，而且稱此一顯示為 :0

- Linux 主機是否可以有兩個以上的 X

是的！可以！第一個 X 通常在 tty7 ，第二個在 tty8 ，第三個在 tty9 ，依序類推。 第幾個是以啟動的順序來定義，並非 :0 , :1 的意思∼

- X Server 的設定檔是 xorg.conf，在該檔案中， Section Files 幹嘛用的？

相當重要！是設定顯示字型用的。而字型一般放置目錄在 /usr/lib/xorg/modules/fonts/ 當中。

- 我發現我的 X 系統鍵盤所輸入的字母老是打不出我所需要的單字，可能原因該如何修訂？

應該是鍵盤符號對應表跑掉了。可以修改 xorg.conf 檔案內， 關於 Keyboard 的 Option XkbLayout 項目，將他改為 us 即可！

- 當我的系統內有安裝 GNOME 及 KDE 兩個 X Widnow Manager ，我原本是以 KDE 為預設的 WM， 若想改為 GNOME 時，應該如何修改？

修改 /etc/sysconfig/desktop 內部，成為 GNOME 即可！

參考資料與延伸閱讀

- 註1：維基百科對 X Window 的介紹：http://en.wikipedia.org/wiki/X_Window_System

- 註2：X Server/X client 與網路相關性的參考圖示：

http://en.wikipedia.org/wiki/File:X_client_sever_example.svg

- 註3：系統的 man page： man xinit 、 man Xorg 、 man startx

- 註4：一些與中文字型有關的網頁連結：

洪朝貴老師主筆的字型設定：http://www.cyut.edu.tw/~ckhung/b/gnu/font.php

李果正先生的 GNU/Linux 初探第十六章：http://edt1023.sayya.org/node17.html

EricCheng 的 fontconfig 軟體簡介：http://fractal.csie.org/~eric/wiki/Fontconfig

- X 相關的官方網站： X.org 官方網站 (http://www.x.org/)、 XFree86 官方網站 (http://www.xfree86.org/)

2003/02/12：第一次完成

2005/06/29：將舊的文章移動到 這裡 。如果你需要舊版的 xf86config 與相關的工具，則請前往該舊文章查閱！

2005/07/11：經歷了許多的時間，將主機的設定檔重複改了改，終於完成一些簡單的 X 測試！

2006/11/07：經由網友x1215 這一篇的介紹，得知該網站，趕緊去處理！

2009/07/03：將舊版基於 FC4 的版本移動到此處

2009/07/15：奮戰好幾天，將驅動程式安裝加上，同時加入字型管理功能。

2009/07/28：網友 LazyBug Chan 兄熱情回報，使用 XFCE 的 Ubuntu 是 Xubuntu 這個分支！感謝回報！

2009/08/07：加入 Window Manger 的全名與連結

2003/02/12以來統計人數

第二十五章、 Linux 備份策略

切換解析度為 800x600

最近更新日期：2009/09/18

萬一不幸你的 Linux 被駭客入侵了、或是你的 Linux 系統由於硬體關係 (不論是天災還是人禍) 而掛掉了！這個時候，請問如何快速的回復你的系統呢？呵呵！當然囉，如果有備份資料的話， 那麼回復系統所花費的時間與成本將降低相當的多！平時最好就養成備份的習慣， 以免突然間的系統損毀造成手足無措！此外，哪些檔案最需要備份呢？又，備份是需要完整的備份還是僅備份重要資料即可？ 嗯！確實需要考慮看看呦！

1. 備份要點

1.1 備份資料的考量

1.2 哪些 Linux 資料具有備份的意義

1.3 備份用儲存媒體的選擇

2. 備份的種類、頻率與工具的選擇

2.1 完整備份之累積備份 (Incremental backup), 使用軟體

2.2 完整備份之差異備份 (Differential backup)

2.3 關鍵資料備份

3. VBird 的備份策略與 scripts

3.1 每週系統備份的 script

3.2 每日備份資料的 script

3.3 遠端備援的 script

4. 災難復原的考量

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23896

備份要點

備份是個很重要的工作，很多人總是在系統損毀的時候才在哀嚎說：『我的資料啊！天那...！』此時才會發現備份資料的可愛！ 但是備份其實也非常可怕！因為你的重要資料都在備份檔裡面，如果這個備份被竊取或遺失，其實對你的系統資安影響也非常大！ 同時，備份使用的媒體選擇也非常多樣，但是各種儲存媒體各有其功能與優劣，所以當然得要選擇囉！閒話少說，來談談備份吧！

備份資料的考量

老實說，備份是系統損毀時等待救援的救星！因為你需要重新安裝系統時， 備份的好壞會影響到你系統復原的進度！不過，我們想先知道的是，系統為什麼會損毀啊？是人為的還是怎樣產生的啊？ 事實上，系統有可能由於不預期的傷害而導致系統發生錯誤！ 什麼是不預期的傷害呢？這是由於系統可能因為不預期的硬體損壞，例如硬碟壞掉等等，或者是軟體問題導致系統出錯， 包括人為的操作不當或是其他不明因素等等所致。底下我們就來談談系統損壞的情況與為何需要備份吧！

- 造成系統損毀的問題-硬體問題

基本上，『電腦是一個相當不可靠的機器』這句話在大部分的時間內還是成立的！ 常常會聽到說『要電腦正常的工作，最重要的是要去拜拜！』嘿嘿！不要笑！這還是真的哩！ 尤其是在日前一些電腦周邊硬體的生產良率 (就是將硬體產生出來之後，經過測試， 發現可正常工作的與不能正常工作的硬體總數之比值) 越來越差的情況之下，電腦的不穩定狀態實在是越來越嚴重了！

舉個例子來說，鳥哥曾經同時買過同一廠牌的 30GB 硬碟三顆，回來之後經過一個星期，嘿嘿！掛掉了兩顆！ 其中一顆是有壞軌，另外一顆是『完全死掉』，拿去公司要求修理，結果呢？嗯！店家直接拿了一顆新的給我， 害我嚇一跳，店家的工程師說『唉呀！目前這個牌子的良率太差了，所以代理商為了怕麻煩，都會直接拿新的替換給我們啦！』 要曉得的是，當初那一顆完全死掉的硬碟，是我用來備份我的主機資料的.... 好在當時我將備份的資料放在三四個地方，還好...

一般來說，會造成系統損毀的硬體元件應該要算硬碟吧！因為其他的元件壞掉時，雖然會影響到系統的運作， 不過至少我們的資料還是存在硬碟當中的啊！為了避免這個困擾，於是乎有可備份用的 RAID1, RAID5 等磁碟陣列的應用啊！但是如果是 RAID 控制晶片壞掉呢？這就麻煩了∼所以說，如果有 RAID 系統時， 鳥哥個人還是覺得需要進行額外的備份才好的！如果資料夠重要的話。

- 造成系統損毀的問題-軟體問題

根據分析，其實系統的軟體傷害最嚴重的就屬使用者的操作不當啦！像最近這幾天才在鳥園討論區發現， 有網友手滑了一下，結果在指令列輸入了『 rm -rf /home 』，這造成什麼後果？就造成使用者家目錄被刪光光∼ 因為當時下達指令的身份是 root 啊∼會欲哭無淚喔！為了避免這方面的『手滑』問題，備份是重要的！

軟體傷害除了來自主機上的使用者操作不當之外，最常見的可能是資安攻擊事件了。 假如你的 Linux 系統上面某些 Internet 的服務軟體是最新的！這也意味著可能是『相對最安全的』， 但是，這個世界目前的閒人是相當多的，你不知道什麼時候會有所謂的『駭客軟體』被提供出來，萬一你在 Internet 上面的服務程序被攻擊，導致你的 Linux 系統全毀，這個時候怎麼辦？當然是要復原系統吧？

那如何復原被傷害的系統呢？『重新安裝就好啦！』或許你會這麼說， 但是，像鳥哥管理的幾個網站的資料，尤其是 MySQL 資料庫的資料，這些都是彌足珍貴的經驗資料， 萬一被損毀而救不回來的時候，不是很可惜嗎？這個還好哩，萬一你是某家銀行的話， 那麼資料的損毀可就不是能夠等閒視之的！關係的可是數千甚至上萬人的身家財產！這就是備份的重要性了！ 他可以最起碼的稍微保障我們的資料有另外一份 copy 的備援以達到『安全回復』的基本要求！

- 主機角色不同，備份任務也不同

由於軟硬體的問題都可能造成系統的損毀，所以備份當然就很重要啦！問題是，每一部主機都需要備份嗎？ 多久備份一次呢？要備份什麼資料呢？

如果是針對個人桌上型電腦使用的資料，那麼 Norton 的『 Ghost 』應該算是一套好到不行的備份大師了！ 最主要是 Ghost 可以針對整個 partition 來進行備份，所以囉，我們可以將 Windows 系統當中的整個 C 或者是整個 D 槽完整的備份下來。甚至在還原方面也是非常的快速，而且操作簡便！ 另外，由於個人桌上型電腦所使用的資料量通常不大，所以當 ghost 完成之後，通常只要將資料燒錄到光碟片當中，大約只要一至兩片的光碟片也就綽綽有餘囉！ 那麼將光碟片保存好，這就是最簡易的資料備份模式囉！ 此外，由於個人的資料變動性不大，所以資料的備份頻率方面也不需要非常的頻繁！

但是，萬一你的主機有提供 Internet 方面的服務呢？又該如何備份啊？舉個例子來說，像是我們 Study Area 團隊的討論區網站 http://phorum.study-area.org 提供的是類似 BBS 的討論文章， 雖然資料量不大，但是由於討論區的文件是天天在增加的，每天都有相當多的資訊流入， 由於某些資訊都是屬於重要的人物之留言，這個時候，我們能夠讓機器死掉嗎？或者是能夠一季三個月才備份一次嗎？ 這個備份頻率需求的考量是非常重要的！

再提到 2002 年左右鳥哥的討論區曾經掛點的問題，以及 2003 年初 Study-Area 討論區掛點的問題，討論區一旦掛點的話，該資料庫內容如果損毀到無法救回來， 嘿嘿！要曉得討論區可不是一個人的心血耶！有的時候 (像 Study-Area 討論區) 是一群熱心 Linux 的朋友們互相建立交流起來的資料流通網，如果死掉了，那麼不是讓這些熱血青年的熱情付之一炬了嗎？ 所以囉，建立備份的策略 (頻率、媒體、方法等) 是相當的重要的。

- 備份因素考量

由於電腦 (尤其是目前的電腦，操作頻率太高、硬體良率太差、使用者操作習慣不良、 『某些』作業系統的當機率太高....) 的穩定性較差，所以囉！備份的工作就越來越重要了！ 那麼一般我們在備份時考慮的因素有哪些呢？

- 備份哪些檔案：

哪些資料對系統或使用者來說是重要的？那些資料就是值得備份的資料！例如 /etc/* 及 /home/* 等。

- 選擇什麼備份的媒介：

是可讀寫光碟、另一顆硬碟、同一顆硬碟的不同 partition、還是使用網路備援系統？ 哪一種的速度最快，最便宜，可將資料保存最久？這都可以考慮的。

- 考慮備份的方式：

是以完整備份(類似 ghost)來備份所有資料，還是使用差異備份僅備份有被更動過的資料即可？

- 備份的頻率：

例如 MySQL 資料庫是否天天備份、若完整備份，需要多久進行一次？

- 備份使用的工具為何：

是利用 tar 、 cpio 、 dd 還是 dump 等等的備份工具？

底下我們就來談一談這些問題的解決之道吧！ ^_^

哪些 Linux 資料具有備份的意義

一般來說，鳥哥比較喜歡備份最重要的檔案而已 (關鍵資料備份)，而不是整個系統都備份起來 (完整備份, Full backup)！那麼哪些檔案是有必要備份的呢？具有備份意義的檔案通常可以粗分為兩大類，一類是系統基本設定資訊、一類則是類似網路服務的內容資料。 那麼各有哪些檔案需要備份的呢？我們就來稍微分析一下。

- 作業系統本身需要備份的檔案：

這方面的檔案主要跟『帳號與系統設定檔』有關係！ 主要有哪些帳號的檔案需要備份呢？就是 /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow, /home 底下的使用者家目錄等等， 而由於 Linux 預設的重要參數檔都在 /etc/ 底下，所以只要將這個目錄備份下來的話， 那麼幾乎所有的設定檔都可以被保存的！

至於 /home 目錄是一般用戶的家目錄，自然也需要來備份一番！再來，由於使用者會有郵件吧！所以呢，這個 /var/spool/mail/ 內容也需要備份呦！另外，由於如果你曾經自行更動過核心，那麼 /boot 裡頭的資訊也就很重要囉！所以囉，這方面的資料你必須要備份的檔案為：

- /etc/ 整個目錄

- /home 整個目錄

- /var/spool/mail

- /boot

- /root

- 如果你自行安裝過其他的套件，那麼 /usr/local/ 或 /opt 也最好備份一下！

- 網路服務的資料庫方面：

這部份的資料可就多而且複雜了，首先是這些網路服務軟體的設定檔部分， 如果你的網路軟體安裝都是以原廠提供的為主，那麼你的設定檔案大多是在 /etc 底下，所以這個就沒啥大問題！但若你的套件大多來自於自行的安裝，那麼 /usr/local 這個目錄可就相當的重要了！

再來，每種服務提供的資料都不相同，這些資料很多都是人們提供的！舉例來說，你的 WWW 伺服器總是需要有人提供網頁檔案吧？否則瀏覽器來是要看啥咚咚？你的討論區總是得要寫入資料庫系統吧？ 否則討論的資料如何更新與記載？所以，使用者主動提供的檔案，以及服務運作過程會產生的資料， 都需要被考慮來備份。若我們假設我們提供的服務軟體都是使用原廠的 RPM 安裝的！所以要備份的資料檔案有：

- 軟體本身的設定檔案，例如：/etc/ 整個目錄，/usr/local/ 整個目錄

- 軟體服務提供的資料，以 WWW 及 MySQL 為例：

WWW 資料：/var/www 整個目錄或 /srv/www 整個目錄，及系統的使用者家目錄

MySQL ： /var/lib/mysql 整個目錄

- 其他在 Linux 主機上面提供的服務之資料庫檔案！

- 推薦需要備份的目錄：

由上面的介紹來看的話，如果你的硬體或者是由於經費的關係而無法全部的資料都予以備份時， 鳥哥建議你至少需要備份這些目錄呦！

- /boot

- /etc

- /home

- /root

- /usr/local(或者是 /opt 及 /srv 等)

- /var(註：這個目錄當中有些暫存目錄則可以不備份！)

- 不需要備份的目錄：

有些資料是不需要備份的啦！例如我們在第六章檔案權限與目錄配置裡頭提到的 /proc 這個目錄是在記錄目前系統上面正在跑的程序，這個資料根本就不需要備份的呢！此外，外掛的機器，例如 /mnt 或 /media 裡面都是掛載了其他的硬碟裝置、光碟機、軟碟機等等，這些也不需要備份吧？ 所以囉！底下有些目錄可以不需要備份啦！

- /dev ：這個隨便你要不要備份

- /proc：這個真的不需要備份啦！

- /mnt 與 /media：如果你沒有在這個目錄內放置你自己系統的東西，也不需要備份

- /tmp ：幹嘛存暫存檔！不需要備份！

備份用儲存媒體的選擇

用來儲存備份資料的媒體非常的多樣化，那該如何選擇呢？在選擇之前我們先來講個小故事先！

- 一個實際發生的故事

在備份的時候，選擇一個『資料存放的地方』也是很需要考慮的一個因素！ 什麼叫做資料存放的地方呢？講個最簡單的例子好了，我們知道說，較為大型的機器都會使用 tape 這一種磁帶機來備份資料，而如果是一般個人電腦的話，很可能是使用類似 Mo 這一種可讀寫式光碟片來存取資料！但是你不要忘記了幾個重要的因素，那就是萬一你的 Linux 主機被偷了呢？

這不是不可能的，之前鳥哥在成大唸書時，隔壁校區的研究室曾經遭小偷， 裡面所有的電腦都被偷走了！包括『Mo 片』，當他們發現的時候，一開始以為是硬體被偷走了，還好， 他們都有習慣進行備份，但是很不幸的，這一次連『備份的 MO 都被拿走了！』怎麼辦？！只能道德勸說小偷先生能夠良心發現的將硬碟拿回來囉！唉∼真慘....

- 異地備援系統

這個時候，所謂的『異地備援系統』就顯的相當的重要了！ 什麼是異地備援呀！說的太文言了！呵！簡單的說，就是將你的系統資料『備份』到其他的地方去， 例如說我的機器在台南，但是我還有另一部機器在高雄老家，這樣的話， 我可以將台南機器上面重要的資料都給他定期的自動的透過網路傳輸回去！ 也可以將家裡重要的資料給他丟到台南來！這樣的最大優點是可以在台南的機器死掉的時候， 即使是遭小偷，也可以有一個『萬一』的備份所在！

有沒有缺點啊？有啊！缺點就是∼頻寬嚴重的不足！ 在這種狀態下，所能採取的策略大概就是『僅將最重要的資料給他傳輸回去囉！』 至於一些只要系統從新安裝就可以回復的咚咚！那就沒有這個必要了！當然囉，如果你的網路是屬於 T1 專線的話，那麼完整備份將資料丟到另一地去，也是很可行的啦！只是鳥哥沒有那麼好命...

- 儲存媒體的考量

在此同時，我們再來談一談，那麼除了異地備援這個『相對較為安全的備份』方法之外， 還有沒有其他的方法可以儲存備份的呢？畢竟這種網路備援系統實在是太耗頻寬了！如果像我們一般家用的 ADSL 根本就是吃不消！那麼怎麼辦？喔∼那就只好使用近端的裝置來備份囉！ 這也是目前我們最常見到的備份方法！例如一般我們使用的 Tape, Mo, Zip, CD-RW, DVD-RW 還有備份用抽取式硬碟與攜帶式硬碟等等！ 那麼在選擇上需要注意些什麼呢？需要注意的地方有幾點：

- 備份速度要求 -- 思考硬碟用途：

『備份』在 Linux 主機上面也是蠻耗系統資源的！因為需要將系統的資料拷貝到其他裝置上面去，這個時候 I/O 與 CPU 的負載都會大！你總不希望系統就這樣給他掛點吧！此外，有些系統的資料實在太多咯， 怎麼樣也備份不完！所以囉，越快的儲存裝置是越好的！如果你是個重視速度甚於一切的人， 那麼我覺得抽取式硬碟是個不錯的方式，只不過.....目前我知道的抽取式硬碟都需要冷開機才行，不太符合 Linux 主機 24 小時全年無休的狀態....

但是硬碟真的越來越大、越來越便宜了，不使用速度快的硬碟來備份實在很可惜∼ 加上目前的火線 (IEEE 1394) 以及 USB 2.0 外接式硬碟盒技術已經相當的成熟， 傳輸速度又快，又可以直接熱拔插 (Plug and Play)，接上 USB 硬碟， 整個複製一下，傳輸速度理論上可達 480Mbps (約 60 MBytes/second) ，快的哩！ 複製完畢，又可以將硬碟帶走，不需要與主機放置在一起，還可以避免同時被偷，真是不錯。

但是，硬碟還是有一定的困擾，那就是『不接電源的硬碟需要很好很好的保養』。 我們知道電腦最好的保養就是常常開機去運作一下，免得長期不開機，造成受潮而損壞。 這個攜帶式硬碟只是偶而才會連上主機來進行備份的資料，除非你額外購買一部防潮箱來放置硬碟， 否則很容易損壞！所以，近年來速度越來越快的 DVD-RW 就變的很方便囉！至於磁帶 (tape)，在速度上完全是落後的.....

至於使用直接安裝在主機上的第二顆硬碟來備份，類似 RAID 或者是安裝一顆備份的硬碟在 Linux 系統當中，這個方案也很好， 而且速度上絕對是最具優勢的！但是就如同我們剛剛提到的，萬一你的機器被偷了，連帶的， 這顆備份的硬碟自然也就不見了.....

- 儲存容量 -- 磁帶備份考量：

這也是一個需要考量的因素！而且常常是最大考量的因素呢！雖然目前硬碟越來越便宜， 但是畢竟就如同前面說的，抽取式硬碟需要將系統冷開機，而建構在系統內的硬碟又同時具有不安全的成分在， 攜帶式硬碟可能又有不容易保存的特性，這個時候一個大容量的替代方案就顯的很重要了！雖然 CD-RW 與 DVD-RW 可以提供不錯的速度，但是其容量畢竟不足 (雖然有高達幾十 GB 的藍光 DVD 可用，但目前 (2009) 尚未普及， 光碟片太貴了！) 所以說，具有大容量的 tape (磁帶容量最小的一款也可以到達 8 GB 左右！) 就相當的具有這方面的優勢了！而且攜帶方便，存放也容易！更可以帶著走∼∼

- 經費與資料可靠性 -- DVD 的使用，可保存 10 年左右：

在經費不短缺的情況下，我們當然會建議你上面的幾個裝置都買一買， 然後分別在不同的時間進行不同的備份作業 (底下我們有些建議的啦！^_^) ！但是如果經費也是需要考量的話，那麼磁帶機這個目前還算貴重的物品可能暫時還動不到！ 這個時候近來漸漸便宜的 DVD-RW 就顯的活躍的多了！而且光碟片也可以保存很久的ㄋㄟ∼ 當然，目前應該不會有人以軟碟來備份了吧！呵呵！軟碟可是相當不安全的。

無論如何，如果經費允許的話， Tape 備份資料真的是一個不錯的點子！因為他的高容量讓我好滿意！ 再來，如果經費稍微短缺的話，那麼 DVD-RW 經常性的將資料燒錄下來，這也是蠻好的，尤其 DVD 片又不佔空間！再來，如果還是沒有辦法，那麼一顆內建在 Linux 的硬碟用來備份也是不錯的！ 什麼！連備份的硬碟都沒有，唉！怎麼跟我一樣∼這個時候沒辦法啦，用原來的安裝系統的硬碟，多留一個 partition 用來當作備份之用吧 (這也是目前鳥哥常用的方法之一！)底下我們來看一看一些常見的裝置代號！

- 光碟機： /dev/cdrom (其實應該是 /dev/sdX 或 /dev/hdX)

- 磁帶機： /dev/st0 (SCSI 介面), /dev/ht0 (IDE 介面)

- 軟碟機： /dev/fd0, /dev/fd1

- 硬碟機： /dev/hd[a-d][1-63] (IDE), /dev/sd[a-p][1-16] (SCSI/SATA)

- 外接式 USB 硬碟機： /dev/sd[a-p][1-16] (與 SCSI 相同)

- 印表機： /dev/lp[0-2]

特別留意的是磁帶機呦！如果你有錢的話，那麼買一部磁帶機是相當不錯的建議！沒錢的話，買 IDE 或 SATA 介面的硬碟也很不錯！！ ^_^

備份的種類、頻率與工具的選擇

講了好多口水了，還是沒有講到重點，真是的....好了，再來提到那個備份的種類，因為想要選擇什麼儲存媒體與相關備份工具， 都與備份使用的方式有關！那麼備份有哪些方式呢？一般可以粗略分為『累積備份』與『差異備份』這兩種 (註1)。當然啦，如果你在系統出錯時想要重新安裝到更新的系統時，僅備份關鍵資料也就可以了！

完整備份之累積備份 (Incremental backup)

備份不就是將重要資料複製出來即可嗎？幹嘛需要完整備份 (Full backup) 呢？如果你的主機是負責相當重要的服務， 因此如果有不明原因的當機事件造成系統損毀時，你希望在最短的時間內復原系統。此時，如果僅備份關鍵資料時， 那麼你得要在系統出錯後，再去找新的 Linux distribution 來安裝，安裝完畢後還得要考慮到資料新舊版本的差異問題， 還得要進行資料的移植與系統服務的重新建立等等，等到建立妥當後，還得要進行相關測試！ 這種種的工作可至少得要花上一個星期以上的工作天才能夠處理妥當！所以，僅有關鍵資料是不夠的！

- 還原的考量

但反過來講，如果是完整備份的話呢？若硬體出問題導致系統損毀時，只要將完整備份拿出來，整個給他傾倒回去硬碟， 所有事情就搞定了！有些時候 (例如使用 dd 指令) 甚至連系統都不需要重新安裝！反正整個系統都給他倒回去，連同重要的 Linux 系統檔案等，所以當然也就不需要重新安裝啊！因此，很多企業用來提供重要服務的主機都會使用完整備份， 若所提供的服務真的非常重要時，甚至會再架設一部一模一樣的機器呢！如此一來， 若是原本的機器出問題，那就立刻將備份的機器拿出來接管！以使企業的網路服務不會中斷哩！

那你知道完整備份的定義了吧？沒錯！完整備份就是將根目錄 (/) 整個系統通通備份下來的意思！ 不過，在某些場合底下，完整備份也可以是備份一個檔案系統 (filesystem)！例如 /dev/sda1 或 /dev/md0 或 /dev/myvg/mylv 之類的檔案系統就是了。

- 累積備份的原則

雖然完整備份在還原方面有相當良好的表現，但是我們都知道系統用的越久，資料量就會越大！如此一來， 完整備份所需要花費的時間與儲存媒體的使用就會相當麻煩∼所以，完整備份並不會也不太可能每天都進行的！ 那你想要每天都備份資料該如何進行呢？有兩種方式啦，一種是本小節會談到的累積備份，一種則是下個小節談到的差異備份。

所謂的累積備份，指的是在系統在進行完第一次完整備份後，經過一段時間的運作， 比較系統與備份檔之間的差異，僅備份有差異的檔案而已。而第二次累積備份則與第一次累積備份的資料比較， 也是僅備份有差異的資料而已。如此一來，由於僅備份有差異的資料，因此備份的資料量小且快速！備份也很有效率。 我們可以從下圖來說明：

圖 2.1.1、 累積備份 (incremental backup) 操作示意圖

假如我在星期一作好完整備份，則星期二的累積備份是系統與完整備份間的差異資料；星期三的備份是系統與星期二的差異資料， 星期四的備份則是系統與星期三的差異資料。那你得要注意的是，星期二的資料是完整備份加第一次累積備份， 星期三的資料是完整備份加第一次累積與第二次累積備份，星期四的資料則是星期一的完整備份加第一次加第二次加第三次累積備份。 由於每次都僅與前一次的備份資料比較而已，因此備份的資料量就會少很多！

那如何還原？經過上面的分析，我們也會知道累積備份的還原方面比較麻煩！ 假設你的系統在星期五的時候掛點了！那你要如何還原？首先，你必須要還原星期一的完整備份，然後還原星期二的累積備份， 再依序還原星期三、星期四的累積備份才算完全復原！那如果你是經過了九次的累積備份，就得要還原到第九次的階段， 才是最完整的還原程序！

- 累積備份使用的備份軟體

完整備份常用的工具有 dd, cpio, dump/restore 等等。因為這些工具都能夠備份裝置與特殊檔案！ dd 可以直接讀取磁碟的磁區 (sector) 而不理會檔案系統，是相當良好的備份工具！不過缺點就是慢很多！ cpio 是能夠備份所有檔名，不過，得要配合 find 或其他找檔名的指令才能夠處理妥當。以上兩個都能夠進行完整備份， 但累積備份就得要額外使用腳本程式來處理。可以直接進行累積備份的就是 dump 這個指令囉！詳細的指令與參數用法， 請前往第九章查閱，這裡僅列出幾個簡單的範例而已。

# 1. 用 dd 來將 /dev/sda 備份到完全一模一樣的 /dev/sdb 硬碟上：

[root@www ~]# dd if=/dev/sda of=/dev/sdb

# 由於 dd 是讀取磁區，所以 /dev/sdb 這顆磁碟可以不必格式化！非常的方便！

# 只是你會等非常非常久！因為 dd 的速度比較慢！

# 2. 使用 cpio 來備份與還原整個系統，假設儲存媒體為 SATA 磁帶機：

[root@www ~]# find / -print | cpio -covB > /dev/st0  <==備份到磁帶機

[root@www ~]# cpio -iduv < /dev/st0                  <==還原

假設 /home 為一個獨立的檔案系統，而 /backupdata 也是一個獨立的用來備份的檔案系統，那如何使用 dump 將 /home 完整的備份到 /backupdata 上呢？可以像底下這樣進行看看：

# 1. 完整備份

[root@www ~]# dump -0u -f /backupdata/home.dump /home

# 2. 第一次進行累積備份

[root@www ~]# dump -1u -f /backupdata/home.dump.1 /home

除了這些指令之外，其實 tar 也可以用來進行完整備份啦！舉例來說，/backupdata 是個獨立的檔案系統， 你想要將整個系統通通備份起來時，可以這樣考慮：將不必要的 /proc, /mnt, /tmp 等目錄不備份，其他的資料則予以備份：

[root@www ~]# tar --exclude /proc --exclude /mnt --exclude /tmp \

> --exclude /backupdata -jcvp -f /backupdata/system.tar.bz2 /

完整備份之差異備份 (Differential backup)

差異備份與累積備份有點類似，也是需要進行第一次的完整備份後才能夠進行。只是差異備份指的是：每次的備份都是與原始的完整備份比較的結果。所以系統運作的越久，離完整備份時間越長， 那麼該次的差異備份資料可能就會越大！差異備份的示意圖如下所示：

圖 2.2.1、 差異備份 (differential backup) 操作示意圖

差異備份常用的工具與累積備份差不多！因為都需要完整備份嘛！如果使用 dump 來備份的話，那麼每次備份的等級 (level) 就都會是 level 1 的意思啦！當然啦，你也可以透過 tar 的 -N 選項來備份喔！如下所示：

[root@www ~]# tar -N '2009-06-01' -jpcv -f /backupdata/home.tar.bz2 /home

# 只有在比 2009-06-01 還要新的檔案，在 /home 底下的檔案才會被打包進 home.bz2 中！

# 有點奇怪的是，目錄還是會被記錄下來，只是目錄內的舊檔案就不會備份。

此外，你也可以透過 rsync 來進行鏡像備份喔！ 這個 rsync 可以對兩個目錄進行鏡像 (mirror) ，算是一個非常快速的備份工具！簡單的指令語法為：

[root@www ~]# rsync -av 來源目錄 目標目錄

# 1. 將 /home/ 鏡像到 /backupdata/home/ 去

[root@www ~]# rsync -av /home /backupdata/

# 此時會在 /backupdata 底下產生 home 這個目錄來！

[root@www ~]# rsync -av /home /backupdata/

# 再次進行會快很多！如果資料沒有更動，幾乎不會進行任何動作！

根據分析 (註2) ，差異備份所使用的磁碟容量可能會比累積備份來的大，但是差異備份的還原較快， 因為只需要還原完整備份與最近一次的差異備份即可。無論如何，請依據你自己的喜好來選擇備份的方式吧！

關鍵資料備份

完整備份雖然有許多好處，但就是需要花費很多時間！所以，如果在主機提供的服務並不是一定要 24 小時提供的前提下， 我們可以僅備份重要的關鍵資料即可。由於主機即使當機個一兩天可能也不會影響到你的正常生活時， 僅備份關鍵資料就好啦！不需要整個系統都備份。僅備份關鍵資料是有許多好處的！ 由於完整備份可能是在系統運作期間進行，不但會花費非常多時間，而且如果備份當時系統已經被攻破， 那你備份的資料是有問題的，那還原回去也是有問題的系統啊！

如果僅是備份關鍵資料而已，那麼由於系統的絕大部分執行檔都可以後來重新安裝，因此若你的系統不是因為硬體問題， 而是因為軟體問題而導致系統被攻破或損毀時，直接捉取最新的 Linux distribution ，然後重新安裝， 然後再將系統資料 (如帳號/密碼與家目錄等等) 與服務資料 (如 www/email/crontab/ftp 等等) 一個一個的填回去！ 那你的系統不但保持在最新的狀態，同時也可以趁機處理一下與重新溫習一下系統設定！是很不錯的呦！

不過，備份關鍵資料最麻煩的地方其實就是在還原啦！上述的還原方式是你必須要很熟悉系統運作， 否則還原得要花費很多時間的！尤其近來的 Linux 強調安全性，所以加入 SELinux 了，你如果要從舊版的 Linux 升級到新版時， 原本若沒有 SELinux 而換成新版則需要啟動 SELinux 時，那個除錯的時間會花很長一段日子哩！ 鳥哥認為這是僅備份關鍵資料的一些優缺點啦∼

備份關鍵資料鳥哥最愛使用 tar 來處理了！如果想要分門別類的將各種不同的服務在不同的時間備份使用不同檔名， 配合 date 指令是非常好用的工具！例如底下的案例是依據日期來備份 mysql 的資料庫喔！

[root@www ~]# tar -jpcvf mysql.`date +%Y-%m-%d`.tar.bz2 /var/lib/mysql

備份是非常重要的工作，你可不希望想到才進行吧？交給系統自動處理就對啦！請自己撰寫 script ， 配合 crontab 去執行吧！這樣子，備份會很輕鬆喔！

鳥哥的備份策略

每部主機的任務都不相同，重要的資料也不相同，重要性也不一樣，因此，每個人的備份思考角度都不一樣！ 有些備份策略是非常有趣的，包括使用多個磁帶機與磁帶來自動備份企業資料哩 (註3) 。

就鳥哥的想法來說，鳥哥並沒有想要將整個系統完整的備份下來，因為太耗時間了！而且就鳥哥的立場而言，似乎也沒有這個必要， 所以通常鳥哥只備份較為重要的檔案而已！不過，由於鳥哥需要備份 /home 與網頁資料，如果天天都備份，我想，系統遲早會受不了 (因為這兩個部分就已經佔去數 10 GB 的硬碟空間...)，所以鳥哥就將我的備份分為兩大部分，一個是每日備份經常性變動的重要資料， 一個則是每週備份就不常變動的資訊。這個時候我就寫了兩個簡單的 scripts ，分別來儲存這些資料。

所以針對鳥哥的『鳥站』來說，我的備份策略是這樣的：

1. 主機硬體：使用一個獨立的 filesystem 來儲存備份資料，此 filesystem 掛載到 /backup 當中；

2. 每日進行：目前僅備份 MySQL 資料庫；

3. 每週進行：包括 /home, /var, /etc, /boot, /usr/local 等目錄與特殊服務的目錄；

4. 自動處理：這方面利用 /etc/crontab 來自動提供備份的進行；

5. 異地備援：每月定期的將資料分別 (a)燒錄到光碟上面 (b)使用網路傳輸到另一部機器上面。

那就來看看鳥哥是怎麼備份的吧！ ^_^

每週系統備份的 script

底下提供鳥哥的備份的 scripts ，希望對大家有點幫助！鳥哥假設你已經知道如何掛載一個新的 filesystem 到 /backup 去，所以格式化與掛載這裡就不再強調囉。

[root@www ~]# vi /backup/backupwk.sh

#!/bin/bash

# ====================================================================

# 使用者參數輸入位置：

# basedir=你用來儲存此腳本所預計備份的資料之目錄(請獨立檔案系統)

basedir=/backup/weekly  <==您只要改這裡就好了！

# ====================================================================

# 底下請不要修改了！用預設值即可！

PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH

export LANG=C

# 設定要備份的服務的設定檔，以及備份的目錄

named=$basedir/named

postfixd=$basedir/postfix

vsftpd=$basedir/vsftp

sshd=$basedir/ssh

sambad=$basedir/samba

wwwd=$basedir/www

others=$basedir/others

userinfod=$basedir/userinfo

# 判斷目錄是否存在，若不存在則予以建立。

for dirs in $named $postfixd $vsftpd $sshd $sambad $wwwd $others $userinfod

do

[ ! -d "$dirs" ] && mkdir -p $dirs

Done

# 1. 將系統主要的服務之設定檔分別備份下來，同時也備份 /etc 全部。

cp -a /var/named/chroot/{etc,var}     $named

cp -a /etc/postfix /etc/dovecot.conf  $postfixd

cp -a /etc/vsftpd/*                   $vsftpd

cp -a /etc/ssh/*                      $sshd

cp -a /etc/samba/*                    $sambad

cp -a /etc/{my.cnf,php.ini,httpd}     $wwwd

cd /var/lib

tar -jpc -f $wwwd/mysql.tar.bz2     mysql

cd /var/www

tar -jpc -f $wwwd/html.tar.bz2      html cgi-bin

cd /

tar -jpc -f $others/etc.tar.bz2     etc

cd /usr/

tar -jpc -f $others/local.tar.bz2   local

# 2. 關於使用者參數方面

cp -a /etc/{passwd,shadow,group}      $userinfod

cd /var/spool

tar -jpc -f $userinfod/mail.tar.bz2 mail

cd /

tar -jpc -f $userinfod/home.tar.bz2 home

cd /var/spool

tar -jpc -f $userinfod/cron.tar.bz2 cron at

[root@www ~]# chmod 700 /backup/backupwk.sh

[root@www ~]# /backup/backupwk.sh  <==記得自己試跑看看！

上面的 script 主要均使用 CentOS 5.x (理論上， Red Hat 系列的 Linux 都是用) 預設的服務與目錄， 如果你有設定某些服務的資料在不同的目錄時，那麼上面的 script 是還需要修改的！不要只是拿來用而已喔！ 上面 script 可以在底下的連結取得。

- http://linux.vbird.org/linux_basic/0580backup/backupwk-0.1.sh

每日備份資料的 script

再來，繼續提供一下每日備份資料的腳本程式！請注意，鳥哥這裡僅有提供 MySQL 的資料庫備份目錄， 與 WWW 的類似留言版程式使用的 CGI 程式與寫入的資料而已。 如果你還有其他的資料需要每日備份，請自行照樣造句囉！ ^_^

[root@www ~]# vi /backup/backupday.sh

#!/bin/bash

# =========================================================

# 請輸入，你想讓備份資料放置到那個獨立的目錄去

basedir=/backup/daily/  <==你只要改這裡就可以了！

# =========================================================

PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH

export LANG=C

basefile1=$basedir/mysql.$(date +%Y-%m-%d).tar.bz2

basefile2=$basedir/cgi-bin.$(date +%Y-%m-%d).tar.bz2

[ ! -d "$basedir" ] && mkdir $basedir

# 1. MysQL (資料庫目錄在 /var/lib/mysql)

cd /var/lib

tar -jpc -f $basefile1 mysql

# 2. WWW 的 CGI 程式 (如果有使用 CGI 程式的話)

cd /var/www

tar -jpc -f $basefile2 cgi-bin

[root@www ~]# chmod 700 /backup/backupday.sh

[root@www ~]# /backup/backupday.sh  <==記得自己試跑看看！

上面的腳本可以在底下的連結取得。這樣一來每天的 MySQL 資料庫就可以自動的被記錄在 /backup/daily/ 目錄裡頭啦！而且還是檔案名稱會自動改變的呦！呵呵！我很喜歡！OK！再來就是開始讓系統自己跑啦！ 怎麼跑？就是 /etc/crontab 呀！提供一下我的相關設定呦！

- http://linux.vbird.org/linux_basic/0580backup/backupday.sh

[root@www ~]# vi /etc/crontab

# 加入這兩行即可 (請注意你的檔案目錄！不要照抄呦！)

30 3 * * 0 root /backup/backupwk.sh

30 2 * * * root /backup/backupday.sh

這樣系統就會自動的在每天的 2:30 進行 MySQL 的備份，而在每個星期日的 3:30 進行重要檔案的備份！呵呵！你說，是不是很容易呢！但是請千萬記得呦！還要將 /backup/ 當中的資料 copy 出來才行耶！否則整部系統死掉的時候...那可不是鬧著玩的！ 所以鳥哥大約一個月到兩個月之間，會將 /backup 目錄內的資料使用 DVD 複製一下，然後將 DVD 放置在家中保存！這個 DVD 很重要的喔！不可以遺失，否則系統的重要資料 (尤其是帳號資訊) 流出去可不是鬧著玩的！

Tips:

有些時候，你在進行備份時，被備份的檔案可能同時間被其他的網路服務所修改喔！ 舉例來說，當你備份 MySQL 資料庫時，剛好有人利用你的資料庫發表文章，此時， 可能會發生一些錯誤的訊息。要避免這類的問題時，可以在備份前，將該服務先關掉， 備份完成後，再啟動該服務即可！感謝討論區 duncanlo 提供這個方法！

遠端備援的 script

如果你有控管兩部以上的 Linux 主機時，那麼互相將對方的重要資料保存一份在自己的系統中也是個不錯的想法！ 那怎麼保存啊？使用 USB 複製來去嗎？當然不是啦！你可以透過網路來處置啦！我們假設你已經有一部主機， 這部主機的 IP 是 192.168.1.100 ，而且這部主機已經提供了 FTP 與 sshd 這兩個網路服務， 同時你已經做好了 FTP 的帳號，sshd 帳號的免密碼登入功能等 (這部分請參考伺服器篇的介紹)，接下來你可以這樣做：

- 使用 FTP 上傳備份資料

假設你要上傳的資料是將 /backup/weekly/ 目錄內的檔案統整為一個 /backup/weekly.tar.bz2 ， 並且上傳到伺服器端的 /home/backup/ 底下，使用的帳號是 dmtsai ，密碼是 dmtsai.pass 。 那麼你可以這樣做看看：

[root@www ~]# vi /backup/ftp.sh

#!/bin/bash

# ===========================================

# 先輸入系統所需要的資料

host="192.168.1.100"           # 遠端主機

id="dmtsai"                    # 遠端主機的 FTP 帳號

pw='dmtsai.pass'               # 該帳號的密碼

basedir="/backup/weekly"       # 本地端的欲被備份的目錄

remotedir="/home/backup"       # 備份到遠端的何處？

# ===========================================

backupfile=weekly.tar.bz2

cd $basedir/..

tar -jpc -f $backupfile $(basename $basedir)

ftp -n "$host" > ${basedir}/../ftp.log 2>&1 <<EOF

user $id $pw

binary

cd $remotedir

put $backupfile

bye

EOF

- 使用 rsync 上傳備份資料

另一個更簡單的方法就是透過 rsync ，但是你必須要在你的伺服器上面取得某個帳號使用權後， 並讓該帳號可以不用密碼即可登入才行！這部分得要先參考伺服器篇的遠端連線伺服器才行！ 假設你已經設定好 dmtsai 這個帳號可以不用密碼即可登入遠端伺服器，而同樣的你要讓 /backup/weekly/ 整個備份到 /home/backup/weekly 底下時，可以簡單這樣做：

[root@www ~]# vi /backup/rsync.sh

#!/bin/bash

remotedir=/home/backup/

basedir=/backup/weekly

host=127.0.0.1

id=dmtsai

# 底下為程式階段！不需要修改喔！

rsync -av -e ssh $basedir ${id}@${host}:${remotedir}

由於 rsync 可以透過 ssh 來進行鏡像備份，所以沒有變更的檔案將不需要上傳的！相當的好用呢！ 好了！大家趕緊寫一個適合自己的備份 script 來進行備份的行為吧！重要重要喔！

災難復原的考量

之所以要備份當然就是預防系統掛點啦！如果系統真的掛點的話，那麼你該如何還原系統呢？

- 硬體損毀，且具有完整備份的資料時

由於是硬體損毀，所以我們不需要考慮系統軟體的不穩定問題，所以可以直接將完整的系統復原回去即可。 首先，你必須要先處理好你的硬體，舉例來說，將你的硬碟作個適當的處理，譬如建置成為磁碟陣列之類的。 然後依據你的備份狀態來復原。舉例來說，如果是使用差異備份，那麼將完整備份復原後， 將最後一次的差異備份復原回去，你的系統就恢復了！非常簡單吧！

- 由於軟體的問題產生的被攻破資安事件

由於系統的損毀是因為被攻擊，此時即使你恢復到正常的系統，那麼這個系統既然會被攻破， 沒道理你還原成舊系統就不會被再次攻破！所以，此時完整備份的復原可能不是個好方式喔！最好是需要這樣進行啦：

1. 先拔除網路線，最好將系統進行完整備份到其他媒體上，以備未來查驗

2. 開始查閱登錄檔，嘗試找出各種可能的問題

3. 開始安裝新系統 (最好找最新的 distribution)

4. 進行系統的升級，與防火牆相關機制的制訂

5. 根據 2 的錯誤，在安裝完成新系統後，將那些 bug 修復

6. 進行各項服務與相關資料的恢復

7. 正式上線提供服務，並且開始測試

軟體資安事件造成的問題可大可小，一般來說，標準流程都是建議你將出問題的系統備份下來， 如果被追蹤到你的主機曾經攻擊過別人的話，那麼你至少可以拿出備份資料來佐證說，你是被攻擊者， 而不是主動攻擊別人的壞人啊！然後，記得一定要找出問題點並予以克服，不然的話，你的系統將一再地被攻擊啊！ 那樣可就傷腦筋囉∼

重點回顧

- 備份是系統損毀時等待救援的救星，但造成系統損毀的因素可能有硬體與軟體等原因。

- 由於主機的任務不同，備份的資料與頻率等考量參數也不相同。

- 常見的備份考慮因素有：關鍵檔案、儲存媒體、備份方式(完整/關鍵)、備份頻率、使用的備份工具等。

- 常見的關鍵資料有：/etc, /home, /var/spool/mail, /boot, /root 等等

- 儲存媒體的選擇方式，需要考慮的地方有：備份速度、媒體的容量、經費與媒體的可靠性等。

- 與完整備份有關的備份策略主要有：累積備份與差異備份。

- 累積備份可具有較小的儲存資料量、備份速度快速等。但是在還原方面則比差異備份的還原慢。

- 完整備份的策略中，常用的工具有 dd, cpio, tar, dump 等等。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 挑戰題：嘗試將你在學習本書所進行的各項任務備份下來，然後刪除你的系統，接下來重新安裝最新的 CentOS 5.x ， 再將你備份的資料復原回來，看看能否成功的讓你的系統回復到之前的狀態呢？

- 挑戰題：查詢一下何謂企鵝龍軟體，討論一下該軟體的還原機制是屬於累積備份？還是完整備份？

- 常用的完整備份 (full backup) 工具指令有哪些？

dump + restore, dd, cpio 搭配 find 等軟體。

- 你所看到的常見的儲存設備有哪些？

Floppy, Mo, Zip, CD-RW, DVD-RW, 外接式 USB 硬碟, Tape, 外接式儲存陣列 (RAID)，額外的儲存架構，如 SAN, NAS 等。

參考資料與延伸閱讀

- 註1：維基百科的備份說明：http://en.wikipedia.org/wiki/Incremental_backup

- 註2：關於 differential 與 incremental 備份的優缺點說明：

http://www.backupschedule.net/databackup/differentialbackup.html

- 註3：一些備份計畫的實施：http://en.wikipedia.org/wiki/Backup_rotation_scheme

2002/07/06：第一次完成

2003/02/12：重新編排與加入 FAQ

2005/10/25：舊版的資料已經移動到 此處 。

2005/10/25：主要是增加了一些簡單的說明，以及將一些不合時宜的資料拿掉而已！

2009/07/15：將原本的基於 FC4 的文章移動到 此處。

2009/09/18：加入簡單的幾個題目練習

2002/07/06以來統計人數

第二十六章、Linux 核心編譯與管理

切換解析度為 800x600

最近更新日期：2009/09/18

我們說的 Linux 其實指的就是核心 (kernel) 而已。這個核心控制你主機的所有硬體並提供系統所有的功能， 所以說，他重不重要啊！我們開機的時候其實就是利用開機管理程式載入這個核心檔案來偵測硬體， 在核心載入適當的驅動程式後，你的系統才能夠順利的運作。現今的系統由於強調線上升級機制，因此非常不建議自訂核心編譯！ 但是，如果你想要將你的 Linux 安裝到 USB 隨身碟、想要將你的 Eee PC 小筆電安裝自己的 Linux ， 想讓你的 Linux 可以驅動你的小家電，此時，核心編譯就是相當重要的一個任務了！ 這一篇比較進階，如果你對系統移植沒有興趣的話，這一篇可以先略過喔！ ^_^

1. 編譯前的任務：認識核心與取得核心原始碼

1.1 什麼是核心 (Kernel)

1.2 更新核心的目的

1.3 核心的版本

1.4 核心原始碼的取得方式：distributions 預設、最新、patch

1.5 核心原始碼的解壓縮/安裝/觀察

2. 核心編譯的前處理與核心功能選擇

2.1 硬體環境檢視與核心功能要求

2.2 保持乾淨原始碼： make mrproper

2.3 開始挑選核心功能： make XXconfig

2.4 核心功能細項選擇

a. 一般設定(General setup)：附加版本名稱、IPC 通訊、程序相關等

b. 核心模組與 block layer 支援

c. CPU 的類型與功能選擇(含虛擬化技術)

d. 電源管理功能

e. 一些匯流排 (bus) 的選項

f. 編譯後執行檔的格式

g. 核心的網路功能

h. 各項裝置的驅動程式

i. 檔案系統的支援

j. 核心駭客、資訊安全、密碼應用

k. 虛擬化與函式庫

3. 核心的編譯與安裝

3.1 編譯核心與核心模組

3.2 實際安裝模組

3.3 開始安裝新核心與多重核心選單 (grub)

4. 額外(單一)核心模組編譯

4.1 編譯前注意事項

4.2 單一模組編譯

4.3 核心模組管理

5. 重點回顧

6. 本章習題

7. 參考資料與延伸閱讀

8. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23899

編譯前的任務：認識核心與取得核心原始碼

我們在第一章裡面就談過 Linux 其實指的是核心！這個『核心 (kernel)』是整個作業系統的最底層，他負責了整個硬體的驅動，以及提供各種系統所需的核心功能，包括防火牆機制、是否支援 LVM 或 Quota 等檔案系統等等，這些都是核心所負責的！所以囉，在第二十章的開機流程中，我們也會看到 MBR 內的 loader 載入核心檔案來驅動整個系統的硬體呢！ 也就是說，如果你的核心不認識某個最新的硬體，那麼該硬體也就無法被驅動，你當然也就無法使用該硬體囉！

什麼是核心 (Kernel)

這已經是整個 Linux 基礎的最後一篇了，所以，底下這些資料你應該都要『很有概念』才行∼ 不能只是『好像有印象』∼好了，那就複習一下核心的相關知識吧！

- Kernel

還記得我們在第十一章的 BASH shell 提到過：電腦真正在工作的東西其實是『硬體』， 例如數值運算要使用到 CPU、資料儲存要使用到硬碟、圖形顯示會用到顯示卡、音樂發聲要有音效晶片、連接 Internet 可能需要網路卡等等。那麼如何控制這些硬體呢？那就是核心的工作了！也就是說，你所希望電腦幫你達成的各項工作， 都需要透過『核心』的幫助才行！當然囉，如果你想要達成的工作是核心所沒有提供的， 那麼你自然就沒有辦法透過核心來控制電腦使他工作囉！

舉例來說，如果你想要有某個網路功能 (例如核心防火牆機制) ，但是你的核心偏偏忘記加進去這項功能， 那麼不論你如何『賣力』的設定該網路套件，很抱歉！不來電！換句話說，你想要讓電腦進行的工作，都必須要『核心有支援』才可以！這個標準不論在 Windows 或 Linux 這幾個作業系統上都相同！如果有一個人開發出來一個『全新的硬體』，目前的核心不論 Windows 或 Linux 都不支援，那麼不論你用什麼系統，哈哈！這個硬體都是英雄無用武之地啦！ 那麼是否瞭解了『核心』的重要了呢？所以我們才需要來瞭解一下如何編譯我們的核心啦！

那麼核心到底是什麼啊？其實核心就是系統上面的一個檔案而已， 這個檔案包含了驅動主機各項硬體的偵測程式與驅動模組。在第二十章的開機流程分析中，我們也提到這個檔案被讀入主記憶體的時機， 當系統讀完 BIOS 並載入 MBR 內的開機管理程式後，就能夠載入核心到記憶體當中。然後核心開始偵測硬體， 掛載根目錄並取得核心模組來驅動所有的硬體，之後呼叫 /sbin/init 就能夠依序啟動所有系統所需要的服務了！

這個核心檔案通常被放置成 /boot/vmlinuz ，不過也不見得， 因為一部主機上面可以擁有多個核心檔案，只是開機的時候僅能選擇一個來載入而已。 甚至我們也可以在一個 distribution 上面放置多個核心，然後以這些核心來做成多重開機呢！

- 核心模組 (kernel module) 的用途

既然核心檔案都已經包含了硬體偵測與驅動模組，那麼什麼是核心模組啊？要注意的是， 現在的硬體更新速度太快了，如果我的核心比較舊，但我換了新的硬體，那麼，這個核心肯定無法支援！ 怎麼辦？重新拿一個新的核心來處理嗎？開玩笑∼核心的編譯過程可是很麻煩的∼

所以囉，為了這個緣故，我們的 Linux 很早之前就已經開始使用所謂的模組化設定了！ 亦即是將一些不常用的類似驅動程式的咚咚獨立出核心，編譯成為模組，然後， 核心可以在系統正常運作的過程當中載入這個模組到核心的支援。如此一來， 我在不需要更動核心的前提之下，只要編譯出適當的核心模組，並且載入他，呵呵！我的 Linux 就可以使用這個硬體啦！簡單又方便！

那我的模組放在哪裡啊？可惡！怎麼會問這個傻問題呢？當然一定要知道的啦！就是 /lib/modules/$(uname -r)/kernel/ 當中啦！

- 自製核心 - 核心編譯

剛剛上面談到的核心其實是一個檔案，那麼這個檔案怎麼來的？當然是透過原始碼 (source code) 編譯而成的啊！因為核心是直接被讀入到主記憶體當中的，所以當然要將他編譯成為系統可以認識的資料才行！也就是說， 我們必須要取得核心的原始碼，然後利用第二十二章 Tarball 安裝方式提到的編譯概念來達成核心的編譯才行啊！(這也是本章的重點啊！ ^_^)

- 關於驅動程式 - 是廠商的責任還是核心的責任？

現在我們知道硬體的驅動程式可以編譯成為核心模組，所以可以在不改變核心的前提下驅動你的新硬體。 但是，很多朋友還是常常感到困惑，就是 Linux 上面針對最新硬體的驅動程式總是慢了幾個腳步， 所以覺得好像 Linux 的支援度不足！其實不可以這麼說的，為什麼呢？因為在 Windows 上面，對於最新硬體的驅動程式需求，基本上，也都是廠商提供的驅動程式才能讓該硬體工作的， 因此，在這個『驅動程式開發』的工作上面來說，應該是屬於硬體發展廠商的問題， 因為他要我們買他的硬體，自然就要提供消費者能夠使用的驅動程式啦！

所以，如果大家想要讓某個硬體能夠在 Linux 上面跑的話，那麼似乎可以發起一人一信的方式，強烈要求硬體開發商發展 Linux 上面的驅動程式！這樣一來，也可以促進 Linux 的發展呢！

更新核心的目的

除了 BIOS 之外，核心是作業系統中最早被載入到記憶體的咚咚， 他包含了所有可以讓硬體與軟體工作的資訊，所以，如果沒有搞定核心的話， 那麼你的系統肯定會有點小問題！好了，那麼是不是將『所有目前核心有支援的東西都給他編譯進去我的核心中， 那就可以支援目前所有的硬體與可執行的工作啦！』！

這話說的是沒錯啦，但是你是否曾經看過一個為了怕自己今天出門會口渴、會餓、會冷、會熱、會被車撞、 會摔跤、會被性騷擾，而在自己的大包包裡面放了大瓶礦泉水、便當、厚外套、短褲、防撞鋼樑、止滑墊、 電擊棒....等一大堆東西，結果卻累死在半路上的案例嗎？當然有！但是很少啦！我相信不太有人會這樣做！ (會這麼做的人通常都已經在醫院了∼) 取而代之的是會看一下天氣，冷了就只帶外套， 熱了就只帶短衣、如果穿的漂亮一點又預計晚點回家就多帶個電擊棒、 出遠門到沒有便利商店的地方才多帶礦泉水....

說這個幹什麼！對啦！就是要你瞭解到，核心的編譯重點在於『你要你的 Linux 作什麼？』，是啦！如果沒有必要的工作，就乾脆不要加在你的核心當中了！這樣才能讓你的 Linux 跑得更穩、更順暢！這也是為什麼我們要編譯核心的最主要原因了！

- Linux 核心特色，與預設核心對終端用戶的角色

Linux 的核心有幾個主要的特色，除了『Kernel 可以隨時、隨各人喜好而更動』之外，Kernel 的『版本更動次數太頻繁』也是一個特點！所以囉，除非你有特殊需求， 否則一次編譯成功就可以啦！不需要隨時保持最新的核心版本，而且也沒有必要 (編譯一次核心要粉久的ㄋㄟ！) 。話說到這裡又突然想到今天看到的一篇文章，大意是說老闆想要雇用的人會希望是 Linux 的老手，因為他們比較容易瞭解問題的所在，除此之外，如果有任何問題發生，由於其使用 Linux 是可以隨時修補漏洞的！但是如果是 Windows 的話，就得要將機器關閉，直到 MS 推出修補套件後才能再啟用∼

那麼是否『我就一定需要在安裝好了 Linux 之後就趕緊給他編譯核心呢？』， 老實說，『並不需要的』！這是因為幾乎每一個 distribution 都已經預設編譯好了相當大量的模組了， 所以使用者常常或者可能會使用到的資料都已經被編譯成為模組，也因此，呵呵！ 我們使用者確實不太需要重新來編譯核心！尤其是『一般的使用者， 由於系統已經將核心編譯的相當的適合一般使用者使用了，因此一般入門的使用者，基本上， 不太需要編譯核心』。

- 核心編譯的可能目的

OK！那麼鳥哥閒閒沒事幹跑來寫個什麼東西？既然都不需要編譯核心還寫編譯核心的分享文章， 鳥哥賣弄才學呀？很抱歉，鳥哥雖然是個『不學有術』的混混，卻也不會平白無故的寫東西請您來指教∼ 當然是有需要才會來編譯核心啦！編譯核心的時機可以歸納為幾大類：

- 新功能的需求：

我需要新的功能，而這個功能只有在新的核心裡面才有，那麼為了獲得這個功能，只好來重新編譯我的核心了。例如 iptables 這個防火牆機制只有在 2.4.xx 以後的版本裡面才有，而新開發的主機板晶片組， 很多也需要新的核心推出之後，才能正常而且有效率的工作！

- 原本核心太過臃腫：

如果你是那種對於系統『穩定性』很要求的人，對於核心多編譯了很多莫名其妙的功能而不太喜歡的時候， 那麼就可以重新編譯核心來取消掉該功能囉；

- 與硬體搭配的穩定性：

由於原本 Linux 核心大多是針對 Intel 的 CPU 來作開發的，所以如果你的 CPU 是 AMD 的系統時，有可能 (注意！只是有可能，不見得一定會如此) 會讓系統跑得『不太穩！』。此外，核心也可能沒有正確的驅動新的硬體，此時就得重新編譯核心來讓系統取得正確的模組才好。

- 其他需求 (如嵌入式系統)：

就是你需要特殊的環境需求時，就得自行設計你的核心囉！( 像是一些商業的套裝軟體系統，由於需要較為小而美的作業系統， 那麼他們的核心就需要更簡潔有力了！)

另外，需要注意重新編譯核心雖然可以針對你的硬體作最佳化的步驟 (例如剛剛提到的 CPU 的問題！) ，不過由於這些最佳化的步驟對於整體效能的影響是很小很小的， 因此如果是為了增加效能來編譯核心的話，基本上，效益不大！然而，如果是針對『系統穩定性』來考量的話， 那麼就有充分的理由來支持你重新編譯核心囉！

『如果系統已經運行很久了，而且也沒有什麼大問題， 加上我又不增加冷門的硬體設備，那麼建議就不需要重新編譯核心了』， 因為重新編譯核心的最主要目的是『想讓系統變的更穩！』既然你的 Linux 主機已經達到這個目的了，何必再編譯核心？不過，就如同前面提到的， 由於預設的核心不見得適合你的需要，加上預設的核心可能並無法與你的硬體配備相配合， 此時才開始考慮重新編譯核心吧！

Tips:

早期鳥哥是強調最好重新編譯核心的一群啦！不過，最近這個想法改變了∼ 既然原本的 distribution 都已經幫我們考慮好如何使用核心了，那麼， 我們也不需要再重新的編譯核心啦！尤其是 distribution 都會主動的釋出新版的核心 RPM 版本， 所以，實在不需要自己重新編譯的！當然啦，如同前面提到的， 如果你有特殊需求的話，那就另當別論嚕！ ^_^

由於『核心的主要工作是在控制硬體！』所以編譯核心之前， 請先瞭解一下你的硬體配備，與你這部主機的未來功能！由於核心是『越簡單越好！』所以只要將這部主機的未來功能給他編進去就好了！ 其他的就不用去理他啦！

核心的版本

核心的版本問題，我們在第一章已經談論過， 主要的版本定義為：『[主].[次].[釋出]-[修改]』的樣式。 你只要知道 2.6.x 是穩定版本，2.5.x 是測試用版本即可。 我們要使用最新的核心來重新編譯核心時，大多就是使用那種偶數的核心版本啦！不過這裡還是要再提一遍！就是『 2.4.x 與 2.6.x 是兩個具有相當大差異的核心版本， 兩者之間使用到的函式庫基本上已經不相同了，所以在升級之前，如果你的核心原本是 2.4.xx 版，那麼就升級到 2.4.xx 版本的最新版，不要由 2.4.xx 直接升級到 2.6.xx 版，否則到時可能會欲哭無淚∼∼』， 這個問題在討論區一再地被提起！這裡再次說明！

Tips:

為什麼不能從 2.4 升級到 2.6 呢？其實還是可以啦！只是過程很複雜！ 我們知道軟體 (packages) 是架構在系統核心上面來進行編譯、安裝與執行的， 也就是說，這些 packages 與核心之間，是有相關性的！這些 packages 會用到很多核心提供的功能。 但是不同的[主][次]版本之間，他們提供的功能架構差異太大，因此，若你由 2.4 升級到 2.6 的話， 那麼絕大部分的軟體『都需要重新再編譯！』這樣瞭解為何不要在不同的版本間升級了吧？

此外，2.4.xx 與 2.6.xx 的比較中，並不是 2.6.xx 就一定比 2.4.xx 還要新，因為這兩種版本同時在進行維護與升級的工作！如果有興趣的話，可以前往 Linux 核心網站 http://www.kernel.org 一看究竟，你就可以瞭解目前的核心變動情況了！

基本上，目前最新的 distributions ，包括 CentOS, FC, SuSE, Mandriva 等等，都使用 2.6 的核心， 所以，你可以直接由 http://www.kernel.org 下載最新的 2.6.xx 版本的核心來嘗試編譯啊！目前 (2009/07/27) 鳥哥可以查到的最新版本是 2.6.30 ， 底下我們將主要以這個版本來測試。另外，由於較新的核心版本可能會多出一些選項， 因此若有不同的項目也沒有關係！稍微查看一下說明內容就可以瞭解啦！

核心原始碼的取得方式

既然核心是個檔案，要製作這個檔案給系統使用則需要編譯，既然要有編譯，當然就得要有原始碼啊！ 那麼原始碼怎麼來？基本上，依據你的 distributions 去挑選的核心原始碼來源主要有：

- 原本 distribution 提供的核心原始碼檔案

事實上，各主要 distributions 在推出他們的產品時，其實已經都附上了核心原始碼了！ 以我們的 CentOS 5.x 為例，你可以在國家高速網路中心網站下載相關的核心 SRPM 的檔案！ 由於 CentOS 5.x 一直有在進行更新動作，因此你也可以在 update 的目錄底下找到核心原始碼喔！如下連結所示：

- 原始推出核心碼：http://ftp.twaren.net/Linux/CentOS/5/os/SRPMS/

- 更新碼：http://ftp.twaren.net/Linux/CentOS/5/updates/SRPMS/

你或許會說：既然要重新編譯，那麼幹嘛還要使用原本 distributions 釋出的原始碼啊？真沒創意∼ 話不是這麼說，因為原本的 distribution 釋出的原始碼當中，含有他們設定好的預設設定值， 所以，我們可以輕易的就瞭解到當初他們是如何選擇與核心及模組有關的各項設定項目的參數值， 那麼就可以利用這些可以配合我們 Linux 系統的預設參數來加以修改，如此一來， 我們就可以『修改核心，調整到自己喜歡的樣子』囉！而且編譯的難度也會比較低一點！

- 取得最新的穩定版核心原始碼

雖然使用 distribution 釋出的核心 source code 來重新編譯比較方便，但是，如此一來， 新硬體所需要的新驅動程式，也就無法藉由原本的核心原始碼來編譯啊！ 所以囉，如果是站在要更新驅動程式的立場來看，當然使用最新的核心可能會比較好啊！

Linux 的核心目前是由其發明者 Linus Torvalds 所屬團隊在負責維護的，而其網站在底下的站址上，在該網站上可以找到最新的 kernel 資訊！不過，美中不足的是目前的核心越來越大了 (linux-2.6.30.3.tar.bz2 這一版，這一個檔案大約 57MB 了！)，所以如果你的 ISP 連外很慢的話，那麼使用台灣的映射站台來下載不失為一個好方法：

- 核心官網：http://www.kernel.org/

- 交大資科：ftp://linux.cis.nctu.edu.tw/kernel/linux/kernel/

- 國高中心：ftp://ftp.twaren.net/pub/Unix/Kernel/linux/kernel/

- 保留原本設定：利用 patch 升級核心原始碼

如果 (1)你曾經自行編譯過核心，那麼你的系統當中應該已經存在前幾個版本的核心原始碼， 以及上次你自行編譯的參數設定值才對； (2)如果你只是想要在原本的核心底下加入某些特殊功能， 而該功能已經針對核心原始碼推出 patch 補丁檔案時。那你該如何進行核心原始碼的更新，以便後續的編譯呢？

其實每一次核心釋出時，除了釋出完整的核心壓縮檔之外，也會釋出『該版本與前一版本的差異性 patch 檔案』， 關於 patch 的製作我們已經在第二十二章當中提及， 你可以自行前往參考。這裡僅是要提供給你的資訊是，每個核心的 patch 僅有針對前一版的核心來分析而已， 所以，萬一你想要由 2.6.27 升級到 2.6.30 的話，那麼你就得要下載 patch-2.6.28, patch-2.6.29, patch-2.6.30 等檔案，然後『依序』一個一個的去進行 patch 的動作後， 才能夠升級到 2.6.30 喔！這個重要！不要忘記了。

但是，如果你想要升級 2.6.30 的修改版本到 2.6.30.3 時，由於修改版本是針對 2.6.30 來製作的， 因此你只要下載 patch-2.6.30.3 來直接將 2.6.30 升級至 2.6.30.3 即可。但反過來說，如果你要從 2.6.30.2 升級到 2.6.30.3 呢？很抱歉的是，並沒有 2.6.30.2 到 2.6.30.3 的補丁檔案，所以你必須要將 2.6.30.2 還原至 2.6.30， 然後才能使用 patch-2.6.30.3 來升級 2.6.30 喔！注意這個差異！

同樣的，如果是某個硬體或某些非官方認定的核心添加功能網站所推出的 patch 檔案時，你也必須要瞭解該 patch 檔案所適用的核心版本，然後才能夠進行 patch ，否則容易出現重大錯誤喔！這個項目對於某些商業公司的工程師來說是很重要的。 舉例來說，鳥哥的一個高中同學在業界服務，他主要是進行類似 Eee PC 開發的計畫，然而該計畫的硬體是該公司自行推出的！ 因此，該公司必須要自行搭配核心版本來設計他們自己的驅動程式，而該驅動程式並非 GPL 授權，因此他們就得要自行將驅動程式整合進核心！如果改天他們要將這個驅動程式釋出，那麼就得要利用 patch 的方式， 將硬體驅動程式檔案釋出，我們就得要自行以 patch 來更新核心啦！

在進行完 patch 之後，你可以直接檢查一下原本的設定值，如果沒有問題， 就可以直接編譯，而不需要再重新的選擇核心的參數值，這也是一個省時間的方法啊！ 至於 patch file 的下載，同樣是在 kernel 的相同目錄下，尋找檔名是 patch 開頭的就是了。

核心原始碼的解壓縮/安裝/觀察

由於鳥哥是比較喜歡直接由核心官網取得原始核心的傢伙，所以，底下的動作是使用 2.6.30.3 這個版本的核心來安裝的！ 如果你想要使用 distributions 提供的 SRPM 來處理的話，得自行找到 SRPM 的相關安裝方法來處理囉！ 其實看一下第二十二章就知道該如何處理啦。 總之，本章的核心原始碼是由底下的連結取得的：

- ftp://linux.cis.nctu.edu.tw/kernel/linux/kernel/v2.6/linux-2.6.30.3.tar.bz2

- 核心原始碼的解壓縮與放置目錄

鳥哥這裡假設你也是下載上述的連結內的檔案，然後該檔案放置到 /root 底下。由於 2.6.x 核心原始碼一般建議放置於 /usr/src/kernels/ 目錄底下，因此你可以這樣處理：

[root@www ~]# tar -jxvf linux-2.6.30.3.tar.bz2 -C /usr/src/kernels/

此時會在 /usr/src/kernels 底下產生一個新的目錄，那就是 linux-2.6.30.3 這個目錄囉！ 我們在下個小節會談到的各項編譯與設定，都必須要在這個目錄底下進行才行喔！好了，那麼這個目錄底下的相關檔案有啥咚咚？ 底下就來談談：

- 核心原始碼下的次目錄

在上述核心目錄下含有哪些重要資料呢？基本上有底下這些東西：

- arch ：與硬體平台有關的項目，大部分指的是 CPU 的類別，例如 x86, x86_64, Xen 虛擬支援等；

- block ：與區塊裝置較相關的設定資料，區塊資料通常指的是大量儲存媒體！還包括類似 ext3 等檔案系統的支援是否允許等。

- crypto ：核心所支援的加密的技術，例如 md5 或者是 des 等等；

- Documentation ：與核心有關的一堆說明文件，若對核心有極大的興趣，要瞧瞧這裡！

- drivers ：一些硬體的驅動程式，例如顯示卡、網路卡、PCI 相關硬體等等；

- firmware ：一些舊式硬體的微指令碼 (韌體) 資料；

- fs ：核心所支援的 filesystems ，例如 vfat, reiserfs, nfs 等等；

- include ：一些可讓其他程序呼叫的標頭 (header) 定義資料；

- init ：一些核心初始化的定義功能，包括掛載與 init 程式的呼叫等；

- ipc ：定義 Linux 作業系統內各程序的溝通；

- kernel ：定義核心的程序、核心狀態、執行緒、程序的排程 (schedule)、程序的訊號 (signle) 等

- lib ：一些函式庫；

- mm ：與記憶體單元有關的各項資料，包括 swap 與虛擬記憶體等；

- net ：與網路有關的各項協定資料，還有防火牆模組 (net/ipv4/netfilter/*) 等等；

- security ：包括 selinux 等在內的安全性設定；

- sound ：與音效有關的各項模組；

- virt ：與虛擬化機器有關的資訊，目前核心支援的是 KVM (Kernel base Virtual Machine)

這些資料先大致有個印象即可，至少未來如果你想要使用 patch 的方法加入額外的新功能時， 你要將你的原始碼放置於何處？這裡就能夠提供一些指引了。當然，最好還是跑到 Documentation 那個目錄底下去瞧瞧正確的說明， 對你的核心編譯會更有幫助喔！

核心編譯的前處理與核心功能選擇

什麼？核心編譯還要進行前處理？沒錯啦！事實上，核心的目的在管理硬體與提供系統核心功能，因此你必須要先找到你的系統硬體， 並且規劃你的主機未來的任務，這樣才能夠編譯出適合你這部主機的核心！所以，整個核心編譯的重要工作就是在『挑選你想要的功能』。 底下鳥哥就以自己的一部主機軟/硬體環境來說明，解釋一下如何處理核心編譯囉！

硬體環境檢視與核心功能要求

鳥哥的一部主機硬體環境如下 (透過 /proc/cpuinfo 及 lspci 觀察)：

- CPU：AMD 的 Athlon64 3000+ (舊式，不含虛擬化功能)

- 主機板晶片組： ALi M1689 K8 北橋 及 M5249, M1563 南橋晶片 (較冷門的硬體)

- 顯示卡： AGP 8X 的 NVidia GeForce 6600LE

- 記憶體： 2.0GB 記憶體

- 硬碟： WD 2.5GB 硬碟，使用 ALi, ULi 5289 SATA 介面

- 電源控制器： ALi M7101 Power Management Controller (PMU)

- 網路卡： 3Com 3c905C-TX/TX-M (對外)

- 網路卡： Realtek Semiconductor RTL-8139/8139C/8139C+

硬體大致如上，至於這部主機的需求，是希望做為未來在鳥哥上課時，可以透過虛擬化功能來處理學生的練習用虛擬機器。 這部主機也是鳥哥用來放置學校上課教材的機器，因此，這部主機的 I/O 需求須要好一點，未來還需要開啟防火牆、 WWW 伺服器功能、FTP 伺服器功能等，基本上，用途就是一部小型的伺服器環境囉。大致上需要這樣的功能啦！

保持乾淨原始碼： make mrproper

瞭解了硬體相關的資料後，我們還得要處理一下核心原始碼底下的殘留檔案才行！假設我們是第一次編譯， 但是我們不清楚到底下載下來的原始碼當中有沒有保留目標檔案 (*.o) 以及相關的設定檔存在， 此時我們可以透過底下的方式來處理掉這些編譯過程的目標檔案以及設定檔：

[root@www linux-2.6.30.3]# make mrproper

請注意，這個動作會將你以前進行過的核心功能選擇檔案也刪除掉， 所以幾乎只有第一次執行核心編譯前才進行這個動作，其餘的時刻，你想要刪除前一次編譯過程的殘留資料， 只要下達：

[root@www linux-2.6.30.3]# make clean

因為 make clean 僅會刪除類似目標檔之類的編譯過程產生的中間檔案，而不會刪除設定檔！ 很重要的！千萬不要搞亂了喔！好了，既然我們是第一次進行編譯，因此，請下達『make mrproper』吧！

開始挑選核心功能： make XXconfig

不知道你有沒有發現 /boot/ 底下存在一個名為 config-xxx 的檔案？那個檔案其實就是核心功能列表檔！ 我們底下要進行的動作，其實就是作出該檔案！而我們後續小節所要進行的編譯動作，其實也就是透過這個檔案來處理的！ 核心功能的挑選，最後會在 /usr/src/kernels/linux-2.6.30.3/ 底下產生一個名為 .config 的隱藏檔， 這個檔案就是 /boot/config-xxx 的檔案啦！那麼這個檔案如何建立呢？你可以透過非常多的方法來建立這個檔案！ 常見的方法有：(註1)

- make menuconfig

最常使用的，是文字模式底下可以顯示類似圖形介面的方式，不需要啟動 X Window 就能夠挑選核心功能選單！

- make oldconfig

透過使用已存在的 ./.config 檔案內容，使用該檔案內的設定值為預設值，只將新版本核心內的新功能選項列出讓使用者選擇， 可以簡化核心功能的挑選過程！對於作為升級核心原始碼後的功能挑選來說，是非常好用的一個項目！

- make xconfig

透過以 Qt 為圖形介面基礎功能的圖形化介面顯示，需要具有 X window 的支援。例如 KDE 就是透過 Qt 來設計的 X Window，因此你如果在 KDE 畫面中，可以使用此一項目。

- make gconfig

透過以 Gtk 為圖形介面基礎功能的圖形化介面顯示，需要具有 X window 的支援。例如 GNOME 就是透過 Gtk 來設計的 X Window，因此你如果在 GNOME 畫面中，可以使用此一項目。

- make config

最舊式的功能挑選方法，每個項目都以條列式一條一條的列出讓你選擇，如果設定錯誤只能夠再次選擇，很不人性化啊！

大致的功能選擇有上述的方法，不過鳥哥個人比較偏好 make menuconfig 這個項目啦！如果你喜歡使用圖形介面， 然後使用滑鼠去挑選所需要的功能時，也能使用 make xconfig 或 make gconfig ，不過需要有相關的圖形介面支援！ 如果你是升級核心原始碼並且需要重新編譯，那麼使用 make oldconfig 會比較適當！好了，那麼如何選擇呢？ 以 make menuconfig 來說，出現的畫面會有點像這樣：

圖 2.3.1 、 make menuconfig 核心功能挑選選單示意圖

看到上面的圖示之後，你會發現畫面主要分為兩大部分，一個是大框框內的反白光柱，另一個則是底下的小框框， 裡面有 select, exit 與 help 三個選項的內容。這幾個元件的大致用法如下：

- 『左右方向鍵』：可以移動最底下的 <Select>, <Exit>, <Help>項目；

- 『上下方向鍵』：可以移動上面大框框部分的反白光柱，若該行有箭頭 (--->) 則表示該行內部還有其他細項需要來設定的意思；

- 選定項目：以『上下鍵』選擇好想要設定的項目之後，並以『左右鍵』選擇 <Select> 之後， 按下『 Enter 』就可以進入該項目去作更進一步的細部設定囉；

- 可挑選之功能：在細部項目的設定當中，如果前面有 [ ] 或 < > 符號時，該項目才可以選擇， 而選擇可以使用『空白鍵』來選擇；

- 若為 [*] <*> 則表示編譯進核心；若為 <M> 則表示編譯成模組！ 盡量在不知道該項目為何時，且有模組可以選，那麼就可以直接選擇為模組囉！

- 當在細項目選擇 <Exit> 後，並按下 Enter ，那麼就可以離開該細部項目囉！

基本上建議只要『上下左右的方向鍵、空白鍵、Enter』這六個按鍵就好了！不要使用 Esc ，否則一不小心就有可能按錯的！另外，關於整個核心功能的選擇上面，建議你可以這樣思考：

- 『肯定』核心一定要的功能，直接編譯進核心內；

- 『可能在未來會用到』的功能，那麼盡量編譯成為模組；

- 『不知道那個東西要幹嘛的，看 help 也看不懂』的話，那麼就保留預設值，或者將他編譯成為模組；

總之，盡量保持核心小而美，剩下的功能就編譯成為模組，尤其是『需要考慮到未來擴充性』， 像鳥哥之前認為螃蟹卡就夠我用的了，結果，後來竟然網站流量大增，鳥哥只好改換 3Com 的網路卡。 不過，我的核心卻沒有相關的模組可以使用∼因為.....鳥哥自己編譯的核心忘記加入這個模組了。 最後，只好重新編譯一次核心的模組，呵呵！真是慘痛的教訓啊！

核心功能細項選擇

由上面的圖示當中，我們知道核心的可以選擇的項目有很多啊！光是第一面，就有 16 個項目，每個項目內還有不同的細項！哇！真是很麻煩啊∼每個項目其實都可能有 <Help> 的說明，所以，如果看到不懂的項目，務必要使用 Help 查閱查閱！ 好了，底下我們就一個一個項目來看看如何選擇吧！

- General setup

與 Linux 最相關的程序互動、核心版本說明、是否使用發展中程式碼等資訊都在這裡設定的。 這裡的項目主要都是針對核心與程式之間的相關性來設計的，基本上，保留預設值即可！ 不要隨便取消底下的任何一個項目，因為可能會造成某些程式無法被同時執行的困境喔！ 不過底下有非常多新的功能，如果你有不清楚的地方，可以按 <Help> 進入查閱，裡面會有一些建議！ 你可以依據 Help 的建議來選擇新功能的啟動與否！

[ ] Prompt for development and/or incomplete code/drivers

# 這個建議不要選擇，因為我們不是核心專家，不需要使用發展中或不完整的程式碼！

(vbird)  Local version - append to kernel release

[*] Automatically append version information to the version string

# 我希望我的核心版本成為 2.6.30.3.vbird ，那這裡可以就這樣設定！

Kernel compression mode (Bzip2)  --->

# 建議選擇成為 Bzip2 即可，因為壓縮比較佳！

[*] Support for paging of anonymous memory (swap)

# 任何人均可存取 swap 是合理的！所以這裡務必要勾選！

[*] System V IPC

# IPC 是 Inter Process Communication (程序通訊) 縮寫，與程序溝通有關，要選！

[*] BSD Process Accounting

[ ]   BSD Process Accounting version 3 file format

# 與標準 Unix (BSD) 的程序支援有關，但不要支援 version 3 ，可能有相容性問題

[ ] Export task/process statistics through netlink (EXPERIMENTAL)

# 這個額外的進階選項可以將他取消的！

[*] Auditing support

[*]   Enable system-call auditing support

# 上面這兩個是額外核心功能 (如 SELinux) 載入時所需要的設定！務必選擇

RCU Subsystem  --->

RCU Implementation (Classic RCU)  --->

# 選擇標準 RCU 即可，不需要使用大量 CPU 的整合功能。

<M> Kernel .config support

[ ]   Enable access to .config through /proc/config.gz (NEW)

# 讓 .config 這個核心功能列表可以寫入實際的核心檔案中！

(17) Kernel log buffer size (16 => 64KB, 17 => 128KB)

[ ] Control Group support (NEW)  --->

# 整合 CPU 或分離裝置的功能，屬於進階設定，我們先不要使用這功能。

[*] Create deprecated sysfs layout for older userspace tools (NEW)

# 如果使用支援舊式裝置，如 /sys/devices 者，這裡要勾選！但如果是 2008

# 年後的 distribution ，這裡可能需要取消喔！ CentOS 5.x 要選的！

-*- Kernel->user space relay support (formerly relayfs)

-*- Namespaces support

[*]   UTS namespace (NEW)

[*]   IPC namespace (NEW)

# 使用 uname 時，會輸出較多的資訊，所以可以嘗試選擇看看。

[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

()    Initramfs source file(s)

# 這是一定要的！因為要支援開機時載入 initail RAM disk 嘛！

[*] Optimize for size

# 可以減低核心的檔案大小，其實是 gcc 參數使用 -Os 而不是 -O2

[ ] Configure standard kernel features (for small systems)  --->

# 給嵌入式系統使用的，我們用 PC ，所以這裡不選。

[ ] Strip assembler-generated symbols during link (NEW)

[ ] Disable heap randomization (NEW)

# 2000 年後推出的版本，可以取消這個項目！

Choose SLAB allocator (SLAB)  --->

[*] Profiling support (EXPERIMENTAL)

[ ] Activate markers (NEW)

<M> OProfile system profiling (EXPERIMENTAL)

[ ]   OProfile AMD IBS support (EXPERIMENTAL) (NEW)

[*] Kprobes

- loadable module + block layer

要讓你的核心能夠支援動態的核心模組，那麼底下的第一個設定就得要啟動才行！至於第二個 block layer 則預設是啟動的， 你也可以進入該項目的細項設定，選擇其中你認為需要的功能即可！

[*] Enable loadable module support  ---> <==底下為細項

--- Enable loadable module support

[ ]   Forced module loading     <==大概就是這個不要選，其他的都選起來！

[*]   Module unloading

[*]   Module versioning support

[*]   Source checksum for all module

================================================================================

-*- Enable the block layer  --->  <==看吧！預設就是已經選擇了！底下為細項

[ ]   Block layer data integrity support  <==特殊儲存裝置支援，可以不選

IO Schedulers  --->

<*> Anticipatory I/O scheduler  <==較複雜的一種I/O排程

<*> Deadline I/O scheduler      <==較適用於 database 的載入

<*> CFQ I/O scheduler           <==較適用於 desktop 的環境

Default I/O scheduler (Deadline)  ---> <==適用於鳥哥環境

- CPU 的類型與功能選擇

進入『Processor type and features』後，請挑選你主機的實際 CPU 形式。鳥哥這裡使用的是 Athlon 64 的 CPU， 而且鳥哥的主機還有啟動 Xen 這個虛擬化的服務 (在一部主機上面同時啟動多個作業系統)，因此，所以底下的選擇是這樣的：

[*] Tickless System (Dynamic Ticks)    <==可增加些許省電功能

[ ] High Resolution Timer Support

[*] Symmetric multi-processing support <==多核心 CPU 環境必選

[ ] Support sparse irq numbering

[*] Enable MPS table                   <==讓多 CPU 支援 ACPI

[ ] Support for extended (non-PC) x86 platforms

[*] Single-depth WCHAN output

[*] Paravirtualized guest support  --->  <==支援半虛擬化功能

--- Paravirtualized guest support <==底下為 Xen 與 KVM 兩種虛擬機器支援！

[*]   Xen guest support

(32)    Maximum allowed size of a domain in gigabytes

[*]     Enable Xen debug and tuning parameters in debugfs

[*]   KVM paravirtualized clock

[*]   KVM Guest support

-*-   Enable paravirtualization code

================================================================================

[ ] paravirt-ops debugging (NEW)  <==不需要具有 debug 的功能

[ ] Memtest

Processor family (Opteron/Athlon64/Hammer/K8)  ---> <==要選對啊！

[*] AMD IOMMU support <==啟動 AMD 的 IOMMU 功能！

(8) Maximum number of CPUs

[ ] SMT (Hyperthreading) scheduler support <==Intel CPU 的超執行緒功能

[*] Multi-core scheduler support <==多核心功能的支援

Preemption Model (No Forced Preemption (Server))  --->

# 這是與程序有關的設定項目，鳥哥這裡建立 Server 主機，因此選這項！

# 如果是桌上型電腦的使用，建議進入選擇 desktop 項目。

[ ] Reroute for broken boot IRQs

[*] Machine Check Exception <==可將核心偵測之錯誤回報到終端機顯示！

[*]   Intel MCE features (NEW)

[*]   AMD MCE features (NEW)

< > Dell laptop support

<M> /dev/cpu/microcode - microcode support

[ ]   Intel microcode patch loading support

[*]   AMD microcode patch loading support

<M> /dev/cpu/*/msr - Model-specific register support

<*> /dev/cpu/*/cpuid - CPU information support

< > /sys/kernel/debug/x86/cpu/* - CPU Debug support

[ ] Numa Memory Allocation and Scheduler Support

Memory model (Sparse Memory)  --->

[*] Sparse Memory virtual memmap <==可強化些許核心效能

[ ] Allow for memory hot-add

[*] Add LRU list to track non-evictable pages

(65536) Low address space to protect from user allocation

[ ] Check for low memory corruption

[*] Reserve low 64K of RAM on AMI/Phoenix BIOSen <==重新偵測 BIOS 資訊

[*] MTRR (Memory Type Range Register) support

# 可以讓 CPU 具有讀取記憶體特殊區塊的能力，尤其在高效能的顯示卡方面，

# 可以增進不少效能。這個項目會產生 /proc/mtrr ，X 會讀取這個咚咚喔。

[*]   MTRR cleanup support

(0)     MTRR cleanup enable value (0-1)

(1)     MTRR cleanup spare reg num (0-7)

[ ]   x86 PAT support

[ ] EFI runtime service support

[*] Enable seccomp to safely compute untrusted bytecode

Timer frequency (300 HZ)  --->

# 這個項目則與核心針對某個事件立即回應的速度有關。Server 用途可以調整到

# 300Hz 即可，如果是桌上型電腦使用，需要調整高一點，例如 1000Hz 較佳！

[*] kexec system call

[ ] kernel crash dumps

-*- Support for hot-pluggable CPUs

[ ] Compat VDSO support  <==舊式功能，可以不要選擇

[ ] Built-in kernel command line <==正常開機選單 (grub) 環境，不需要此項功能

- 電源管理功能

如果選擇了『Power management and ACPI options』之後，就會進入系統的電源管理機制中。 其實電源管理機制還需要搭配主機板以及 CPU 的相關省電功能，才能夠實際達到省電的效率啦！ 不論是 Server 還是 Desktop 的使用，在目前電力不足的情況下，能省電就加以省電吧！

[*] Power Management support

[ ]   Power Management Debug Support

[*] Suspend to RAM and standby

[ ] Hibernation (aka 'suspend to disk')

[*] ACPI (Advanced Configuration and Power Interface) Support  --->

# 這是個較新的電源管理模組，由於選擇後會增加核心約 70K ，所以

# 對嵌入式系統來說，可能需要考慮考慮。至於 desktop/server 當然就選擇啊

--- ACPI (Advanced Configuration and Power Interface) Support

[ ]   Deprecated /proc/acpi files

[*]   Deprecated power /proc/acpi directories

[*]   Future power /sys interface

[*]   Deprecated /proc/acpi/event support

<M>   AC Adapter

<M>   Battery

<M>   Button

-M-   Video

<*>   Fan

<*>   Processor

<*>     Thermal Zone

[ ]   Debug Statements

<M>   PCI slot detection driver

<M>   Smart Battery System

================================================================================

CPU Frequency scaling  --->

# 可以經過核心修改 CPU 的運作頻率，在說明檔當中也提及，還需要啟動底下的

# dynamic cpufreq governor 才可以順利的啟動這個項目。

[*] CPU Frequency scaling

[*]   Enable CPUfreq debugging

<M>   CPU frequency translation statistics

[*]     CPU frequency translation statistics details

Default CPUFreq governor (userspace)  --->

-*-   'performance' governor

<M>   'powersave' governor

<M>   'userspace' governor for userspace frequency scaling

<M>   'ondemand' cpufreq policy governor

-*-   'conservative' cpufreq governor

*** CPUFreq processor drivers ***

<M>   ACPI Processor P-States driver

<*>   AMD Opteron/Athlon64 PowerNow!  <==因為我們是 AMD 的 CPU 啊！

<M>   Intel Enhanced SpeedStep (deprecated)

< >   Intel Pentium 4 clock modulation

================================================================================

-*- CPU idle PM support

Memory power savings  --->

- 一些匯流排 (bus) 的選項

這個項目則與匯流排有關啦！分為最常見的 PCI 與 PCI-express 的支援，還有筆記型電腦常見的 PCMCIA 插卡啊！要記住的是，那個 PCI-E 的介面務必要選取！不然你的新顯示卡可能會捉不到！

[*] PCI support

[*]   Support mmconfig PCI config space access

[*] PCI Express support

<M>   PCI Express Hotplug driver

[*]   Root Port Advanced Error Reporting support

-*- Message Signaled Interrupts (MSI and MSI-X)

[*] Enable deprecated pci_find_* API

[ ] PCI Debugging

<M> PCI Stub driver

[*] Interrupts on hypertransport devices

[*] PCI IOV support  <==與虛擬化有關！請加選此項！

< > PCCard (PCMCIA/CardBus) support  ---> <==鳥哥的主機不是 notebook，所以不選。

<*> Support for PCI Hotplug  --->  <==不關機情況下，熱拔插 PCI 裝置

--- Support for PCI Hotplug

<M>   Fake PCI Hotplug driver

<M>   ACPI PCI Hotplug driver

<M>     ACPI PCI Hotplug driver IBM extensions

[ ]   CompactPCI Hotplug driver

<M>   SHPC PCI Hotplug driver

- 編譯後執行檔的格式

選擇『Executable file formats / Emulations』會見到如下選項。 底下的選項必須要勾選才行喔！因為是給 Linux 核心運作執行檔之用的資料。通常是與編譯行為有關啦！

[*] Kernel support for ELF binaries

[ ] Write ELF core dumps with partial segments

<*> Kernel support for MISC binaries

[*] IA32 Emulation  <==因為我們這裡是 64 位元，因此 32 位元為模擬結果

<M>   IA32 a.out support

- 核心的網路功能

這個『Networking support』項目是相當重要的選項，因為他還包含了防火牆相關的項目！就是未來在伺服器篇會談到的防火牆 iptables 這個資料啊！所以，千萬注意了！在這個設定項目當中，很多東西其實我們在基礎篇還沒有講到， 因為大部分的參數都與網路、防火牆有關！由於防火牆是在啟動網路之後再設定即可，所以絕大部分的內容都可以被編譯成為模組，而且也建議你編成模組！有用到再載入到核心即可啊！

--- Networking support

Networking options  --->

# 就是這個光啊！裡面的資料全部都是重要的防火牆項目！盡量編成模組囉！

# 至於不曉得功能的部分，就盡量保留預設值即可！

<*> Packet socket          <==網路封包，當然要選擇啊！

[*]   Packet socket: mmapped IO

<*> Unix domain sockets    <==Unix 插槽檔，也一定要選擇啊！

<*> Transformation user configuration interface

<M> PF_KEY sockets

[*] TCP/IP networking      <==能不選擇 TCP/IP 嗎？

[*]   IP: multicasting

[*]   IP: advanced router

Choose IP: FIB lookup algorithm (FIB_HASH)  --->

[*]   IP: policy routing

[*]   IP: equal cost multipath

[*]   IP: verbose route monitoring

[ ]   IP: kernel level autoconfiguration

<M>   IP: tunneling

<M>   IP: GRE tunnels over IP

[*]     IP: broadcast GRE over IP

[*]   IP: multicast routing

[*]     IP: PIM-SM version 1 support

[*]     IP: PIM-SM version 2 support

[*]   IP: TCP syncookie support (disabled per default)

<M>   IP: AH transformation

<M>   IP: ESP transformation

<M>   IP: IPComp transformation

<M>   IP: IPsec transport mode

<M>   IP: IPsec tunnel mode

<*>   IP: IPsec BEET mode

-*-   Large Receive Offload (ipv4/tcp)

<M>   INET: socket monitoring interface

[*]   TCP: advanced congestion control  ---> <==內部細項全為模組

<M>   The IPv6 protocol  ---> <==除必選外，內部細項全為模組

[*]   NetLabel subsystem support

-*- Security Marking

[*] Network packet filtering framework (Netfilter)  --->

# 這個就是我們一直講的防火牆部分！裡面細項幾乎全選擇成為模組！

--- Network packet filtering framework (Netfilter)

[ ]   Network packet filtering debugging  <==debug 部分不選！

[*]   Advanced netfilter configuration

[*]     Bridged IP/ARP packets filtering

Core Netfilter Configuration  --->

<M>   IP virtual server support  --->

IP: Netfilter Configuration  --->

IPv6: Netfilter Configuration  --->

<M>   Ethernet Bridge tables (ebtables) support  --->

# 上面的細項，除了必選外其他的都編成模組喔！原始沒選的也請選為模組

==============================================================

<M> Asynchronous Transfer Mode (ATM)

<M>   Classical IP over ATM

[ ]     Do NOT send ICMP if no neighbour

<M>   LAN Emulation (LANE) support

< >     Multi-Protocol Over ATM (MPOA) support

<M>   RFC1483/2684 Bridged protocols

[ ]     Per-VC IP filter kludge

<M> 802.1d Ethernet Bridging

<M> 802.1Q VLAN Support

[ ]   GVRP (GARP VLAN Registration Protocol) support

<M> DECnet Support

<M> ANSI/IEEE 802.2 LLC type 2 Support

[ ]   IPX: Full internal IPX network (NEW)

<M> Appletalk protocol support

< >   Appletalk interfaces support

<M> Phonet protocols family

[*] QoS and/or fair queueing  ---> <==內容同樣全為模組！

[ ] Data Center Bridging support

Network testing  ---> <==保留成模組預設值

====================================================================

# 底下的則是一些特殊的網路設備，例如紅外線啊、藍芽啊！

# 如果不清楚的話，就使用模組吧！除非你真的知道不要該項目！

[ ]   Amateur Radio support  --->

< >   CAN bus subsystem support  --->

< >   IrDA (infrared) subsystem support  --->

<M>   Bluetooth subsystem support  --->

# 這個是藍芽支援，同樣的，裡面除了必選之外，其他通通挑選成為模組！

[*]   Wireless  --->

# 這個則是無線網路設備，裡面保留預設值，但可編成模組的就選模組

<M>   WiMAX Wireless Broadband support  --->

# 新一代的無線網路，也請勾選成為模組！

{M}   RF switch subsystem support  --->

- 各項裝置的驅動程式

進入『Device Drivers』這個是所有硬體裝置的驅動程式庫！哇！光是看到裡面這麼多內容，鳥哥頭都昏了∼ 不過，為了你自己的主機好，建議你還是得要一個項目一個項目的去挑選挑選才行∼ 這裡面的資料就與你主機的硬體有絕對的關係了！

在這裡面真的很重要，因為很多資料都與你的硬體有關。核心推出時的預設值是比較符合一般狀態的， 所以很多資料其實保留預設值就可以編的很不錯了！不過，也因為較符合一般狀態， 所以核心額外的編譯進來很多跟你的主機系統不符合的資料，例如網路卡裝置∼ 你可以針對你的主機板與相關硬體來進行編譯。不過，還是要記得有『未來擴充性』的考量！ 之前鳥哥不是談過嗎，我的網路卡由螃蟹卡換成 3Com 時，核心捉不到∼ 因為...鳥哥並沒有將 3Com 的網路卡編譯成為模組啊！ @_@

Generic Driver Options  --->    <==與韌體有關，保留預設值即可

<*> Connector - unified userspace <-> kernelspace linker  --->

# 與使用者/核心層級的資訊溝通有關，務必要選擇啊！

<M> Memory Technology Device (MTD) support  --->

# 例如快閃記憶體(拇指碟之類)之支援，通常與嵌入式系統有關！

# 但由於我們也會用到隨身碟，所以裡面的資料全編為模組！

<M> Parallel port support  --->

# 平行序列埠的支援，例如早期的 25 針印表機與 9 針滑鼠等，細項全編為模組！

-*- Plug and Play support  --->     <==不囉唆！當然要選擇這個項目！

[*] Block devices  --->   <==區塊裝置，就是一些儲存媒體！細項內容請全編為模組

[*] Misc devices  --->    <==一些較冷門的設備，建議還是全部編為模組！

<*> ATA/ATAPI/MFM/RLL support  ---> <==IDE 介面相關的晶片組！

# 這個其實與主機板的南橋晶片有關！由於鳥哥的主機為 ALi 的板子，所以：

<*>   ALI M15x3 chipset support

# 除了可以保留預設值之外，你也可以將沒用到的驅動程式取消選擇。較重要的還有：

[ ]   Support for SATA (deprecated; conflicts with libata SATA driver)

# 這個一定不能選！因為 SATA 的模組是在 SCSI 中！

<*>   Include IDE/ATAPI CDROM support

# IDE 的 CDROM 最好直接編譯進核心！

# 其餘的驅動程式鳥哥幾乎都選擇成為模組了！沒用到的晶片也將 * 也改成 M 哩！

======================================================================

SCSI device support  --->

# 這部份是 SCSI 儲存媒體的驅動程式！請一定要選擇！因為：

# 1. 因為 USB 裝置用的就是模擬 SCSI 啊！

# 2. 因為 SATA 的設定項目就在這裡面！

<M> RAID Transport Class

{M} SCSI device support

[*] legacy /proc/scsi/ support

*** SCSI support type (disk, tape, CD-ROM) ***

<M> SCSI disk support   <==幾乎全編為模組即可！

<M> SCSI tape support

<M> SCSI OnStream SC-x0 tape support

<M> SCSI CDROM support

[*]   Enable vendor-specific extensions (for SCSI CDROM)

<M> SCSI generic support

<M> SCSI media changer support

<M> SCSI Enclosure Support

*** Some SCSI devices (e.g. CD jukebox) support multiple LUNs ***

[*] Probe all LUNs on each SCSI device

[*] Verbose SCSI error reporting (kernel size +=12K)

[*] SCSI logging facility

[*] Asynchronous SCSI scanning

SCSI Transports  --->         <==細項保留預設值

[*] SCSI low-level drivers  --->  <==主要是磁碟陣列卡，細項可全選為模組

<M> SCSI Device Handlers  --->    <==細項全選為模組

< > OSD-Initiator library

======================================================================

<M> Serial ATA (prod) and Parallel ATA (experimental) drivers  --->

# SATA 之類的磁碟驅動程式！這裡的模組與 SCSI 模組是有相依屬性的關係！

# 底下的細項全部選擇模組，尤其是 ALi 的這個項目，對鳥哥來說，是一定要勾選的

<M>     ALi PATA support

[*] Multiple devices driver support (RAID and LVM)  --->

# RAID 與 LVM 怎可不選！我們第十五章才講過這東西！細項均保留預設值即可

[ ] Fusion MPT device support  --->

# 一種高階的 SCSI 控制器，可選可不選！因為鳥哥這裡不會用到，所以不選！

IEEE 1394 (FireWire) support  --->

# 這個就是俗稱的『火線』，許多外接式設備可能會用這個介面，因此，

# 在此部分內的細項部分，請務必設定為模組喔！不要忘了！

<M> I2O device support  --->       <==細項亦全選為模組！

[ ] Macintosh device drivers  ---> <==我們是 PC ，所以不需支援麥金塔周邊

[*] Network device support  --->   <==網路設備的支援是必選！

--- Network device support

[*]   Enable older network device API compatibility

<M>   Intermediate Functional Block support

<M>   Dummy net driver support

<M>   Bonding driver support

<M>   EQL (serial line load balancing) support

<M>   Universal TUN/TAP device driver support

<M>   Virtual ethernet pair device

<M>   General Instruments Surfboard 1000

< >   ARCnet support  ---> <==較早期的網卡規格，可不選擇！

{M}   PHY Device support and infrastructure  ---> <==細項全為模組

[*]   Ethernet (10 or 100Mbit)  --->

[*]   Ethernet (1000 Mbit)  --->

[*]   Ethernet (10000 Mbit)  --->

# 上面三個乙太網路網卡支援，不論是否用的到，細項請全編為模組來待命吧！

< >   Token Ring driver support  ---> <==IBM 的 LAN ，可不選！

Wireless LAN  --->

WiMAX Wireless Broadband devices  --->

USB Network Adapters  --->

# 上面三個為現階段很熱門的無線網路設備，所以全部內容的細項全選擇

# 為模組！免得未來你的主機加上新的無線設備時會找不到驅動程式！

[ ]   Wan interfaces support  ---> <==WAN 的廣域網路設備應該就不用選擇了！

[ ]   ATM drivers  ---> <==高階的 ATM 設備也不用選吧！

<*>   Xen network device frontend driver

<*>   FDDI driver support

<M>     Digital DEFTA/DEFEA/DEFPA adapter support

[ ]       Use MMIO instead of PIO (NEW)

<M>     SysKonnect FDDI PCI support

<M>   PLIP (parallel port) support

<M>   PPP (point-to-point protocol) support

[*]     PPP filtering

<M>     PPP support for async serial ports

<M>     PPP support for sync tty ports

<M>     PPP Deflate compression

<M>     PPP BSD-Compress compression

<M>     PPP over ATM

# 如果你有 ADSL 撥接的話，呵呵！PPP 的裝置也要選擇上喔！

<M>   SLIP (serial line) support

[*]     CSLIP compressed headers

[*]   Keepalive and linefill

[ ]   Six bit SLIP encapsulation

[*]   Fibre Channel driver support

======================================================================

[ ] ISDN support  --->

< > Telephony support  --->

# 這兩個設備沒用到，所以也可以不要選擇！

Input device support  --->

# 這裡面含有滑鼠、鍵盤、搖桿、觸控版等輸入裝置，盡量全選為模組吧！

Character devices  --->

# 周邊元件設備部分，也全選為模組吧！

{M} I2C support  --->

# 還記得我們去偵測主機板的溫度與壓力吧？呵呵！那就是透過核心的這個 I2C

# 的模組功能！ALi 預設沒有被編入核心，所以請進入選擇成模組！

[ ] SPI support  --->

[ ] GPIO Support  --->

< > Dallas's 1-wire support  --->

-*- Power supply class support  --->

# 絕大部分都沒有用到的咚咚，所以保留預設值，不選擇！

<M> Hardware Monitoring support  --->

# 硬體偵測器的支援，記得也要挑選，然後內容全為模組！

-*- Generic Thermal sysfs driver  --->

[*] Watchdog Timer Support  ---> <==需搭配 watchdog 服務

# 若搭配 watchdog 服務，可以設定在某些特定狀況下重新啟動主機！

Sonics Silicon Backplane  --->

Multifunction device drivers  --->

# 鳥哥沒有這樣的設備，所以也沒有選擇！

[ ] Voltage and Current Regulator Support  --->

Multimedia devices  --->

# 一堆多媒體裝置如影像擷取卡、FM 廣播音效卡。但如果你的 Linux 是桌上型電腦，

# 裡面需要挑選成模組較佳！因為一大堆多媒體介面卡！

Graphics support  --->  <==這就重要了！顯示卡選擇！

# 嘿嘿！重點之一，顯示卡的晶片組∼剛剛前面提到的都是主機板的對顯示卡的

# 匯流排支援 (PCI-E 與 AGP) ，這裡則是針對顯示卡晶片！鳥哥的顯示卡是 NVidia

# 的，所以將他選擇即可！其他的可以編成模組！

<M> Sound card support  --->

# 音效卡部分，也全部選擇成為模組啦！反正編成模組又不用錢∼

[*] HID Devices  ---> <==人機介面裝置，保留預設值即可(也可不選)

[*] USB support  --->

# 不能不選的 USB ，內容也全部是模組即可！尤其底下這三個：

<M>     EHCI HCD (USB 2.0) support

<M>     OHCI HCD support

<M>     UHCI HCD (most Intel and VIA) support

<M> MMC/SD/SDIO card support  --->  <==多媒體介面卡，保留預設值

< > Sony MemoryStick card support (EXPERIMENTAL)  --->

-*- LED Support  --->

[ ] Accessibility support  --->

<M> InfiniBand support  ---> <==高階網路設備

[*] EDAC - error detection and reporting  --->

<M> Real Time Clock  ---> <==內容選為模組吧！

[ ] DMA Engine support  --->

[ ] Auxiliary Display support  --->

< > Userspace I/O drivers  --->

[*] Xen memory balloon driver

[*]   Scrub pages before returning them to system

<*> Xen filesystem

[*]   Create compatibility mount point /proc/xen

[ ] Staging drivers  --->

[ ] X86 Platform Specific Device Drivers  --->

# 一堆筆記型電腦的驅動，可以不選啦！

底下則與 Firmware Drivers 有關喔！基本上，都保留預設值就好了！

<M> BIOS Enhanced Disk Drive calls determine boot disk

[ ]   Sets default behavior for EDD detection to off (NEW)

<M> BIOS update support for DELL systems via sysfs

<M> Dell Systems Management Base Driver

[*] Export DMI identification via sysfs to userspace

[*] iSCSI Boot Firmware Table Attributes

<M>   iSCSI Boot Firmware Table Attributes module

- 檔案系統的支援

檔案系統的支援也是很重要的一項核心功能！因為如果不支援某個檔案系統，那麼我們的 Linux kernel 就無法認識，當然也就無法使用啦！例如 Quota, NTFS 等等特殊的 filesystem 。 這部份也是有夠麻煩∼因為涉及核心是否能夠支援某些檔案系統，以及某些作業系統支援的 partition table 項目。在進行選擇時，也務必要特別的小心在意喔！ 尤其是我們常常用到的網路作業系統 (NFS/Samba 等等)，以及基礎篇談到的 Quota 等， 你都得要勾選啊！否則是無法被支援的。比較有趣的是 NTFS 在這一版的核心裡面竟然有支援可寫入的項目， 著實讓鳥哥嚇了一跳了！^_^

<*> Second extended fs support

[*]   Ext2 extended attributes

[*]     Ext2 POSIX Access Control Lists

[*]     Ext2 Security Labels

[*]   Ext2 execute in place support

<*> Ext3 journalling file system support <==建議這裡直接編進核心

[ ]   Default to 'data=ordered' in ext3 (legacy option)

[*]   Ext3 extended attributes

[*]     Ext3 POSIX Access Control Lists

[*]     Ext3 Security Labels

<M> The Extended 4 (ext4) filesystem

[*]   Enable ext4dev compatibility

[*]   Ext4 extended attributes (NEW)

[*]     Ext4 POSIX Access Control Lists

[*]     Ext4 Security Labels

# 上面是傳統的 EXT2/EXT3 及進階的 EXT4 支援！除了 EXT4 外，其他編入核心吧！

=====================================================================

[ ] JBD (ext3) debugging support

[ ] JBD2 (ext4) debugging support (NEW)

<M> Reiserfs support

[ ]   Enable reiserfs debug mode (NEW)

[ ]   Stats in /proc/fs/reiserfs (NEW)

[ ]   ReiserFS extended attributes (NEW)

< > JFS filesystem support

<M> XFS filesystem support

[*]   XFS Quota support

[*]   XFS POSIX ACL support

[*]   XFS Realtime subvolume support

< > OCFS2 file system support

[*] Dnotify support

[*] Inotify file change notification support

[*]   Inotify support for userspace

[*] Quota support

[ ]   Report quota messages through netlink interface

[*]   Print quota warnings to console (OBSOLETE)

< > Old quota format support

<*> Quota format v2 support

<M> Kernel automounter support

<M> Kernel automounter version 4 support (also supports v3)

< > FUSE (Filesystem in Userspace) support

# XFS 以及 Reiserfs 與 Quota 建議也是選擇起來放啦！

====================================================================

Caches  --->

CD-ROM/DVD Filesystems  --->  <==CD內的檔案格式，預設值即可

DOS/FAT/NT Filesystems  --->  <==有支援 NTFS ，要進入挑挑！

<M> MSDOS fs support

<M> VFAT (Windows-95) fs support

(950) Default codepage for FAT    <==支援繁體中文

(utf8) Default iocharset for FAT  <==支援萬國碼

<M> NTFS file system support

[ ]   NTFS debugging support (NEW)

[*]   NTFS write support

===================================================================

Pseudo filesystems  --->        <==類似 /proc ，保留預設值

[*] Miscellaneous filesystems  ---> <==其他檔案系統的支援，保留預設值

[*] Network File Systems  --->      <==網路檔案系統！很重要！也要挑挑！

--- Network File Systems

<M>   NFS client support

[*]     NFS client support for NFS version 3

[*]       NFS client support for the NFSv3 ACL protocol extension

<M>   NFS server support

[*]     NFS server support for NFS version 3

[*]       NFS server support for the NFSv3 ACL protocol extension

< >   SMB file system support (OBSOLETE, please use CIFS)

<M>   CIFS support (advanced network filesystem, SMBFS successor)

# 最重要就這幾項，其他保留預設值即可！

===================================================================

Partition Types  --->          <==分割類型，也是保持預設值即可！

-*- Native language support  --->  <==選擇預設的語系

--- Native language support

(utf8) Default NLS Option

<*>   Traditional Chinese charset (Big5)

# 除了上述這兩個之外，其他的請選擇成為模組即可！

- 核心駭客、資訊安全、密碼應用

再接下來有個『Kernel hacking』的項目，那是與核心開發者比較有關的部分，這部分建議保留預設值即可， 應該不需要去修改他！除非你想要進行核心方面的研究喔。然後底下有個『 Security Options 』，那是屬於資訊安全方面的設定， 包括 SELinux 這個細部權限強化模組也在這裡編入核心的！這部分可以作一些額外的設定。 另外還有『 Cryptographic API 』這個密碼應用程式介面工具選項，也是可以保留預設值啦！ 我們來看看有什麼比較特殊的地方吧！

Security options  --->

[*] Enable access key retention support

[*]   Enable the /proc/keys file by which keys may be viewed

[*] Enable different security models

[ ] Enable the securityfs filesystem

[*] Socket and Networking Security Hooks

[*]   XFRM (IPSec) Networking Security Hooks

[ ] Security hooks for pathname based access control

[ ] File POSIX Capabilities

[ ] Root Plug Support

[*] NSA SELinux Support

[*]   NSA SELinux boot parameter

(1)     NSA SELinux boot parameter default value

[*]   NSA SELinux runtime disable

[*]   NSA SELinux Development Support

[*]   NSA SELinux AVC Statistics

(1)   NSA SELinux checkreqprot default value

[ ]   NSA SELinux maximum supported policy format version

[ ] Simplified Mandatory Access Control Kernel Support

[ ] TOMOYO Linux Support

[ ] Integrity Measurement Architecture(IMA)

# 基本上，這部分保留預設值就對了！你也會發現 NSA 的資料都是直接編進核心！

================================================================================

Cryptographic API  --->

# 基本上，除了底下這兩個編譯進核心之外，其他的通通選擇成為模組吧！

{*}   MD5 digest algorithm

{*}   SHA1 digest algorithm

在密碼應用程式介面方面，一般我們使用的帳號密碼登入利用的就是 MD5 這個加密機制，要讓核心有支援才行啊！幾乎所有的項目都給他做成模組即可！ 不過 MD5 與 SHA1 必須要直接由核心支援比較好！

- 虛擬化與函式庫

虛擬化是近年來非常熱門的一個議題，因為電腦的能力太強，所以時常閒置在那邊， 此時，我們可以透過虛擬化技術在一部主機上面同時啟動多個作業系統來運作，這就是所謂的虛擬化。 Linux 核心已經主動的納入虛擬化功能喔！而 Linux 認可的虛擬化使用的機制為 KVM (Kernel base Virtual Machine)。 至於常用的核心函式庫也可以全部編為模組囉！

[*] Virtualization  --->

--- Virtualization

<M>   Kernel-based Virtual Machine (KVM) support

<M>     KVM for Intel processors support

<M>     KVM for AMD processors support

[ ]     KVM trace support (NEW)

<M>   Virtio balloon driver (EXPERIMENTAL)

================================================================================

Library routines  --->

{M} CRC-CCITT functions

{M} CRC16 functions

{M} CRC calculation for the T10 Data Integrity Field

{M} CRC ITU-T V.41 functions

-*- CRC32 functions

<M> CRC7 functions

{*} CRC32c (Castagnoli, et al) Cyclic Redundancy-Check

最後，還有底下這兩個項目，這兩個項目與核心功能無關，但是與挑選時的設定檔案有關：

Load an Alternate Configuration File

Save an Alternate Configuration File

這兩個項目分別是儲存剛剛做好的所有項目的設定資料，另一個則是將來自其他人作的選擇給他讀入！ 事實上，剛剛我們所做的設定只要在離開時選擇 SAVE ，那麼這些項目 通通會記錄到目前這個目錄下的 .config 檔案內。 而我們也可以使用上面提到的 Save Configuration 這個項目來將剛剛做完的設定儲存成另外的檔案， 做成這個檔案的好處是，你可以在下次在其他版本的核心作選擇時，直接以 Load 來將這個檔案的設定項目讀入，這樣可以減少你還要重新挑選一遍的困境啊！

要請你注意的是，上面的資料主要是適用在鳥哥的個人機器上面的， 目前鳥哥比較習慣使用原本 distributions 提供的預設核心，因為他們也會主動的進行更新， 所以鳥哥就懶的自己重編核心了∼ ^_^

此外，因為鳥哥重視的地方在於『網路伺服器』上面，所以裡頭的設定少掉了相當多的個人桌上型 Linux 的硬體編譯！所以，如果你想要編譯出一個適合你的機器的核心， 那麼可能還有相當多的地方需要來修正的！不論如何，請隨時以 Help 那個選項來看一看內容吧！反正 Kernel 重編的機率不大！花多一點時間重新編譯一次！ 然後將該編譯完成的參數檔案儲存下來，未來就可以直接將該檔案叫出來讀入了！ 所以花多一點時間安裝一次就好！那也是相當值得的！

核心的編譯與安裝

將最複雜的核心功能選擇完畢後，接下來就是進行這些核心、核心模組的編譯了！而編譯完成後，當然就是需要使用嚕∼ 那如何使用新核心呢？就得要考慮 grub 這個玩意兒啦！底下我們就來處理處理：

編譯核心與核心模組

核心與核心模組需要先編譯起來，而編譯的過程其實非常簡單，你可以先使用『 make help 』去查閱一下所有可用編譯參數， 就會知道有底下這些基本功能：

[root@www linux-2.6.30.3]# make vmlinux  <==未經壓縮的核心

[root@www linux-2.6.30.3]# make modules  <==僅核心模組

[root@www linux-2.6.30.3]# make bzImage  <==經壓縮過的核心(預設)

[root@www linux-2.6.30.3]# make all      <==進行上述的三個動作

我們常見的在 /boot/ 底下的核心檔案，都是經過壓縮過的核心檔案，因此，上述的動作中比較常用的是 modules 與 bzImage 這兩個，其中 bzImage 第三個字母是英文大寫的 I 喔！bzImage 可以製作出壓縮過後的核心， 也就是一般我們拿來進行系統開機的資訊囉！所以，基本上我們會進行的動作是：

[root@www linux-2.6.30.3]# make clean    <==先清除暫存檔

[root@www linux-2.6.30.3]# make bzImage  <==先編譯核心

[root@www linux-2.6.30.3]# make modules  <==再編譯模組

上述的動作會花費非常長的時間，編譯的動作依據你選擇的項目以及你主機硬體的效能而不同。 最後製作出來的資料是被放置在 /usr/src/kernels/linux-2.6.30.3/ 這個目錄下，還沒有被放到系統的相關路徑中喔！在上面的編譯過程當中，如果有發生任何錯誤的話， 很可能是由於核心項目的挑選選擇的不好，可能你需要重新以 make menuconfig 再次的檢查一下你的相關設定喔！ 如果還是無法成功的話，那麼或許將原本的核心資料內的 .config 檔案，複製到你的核心原始檔目錄下， 然後據以修改，應該就可以順利的編譯出你的核心了。最後注意到，下達了 make bzImage 後，最終的結果應該會像這樣：

Root device is (8, 1)

Setup is 12696 bytes (padded to 12800 bytes).

System is 2207 kB

CRC 7701ab0e

Kernel: arch/x86/boot/bzImage is ready  (#1)

[root@www linux-2.6.30.3]# ll arch/x86/boot/bzImage

-rw-r--r-- 1 root root 2272432  7月 30 13:35 arch/x86/boot/bzImage

可以發現你的核心已經編譯好而且放置在 /usr/src/kernels/linux-2.6.30.3/arch/x86/boot/bzImage 裡面囉∼那個就是我們的核心檔案！最重要就是他啦！我們等一下就會安裝到這個檔案哩！ 然後就是編譯模組的部分囉∼ make modules 進行完畢後，就等著安裝啦！ ^_^

實際安裝模組

安裝模組前有個地方得要特別強調喔！我們知道模組是放置到 /lib/modules/$(uname -r) 目錄下的，那如果同一個版本的模組被反覆編譯後來安裝時，會不會產生衝突呢？舉例來說，鳥哥這個 2.6.30.3 的版本第一次編譯完成且安裝妥當後，發現有個小細節想要重新處理，因此又重新編譯過一次，那兩個版本一模一樣時， 模組放置的目錄會一樣，此時就會產生衝突了！如何是好？有兩個解決方法啦：

- 先將舊的模組目錄更名，然後才安裝核心模組到目標目錄去；

- 在 make menuconfig 時，那個 General setup 內的 Local version 修改成新的名稱。

鳥哥建議使用第二個方式，因為如此一來，你的模組放置的目錄名稱就不會相同，這樣也就能略過上述的目錄同名問題囉！ 好，那麼如何安裝模組到正確的目標目錄呢？很簡單，同樣使用 make 的功能即可：

[root@www linux-2.6.30.3]# make modules_install

[root@www linux-2.6.30.3]# ll /lib/modules/

drwxr-xr-x 3 root root 4096  7月 30 14:31 2.6.30.3vbird

看到否，最終會在 /lib/modules 底下建立起你這個核心的相關模組喔！不錯吧！模組這樣就已經處理妥當囉∼ 接下來，就是準備要進行核心的安裝了！哈哈！又跟 grub 有關囉∼

開始安裝新核心與多重核心選單 (grub)

現在我們知道核心檔案放置在 /usr/src/kernels/linux-2.6.30.3/arch/x86/boot/bzImage ，但是其實系統核心理論上都是擺在 /boot 底下，且為 vmlinuz 開頭的檔名。 此外，我們也曉得一部主機是可以做成多重開機系統的！這樣說，應該知道鳥哥想要幹嘛了吧？ 對啦！我們將同時保留舊版的核心，並且新增新版的核心在我們的主機上面。

- 移動核心到 /boot 且保留舊核心檔案

保留舊核心有什麼好處呢？最大的好處是可以確保系統能夠順利開機啦！因為核心雖然被編譯成功了， 但是並不保證我們剛剛挑選的核心項目完全適合於目前這部主機系統， 可能有某些地方我們忘記選擇了，這將導致新核心無法順利驅動整個主機系統，更差的情況是， 你的主機無法成功開機成功！此時，如果我們保留舊的核心，呵呵！若新核心測試不通過，就用舊核心來啟動啊！嘿嘿！ 保證比較不會有問題嘛！新核心通常可以這樣作的：

[root@www ~]# cp /usr/src/kernels/linux-2.6.30.3/arch/x86/boot/bzImage \

> /boot/vmlinuz-2.6.30.3vbird  <==實際核心

[root@www ~]# cp /usr/src/kernels/linux-2.6.30.3/.config \

> /boot/config-2.6.30.3vbird   <==建議設定檔也複製備份

- 建立相對應的 Initial Ram Disk (initrd)

還記得第二十章談過的 initrd 這個玩意兒吧！ 由於鳥哥的系統使用 SATA 磁碟，加上剛剛 SATA 磁碟支援的功能並沒有直接編譯到核心去，所以當然要使用 initrd 來載入才行！ 使用如下的方法來建立 initrd 吧！記得搭配正確的核心版本喔！

[root@www ~]# mkinitrd -v /boot/initrd-2.6.30.3vbird.img  2.6.30.3vbird

....(前面省略)....

Adding module ehci-hcd

Adding module ohci-hcd

Adding module uhci-hcd

....(後面省略)....

- 編輯開機選單 (grub)

鳥哥這部測試機之前是使用 Xen 的核心來啟動的，但因為 Xen 核心的製作比較複雜，本章並沒有實作出 Xen 虛擬機器的核心。 底下鳥哥使用的是剛剛編譯成功的核心來進行開機選單的設定，你會看到的設定檔與你的環境可能會有不一樣喔！ 那就來看看吧！

[root@www ~]# vim /boot/grub/menu.lst

default=0

timeout=10

splashimage=(hd0,0)/boot/grub/splash.xpm.gz

#hiddenmenu

title CentOS (2.6.18-128.2.1.el5xen)

root (hd0,0)

kernel /boot/xen.gz-2.6.18-128.2.1.el5

module /boot/vmlinuz-2.6.18-128.2.1.el5xen ro root=LABEL=/ rhgb quiet

module /boot/initrd-2.6.18-128.2.1.el5xen.img

title CentOS testing kernel from vbird

root (hd0,0)

kernel /boot/vmlinuz-2.6.30.3vbird ro root=LABEL=/ rhgb

initrd /boot/initrd-2.6.30.3vbird.img

新增上述的特殊字體到你的設定檔當中。另外，你會發現我上頭的 default 並沒有修改到最新的那個核心的選單上， 因為我必須要測試一下新核心能否順利開機！如果順利開機且運作沒有問題後，那麼才來修訂這個 default 的值吧！

- 重新以新核心開機、測試、修改

如果上述的動作都成功後，接下來就是重新開機並選擇新核心來啟動系統啦！如果系統順利啟動之後，你使用 uname -a 會出現類似底下的資料：

[root@www ~]# uname -a

Linux www.vbird.tsai 2.6.30.3vbird #1 SMP Thu Jul 30 13:34:31

CST 2009 x86_64 x86_64 x86_64 GNU/Linux

包括核心版本與支援的硬體平台都是 OK 的！嘿嘿！那你所編譯的核心就是差不多成功的啦！ 如果運作一陣子後，你的系統還是穩定的情況下，那就能夠將 default 值使用這個新的核心來作為預設開機囉！ 這就是核心編譯！那你也可以自己處理嵌入式系統的核心編譯囉！ ^_^

額外(單一)核心模組編譯

我們現在知道核心所支援的功能當中，有直接編譯到核心內部的，也有使用外掛模組的，外掛模組可以簡單的想成就是驅動程式 啦！那麼也知道這些核心模組依據不同的版本，被分別放置到 /lib/modules/$(uname -r)/kernel/ 目錄中，各個硬體的驅動程式則是放置到 /lib/modules/$(uname -r)/kernel/drivers/ 當中！換個角度再來思考一下，如果剛剛我自己編譯的資料中，有些驅動程式忘記編譯成為模組了，那是否需要重新進行上述的所有動作？ 又如果我想要使用硬體廠商釋出的新驅動程式，那該如何是好？

編譯前注意事項

由於我們的核心原本就有提供很多的核心工具給硬體開發商來使用， 而硬體開發商也需要針對核心所提供的功能來設計他們的驅動程式模組，因此， 我們如果想要自行使用硬體開發商所提供的模組來進行編譯時，就需要使用到核心所提供的原始檔當中， 所謂的標頭檔案 (header include file) 來取得驅動模組所需要的一些函式庫或標頭的定義啦！ 也因此我們常常會發現到，如果想要自行編譯核心模組時，就得要擁有核心原始碼嘛！

那核心原始碼我們知道他是可能放置在 /usr/src/ 底下，早期的核心原始碼被要求一定要放置到 /usr/src/linux/ 目錄下，不過，如果你有多個核心在一個 Linux 系統當中，而且使用的原始碼並不相同時， 呵呵∼問題可就大了！所以，在 2.6 版以後，核心使用比較有趣的方法來設計他的原始碼放置目錄， 那就是以 /lib/modules/$(uname -r)/build 及 /lib/modules/$(uname -r)/source 這兩個連結檔來指向正確的核心原始碼放置目錄。如果以我們剛剛由 kernel 2.6.30.3 建立的核心模組來說， 那麼他的核心模組目錄底下有什麼咚咚？

[root@www ~]# ll -h /lib/modules/2.6.30.3vbird/

lrwxrwxrwx  1 root root   31  7月 30 14:29 build -> /usr/src/kernels/linux-2.6.30.3

drwxr-xr-x 10 root root 4.0K  7月 30 14:30 kernel

-rw-r--r--  1 root root 337K  7月 30 14:31 modules.alias

-rw-r--r--  1 root root   69  7月 30 14:31 modules.ccwmap

-rw-r--r--  1 root root 224K  7月 30 14:31 modules.dep

....(中間省略)....

lrwxrwxrwx  1 root root   31  7月 30 14:29 source -> /usr/src/kernels/linux-2.6.30.3

比較有趣的除了那兩個連結檔之外，還有那個 modules.dep 檔案也挺有趣的， 那個檔案是記錄了核心模組的相依屬性的地方，依據該檔案，我們可以簡單的使用 modprobe 這個指令來載入模組呢！至於核心原始碼提供的標頭檔，在上面的案例當中， 則是放置到 /usr/src/kernels/linux-2.6.30.3/include/ 目錄中，當然就是藉由 build/source 這兩個連結檔案來取得目錄所在的啦！^_^

由於核心模組的編譯其實與核心原本的原始碼有點關係的，因此如果你需要重新編譯模組時， 那除了 make, gcc 等主要的編譯軟體工具外，你還需要的就是 kernel-devel 這個軟體！記得一定要安裝喔！而如果你想要在預設的核心底下新增模組的話，那麼就得要找到 kernel 的 SRPM 檔案了！ 將該檔案給他安裝，並且取得 source code 後，才能夠順利的編譯喔！

單一模組編譯

想像兩個情況：

- 如果我的預設核心忘記加入某個功能，而且該功能可以編譯成為模組，不過， 預設核心卻也沒有將該項功能編譯成為模組，害我不能使用時，該如何是好？

- 如果 Linux 核心原始碼並沒有某個硬體的驅動程式 (module) ，但是開發該硬體的廠商有提供給 Linux 使用的驅動程式原始碼，那麼我又該如何將該項功能編進核心模組呢？

很有趣對吧！不過，在這樣的情況下其實沒有什麼好說的，反正就是 『去取得原始碼後，重新編譯成為系統可以載入的模組』啊！很簡單，對吧！^_^！ 但是，上面那兩種情況的模組編譯行為是不太一樣的，不過，都是需要 make, gcc 以及核心所提供的 include 標頭檔與函式庫等等。

- 硬體開發商提供的額外模組

很多時候，可能由於核心預設的核心驅動模組所提供的功能你不滿意，或者是硬體開發商所提供的核心模組具有更強大的功能， 又或者該硬體是新的，所以預設的核心並沒有該硬體的驅動模組時，那你只好自行由硬體開發商處取得驅動模組， 然後自行編譯囉！

如果你的硬體開發商有提供驅動程式的話，那麼真的很好解決，直接下載該原始碼，重新編譯， 將他放置到核心模組該放置的地方後就能夠使用了！舉個例子來說，為了省電，鳥哥在 2009 年初買了整合型主機板來架設家用的伺服器，沒想到 CentOS 5.1 以前的版本對鳥哥新買的主機板內建網卡支援度不足， 使用的網卡驅動程式 r8169 有問題！搜尋了 google 才發現大家都有這個問題。解決方法就是到 Realtek 官網下載網卡驅動程式來編譯即可。

- Realtek 的 r8168 網卡驅動程式：http://www.realtek.com.tw/downloads/

- 選擇『Communications Network ICs』-->『Network Interface Controlllers』--> 『10/100/1000M Gigabit Ethernet』--> 『PCI Express』--> 『Software』就能夠下載了！

你可以利用各種方法將他下載後，假設這個檔案放置到 /root ，那麼直接將他解壓縮吧！ 之後就可以讀一讀 INSTALL/README ，然後找一下 Makefile ，就能夠編譯了。整體流程有點像這樣：

# 1. 將檔案解壓縮：

[root@www ~]# cd /usr/local/src

[root@www src]# tar -jxvf /root/r8168-8.013.00.tar.bz2

[root@www src]# cd r8168-8.013.00/

# 2. 開始進行編譯與安裝：

[root@www r8168-8.013.00]# vi readme  <==注意查一下該檔案內容

[root@www r8168-8.013.00]# make clean modules

[root@www r8168-8.013.00]# ll src/*.ko  <==建立底下的模組檔！

-rw-r--r-- 1 root root 112216  7月 31 01:11 src/r8168.ko

[root@www r8168-8.013.00]# make install

install -m 744 -c r8168.ko /lib/modules/2.6.30.3vbird/kernel/drivers/net/

# 重點在上面這行！會發現模組已經被移動到核心模組目錄！

4. 更新模組相依屬性！

[root@www r8168-8.013.00]# depmod -a

有趣吧！透過這樣的動作，我們就可以輕易的將模組編譯起來，並且還可以將他直接放置到核心模組目錄中， 同時以 depmod 將模組建立相關性，未來就能夠利用 modprobe 來直接取用啦！ 但是需要提醒你的是，當自行編譯模組時， 若你的核心有更新 (例如利用自動更新機制進行線上更新) 時，則你必須要重新編譯該模組一次， 重複上面的步驟才行！因為這個模組僅針對目前的核心來編譯的啊！對吧！

- 利用舊有的核心原始碼進行編譯

如果你後來發現忘記加入某個模組功能了，那該如何是好？其實如果僅是重新編譯模組的話， 那麼整個過程就會變的非常簡單！我們先到目前的核心原始碼所在目錄下達 make menuconfig ， 然後將 NTFS 的選項設定成為模組，之後直接下達：

make fs/ntfs/

那麼 ntfs 的模組 (ntfs.ko) 就會自動的被編譯出來了！ 然後將該模組複製到 /lib/modules/2.6.30.3vbird/kernel/fs/ntsf/ 目錄下， 再執行 depmod -a ，呵呵∼就可以在原來的核心底下新增某個想要加入的模組功能囉∼ ^_^

核心模組管理

核心與核心模組是分不開的，至於驅動程式模組在編譯的時候，更與核心的原始碼功能分不開∼ 因此，你必須要先瞭解到：核心、核心模組、驅動程式模組、核心原始碼與標頭檔案的相關性， 然後才有辦法瞭解到為何編譯驅動程式的時候老是需要找到核心的原始碼才能夠順利編譯！ 然後也才會知道，為何當核心更新之後，自己之前所編譯的核心模組會失效∼

此外，與核心模組有相關的，還有那個很常被使用的 modprobe 指令， 以及開機的時候會讀取到的模組定義資料檔案 /etc/modprobe.conf ， 這些資料你也必須要瞭解才行∼相關的指令說明我們已經在第二十章內談過了， 你應該要自行前往瞭解喔！ ^_^

重點回顧

- 其實核心就是系統上面的一個檔案而已，這個檔案包含了驅動主機各項硬體的偵測程式與驅動模組；

- 上述的核心模組放置於：/lib/modules/$(uname -r)/kernel/

- 『驅動程式開發』的工作上面來說，應該是屬於硬體發展廠商的問題

- 一般的使用者，由於系統已經將核心編譯的相當的適合一般使用者使用了，因此一般入門的使用者，基本上，不太需要編譯核心

- 編譯核心的一般目的：新功能的需求、原本的核心太過臃腫、與硬體搭配的穩定性、其他需求(如嵌入式系統)

- 編譯核心前，最好先瞭解到您主機的硬體，以及主機的用途，才能選擇好核心功能；

- 編譯前若想要保持核心原始碼的乾淨，可使用 make mrproper 來清除暫存檔與設定檔；

- 挑選核心功能與模組可用 make 配合：menuconfig, oldconfig, xconfig, gconfig 等等

- 核心功能挑選完畢後，一般常見的編譯過程為：make bzImage, make modules

- 模組編譯成功後的安裝方式為： make modules_install

- 核心的安裝過程中，需要移動 bzImage 檔案、建立 initrd 檔案、編輯 /boot/grub/menu.lst 等動作；

- 我們可以自行由硬體開發商之官網下載驅動程式來自行編譯核心模組！

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

- 簡單說明核心編譯的步驟為何？

1. 先下載核心原始碼，可以從 http://www.kernel.org 或者是 distributions 的 SRPM 來著手；

2. 以下以 Tarball 來處理，解開原始碼到 /usr/src/kernels 目錄下；

3. 先進行舊資料刪除的動作：『make mrproper』；

4. 開始挑選核心功能，可以利用『make menuconfig』、『make oldconfig』、『make gconfig』等等；

5. 清除過去的中間暫存檔資料：『make clean』

6. 開始核心檔案與核心模組的編譯：『make bzImage』、『make modules』

7. 開始核心模組的安裝：『make modules_install』

8. 開始核心檔案的安裝，可以使用的方式有：『make install』或者是透過手動的方式複製核心檔案到 /boot/grub 當中；

9. 建立 initrd 檔案；

10. 修改 /boot/grub/menu.lst 檔案；

- 如果你利用新編譯的核心來操作系統，發現系統並不穩定，你想要移除這個自行編譯的核心該如何處理？

首先，可以將原始碼刪除：rm -rf /usr/src/kernels/linux-2.6.30

再者，刪除掉核心模組的目錄： rm -rf /lib/modules/2.6.30

最後刪除掉 /boot/ 內的核心檔案與 initrd 檔案，以及 /boot/grub/menu.lst 內的 title 設定即可。

參考資料與延伸閱讀

- 註1：透過在 /usr/src/kernels/linux-2.6.30.3 底下的 README 以及『 make help 』可以得到相當多的解釋

- 核心編譯的功能：可以用來測試 CPU 效能喔！因為 compile 非常耗系統資源！

- http://lxr.xensource.com/lxr/source/README?a=x86_64

2002/05/29：第一次完成

2003/02/11：重新編排與加入 FAQ

2004/06/11：原本的 2.4.xx 版本核心被移動到 此處

2005/11/15：原本的模組管理已經先移動到開機流程管理那一篇囉！

2005/12/05：經過將近一個月，呵呵！終於給他整理出來這一篇了∼真難得∼

2007/06/27：增加了 initrd 的簡單說明，詳細還是得看 loader 那一章。

2009/07/21：將基於 FC4 所撰寫的文章移動到此處

2009/08/03：原本的 KDE/GNOME 使用的引擎寫錯了！ KDE 用 Qt ，而 GNOME 是用 Gtk ！非常感謝 Chua Tze An 兄提供的指正！

2009/09/18：加入兩個簡單的題目，給大家思考一下而已。

2002/05/29以來統計人數

基礎學習篇快速索引

切換解析度為 800x600

為了方便讀者可以快速的找到自己想要查詢的指令功能與相關用語說明，底下建立的就是一些指令速查表囉！

指令與用語速查表

A B C D E F G H I J K L M N O P Q R S T U W X Y 其他

指令與用語

相關連結

A

ACL

第十四章、3.1

alias

第十一章、3.1

anacron

第十六章、4.1

apropos

第五章、3.1

array

第十一章、2.6

at

第十六章、2.2

atq, atrm

第十六章、2.2

auditd

第十七章、5.5

audit2why

第十七章、5.5

awk

第十二章、4.2

B

badblocks

第八章、3.3

basename

第七章、2.3

bash

第十一章

第五章、2.1

bashrc

第十一章、4.3

batch

第十六章、2.2

bg

第十七章、2.2

BIOS vs CMOS

第零章、2.6

bc

第五章、2.2

block

第八章、1.3

boot loader

第二十章、1.2

bzip2, bzcat

第九章、2.3

C

cal

第五章、2.2

case

第十三章、4.2

cat

第七章、3.1

cd

第七章、1.2

cdrecord

第九章、5.2

chage

第十四章、2.1

chattr

第七章、4.2

chcon

第十七章、5.4

chfn

第十四章、2.2

chgrp

第六章、2.2

chkconfig

第十八章、4.2

chkfontpath

第二十四章、2.2

chmod

第六章、2.2

chown

第六章、2.2

chpasswd

第十四章、7.1

chroot

第二十章、4.5

chsh

第十四章、2.2

CISC

第零章、1.2

cmp

第十二章、4.3

col

第十一章、6.4

compress

第九章、2.1

cp

第七章、2.2

cpio

第九章、6.2

crontab

第十六章、3.1

cups

第二十一章、2.0

cut

第十一章、6.1

D

date

第五章、2.2

第十三章、2.1

dd

第八章、5.2

第九章、6.1

declare

第十一章、2.6

depmod

第二十章、2.1

device.map

第二十章、4.3

df

第八章、2.1

diff

第十二章、4.3

dirname

第七章、2.3

dmesg

第十七章、3.4

dos2unix

第十章、4.2

du

第八章、2.1

dump

第九章、4.0

dumpe2fs

第八章、1.3

E

e2label

第八章、3.5

echo

第十一章、2.2

edquota

第十五章、1.5

env

第十一章、2.3

expand

第十一章、6.4

export

第十一章、2.3

EXT2 filesystem

第八章、1.3

F

fc-cache, fc-list

第二十四章、2.2

fdisk

第八章、3.1

fg

第十七章、2.2

free

第八章、5.1

第十七章、3.4

file

第七章、4.4

find

第七章、5.2

finger

第十四章、2.2

FHS

第一章、2.6

第六章、3.1

fsck

第八章、3.3

fstab

第八章、4.1

function

第十三章、4.3

fuser

第十七章、4.3

G

gcc

第二十二章、2.4

getenforce

第十七章、5.3

getsebool

第十七章、5.6

getfacl

第十四章、3.3

GNU

第一章、1.3

GNU GPL

第一章、1.2

gpasswd

第十四章、2.3

grep

第十一章、6.1

第十二章、2.2

group

第十四章、1.3

groupadd

第十四章、2.3

groupdel

第十四章、2.3

groupmod

第十四章、2.3

groups

第十四章、1.3

grub

第二十章、3.0

第二十章、3.4

grub-install

第二十章、3.4

grub-md5-crypt

第二十章、3.8

gtf

第二十四章、2.3

gzip, zcat

第九章、2.2

H

hal

第二十一章、3.4

Hardware support

第三章、1.2

hdparm

第八章、3.5

head

第七章、3.3

history

第十一章、3.2

I

iconv

第十章、4.3

id

第十四章、2.2

if

第十三章、4.1

info

第五章、3.2

init

第五章、5.0

第二十章、1.3

第二十章、1.9

initrd

第二十章、3.3

inode

第八章、1.3

insmod

第二十章、2.3

iostat

第二十一章、3.1

issue

第十一章、4.2

J

jobs

第十七章、2.2

join

第十一章、6.4

journaling filesystem

第八章、1.5

K

kill

第十七章、2.2

第十七章、3.2

killall

第十七章、3.2

L

LANG

第五章、2.1

第十章、4.1

第十二章、2.1

last

第十四章、6.1

lastlog

第十四章、6.1

ldconfig

第二十二章、5.2

ldd

第十八章、3.1

第二十二章、5.3

less

第七章、3.2

link (hard, symbolic)

第八章、2.2

Linux distributions

第一章、2.6

Linux 核心版本

第一章、2.5

lm_sensors

第二十一章、3.0

ln

第八章、2.2

locale

第十一章、2.4

locate

第七章、5.2

login-shell

第十一章、4.3

logrotate

第十九章、3.0

logwatch

第十九章、4.1

lp

第二十一章、2.6

lpadmin

第二十一章、2.6

lpq

第二十一章、2.6

lpr

第二十一章、2.6

lprm

第二十一章、2.6

lpstat

第二十一章、2.6

ls, ll

第七章、2.1

lsattr

第七章、4.2

LSB

第一章、2.6

lsb_release

第六章、3.4

lsmod

第二十章、2.2

lsof

第十七章、4.3

lspci

第二十一章、3.1

lsusb

第二十一章、3.1

LVM

第十五章、3.0

lvcreate, lvscan, lvdisplay

lvextend, lvreduce

lvremove, lvresize

第十五章、3.2

M

mail

第十一章、2.1

第十四章、6.3

make

第二十二章、1.3

makefile

第二十二章、3.2

man

第五章、3.1

MBR

第三章、2.4

md5sum

第二十二章、6.1

mdadm

第十五章、2.3

mdadm.conf

第十五章、2.5

mesg

第十四章、6.2

menu.list

第二十章、3.2

mkdir

第七章、1.2

mke2fs

第八章、3.2

mkfs

第八章、3.2

mkinitrd

第二十章、3.3

mknod

第八章、3.5

mkisofs

第九章、5.1

mkswap

第八章、5.1

modinfo

第二十章、2.2

modprobe

第二十章、2.3

more

第七章、3.2

motd

第十一章、4.2

mount (含常用參數)

第八章、3.4

mount (remount)

第八章、3.4

mount (vfat, 中文)

第八章、3.4

mount (--bind)

第八章、3.4

mount (option)

第八章、4.1

mount (loop)

第八章、4.2

mv

第七章、2.2

N

nano

第五章、4.0

netstat

第十七章、3.4

newgrp

第十四章、1.3

nice

第十七章、3.3

nl

第七章、3.1

nohup

第十七章、2.3

nologin

第十四章、5.1

non-login-shell

第十一章、4.3

ntsysv

第十八章、4.2

O

od

第七章、3.4

P

PAM

第十四章、5.1

parted

第八章、6.3

partition table

第三章、2.3

partprobe

第八章、3.1

passwd

第十四章、1.2

第十四章、2.1

paste

第十一章、6.4

patch

第十二章、4.3

第二十二章、4.5

PATH

第七章、1.3

第十一章、4.1

permission

第六章、2.1

pidof

第十七章、4.3

pr

第十二章、4.4

printf

第十二章、4.1

profile

第十一章、4.3

ps

第十七章、3.1

pstree

第十七章、3.1

pvscan, pvcreate

pvdisplay, pvremove

第十五章、3.2

pwck

第十四章、7.1

pwconv

第十四章、7.1

pwd

第七章、1.2

pwunconv

第十四章、7.1

Q

quota

第十五章、1.0

第十五章、1.6

quotacheck

第十五章、1.4

quotaoff

第十五章、1.5

quotaon

第十五章、1.5

R

RAID

第十五章、2.1

read

第十一章、2.6

第十三章、2.1

reboot, halt, poweroff

第五章、5.0

renice

第十七章、3.3

repquota

第十五章、1.6

resize2fs

第十五章、3.3

restore

第九章、4.0

restorecon

第十七章、5.4

RISC

第零章、1.2

rm

第七章、2.2

rmdir

第七章、1.2

rmmod

第二十章、2.3

rpm

第二十三章、1.0

第二十三章、2.0

rpmbuild

第二十三章、3.0

rsync

第十八章、2.2

runlevel

第二十章、1.3

第二十章、1.9

S

SBIT

第七章、4.4

sealert

第十七章、5.5

securetty

第十四章、5.4

sed

第十二章、2.5

seinfo

第十七章、5.6

semanage

第十七章、5.6

sensors

第二十一章、3.3

sensors-detect

第二十一章、3.3

service

第十八章、1.3

sesearch

第十七章、5.6

sestatus

第十七章、5.3

set

第十一章、2.3

第十一章、4.4

setenforce

第十七章、5.3

setfacl

第十四章、3.3

setquota

第十五章、1.7

setroubleshoot

第十七章、5.5

setsebool

第十七章、5.6

setup

第二十一章、1.0

SGID

第七章、4.4

shadow

第十四章、1.2

sha1sum

第二十二章、6.1

shells

第十一章、1.3

shift

第十三章、3.3

shutdown

第五章、5.0

signal

第十七章、3.2

sort

第十一章、6.2

source (.)

第十一章、4.3

split

第十一章、6.5

stand alone daemon

第十八章、1.1

startx

第五章、1.4

第二十四章、1.3

su

第十四章、4.1

sudo

第十四章、4.2

SUID

第七章、4.4

super block

第八章、1.3

第八章、6.1

syslog

第十九章、2.0

super daemon

第十八章、1.1

swapoff

第八章、5.1

swapon

第八章、5.1

sync

第五章、5.0

T

[tab]/[ctrl]-c/[ctrl]-d

第五章、2.3

第十一章、1.4

tac

第七章、3.1

tail

第七章、3.3

tar

第九章、3.0

TCP Wrappers

第十八章、3.2

tee

第十一章、6.3

test

第十三章、3.1

time

modification time(mtime)

status time(ctime)

access time(atime)

第七章、3.5

top

第十七章、3.1

touch

第七章、3.5

tr

第十一章、6.4

tty1 ~ tty7

第五章、1.4

tune2fs

第八章、3.5

type

第十一章、1.5

U

udev

第二十一章、3.4

ulimit

第十一章、2.7

第十四章、5.5

umask

第七章、4.1

umount

第八章、3.4

unalias

第十一章、3.1

uname

第十七章、3.4

uniq

第十一章、6.2

UNIX

第一章、1.2

unix2dos

第十章、4.2

unset

第十一章、2.2

updatedb

第七章、5.2

uptime

第十七章、3.4

useradd

第十四章、2.1

userdel

第十四章、2.1

usermod

第十四章、2.1

V

VFS

第八章、1.8

vgcreate, vgscan, vgdisplay

vgextend, vgreduce, vgchange

vgremove

第十五章、3.2

vim 按鍵說明

第十章、2.2

.vimrc

第十章、3.4

visudo

第十四章、4.2

vmstat

第十七章、3.4

W

w, who

第十四章、6.1

wall

第十四章、6.2

warnquota

第十五章、1.7

wc

第十一章、6.2

whatis

第五章、3.1

whereis

第七章、5.2

which

第七章、5.1

write

第十四章、6.2

X

xargs

第十一章、6.5

xinetd, xinetd.conf

第十八章、2.1

xinit

第二十四章、1.3

xorg.conf

第二十四章、2.1

X window system

第二十四章、1.0

Y

yum

第二十三章、4.0

其他

; && ||

第十一章、5.2

$?

第十一章、2.3

&

第十七章、2.2

絕對路徑與相對路徑

第六章、3.3

第七章、1.1

磁碟重組

第八章、1.2

變數

第十一章、2.1

變數設定規則

第十一章、2.2

萬用字元

第十一章、4.5

資料流重導向

第十一章、5.1

管線命令 (pipe)

第十一章、6.0

2009/08/18 以來統計人數

附錄 A： GNU 的 GPL 條文 version 2

我們在 Linux 基礎裡面提到了 Linux 是 基於 GPL 的情況下而允許大眾可以做最大限度的使用！那麼 GPL 是什麼呢？ 基本上他是基於 GNU 的架構下的！簡單的說， GNU 就是『自由軟體』的意思， 『自由軟體』是放置於網路上供人自由下載使用的軟體，基本上他會提供原始程式碼與編譯完成的執行檔 （有的僅提供原始碼，要編譯得自己來才行），並鼓勵使用者修改程式使符合使用者本身的服務需求， 當然囉，如果你將這些自由軟體修改之後，以商業的手法來販賣，也不會觸犯到什麼法律上的責任啦， 只是如此一來則違反了自由軟體的創作美意了！

在目前的臺灣教育界中，有一群老師也是在積極的從事這一種『自由軟體』 的集體創作呢！如此一來將有助於臺灣中小學教師的電腦程度，並提供良好的學習環境呢！當真是很不錯呦！以下將 GNU/GPL 的中文譯本附上，大家可以稍微看一看囉！

版權所有 (C) 1989，1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307USA

允許每個人複製和發佈這一許可證原始文件的副本，但絕對不允許對它進行任何修改。

聲明

This is an unofficial translation of the GNU General Public License into Chinese. It was not published by the Free Software Foundation, and does not legally state the distribution terms for software that uses the GNU GPL-- only the original English text of the GNU GPL does that. However, we hope that this translation will help Chinese speakers understand the GNU GPL better.

這是一份 GNU 通用公共許可證非正式的中文翻譯。它不是自由軟體基金會所發布， 並且不能適用於使用 GNU GPL 的軟體 ── 只有 GNU GPL 英文原文的版本才行。然而， 我們希望這份翻譯能幫助中文的使用者更了解 GNU GPL。

序言

大多數軟體許可證的用意在於剝奪您共享和修改軟體的自由。相反的，GNU 通用公共許可證力圖保證您共享和修改自由軟體的自由 ── 保證自由軟體對所有使用者都是自由的。GNU GPL 適用於大多數自由軟體基金會的軟體，以及任何因信任而採用 GNU GPL 的作者所開發的軟體。(有些自由軟體基金會軟體受 GNU 函式庫通用許可證的保護)。您也可以將它用到您的程式中。

當我們談到自由軟體 ( free software ) 時，我們指的是自由而不是價格。我們把 GNU 通用公共許可證設計成您的保障，讓您保有發佈自由軟體的自由 ( 您可以自由決定是否要對此項服務收取費用)； 確保您能收到程式原始碼或者在您需要時能得到它；確保您能修改軟體或將它的一部分用於新的自由軟體； 而且還確保您知道您擁有這些權利。

為了保護您的權利，我們需要作出規定：禁止任何人剝奪您的權利，或者要求您放棄這些權利。 如果您修改了自由軟體或者發佈了軟體的副本，這些規定就轉化為您的責任。

例如，如果您發佈這樣一個程式的副本，不管是免費的還是收費的， 您必須將您具有的一切權利給予您的接受者；您必須確認他們能收到或得到原始程式碼； 並且將這些條款給他們看，使他們知道他們有這樣的權利。

我們採取兩項措施來保護您的權利：

1. 用版權來保護軟體。

2. 提供您許可證，賦予您複製，發佈和修改這些軟體的法律許可。

同樣，為了保護每個作者和我們自己，我們需要清楚地讓每個人明白，自由軟體沒有擔保 ( no warranty )。如果由於某人修改了軟體，並繼續加以傳播，我們需要它的接受者明白： 他們所得到的並不是原來的自由軟體。由其他人引入的任何問題，不應損害原作者的聲譽。

最後，由於任何自由軟體不斷受到軟體專利的威脅，故我們希望避免這樣的風險。 如果自由軟體的再發佈者以個人名義獲得專利許可證，也就等同將軟體變為私有。 為防止這一點，我們必須明確聲明：任何專利必須以允許每個人自由使用為前提，否則就不准許有專利。

下面是有關複製、發佈和修改的確切的條款和條件。

GNU 通用公共許可證 有關複製，發佈和修改的條款和條件

凡是版權所有者在其程式和作品中聲明其程式和作品可以在 GNU GPL 條款的約束下發佈，這樣的程式或作品都受到本許可證約束。下面提到的 "程式" 指的是任何這樣的程式或作品。而 "程式的衍生作品" 指的是這樣的程式或者版權法認定下的衍生作品，也就是說包含此程式或程式的一部分的套件， 可以是原封不動的，或經過修改的，和/或翻譯成其他語言的 ( 程式 )。( 在下文中，"修改" 一詞的涵義一律包含翻譯作品。) 每個許可證接受人 ( license ) 用 "您" 來稱呼。

本許可證條款不適用於複製，發佈和修改以外的行為。這些行為超出這些條款的範圍。 執行本程式的行為不受條款的限制。而程式的輸出只有在其內容構成本程式的衍生作品 ( 並非只是因為該輸出由本程式所產生 ) 時，這一條款才適用。 至於程式的輸出內容是否構成本程式的衍生作品，則取決於程式具體的用途。

1. 只要您在每一程式副本上明顯和恰當地宣告版權聲明和不承擔擔保的聲明， 並原封不動保持此許可證的聲明和沒有擔保的聲明，並將此許可證連同程式 一起給其他每位程式接受者，您就可以用任何媒體複製和發佈您收到的程式的原始碼。

您可以為轉讓副本的實際行動收取一定費用。您也可以自由決定是否以提供擔保來換取一定的費用。

2. 您可以修改程式的一個或幾個副本或程式的任何部分，以此形成基於這些程式的衍生作品。 只要您同時滿足下面的所有條件，您就可以按前面第一款的要求複製和發佈這一經過修改的程式或作品。

- 您必須在修改過的檔案中附有明顯的說明：您修改了此一檔案及任何修改的日期。

- 您必須讓您發佈或出版的作品，包括本程式的全部或一部分，或內含本程式的全部或部分所衍生的作品， 允許第三方在此許可證條款下使用，並且不得因為此項授權行為而收費。

- 如果修改的程式在執行時以交談方式讀取命令，您必須使它在開始進入一般的交談使用方式時列印或顯示聲明： 包括適當的版權聲明和沒有擔保的聲明( 或者您提供擔保的聲明 )； 使用者可以按此許可證條款重新發佈程式的聲明；並告訴使用者如何看到這一許可證的副本。 ( 例外的情況：如果原始程式以交談方式工作，但它通常並不列印這樣的聲明， 那麼您基於此程式的作品也就不用列印聲明)。

這些要求適用於整個修改過的作品。如果能夠確定作品的一部分並非本程式的衍生產品， 且可以合理地單獨考慮並將它與原作品分開的話，則當您將它作為獨立的作品發佈時， 它不受此許可證和其條款的約束。但是當您將這部分與基於本程式的作品一同發佈時， 則整個套件將受到本許可證條款約束，因為本許可證對於其他許可證持有人的授權擴大到整個產品， 也就是套件的每個部分，不管它是誰寫的。

因此，本條款的意圖不在於剝奪您對完全由您自身完成作品的權利， 而是履行權利來控制基於本程式的集體作品或衍生作品的發佈。

此外，將與本程式無關的作品和本程式 ( 或本程式的衍生作品 ) 一起放在貯存媒體或發佈媒體的同一卷上，並不導致將其他作品置於此許可證的約束範圍之內。

1. 您可以以目標碼或可執行形式複製或發佈程式 ( 或符合第 2 款，本程式的衍生作品 )， 只要您遵守前面的第 1、2 款，並同時滿足下列三條中的任一條。

- 在通常用作軟體交換的媒體上，和目標碼一起附有機器可讀的完整的本程式原始碼。 這些原始碼的發佈應符合上面第 1，2 款的要求。或者

- 在通常用作軟體交換的媒體上，和目標碼一起，附上書面報價，提供替第三方複製原始碼的服務。 該書面報價有效期不得少於 3 年，費用不得超過完成原程式發佈的實際成本，原始碼的發佈應符合上面的第 1，2 款的要求。或者

- 和目標碼一起，附有您收到的發佈原碼的報價信息。 ( 這一條款只適用於非商業性發佈，而且您只收到程式的目標碼或可執行碼，和按 b 款要求提供的報價 )

作品的原始碼指的是對作品進行修改最優先擇取的形式。對可執行的作品而言，完整的原始碼套件包括： 所有模組的所有原始程式，加上有關的介面的定義，加上控制可執行作品的安裝和編譯的 script。至於那些通常伴隨著執行本程式所需的作業系統元件 ( 如編譯器、核心等 ) 而發佈的軟體 ( 不論是原始碼或可執行碼 )，則不在本許可證要求以程式原始碼形式伴隨發佈之列， 除非它是本程式的一部分。

如果可執行碼或目標碼是以指定複製地點的方式來發佈，那麼在同一地點提供等價的原始碼複製服務 也可以算作原始碼的發佈，然而第三方並不需因此而負有必與目標碼一起複製原始碼的義務。

1. 除了本許可證明白聲明的方式之外, 您不能複製，修改，轉發許可證和發佈程式。任何試圖用其他方式複製， 修改，轉發許可證和發佈程式是無效的，而且將自動結束許可證賦予您的權利。然而， 對那些從您那裡按許可證條款得到副本和權利的人們，只要他們繼續全面履行條款，許可證賦予他們的權利仍然有效。

2. 您沒有在許可證上簽字，因而您沒有必要一定接受此一許可證。然而， 沒有任何其他東西賦予您修改和發佈程式及其衍生作品的權利。如果您不接受許可證， 這些行為是法律禁止的。因此，如果您修改或發佈程式 ( 或本程式的衍生作品 ) ，您就表明您接受這一許可證以及它的所有有關複製、 發佈和修改程式或基於程式的作品的條款和條件。

3. 每當您重新發佈程式 ( 或任何程式的衍生作品 ) 時，接受者自動從原始許可證頒發者那裡接到 受這些條款和條件支配的複製、發佈或修改本程式的許可。您不可以增加任何條款來進一步限制本許可證賦予他們的權利。 您也沒有強求第三方履行許可證條款的義務。

4. 如果由於法院判決或違反專利的指控或任何其他原因 ( 不限於專利問題 ) 的結果，使得強加於您的條件 ( 不管是法院判決，協議或其他 ) 和許可證的條件有衝突時，他們也不能令您背離許可證的條款。 在您不能同時滿足本許可證規定的義務及其他相關的義務來發佈程式時，則結果您只能夠根本不發佈程式。 例如，如果某一專利許可證不允許所有直接或間接從您那裡接受副本的人們，在不付專利費的情況下重新發佈程式， 唯一能同時滿足兩方面要求的辦法是停止發佈程式。

如果本條款的任何部分在特定的環境下無效或無法實施，就使用條款的其餘部分，並將這部分條款作為整體用於其他環境。

本條款的目的不在於引誘您侵犯專利或其他財產權的要求，或爭論這種要求的有效性。 本條款的主要目的在於保護自由軟體發佈系統的完整性。它是通過公共許可證的應用來實現的。 許多人已依賴同是出自此系統的應用程式，經由此系統發佈大量自由軟體而做出慷慨的供獻。作者 / 捐獻者有權決定他/她是否通過任何其他系統發佈軟體，許可證接受者不能強迫作者 / 捐獻者做某種特定的選擇。

我們相信許可證其他部分已涵蓋本節所述狀況，本節目的只在更明確說明許可證其餘部分可能產生的結果。

5. 如果由於專利或者由於有版權的介面問題使程式在某些國家的發佈和使用受到限制， 則以本許可證發佈程式的原始作者可以增加發佈地區的限制條款，將這些國家明確排除在外， 並在這些國家以外的地區發佈程式。在這種情況下，這些限制條款如同寫入本許可證一樣，成為許可證的條款。

6. 自由軟體基金會可能隨時出版通用公共許可證的修改版或新版。新版和當前的版本在精神上保持一致， 但在細節上可能有出入，以處理新的問題與狀況。

每一版本都有不同的版本號。如果程式指定可適用的許可證版本號以及 "任何更新的版本" ，您有權選擇遵循指定的版本或自由軟體基金會以後出版的新版本。 如果程式未指定許可證版本，您可選擇自由軟體基金會已經出版的任何版本。

7. 如果您願意將程式的一部分結合到其他自由程式中，而它們的發佈條件不同，請寫信給作者，要求準予使用。 如果是自由軟體基金會加以版權保護的軟體，請寫信給自由軟體基金會，我們有時會作為例外的情況處理。 我們的決定受兩個主要目標的指導，這兩個主要目標是：我們的自由軟體的衍生作品繼續保持自由狀態， 以及從整體上促進軟體的共享和重複利用。

8. 沒有擔保

由於程式准予免費使用，在適用法准許的範圍內，對程式沒有擔保。除非另有書面說明， 版權所有者和/或其他提供程式的人們 "一樣" 不提供任何類型的擔保，不論是明確的，還是隱含的，包括但不限於可銷售和適合特定用途的隱含保證。 全部的風險，如程式的質量和性能問題都由您來承擔。如果程式出現缺陷，您應當承擔所有必要的服務、 修復和改正的費用。

9. 除非適用法或書面協議的要求，在任何情況下， 任何版權所有者或任何按許可證條款修改和發佈程式的人們都不對您的損失負有任何責任。 包括由於使用或不能使用程式引起的任何一般的、特殊的、偶然發生的或重大的損失 ( 包括但不限於數據的損失，或者數據變得不精確，或者您或第三方的持續的損失，或者程式不能和其他程式協調運行等 ) 。即使版權所有者和其他人已被告知這種損失的可能性也不例外。

條款結束

譯註：以下不是法律條文，只是要教一般的程式設計師如何使用 GNU GPL

如何將這些條款用到您的新程式

如果您開發了新程式，而且您需要它得到公眾最大限度的利用，要做到這一點的最好辦法是將它施以 GNU GPL，使得每個人都能循此條款來修改和重新發佈你寫的軟體。

為了做到這一點，請將程式附上下列聲明。最安全的方式是將它放在每個原始碼檔案的開頭，以便最有效地傳遞沒有擔保的信息。每個文件至少應有 "版權所有" 行以及在什麼地方能看到聲明全文的說明。

用一行空間描述程式的名稱和它的用途版權所有 (C) 19XX 作者姓名

本程式是自由軟體，您可以遵照自由軟體基金會 ( Free Software Foundation ) 出版的 GNU 通用公共許可證條款 ( GNU General Public License ) 第二版來修改和重新發佈這一程式，或者自由選擇使用任何更新的版本。

發佈這一程式的目的是希望它有用，但沒有任何擔保。甚至沒有適合特定目的而隱含的擔保。更詳細的情況請參閱 GNU 通用公共許可證。

您應該已經和程式一起收到一份 GNU 通用公共許可證的副本。如果還沒有，寫信給：

Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

此外還應加上如何和您保持聯繫的信息。

如果程式以交談方式進行工作，當它開始進入交互方式工作時，應輸出類似下面的簡短聲明：

Gnomovision 第 69 版，版權所有 (C) 19XX，作者姓名， Gnomovision 絕對沒有擔保。要知道詳細情況，請輸入 "show w"。 這是自由軟體，歡迎您遵守一定的條件重新發佈它，要知道詳細情況，請輸入 "show c"。

假設的命令 "show w" 和 "show c" 應顯示通用公共許可證的相應條款。當然，您使用的命令名稱可以不同於 "show w" 和 "show c" 。根據您的程式的具體情況，也可以用選單或滑鼠來顯示這些條款。

如果需要，您應該取得您的上司 ( 如果您是程式員 ) 或您的學校簽署放棄程式版權的聲明。下面只是一個例子，您應該改變相應的名稱：

Yoyodyne 公司以此方式放棄 James Hacker 所寫的 Gnomovision 程式的全部版權利益。

Ty coon 簽名，1989.4.1 Ty coon 副總裁

這一許可證不允許您將程式併入私有程式。如果您的程式是一個子函式庫。您可能會認為讓它和私有的應用程式連接會更有用。如果您想這麼做，請使用 GNU 函式庫通用公共許可證代替本許可證。

附錄 B： EXT2 / EXT3 檔案系統

第二延伸檔案系統 (EXT2)

全文出處： http://www.freeos.com/articles/3912/

第二延伸檔案系統(ext2)介紹

自從我們開始使用電腦後，大多數的使用者都曾經使用過檔案，而我們總是對關於硬碟如何正確地儲存檔案感到好奇， 它看起來似乎非常抽象，所以今天讓我們看一看 Linux 作業系統中較新的檔案系統版本『第二延伸系統( ext2 )』 ，並了解它各方面之用途。

這個檔案系統是主要來自於 Andrew Tanenbaum 所寫的 Minix 檔案系統，它也是唯一可用在免費作業系統的檔案系統，稱之為 Minix。它後來修正為 Linux 所慣用的檔案系統並稱為延伸檔案系統，到現在 Linux 的檔案系統稱為 ext2 (第二延伸檔案系統)，它是延伸檔案系統中較新的版本並支援存取控制列(ACL)。

但是在著手研究 ext2 檔案系統之前，讓我們先了解檔案系統中之專有名詞的關聯。

- Block (區塊)： 檔案在磁碟中被儲存在整數固定大小的區塊中， 那區塊的大小通常是2的次方。在預設中，ext2檔案系統的區塊大小是4K。研究顥示， 4K位元組對於一磁碟區塊而言是最理想的大小，假如一個檔案的大小無法達成4K位元組的倍數時， 那最後的磁碟區塊部分就會被浪費。在最不好的例子中幾乎在完整的區塊中就有一位元組被浪費掉。

對於這情況有一點技巧，假如我們選擇了一個較大的區塊，則對於小的檔案而言會有一些磁碟空間被浪費掉。 另外一方面，假如我們使用一個非常小的區塊，則磁碟區塊數量會成指數的增加， 因此對於檔案而言需有更多的搜尋時間。所以，選擇區塊大小必須三思而後行。

當一個檔案被載入到記憶體時，那磁碟區塊會被放在主記憶體中之緩衝快取區，假如它們已經變更了， 區塊在緩衝區中會被標記為’Dirty’， 其意指的是這些區塊必須先寫到磁碟中來維持磁碟上的區塊及在主記憶體中的區塊之一致性．

- Superblock：superblock 是在每個檔案系統開始的位置， 其儲存資訊像是檔案系統的大小，空的和填滿的區塊，它們各自的總數和其他諸如此類的資料。 要從一個檔案系統中存取任何檔案皆須經過檔案系統中之superblock。如果superblock損壞了， 它可能無法從磁碟中去取得資料。

- Inode: 對於檔案系統而言一個inode是在inode表格中的一個項目。 Inode包含了所有檔案有關的資訊例如名稱、大小、連接的數量、資料建立之日期，修改及存取的時間。 它也包含了磁碟區塊的檔案指向(pointer)。pointer是用來記錄檔案被儲存在何處。

Ext2fs公用程式

現在讓我們來看看一些標準Linux版本之ext2fsprogs公用程式：

- e2fsck

這個程式允許我們在ext2檔案系統上去執行檔案系統檢查，它像是Windows中之 Scandisk一樣，但卻是一種更有效的系統檢查方式。在此，我們可以加上一個檔案名稱來檢查上面之損壞區塊。

警告:絕對不要在任何已掛載的檔案系統上執行 e2fsck/fsck。假如我們想要去執行 fsck，我們應該卸下檔案系統後再去執行 fsck（亦即需要 umount 該磁區囉）。如果不這樣做，可能會讓檔案系統毀損。

- tune2fs

這允許我們去調整檔案系統的參數設定。在此，我們可以設定在兩個檔案系統檢查間之最大掛載總數、 容量標記、錯誤行為、變更保留的資訊和許多其他參數。

- dumpe2fs

這個程式將ext2檔案系統狀態輸出到標準的設備上。它對於分析問題以及存取一般關於檔案系統用法的資訊是有幫助的。

- mke2fs

這個程式允許我們在先前尚未格式化的磁碟中，去建立一個ext2的檔案系統。 它提供了許多的選項包含區塊的大小、段落的大小、每一個inode的位元組到多種磁碟陣列的選項。 mke2fs通常在第一次安裝的期間執行，並建立完成新的 root 及其他的檔案系統。（就相當於 DOS 底下的 format 程式啦！）

- badblocks

這個程式去搜尋磁碟並檢查區塊是否已經損壞，它通常會在新的檔案系統安裝程式前執行， 但請不要在掛載好的檔案系統上執行。

在Linux檔案系統中最新的版本被稱為ext3，並已有 Journaling 之支援。Journaling 檔案系統對於所有已完成的步驟，持有記錄以及檢查點，所以假使系統當機時，它可以從最後的檢查點來還原檔案系統。

為何選擇 EXT3 呢

全文出處： http://www.linuxplanet.com/linuxplanet/reports/3726/1/

Red Hat Linux 7.2 為何決定採用ext3檔案系統？

Red Hat決定在7.2版中使用 ext3 的格式來作為預設的檔案系統在，引起相當多熟悉 Linux 使用者的關注，但 ext3 並不是唯一的，也不是眾多日誌式 (journaling)檔案系統中最佳的。

傳統的 Linux 檔案系統 ext2，對於在相當小容量的硬碟上之小檔案而言是相當的理想。隨著硬碟的容量及檔案大小大幅增加， 整體性能會下滑。有些原因是來自讀取未有效利用的磁碟空間，有些原因是來自不正常關機或是電源中斷檔案系統的恢復時間。 檔案系統經由 e2fsck 在一個 1GB 的硬碟做檢查是毫不費力的，但相同的測試在 40GB 的硬碟上可能會相當的秏費時間。 所以就有日誌式檔案系統的誕生。

這些記錄硬碟狀態的檔案稱為日誌。 所以在不正確關機之後重新啟動需要參考到日誌檔案來重新回復檔案系統的狀態， 而非將整個硬碟做掃描。 同時， 日誌式檔案系統可以有更高的硬碟空間使用效率及使資料在各種不同之檔案大小中能夠快速的讀取及寫入。

Linux並不是只有一個日誌式的檔案系統，它有四個，或是說成三又二分之一個：

- Reiser檔案系統： 依照 Hans Reiser 的名字而取。Reiser 是眾所皆知的一種新式快速記錄硬碟內容的檔案系統，它曾經被廣泛的使用超過一年， 且這個檔案系統被推薦安裝在 SuSE7.1版及7.2版上。

- JFS檔案系統：經由 IBM 所開發的，其設計的理念在於提供一高速的處理能力。 IBM 從 2000 年 2 月間開始經過一系列的測試版本，它的 1.0 版本已在六月底公開發表。

- XFS 檔案系統：XFS 是 SGI 公司在 Linux 上所開發的日誌式檔案系統， 它也提供了所有以完整發展為特色的日誌式檔案系統。

- ext3 檔案系統：ext3 是之前所提及的二分之一日誌式檔案系統。 為何只有一半呢?原因是 ext3 是一種疊在傳統 ext2 檔案系統上面並保有磁碟活動紀錄的日誌式檔案系統。 所以當不正確關機時，檔案的恢復速度會比 ext2 檔案系統來的快。但是，因為它是被結合在 ext2 中，它會遭受到一些老舊系統的限制並因此不能利用所有日誌式檔案系統的完整功能。 這樣並非是完全不好，因為 ext3 分割區並沒有不同於 ext2 檔案系統，因此如 ext3 損毀要回到 ext2檔案系統卻是非常的簡單。

Red Hat 是第一個採用 ext3 的公司，它嘗試性的將 Linux 檔案系統推向日誌式檔案系統。當公司計畫在 7.2 版的第二個測試版本採用 ext3 時，公司中首席核心開發者Michael K. Johnson便迅速的提供一個原理的闡述：

”為什麼你想要從 ext2 轉換到 ext3 呢？有四個主要的理由： 可利用性、資料完整性、速度及易於轉換”。可利用性，他指出，這意味著從系統中止到快速重新復原而不是持續的讓 e2fsc k執行長時間的修復。ext3 的日誌式條件可以避免資料毀損的可能。他也指出”除了寫入若干資料超過一次時， ext3 往往會較快於 ext2，因為 ext3 的日誌使硬碟讀取頭的移動能更有效的進行“。 然而或許決定的因素還是在Johnson先生的第四個理由中：

“它是可以輕易的從 ext2 變更到 ext3 來獲得一個強而有力的日誌式檔案系統而不需要重新做格式化” 他說道。”那是正確的，為了體驗一下 ext3 的好處是不需要去做一種長時間的， 冗長乏味的且易於產生錯誤的備份工作及重新格式化的動作”。

一個簡單的 SPFdisk 分割實例

切換解析度為 800x600

最近更新日期：2005/06/12

磁碟分割是個很重要的學習知識！尤其是在您原本的硬碟空間不足了，或者是新增硬碟了， 或者是為了增加磁碟效能而必須要規劃出比較適當大小的磁碟空間等等。 市面上很多工具可以讓我們來進行磁碟的分割的，不過，都需要錢∼ 當然，您也可以使用 Linux 的 fdisk 程式，不過，純文字介面的方式，可能您也不容易學∼ 相較之下，由台灣人自行開發的 spfdisk (special fdisk) 程式，不但純中文介面， 使用圖形介面的顯示，耗用的系統資源又少！還可以作為開機管理程式！太完美了！趕緊來看看！

1. 什麼是硬碟分割？

2. SPFdisk

2.1 刪除原有分割

2.2 建立主要分割磁區

2.3 儲存分割表

2.4 格式化硬碟

3. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23875

什麼是硬碟分割(Partition)

在開始進行 Linux 之前，應該有很多的工作要做的！最重要的就如同前面『Linux 主機規劃』當中說的，要如何規劃硬碟呢？！到底要如何分割硬碟才好！是要將 swap （虛擬記憶體）規劃的大一點比較好？或者是只要一個根目錄就可以了呢？另外，如果我的硬碟上面已經有 Windows 系統，我又不想要將 Windows 殺掉，想使用多重開機來安裝我的多個作業系統，那要怎麼做呢？！況且，由於 DOS 的 fdisk 不認識 Linux 的檔案格式，那麼我要如何將 Linux 完全的從我的硬碟中移除呢？！呵呵！ 這裡就來說一下該如何是好吧！

由於不同的作業系統所使用的檔案系統架構(file system)並不相同，有些甚至是不相容的，例如 Windows 所使用的是 FAT 表，而 Linux 所使用的是 ext2 這個檔案格式，這兩種格式完全不相同，在 Linux 底下還可以藉由編輯核心來支援 Windows 的 FAT 檔案格式，但是 Windows 則完全無法讀取 Linux 的檔案格式了！此外， Windows 使用的磁碟分割工具 fdisk ，很抱歉的，並不認識 Linux 的 ext2 這個檔案格式，所以如果您有一棵已經安裝有 Linux 系統的硬碟，呵呵，使用 Windows 的 fdisk 是完全無法分割這塊硬碟的！

那麼到底什麼是硬碟分割呢？真的要將硬碟用刀子割一割嗎？！不是這樣的，實際上，硬碟是以 sectors(磁區), cylinder(磁柱), partitions(分割槽) 這些東西來作為儲存的單位，而最底層的實體硬碟單位就是 sectors 了，通常一個 sector 大約是 512 bytes 左右。不過，在磁碟進行格式化的時候，可以將數個 sector 格式化成為一個邏輯磁區(logical block)，通稱為 block。blocks 為一個檔案系統(filesystem)存取的最小量。 那麼 partition 是什麼？簡單的來說，你知道你的 Windows 有所謂的 C:, D: 是吧！其實他們是同一顆硬碟，只是利用『磁碟分割表』(partition table)來將實體的硬碟規劃出不同的區塊。

舉個例子說，假設你的硬碟總共有 1024 個 cylinder （利用 blocks 結合而成的硬碟計算單位）， 那麼你在這塊硬碟的檔頭地方 （就是磁碟分割表，可以想成要讀取一塊硬碟時最先讀取的地方）如果寫入你的 partitions 共有兩塊，一塊是 primary 一塊是 extended ，而且 extended 也只規劃成一個 logical ，那麼你的硬碟就是只有兩個槽啦（對於系統來說，真正能使用的有 Primary 與 Logical 的磁區， Extended 並無法直接使用的！需要再加以規劃成為 Logical 才行！ ) ，而且在 partition table 也會記錄 primary 是由『第 n1 個 cylinder 到第 n2 個 cylinder 』，所以囉，這樣子一來，當系統要去讀取 primary （就是 c 槽）的時後，就只會在！n1~n2 之間的實體硬碟當中活動囉！

基本上， Windows 98 系統中的 Fdisk 這支程式僅支援一個 primary 與一個 extended ，其中， extended 可以再細分成多個 logical 的硬碟槽。NT 很抱歉，小弟不熟，所以就不提了！那麼 Linux 呢？嗯！基本上最多可以有 4 個 primary 的硬碟，而可以支援到 3 個 primary 與一個 extended ，其中， extended 若再細分成 logical 的話，則全部 primary + extended + logical 應該可以支援到 64 個之多。底下我們將以 spfdisk 這個全中文介面的 fdisk 磁碟分割工具來介紹如何分割硬碟！(註：更多詳細的磁碟與磁碟分割資訊，可以參考 SPFdisk 的官方網站喔！ 在最底下的參考資料當中有提供連結呢！)

硬碟分割 ==> SPFdisk

SPFdisk 是一套由國人開發完成的全中文介面的硬碟分割工具，他要比微軟出的 Fdisk 功能強多了， 他的好處有：

- 全中文介面讓你一定可以看的懂之外，簡單的類圖形介面可以讓你輕易的進行硬碟分割；

- 除此之外，這套軟體的『DOS工具』內的『格式化工具』格式化硬碟的速度真是 DOS 比不上的， 我格式化一個 30GB 的硬碟不用十秒就可以格式化完全！

另外，其他的優點我在此也不多說了，若有需要你可以自行自一些搜尋網站下載最新的程式， 或從 這裡 下載鳥哥有的程式，不過可能舊一點。

另外，由於 DOS 的 Fdisk 並不認識 Linux 的分割表，所以用 DOS 的 Fdisk 是無法將 Linux 的分割表去除的。因此，你要刪除 Linux 的分割表，只有兩個比較快的方法，一個是以 Linux 直接再分割，一個則是使用 SPfdisk 分割啦！

Tips:

由於您正在閱讀的這個頁面的影像檔案很大，有時候會有沒辦法顯示的情況發生， 這時請在畫面上『按滑鼠右鍵』，再選擇『顯示圖片』這個選項，即可顯示畫面啦！

硬碟分割主要可分為下面幾個步驟：

1. 將舊有的分割表刪除；

2. 建立新的主分割及擴充分割（若有需要的話）；

3. 貯存分割表；

4. 以 DOS 工具格式化已分割的硬碟。

1. 刪除原有的分割：

假設你的主機中沒有任何系統存在，則請以 Windows98 製作開機片後，將 spfdisk 拷貝至開機片。以此磁片開機之後，執行：

A:\>spfdisk

會出現如下歡迎畫面。

按任意鍵後出現下面畫面：

以方向鍵移動游標至『硬碟分割工具』按 Enter 鍵後會出現畫面如下：

這是向你詢問是否需要使用 FAT32 的檔案系統，由於 Windows 98 支援的長檔名及相關的檔案型態是以 FAT32 為準，所以當然按 『Y』！按了 Y 之後會出現硬碟的資訊，如下所示：

因為我是在我原有的機器上執行這個程式，所以會有兩顆硬碟，如果你的系統只有一顆硬碟的話， 則只會顯示你有的硬碟資料，在上圖中，1.19GB 的硬碟其總磁柱僅有 621 單位，比可開機磁區範圍（0 ~ 1023）小得多，所以可以隨意分割。將游標以方向鍵移動至 1.19GB 這顆硬碟後，按 Enter ：

因為這顆硬碟之前被我灌過 Linux ，所以會顯示 Linux 的磁區劃分情況。上面的意義為：

- 啟動：由於系統開機時會去先去找分割表， 由分割表所設定的『可開機磁區』進行開機程序， 因此若這個磁區為開機磁區，則『啟動』項目會有一個心型的符號存在！

- 起始磁柱與結束磁柱：這一個被分割的磁區的開始與結束磁區。

- MBytes：這個磁區的硬碟容量。

- 系統 ID 與系統種類：這一個分割表的類型。因為這是 Linux 的分割類型，所以其 ID 顯示為 83，若是 FAT32 的話，則為 0b。

將游標以方向鍵移動至這個磁區後，按 Enter ：

在這個畫面中，將游標以方向鍵移動至『刪除分割』這個項目，並按下 Enter ：

出現此畫面後，確定要刪除這個分割就按『[Y]是』這個項目。

刪除分割之後你的硬碟中就沒有分割表的存在了，所以這個硬碟的系統種類則變成了 未規劃。

2. 建立主要分割磁區：

在上面的畫面中，按下 Enter 鍵，會出現下面畫面。

由於這一顆硬碟的分割表被刪除了，所以『系統ID』與『刪除分割』被取消了。這時按下『建立分割』會出現如下畫面：

然後選擇『建立主分割』，那何謂主分割與擴充分割呢？所謂的主分割在 windows 系統下即是 『C槽』 啦！ 但是擴充分割並非『邏輯分割』，這裡要注意一下， 所謂的『邏輯分割』是包含在擴充分割中的，例如當你的擴充分割共有 10GB 但是你想將之分為兩槽，則可以使用邏輯分割將擴充分割分為兩槽， 這兩槽即稱為『邏輯分割』。所以這裡要注意啦，建立擴充分割的時候就要選擇『配置整個區域』啦！ 好！下一步按下『建立主分割』：

這裡會問你是否要將整個硬碟分割為僅有一個磁碟區？由於我們要將硬碟分為兩槽， 所以這裡當然選擇『[N]否』啦！

由於你選擇了『不要配置整個區域為一塊磁區』，所以這時程式要你輸入你所需要的磁區。 通常在第一步是輸入『啟始磁柱』，這時只要按 Enter 就可以啦，然後會要你輸入『結束磁柱』， 結束磁柱的輸入方法有兩種模式，一種是輸入磁柱區，一種是輸入你所需要的 MB 數，通常我是輸入 MB 數啦，例如如上所示，我所需要的空間大小是 600MB ， 所以輸入『+600』即可，而如果你的硬碟很大，你要輸入 4GB 時，則需要輸入 『+4000』，以此類推！輸入『+600』並按 Enter 之後出現如下畫面。

這時出現了你剛剛劃分的硬碟資訊啦，由於我們是劃分為 DOS 分割區，所以系統種類是 FAT-32 ，而 ID 則為 0b 。至於另外尚未劃分的就會顯示為 <未規劃> 啦！如果你還需要再繼續劃分的話，這時將游標移動至 <未規劃> 的那一個磁區按 Enter 後選擇『擴充分割』即可繼續劃分。如果劃分完畢之後， 當然就是貯存分割表囉。這裡注意一下，因為剛剛的動作均尚未完成貯存的工作，所以要反悔還來得及！

3. 貯存分割表：

接下來要做貯存的動作了，按下『Esc』鍵 （鍵盤左上角那個鍵）後會出現如下畫面：

按『[Y]是』，將剛分割好的分割表貯存至硬碟中！ 然後出現如下畫面：

這裡的動作是連續的：

1. 程式會先跟你確認你的硬碟有沒有錯誤，這裡還可以反悔。

2. 然後程式會問你是否需要使用破壞貯存，一般來說是需要使用『破壞貯存』的， 因為需要將你的硬碟劃分完全啦！所以要按 [Y]；

3. 為了可以讓你以後回復分割情況，所以你可以選擇 『建立 UNDO』檔，所謂的 UNDO 檔即是記錄你之前硬碟分割表資訊的檔案啦。

這樣一來你的硬碟就劃分完畢而且貯存啦！這時要做的就是重新開機並格式化硬碟。格式化硬碟可以使用 DOS 的 Format ，當然也可以使用 spfdisk 的內建功能喔！

4. 格式化硬碟：

再進入剛剛你劃分完畢的那個硬碟區，按下 Enter 之後會出現一串選單，然後最下方的選單為 『DOS 工具』，選擇這一項並按 Enter 後，會出現另一個選單：

在這個次選單中的第二項即是快速格式化，這個格式化的動作非常的快喔！比 DOS 的格式化快多了！不過，這裡也必須指出一個問題，那就是若你的硬碟有壞軌的話，那最好還是使用 DOS 的 format 比較完整一點。

參考資料

- SPFdisk http://spfdisk.sourceforge.net/

事實上， SFPdisk 能作的事情還很多，包括最為人所熟知的 boot loader 的應用！ 建議您一定要到 SPFdisk 的官方網站上面瞧一瞧喔！ ^_^

2002/04/09：第一次完成吧？

2003/02/03：重新編排

2005/06/12：將舊文移動到 這裡 。並且約略編排了一下版面！

2005/07/18：原本文章當中的 cluster 為錯誤的，應該是 cylinder 才對∼

2002/01/01以來統計人數

- 記憶體欄位 (procs) 的項目分別為：

r ：等待運作中的程序數量；b：不可被喚醒的程序數量。這兩個項目越多，代表系統越忙碌 (因為系統太忙，所以很多程序就無法被執行或一直在等待而無法被喚醒之故)。

- 記憶體欄位 (memory) 項目分別為：

swpd：虛擬記憶體被使用的容量； free：未被使用的記憶體容量； buff：用於緩衝記憶體； cache：用於快取記憶體。 這部份則與 free 是相同的。

- 記憶體置換空間 (swap) 的項目分別為：

si：由磁碟中將程序取出的量； so：由於記憶體不足而將沒用到的程序寫入到磁碟的 swap 的容量。 如果 si/so 的數值太大，表示記憶體內的資料常常得在磁碟與主記憶體之間傳來傳去，系統效能會很差！

- 磁碟讀寫 (io) 的項目分別為：

bi：由磁碟寫入的區塊數量； bo：寫入到磁碟去的區塊數量。如果這部份的值越高，代表系統的 I/O 非常忙碌！

- 系統 (system) 的項目分別為：

in：每秒被中斷的程序次數； cs：每秒鐘進行的事件切換次數；這兩個數值越大，代表系統與周邊設備的溝通非常頻繁！ 這些周邊設備當然包括磁碟、網路卡、時間鐘等。

- CPU 的項目分別為：

us：非核心層的 CPU 使用狀態； sy：核心層所使用的 CPU 狀態； id：閒置的狀態； wa：等待 I/O 所耗費的 CPU 狀態； st：被虛擬機器 (virtual machine) 所盜用的 CPU 使用狀態 (2.6.11 以後才支援)。

由於鳥哥的機器是測試機，所以並沒有什麼 I/O 或者是 CPU 忙碌的情況。如果改天你的伺服器非常忙碌時， 記得使用 vmstat 去看看，到底是哪個部分的資源被使用的最為頻繁！一般來說，如果 I/O 部分很忙碌的話，你的系統會變的非常慢！ 讓我們再來看看，那麼磁碟的部分該如何觀察：

範例二：系統上面所有的磁碟的讀寫狀態

[root@www ~]# vmstat -d

disk- ------------reads------------ ------------writes----------- -----IO------

total merged sectors      ms  total merged sectors      ms    cur    sec

ram0       0      0       0       0      0      0       0       0      0      0

....(中間省略)....

hda   144188 182874 6667154 7916979 151341 510244 8027088 15244705      0    848

hdb        0      0       0       0      0      0       0       0      0      0

詳細的各欄位就請諸位大德查閱一下 man vmstat 囉！反正與讀寫有關啦！這樣瞭解乎！

特殊檔案與程序

我們在第七章曾經談到特殊權限的 SUID/SGID/SBIT ，雖然第七章已經將這三種特殊權限作了詳細的解釋，不過，我們依舊要來探討的是，那麼到底這些權限對於你的『程序』是如何影響的？ 此外，程序可能會使用到系統資源，舉例來說，磁碟就是其中一項資源。哪天你在 umount 磁碟時，系統老是出現『 device is busy 』的字樣∼到底是怎麼回事啊？我們底下就來談一談這些和程序有關係的細節部分：

具有 SUID/SGID 權限的指令執行狀態

SUID 的權限其實與程序的相關性非常的大！為什麼呢？先來看看 SUID 的程式是如何被一般使用者執行，且具有什麼特色呢？

- SUID 權限僅對二進位程式(binary program)有效；

- 執行者對於該程式需要具有 x 的可執行權限；

- 本權限僅在執行該程式的過程中有效 (run-time)；

- 執行者將具有該程式擁有者 (owner) 的權限。

所以說，整個 SUID 的權限會生效是由於『具有該權限的程式被觸發』，而我們知道一個程式被觸發會變成程序， 所以囉，執行者可以具有程式擁有者的權限就是在該程式變成程序的那個時候啦！第七章我們還沒談到程序的概念， 所以你或許那時候會覺得很奇怪，為啥執行了 passwd 後你就具有 root 的權限呢？不都是一般使用者執行的嗎？ 這是因為你在觸發 passwd 後，會取得一個新的程序與 PID，該 PID 產生時透過 SUID 來給予該 PID 特殊的權限設定啦！ 我們使用 dmtsai 登入系統且執行 passwd 後，透過工作控制來理解一下！

[dmtsai@www ~]$ passwd

Changing password for user dmtsai.

Changing password for dmtsai

(current) UNIX password: <==這裡按下 [ctrl]-z 並且按下 [enter]

[1]+  Stopped                 passwd

[dmtsai@www ~]$ pstree -u

init-+-acpid

....(中間省略)....

|-sshd---sshd---sshd(dmtsai)---bash-+-more

|                                   |-passwd(root)

|                                   `-pstree

....(底下省略)....

從上表的結果我們可以發現，底線的部分是屬於 dmtsai 這個一般帳號的權限，特殊字體的則是 root 的權限！ 但你看到了， passwd 確實是由 bash 衍生出來的！不過就是權限不一樣！透過這樣的解析， 你也會比較清楚為何不同程式所產生的權限不同了吧！這是由於『SUID 程式運作過程中產生的程序』的關係啦！

那麼既然 SUID/SGID 的權限是比較可怕的，您該如何查詢整個系統的 SUID/SGID 的檔案呢？ 應該是還不會忘記吧？使用 find 即可啊！

find / -perm +6000

/proc/* 代表的意義

其實，我們之前提到的所謂的程序都是在記憶體當中嘛！而記憶體當中的資料又都是寫入到 /proc/* 這個目錄下的，所以囉，我們當然可以直接觀察 /proc 這個目錄當中的檔案啊！ 如果你觀察過 /proc 這個目錄的話，應該會發現他有點像這樣：

[root@www ~]# ll /proc

dr-xr-xr-x  5 root      root              0 Mar 11 08:46 1

dr-xr-xr-x  5 root      root              0 Mar 11 00:46 10

dr-xr-xr-x  5 root      root              0 Mar 11 00:46 11

....(中間省略)....

-r--r--r--  1 root      root              0 Mar 20 12:11 uptime

-r--r--r--  1 root      root              0 Mar 20 12:11 version

-r--r--r--  1 root      root              0 Mar 20 12:11 vmstat

-r--r--r--  1 root      root              0 Mar 20 12:11 zoneinfo

基本上，目前主機上面的各個程序的 PID 都是以目錄的型態存在於 /proc 當中。 舉例來說，我們開機所執行的第一支程式 init 他的 PID 是 1 ， 這個 PID 的所有相關資訊都寫入在 /proc/1/* 當中！若我們直接觀察 PID 為 1 的資料好了，他有點像這樣：

[root@www ~]# ll /proc/1

dr-xr-xr-x 2 root root 0 Mar 12 11:04 attr

-r-------- 1 root root 0 Mar 17 14:32 auxv

-r--r--r-- 1 root root 0 Mar 17 14:32 cmdline  <==就是指令串

-rw-r--r-- 1 root root 0 Mar 17 14:32 coredump_filter

-r--r--r-- 1 root root 0 Mar 17 14:32 cpuset

lrwxrwxrwx 1 root root 0 Mar 17 14:32 cwd -> /

-r-------- 1 root root 0 Mar 17 14:32 environ  <==一些環境變數

lrwxrwxrwx 1 root root 0 Mar 17 14:32 exe -> /sbin/init  <==實際執行的指令

....(以下省略)....

裡面的資料還挺多的，不過，比較有趣的其實是兩個檔案，分別是：

- cmdline：這個程序被啟動的指令串；

- environ：這個程序的環境變數內容。

很有趣吧！如果你查閱一下 cmdline 的話，就會發現：

[root@www ~]# cat /proc/1/cmdline

init [5]

就是這個指令、選項與參數啟動 init 的啦！這還是跟某個特定的 PID 有關的內容呢，如果是針對整個 Linux 系統相關的參數呢？那就是在 /proc 目錄底下的檔案啦！相關的檔案與對應的內容是這樣的： (註3)

檔名

檔案內容

/proc/cmdline

載入 kernel 時所下達的相關參數！查閱此檔案，可瞭解系統是如何啟動的！

/proc/cpuinfo

本機的 CPU 的相關資訊，包含時脈、類型與運算功能等

/proc/devices

這個檔案記錄了系統各個主要裝置的主要裝置代號，與 mknod 有關呢！

/proc/filesystems

目前系統已經載入的檔案系統囉！

/proc/interrupts

目前系統上面的 IRQ 分配狀態。

/proc/ioports

目前系統上面各個裝置所配置的 I/O 位址。

/proc/kcore

這個就是記憶體的大小啦！好大對吧！但是不要讀他啦！

/proc/loadavg

還記得 top 以及 uptime 吧？沒錯！上頭的三個平均數值就是記錄在此！

/proc/meminfo

使用 free 列出的記憶體資訊，嘿嘿！在這裡也能夠查閱到！

/proc/modules

目前我們的 Linux 已經載入的模組列表，也可以想成是驅動程式啦！

/proc/mounts

系統已經掛載的資料，就是用 mount 這個指令呼叫出來的資料啦！

/proc/swaps

到底系統掛載入的記憶體在哪裡？呵呵！使用掉的 partition 就記錄在此啦！

/proc/partitions

使用 fdisk -l 會出現目前所有的 partition 吧？在這個檔案當中也有紀錄喔！

/proc/pci

在 PCI 匯流排上面，每個裝置的詳細情況！可用 lspci 來查閱！

/proc/uptime

就是用 uptime 的時候，會出現的資訊啦！

/proc/version

核心的版本，就是用 uname -a 顯示的內容啦！

/proc/bus/*

一些匯流排的裝置，還有 USB 的裝置也記錄在此喔！

其實，上面這些檔案鳥哥在此建議您可以使用 cat 去查閱看看，不必深入瞭解， 不過，觀看過檔案內容後，畢竟會比較有感覺啦！如果未來您想要自行撰寫某些工具軟體， 那麼這個目錄底下的相關檔案可能會對您有點幫助的喔！

查詢已開啟檔案或已執行程序開啟之檔案

其實還有一些與程序相關的指令可以值得參考與應用的，我們來談一談：

- fuser：藉由檔案(或檔案系統)找出正在使用該檔案的程序

有的時候我想要知道我的程序到底在這次啟動過程中開啟了多少檔案，可以利用 fuser 來觀察啦！ 舉例來說，你如果卸載時發現系統通知：『 device is busy 』，那表示這個檔案系統正在忙碌中， 表示有某支程序有利用到該檔案系統啦！那麼你就可以利用 fuser 來追蹤囉！fuser 語法有點像這樣：

[root@www ~]# fuser [-umv] [-k [i] [-signal]] file/dir

選項與參數：

-u  ：除了程序的 PID 之外，同時列出該程序的擁有者；

-m  ：後面接的那個檔名會主動的上提到該檔案系統的最頂層，對 umount 不成功很有效！

-v  ：可以列出每個檔案與程序還有指令的完整相關性！

-k  ：找出使用該檔案/目錄的 PID ，並試圖以 SIGKILL 這個訊號給予該 PID；

-i  ：必須與 -k 配合，在刪除 PID 之前會先詢問使用者意願！

-signal：例如 -1 -15 等等，若不加的話，預設是 SIGKILL (-9) 囉！

範例一：找出目前所在目錄的使用 PID/所屬帳號/權限 為何？

[root@www ~]# fuser -uv .

USER        PID ACCESS COMMAND

.:                   root      20639 ..c.. (root)bash

看到輸出的結果沒？他說『.』底下有個 PID 為 20639 的程序，該程序屬於 root 且指令為 bash 。 比較有趣的是那個 ACCESS 的項目，那個項目代表的意義為：

- c ：此程序在當前的目錄下(非次目錄)；

- e ：可被觸發為執行狀態；

- f ：是一個被開啟的檔案；

- r ：代表頂層目錄 (root directory)；

- F ：該檔案被開啟了，不過在等待回應中；

- m ：可能為分享的動態函式庫；

那如果你想要查閱某個檔案系統底下有多少程序正在佔用該檔案系統時，那個 -m 的選項就很有幫助了！ 鳥哥的測試主機僅有分割出 /, /boot, /home ，所以無法進行測試。不過好在還有個 /proc 的虛擬檔案系統， 讓我們來瞭解一下這個 /proc 的檔案系統有多少程序正在利用他吧！

範例二：找到所有使用到 /proc 這個檔案系統的程序吧！

[root@www ~]# fuser -uv /proc

# 不會顯示任何資料，因為沒有任何程序會去使用 /proc 這個目錄啊！

# 會被用到的是 /proc 底下的檔案啦！所以你應該要這樣做：

[root@www ~]# fuser -mvu /proc

USER        PID ACCESS COMMAND

/proc:               root       4289 f.... (root)klogd

root       4555 f.... (root)acpid

haldaemon  4758 f.... (haldaemon)hald

root       4977 F.... (root)Xorg

# 有這幾支程序在進行 /proc 檔案系統的存取喔！這樣清楚了嗎？

既然可以針對整個檔案系統，那麼能不能僅針對單一檔案啊？當然可以囉！看一下底下的案例先：

範例三：找到 /var 底下屬於 FIFO 類型的檔案，並且找出存取該檔案的程序

[root@www ~]# find /var -type p

/var/gdm/.gdmfifo     <==我們針對這玩意即可！

/var/run/autofs.fifo-misc

/var/run/autofs.fifo-net

[root@www ~]# fuser -uv /var/gdm/.gdmfifo

USER        PID ACCESS COMMAND

/var/gdm/.gdmfifo:   root       4892 F.... (root)gdm-binary

範例四：同範例三，但試圖刪除該 PID？且『不要』刪除喔！

[root@www ~]# fuser -ki /var/gdm/.gdmfifo

/var/gdm/.gdmfifo:    4892

Kill process 4892 ? (y/N) n

如何？很有趣的一個指令吧！透過這個 fuser 我們可以找出使用該檔案、目錄的程序，藉以觀察的啦！ 他的重點與 ps, pstree 不同。 fuser 可以讓我們瞭解到某個檔案 (或檔案系統) 目前正在被哪些程序所利用！

- lsof ：列出被程序所開啟的檔案檔名

相對於 fuser 是由檔案或者裝置去找出使用該檔案或裝置的程序，反過來說， 如何查出某個程序開啟或者使用的檔案與裝置呢？呼呼！那就是使用 lsof 囉∼

[root@www ~]# lsof [-aUu] [+d]

選項與參數：

-a  ：多項資料需要『同時成立』才顯示出結果時！

-U  ：僅列出 Unix like 系統的 socket 檔案類型；

-u  ：後面接 username，列出該使用者相關程序所開啟的檔案；

+d  ：後面接目錄，亦即找出某個目錄底下已經被開啟的檔案！

範例一：列出目前系統上面所有已經被開啟的檔案與裝置：

[root@www ~]# lsof

COMMAND PID  USER   FD  TYPE  DEVICE   SIZE     NODE NAME

init      1  root  cwd   DIR     3,2   4096        2 /

init      1  root  rtd   DIR     3,2   4096        2 /

init      1  root  txt   REG     3,2  38620  1426405 /sbin/init

....(底下省略)....

# 注意到了嗎？是的，在預設的情況下， lsof 會將目前系統上面已經開啟的

# 檔案全部列出來∼所以，畫面多的嚇人啊！您可以注意到，第一個檔案 init 執行的

# 地方就在根目錄，而根目錄，嘿嘿！所在的 inode 也有顯示出來喔！

範例二：僅列出關於 root 的所有程序開啟的 socket 檔案

[root@www ~]# lsof -u root -a -U

COMMAND     PID USER   FD   TYPE     DEVICE SIZE   NODE NAME

udevd       400 root    3u  unix 0xedd4cd40        1445 socket

auditd     4256 root    7u  unix 0xedd4c380        9081 socket

audispd    4258 root    0u  unix 0xedd4c1e0        9080 socket

# 注意到那個 -a 吧！如果你分別輸入 lsof -u root 及 lsof -U ，會有啥資訊？

# 使用 lsof -u root -U 及 lsof -u root -a -U ，呵呵！都不同啦！

# -a 的用途就是在解決同時需要兩個項目都成立時啊！ ^_^

範例三：請列出目前系統上面所有的被啟動的周邊裝置

[root@www ~]# lsof +d /dev

COMMAND     PID      USER   FD   TYPE     DEVICE SIZE  NODE NAME

init          1      root   10u  FIFO       0,16       1147 /dev/initctl

udevd       400      root    0u   CHR        1,3       1420 /dev/null

udevd       400      root    1u   CHR        1,3       1420 /dev/null

udevd       400      root    2u   CHR        1,3       1420 /dev/null

# 看吧！因為裝置都在 /dev 裡面嘛！所以囉，使用搜尋目錄即可啊！

範例四：秀出屬於 root 的 bash 這支程式所開啟的檔案

[root@www ~]# lsof -u root | grep bash

bash   20639 root  cwd    DIR    3,2    4096    648321 /root

bash   20639 root  rtd    DIR    3,2    4096         2 /

bash   20639 root  txt    REG    3,2  735004   1199424 /bin/bash

bash   20639 root  mem    REG    3,2   46680     64873 /lib/libnss_files-2.5.so

....(底下省略)....

這個指令可以找出您想要知道的某個程序是否有啟用哪些資訊？例如上頭提到的範例四的執行結果呢！ ^_^

- pidof ：找出某支正在執行的程式的 PID

[root@www ~]# pidof [-sx] program_name

選項與參數：

-s  ：僅列出一個 PID 而不列出所有的 PID

-x  ：同時列出該 program name 可能的 PPID 那個程序的 PID

範例一：列出目前系統上面 init 以及 syslogd 這兩個程式的 PID

[root@www ~]# pidof init syslogd

1 4286

# 理論上，應該會有兩個 PID 才對。上面的顯示也是出現了兩個 PID 喔。

# 分別是 init 及 syslogd 這兩支程式的 PID 啦。

很簡單的用法吧，透過這個 pidof 指令，並且配合 ps aux 與正規表示法，就可以很輕易的找到您所想要的程序內容了呢。

SELinux 初探

在進入了 CentOS 5.x 之後，SELinux 已經是個非常完備的核心模組了！CentOS 5.x 提供了很多管理 SELinux 的指令與機制， 因此在整體架構上面比以前的版本要單純且容易操作管理！所以，在這一版以後，我們建議大家千萬不要關掉 SELinux 這玩意兒！ 讓我們來仔細的玩玩這傢伙吧！

什麼是 SELinux

什麼是 SELinux 呢？其實他是『 Security Enhanced Linux 』的縮寫，字面上的意義就是安全強化的 Linux 之意！那麼所謂的『安全強化』是強化哪個部分？ 是網路資安還是權限管理？底下就讓我們來談談吧！

- 當初設計的目標：避免資源的誤用

SELinux 是由美國國家安全局 (NSA) 開發的，當初開發這玩意兒的目的是因為很多企業界發現， 通常系統出現問題的原因大部分都在於『內部員工的資源誤用』所導致的，實際由外部發動的攻擊反而沒有這麼嚴重。 那麼什麼是『員工資源誤用』呢？舉例來說，如果有個不是很懂系統的系統管理員為了自己設定的方便，將網頁所在目錄 /var/www/html/ 的權限設定為 drwxrwxrwx 時，你覺得會有什麼事情發生？

現在我們知道所有的系統資源都是透過程序來進行存取的，那麼 /var/www/html/ 如果設定為 777 ， 代表所有程序均可對該目錄存取，萬一你真的有啟動 WWW 伺服器軟體，那麼該軟體所觸發的程序將可以寫入該目錄， 而該程序卻是對整個 Internet 提供服務的！只要有心人接觸到這支程序，而且該程序剛好又有提供使用者進行寫入的功能， 那麼外部的人很可能就會對你的系統寫入些莫名其妙的東西！那可真是不得了！一個小小的 777 問題可是大大的！

為了控管這方面的權限與程序的問題，所以美國國家安全局就著手處理作業系統這方面的控管。 由於 Linux 是自由軟體，程式碼都是公開的，因此她們便使用 Linux 來作為研究的目標， 最後更將研究的結果整合到 Linux 核心裡面去，那就是 SELinux 啦！所以說， SELinux 是整合到核心的一個模組喔！ 更多的 SELinux 相關說明可以參考：

- http://www.nsa.gov/research/selinux/

這也就是說：其實 SELinux 是在進行程序、檔案等細部權限設定依據的一個核心模組！ 由於啟動網路服務的也是程序，因此剛好也能夠控制網路服務能否存取系統資源的一道關卡！ 所以，在講到 SELinux 對系統的存取控制之前，我們得先來回顧一下之前談到的系統檔案權限與使用者之間的關係。 因為先談完這個你才會知道為何需要 SELinux 的啦！

- 傳統的檔案權限與帳號關係：自主式存取控制, DAC

我們第十四章的內容，知道系統的帳號主要分為系統管理員 (root) 與一般用戶，而這兩種身份能否使用系統上面的檔案資源則與 rwx 的權限設定有關。 不過你要注意的是，各種權限設定對 root 是無效的。因此，當某個程序想要對檔案進行存取時， 系統就會根據該程序的擁有者/群組，並比對檔案的權限，若通過權限檢查，就可以存取該檔案了。

這種存取檔案系統的方式被稱為『自主式存取控制 (Discretionary Access Control, DAC)』，基本上，就是依據程序的擁有者與檔案資源的 rwx 權限來決定有無存取的能力。 不過這種 DAC 的存取控制有幾個困擾，那就是：

- root 具有最高的權限：如果不小心某支程序被有心人士取得， 且該程序屬於 root 的權限，那麼這支程序就可以在系統上進行任何資源的存取！真是要命！

- 使用者可以取得程序來變更檔案資源的存取權限：如果你不小心將某個目錄的權限設定為 777 ，由於對任何人的權限會變成 rwx ，因此該目錄就會被任何人所任意存取！

這些問題是非常嚴重的！尤其是當你的系統是被某些漫不經心的系統管理員所掌控時！她們甚至覺得目錄權限調為 777 也沒有什麼了不起的危險哩...

- 以政策規則訂定特定程序讀取特定檔案：委任式存取控制, MAC

現在我們知道 DAC 的困擾就是當使用者取得程序後，他可以藉由這支程序與自己預設的權限來處理他自己的檔案資源。 萬一這個使用者對 Linux 系統不熟，那就很可能會有資源誤用的問題產生。為了避免 DAC 容易發生的問題，因此 SELinux 導入了委任式存取控制 (Mandatory Access Control, MAC) 的方法！

委任式存取控制 (MAC) 有趣啦！他可以針對特定的程序與特定的檔案資源來進行權限的控管！ 也就是說，即使你是 root ，那麼在使用不同的程序時，你所能取得的權限並不一定是 root ， 而得要看當時該程序的設定而定。如此一來，我們針對控制的『主體』變成了『程序』而不是使用者喔！ 此外，這個主體程序也不能任意使用系統檔案資源，因為每個檔案資源也有針對該主體程序設定可取用的權限！ 如此一來，控制項目就細的多了！但整個系統程序那麼多、檔案那麼多，一項一項控制可就沒完沒了！ 所以 SELinux 也提供一些預設的政策 (Policy) ，並在該政策內提供多個規則 (rule) ，讓你可以選擇是否啟用該控制規則！

在委任式存取控制的設定下，我們的程序能夠活動的空間就變小了！舉例來說， WWW 伺服器軟體的達成程序為 httpd 這支程式， 而預設情況下， httpd 僅能在 /var/www/ 這個目錄底下存取檔案，如果 httpd 這個程序想要到其他目錄去存取資料時， 除了規則設定要開放外，目標目錄也得要設定成 httpd 可讀取的模式 (type) 才行喔！限制非常多！ 所以，即使不小心 httpd 被 cracker 取得了控制權，他也無權瀏覽 /etc/shadow 等重要的設定檔喔！

SELinux 的運作模式

再次的重複說明一下，SELinux 是透過 MAC 的方式來控管程序，他控制的主體是程序， 而目標則是該程序能否讀取的『檔案資源』！所以先來說明一下這些咚咚的相關性啦！(註4)

- 主體 (Subject)：

SELinux 主要想要管理的就是程序，因此你可以將『主體』跟本章談到的 process 劃上等號；

- 目標 (Object)：

主體程序能否存取的『目標資源』一般就是檔案系統。因此這個目標項目可以等檔案系統劃上等號；

- 政策 (Policy)：

由於程序與檔案數量龐大，因此 SELinux 會依據某些服務來制訂基本的存取安全性政策。這些政策內還會有詳細的規則 (rule) 來指定不同的服務開放某些資源的存取與否。在目前的 CentOS 5.x 裡面僅有提供兩個主要的政策，分別是：

- targeted：針對網路服務限制較多，針對本機限制較少，是預設的政策；

- strict：完整的 SELinux 限制，限制方面較為嚴格。

建議使用預設的 targeted 政策即可。

- 安全性本文 (security context)：

我們剛剛談到了主體、目標與政策面，但是主體能不能存取目標除了政策指定之外，主體與目標的安全性本文必須一致才能夠順利存取。 這個安全性本文 (security context) 有點類似檔案系統的 rwx 啦！安全性本文的內容與設定是非常重要的！ 如果設定錯誤，你的某些服務(主體程序)就無法存取檔案系統(目標資源)，當然就會一直出現『權限不符』的錯誤訊息了！

圖 5.2.1、SELinux 運作的各元件之相關性(本圖參考小州老師的上課講義)

上圖的重點在『主體』如何取得『目標』的資源存取權限！ 由上圖我們可以發現，主體程序必須要通過 SELinux 政策內的規則放行後，就可以與目標資源進行安全性本文的比對， 若比對失敗則無法存取目標，若比對成功則可以開始存取目標。問題是，最終能否存取目標還是與檔案系統的 rwx 權限設定有關喔！如此一來，加入了 SELinux 之後，出現權限不符的情況時，你就得要一步一步的分析可能的問題了！

- 安全性本文 (Security Context)

CentOS 5.x 已經幫我們制訂好非常多的規則了，這部份你只要知道如何開啟/關閉某項規則的放行與否即可。 那個安全性本文比較麻煩！因為你可能需要自行設定檔案的安全性本文呢！為何需要自行設定啊？ 舉例來說，你不也常常進行檔案的 rwx 的重新設定嗎？這個安全性本文你就將他想成 SELinux 內必備的 rwx 就是了！這樣比較好理解啦。

安全性本文存在於主體程序中與目標檔案資源中。程序在記憶體內，所以安全性本文可以存入是沒問題。 那檔案的安全性本文是記錄在哪裡呢？事實上，安全性本文是放置到檔案的 inode 內的，因此主體程序想要讀取目標檔案資源時，同樣需要讀取 inode ， 這 inode 內就可以比對安全性本文以及 rwx 等權限值是否正確，而給予適當的讀取權限依據。

那麼安全性本文到底是什麼樣的存在呢？我們先來看看 /root 底下的檔案的安全性本文好了。 觀察安全性本文可使用『 ls -Z 』去觀察如下：(注意：你必須已經啟動了 SELinux 才行！若尚未啟動，這部份請稍微看過一遍即可。底下會介紹如何啟動 SELinux 喔！)

[root@www ~]# ls -Z

drwxr-xr-x  root root root:object_r:user_home_t   Desktop

-rw-r--r--  root root root:object_r:user_home_t   install.log

-rw-r--r--  root root root:object_r:user_home_t   install.log.syslog

# 上述特殊字體的部分，就是安全性本文的內容！

如上所示，安全性本文主要用冒號分為三個欄位，這三個欄位的意義為：

Identify:role:type

身份識別:角色:類型

這三個欄位的意義仔細的說明一下吧：

- 身份識別 (Identify)：

相當於帳號方面的身份識別！主要的身份識別則有底下三種常見的類型：

- root：表示 root 的帳號身份，如同上面的表格顯示的是 root 家目錄下的資料啊！

- system_u：表示系統程序方面的識別，通常就是程序囉；

- user_u：代表的是一般使用者帳號相關的身份。

你會發現身份識別中，除了 root 之外，其他的識別後面都會加上『 _u 』的字樣呢！ 這個身份識別重點再讓我們瞭解該資料為何種身份所有哩∼ 而系統上面大部分的資料都會是 system_u 或 root 啦！至於如果是在 /home 底下的資料，那麼大部分應該就會是 user_u 囉！

- 角色 (Role)：

透過角色欄位，我們可以知道這個資料是屬於程序、檔案資源還是代表使用者。一般的角色有：

- object_r：代表的是檔案或目錄等檔案資源，這應該是最常見的囉；

- system_r：代表的就是程序啦！不過，一般使用者也會被指定成為 system_r 喔！

你也會發現角色的欄位最後面使用『 _r 』來結尾！因為是 role 的意思嘛！

- 類型 (Type) ：(最重要！)

在預設的 targeted 政策中， Identify 與 Role 欄位基本上是不重要的！重要的在於這個類型 (type) 欄位！ 基本上，一個主體程序能不能讀取到這個檔案資源，與類型欄位有關！而類型欄位在檔案與程序的定義不太相同，分別是：

- type：在檔案資源 (Object) 上面稱為類型 (Type)；

- domain：在主體程序 (Subject) 則稱為領域 (domain) 了！

domain 需要與 type 搭配，則該程序才能夠順利的讀取檔案資源啦！

- 程序與檔案 SELinux type 欄位的相關性

那麼這三個欄位如何利用呢？首先我們來瞧瞧主體程序在這三個欄位的意義為何！透過身份識別與角色欄位的定義， 我們可以約略知道某個程序所代表的意義喔！基本上，這些對應資料在 targeted 政策下的對應如下：

身份識別

角色

該對應在 targeted 的意義

root

system_r

代表供 root 帳號登入時所取得的權限

system_u

system_r

由於為系統帳號，因此是非交談式的系統運作程序

user_u

system_r

一般可登入使用者的程序囉！

但就如上所述，其實最重要的欄位是類型欄位，主體與目標之間是否具有可以讀寫的權限，與程序的 domain 及檔案的 type 有關！這兩者的關係我們可以使用達成 WWW 伺服器功能的 httpd 這支程式與 /var/www/html 這個網頁放置的目錄來說明。 首先，看看這兩個咚咚的安全性本文內容先：

[root@www ~]# ll -Zd /usr/sbin/httpd /var/www/html

-rwxr-xr-x  root root system_u:object_r:httpd_exec_t   /usr/sbin/httpd

drwxr-xr-x  root root system_u:object_r:httpd_sys_content_t /var/www/html

# 兩者的角色欄位都是 object_r ，代表都是檔案！而 httpd 屬於 httpd_exec_t 類型，

# /var/www/html 則屬於 httpd_sys_content_t 這個類型！

httpd 屬於 httpd_exec_t 這個可以執行的類型，而 /var/www/html 則屬於 httpd_sys_content_t 這個可以讓 httpd 領域 (domain) 讀取的類型。文字看起來不太容易瞭解吧！我們使用圖示來說明這兩者的關係！

圖 5.2.2、主體程序取得的 domain 與目標檔案資源的 type 相互關係

上圖的意義我們可以這樣看的：

1. 首先，我們觸發一個可執行的目標檔案，那就是具有 httpd_exec_t 這個類型的 /usr/sbin/httpd 檔案；

2. 該檔案的類型會讓這個檔案所造成的主體程序 (Subject) 具有 httpd 這個領域 (domain)， 我們的政策針對這個領域已經制定了許多規則，其中包括這個領域可以讀取的目標資源類型；

3. 由於 httpd domain 被設定為可以讀取 httpd_sys_content_t 這個類型的目標檔案 (Object)， 因此你的網頁放置到 /var/www/html/ 目錄下，就能夠被 httpd 那支程序所讀取了；

4. 但最終能不能讀到正確的資料，還得要看 rwx 是否符合 Linux 權限的規範！

上述的流程告訴我們幾個重點，第一個是政策內需要制訂詳細的 domain/type 相關性；第二個是若檔案的 type 設定錯誤， 那麼即使權限設定為 rwx 全開的 777 ，該主體程序也無法讀取目標檔案資源的啦！不過如此一來， 也就可以避免使用者將他的家目錄設定為 777 時所造成的權限困擾。

SELinux 的啟動、關閉與觀察

並非所有的 Linux distributions 都支援 SELinux 的，所以你必須要先觀察一下你的系統版本為何！ 鳥哥這裡介紹的 CentOS 5.x 本身就有支援 SELinux 啦！所以你不需要自行編譯 SELinux 到你的 Linux 核心中！ 目前 SELinux 支援三種模式，分別如下：

- enforcing：強制模式，代表 SELinux 運作中，且已經正確的開始限制 domain/type 了；

- permissive：寬容模式：代表 SELinux 運作中，不過僅會有警告訊息並不會實際限制 domain/type 的存取。這種模式可以運來作為 SELinux 的 debug 之用；

- disabled：關閉，SELinux 並沒有實際運作。

那你怎麼知道目前的 SELinux 模式呢？就透過 getenforce 吧！

[root@www ~]# getenforce

Enforcing  <==諾！就顯示出目前的模式為 Enforcing 囉！

另外，我們又如何知道 SELinux 的政策 (Policy) 為何呢？這時可以使用 sestatus 來觀察：

[root@www ~]# sestatus [-vb]

選項與參數：

-v  ：檢查列於 /etc/sestatus.conf 內的檔案與程序的安全性本文內容；

-b  ：將目前政策的規則布林值列出，亦即某些規則 (rule) 是否要啟動 (0/1) 之意；

範例一：列出目前的 SELinux 使用哪個政策 (Policy)？

[root@www ~]# sestatus

SELinux status:                 enabled    <==是否啟動 SELinux

SELinuxfs mount:                /selinux   <==SELinux 的相關檔案資料掛載點

Current mode:                   enforcing  <==目前的模式

Mode from config file:          enforcing  <==設定檔指定的模式

Policy version:                 21

Policy from config file:        targeted   <==目前的政策為何？

如上所示，目前是啟動的，而且是 Enforcing 模式，而由設定檔查詢得知亦為 Enforcing 模式。 此外，目前的預設政策為 targeted 這一個。你應該要有疑問的是， SELinux 的設定檔是哪個檔案啊？ 其實就是 /etc/selinux/config 這個檔案喔！我們來看看內容：

[root@www ~]# vi /etc/selinux/config

SELINUX=enforcing     <==調整 enforcing|disabled|permissive

SELINUXTYPE=targeted  <==目前僅有 targeted 與 strict

- SELinux 的啟動與關閉

上面是預設的政策與啟動的模式！你要注意的是，如果改變了政策則需要重新開機；如果由 enforcing 或 permissive 改成 disabled ，或由 disabled 改成其他兩個，那也必須要重新開機。這是因為 SELinux 是整合到核心裡面去的， 你只可以在 SELinux 運作下切換成為強制 (enforcing) 或寬容 (permissive) 模式，不能夠直接關閉 SELinux 的！ 同時，由 SELinux 關閉 (disable) 的狀態到開啟的狀態也需要重新開機啦！所以，如果剛剛你發現 getenforce 出現 disabled 時， 請到上述檔案修改成為 enforcing 吧！

所以，如果你要啟動 SELinux 的話，請將上述的 SELINUX=enforcing 設定妥當，並且指定 SELINUXTYPE=targeted 這一個設定， 並且到 /boot/grub/menu.lst 這個檔案去，看看核心有無關閉 SELinux 了呢？

[root@www ~]# vi /boot/grub/menu.lst

default=0

timeout=5

splashimage=(hd0,0)/grub/splash.xpm.gz

hiddenmenu

title CentOS (2.6.18-92.el5)

root (hd0,0)

kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet selinux=0

initrd /initrd-2.6.18-92.el5.img

# 如果要啟動 SELinux ，則不可以出現 selinux=0 的字樣在 kernel 後面！

請注意到上面特殊字體的那一行，確認 kernel 後面不可以接『 selinux=0 』這個項目！因為 selinux=0 指定給核心時， 則核心會自動的忽略 /etc/selinux/config 的設定值，而直接略過 SELinux 的載入，所以你的 SELinux 模式就會變成 disabled 啦！因為我們要啟動，所以這裡得要確認不存在 selinux=0 才行喔！切記切記！ 如果一切設定妥當，接下來就是 reboot 重新開機吧！

不過你要注意的是，如果從 disable 轉到啟動 SELinux 的模式時， 由於系統必須要針對檔案寫入安全性本文的資訊，因此開機過程會花費不少時間在等待重新寫入 SELinux 安全性本文 (有時也稱為 SELinux Label) ，而且在寫完之後還得要再次的重新開機一次喔！你必須要等待粉長一段時間！ 等到下次開機成功後，再使用 getenforce 或 sestatus 來觀察看看有否成功的啟動到 Enforcing 的模式囉！

如果你已經在 Enforcing 的模式，但是可能由於一些設定的問題導致 SELinux 讓某些服務無法正常的運作， 此時你可以將 Enforcing 的模式改為寬容 (permissive) 的模式，讓 SELinux 只會警告無法順利連線的訊息， 而不是直接抵擋主體程序的讀取權限。讓 SELinux 模式在 enforcing 與 permissive 之間切換的方法為：

[root@www ~]# setenforce [0|1]

選項與參數：

0 ：轉成 permissive 寬容模式；

1 ：轉成 Enforcing 強制模式

範例一：將 SELinux 在 Enforcing 與 permissive 之間切換與觀察

[root@www ~]# setenforce 0

[root@www ~]# getenforce

Permissive

[root@www ~]# setenforce 1

[root@www ~]# getenforce

Enforcing

不過請注意， setenforce 無法在 Disabled 的模式底下進行模式的切換喔！

SELinux 網路服務運作範例

由於 CentOS 5.x 預設使用 targeted 這個政策，而這個政策主要是在管理網路服務，本機端的程序則比較不受 SELinux 的管制。 既然上頭我們曾經舉過 /usr/sbin/httpd 這個程式來當作範例，那麼我們就使用 WWW 伺服器來說明一下 SELinux 的運作方式吧。

- 網路服務的啟動與觀察

首先，讓我們啟動 httpd 這支服務吧！要記得的是，一般服務啟動的腳本會在 /etc/init.d/ 底下， 所以我們可以這樣啟動與觀察：

# 1. 先啟動這個網路服務吧！

[root@www ~]# /etc/init.d/httpd start

正在啟動 httpd:          [  確定  ]

# 2. 觀察有無此程序，並且觀察此程序的 SELinux 安全性本文資料

[root@www ~]# pstree | grep httpd

|-httpd---8*[httpd]   <==httpd 會產生很多子程序來負責網路服務喔！

[root@www ~]# ps aux -Z |grep http

root:system_r:httpd_t root   24089 0.2 1.2 22896 9256 ? Ss 16:06 0:00 /usr/sbin/httpd

root:system_r:httpd_t apache 24092 0.0 0.6 22896 4752 ? S  16:06 0:00 /usr/sbin/httpd

root:system_r:httpd_t apache 24093 0.0 0.6 22896 4752 ? S  16:06 0:00 /usr/sbin/httpd

....(後面省略)....

ps -Z 這個『 -Z 』的選項可以讓我們查閱程序的安全性本文！其他相關的程序說明請自行查閱本章上面各節的內容。 我們可以發現這整個程序的 domain 是 httpd_t 這個咚咚喔！再來我們來處理一下首頁的資料先。 由於首頁是放置到 /var/www/html，且檔名應該要是『 index.html 』，因此我們可以這樣簡單的製作首頁：

[root@www ~]# echo "This is my first web page." > /var/www/html/index.html

接下來，如果你在瀏覽器上面輸入『 http://127.0.0.1 』應該會看到如下的畫面才對！

圖 5.4.1、httpd 順利運作時，能夠看到的首頁畫面

此時你的瀏覽器會透過 httpd 這個程序擁有的 httpd_t 這個 domain 去讀取 /var/www/html/index.html 這個檔案的！ 先來看看這個檔案的權限與 SELinux 的安全性本文資料：

[root@www ~]# ll -Z /var/www/html/index.html

-rw-r--r-- root root root:object_r:httpd_sys_content_t /var/www/html/index.html

權限是 apache 可以讀取的 r 標誌，而 SELinux 則是 httpd_sys_content_t 的類型 (type)，也是 httpd_t 能讀取的哩！ 那麼為何 httpd_t 可以讀取呢？因為 targeted 政策裡面有設定嘛！關於政策設定的查詢我們可以在後續跟大家作介紹， 這裡先瞭解一下即可。

- 錯誤的 SELinux 安全性本文

讓我們來瞭解一下什麼是錯誤的安全性本文設定好了！現在，我們將重要的網頁資料在 root 的家目錄底下製作！ 設定如下：

# 1. 先在 root 的家目錄建置所需的首頁：

[root@www ~]# echo "My 2nd web page..." > index.html

# 2. 將首頁 index.html 『搬移』到 /var/www/html 目錄去：

[root@www ~]# rm /var/www/html/index.html

[root@www ~]# mv index.html /var/www/html

# 這個測試的重點在 mv 這個指令的處理上！務必使用 mv 喔！

等到上述的動作都做完後，如果在瀏覽器輸入 http://127.0.0.1/index.html ，你應該會想到畫面會出現我們想要的『 My 2nd web page...』才對，但是結果卻變成：

圖 5.4.2、錯誤的安全性本文所造成的困擾

記得要在網址列指定 index.html 否則出現的會變成歡迎首頁的畫面。而螢幕上出現的錯誤訊息是沒有權限 (You don't have permission...)。看看這個 /var/www/html/index.html 的權限吧！

[root@www ~]# ll -Z /var/www/html/index.html

-rw-r--r-- root root root:object_r:user_home_t /var/www/html/index.html

你會發現，權限是對的 (apache 使用者依舊可以讀取)，但是安全性本文內容卻是使用者家目錄呢！ 真是要命！這個使用者家目錄預設可不能給 httpd_t 這個 domain 讀取的！所以就產生錯誤啦！那該如何處置呢？

- 重設 SELinux 安全性本文

既然安全性本文是錯的，那麼就將他改回來即可嘛！怎麼修改呢？可以透過兩個指令喔！首先我們使用 chcon 來處理：

[root@www ~]# chcon [-R] [-t type] [-u user] [-r role] 檔案

[root@www ~]# chcon [-R] --reference=範例檔 檔案

選項與參數：

-R  ：連同該目錄下的次目錄也同時修改；

-t  ：後面接安全性本文的類型欄位！例如 httpd_sys_content_t ；

-u  ：後面接身份識別，例如 system_u；

-r  ：後面街角色，例如 system_r；

--reference=範例檔：拿某個檔案當範例來修改後續接的檔案的類型！

範例一：將剛剛的 index.html 類型改為 httpd_sys_content_t 的類型

[root@www ~]# chcon -t httpd_sys_content_t /var/www/html/index.html

[root@www ~]# ll -Z /var/www/html/index.html

-rw-r--r--  root root root:object_r:httpd_sys_content_t /var/www/html/index.html

# 瞧！這樣就改回來啦！

範例二：以 /etc/passwd 為依據，將 index.html 修改成該類型

[root@www ~]# ll -Z /etc/passwd

-rw-r--r--  root root system_u:object_r:etc_t          /etc/passwd

[root@www ~]# chcon --reference=/etc/passwd /var/www/html/index.html

[root@www ~]# ll -Z /var/www/html/index.html

-rw-r--r--  root root root:object_r:etc_t /var/www/html/index.html

# 看看！是否與上面的 /etc/passwd 相同了！不過，這又是錯誤的安全性本文！

# 先不要急著修改！我們來進行底下的另外一個指令處置看看！

chcon 是透過直接指定的方式來處理安全性本文的類型資料。那我們知道其實系統預設的目錄都有特殊的 SELinux 安全性本文， 舉例來說， /var/www/html 原本就是 httpd 可以讀取的目錄嘛！既然如此，那有沒有可以使用預設的安全性本文來還原的方式？ 有的，那就是 restorecon 這玩意兒：

[root@www ~]# restorecon [-Rv] 檔案或目錄

選項與參數：

-R  ：連同次目錄一起修改；

-v  ：將過程顯示到螢幕上

範例一：將剛剛錯誤的 index.html 以預設的安全性本文改正過來

[root@www ~]# restorecon -Rv /var/www/html/index.html

restorecon reset /var/www/html/index.html context system_u:object_r:etc_t:s0->

system_u:object_r:httpd_sys_content_t:s0

# 上面這兩行其實是同一行喔！表示將 index.html 由 etc_t 改為 httpd_sys_content_t

然後回到剛剛圖 5.4.2 給他重讀一下，嘿嘿！又可以看到正確的內容啦！這個過程完全沒有動到 rwx 權限， 因為該權限本來就是對的！而錯的部分是在於 SELinux 的安全性本文當中那個類型 (type) 設定錯誤！ 而設定錯誤的原因很可能是因為該檔案由其他位置複製或移動過來所導致的！因此， 你得要善用 restorecon 以及 chcon 來處理這方面的問題喔！

SELinux 所需的服務

由於 SELinux 是整合到核心的一個核心功能，因此你幾乎不需要啟動什麼額外的服務來開啟 SELinux 的。 開機完成後， SELinux 就啟動了。不過，你剛剛也發現到當我們複製或移動某些資料到特定的目錄時， 可能由於沒有注意到修改 SELinux 的安全性本文內容，結果導致網路服務無法順利運行的問題！ 有沒有什麼方法可以記錄當發生 SELinux 錯誤時，將那些有用的資訊記錄下來，並且提供解決的方案呢？ 此時就得要底下的幾個服務的輔助囉！

- setroubleshoot --> 錯誤訊息寫入 /var/log/messages

幾乎所有 SELinux 相關的程式都會以 se 為開頭，這個服務也是以 se 為開頭！而 troubleshoot 大家都知道是錯誤克服， 因此這個 setroubleshoot 自然就得要啟動他啦！這個服務會將關於 SELinux 的錯誤訊息與克服方法記錄到 /var/log/messages 裡頭，所以你一定得要啟動這個服務才好。那如何在開機的時候就啟動 setroubleshoot 呢？這樣處理先：

[root@www ~]# chkconfig --list setroubleshoot

setroubleshoot  0:off  1:off  2:off 3:on  4:on  5:on  6:off

# 我們的 Linux 運作模式是在 3 或 5 號，因此這兩個要 on 即可。

[root@www ~]# chkconfig setroubleshoot on

# 關於 chkconfig 我們會在後面章節介紹， --list 是列出目前的執行等級是否有啟動，

# 如果加上 on ，則是在開機時啟動，若為 off 則開機時不啟動。

這支服務預設幾乎都會啟動啦！除非你看到 3:off 或 5:off 時，才需要以『 chkconfig setroubleshoot on 』 去設定一下。那麼如果有發生錯誤時，訊息像什麼呢？我們剛剛不是以瀏覽器瀏覽 index.html 並導致錯誤嗎？ 那就將該錯誤捉來瞧瞧！

[root@www ~]# cat /var/log/messages | grep setroubleshoot

Mar 23 17:18:44 www setroubleshoot: SELinux is preventing the httpd from using

potentially mislabeled files (/var/www/html/index.html). For complete SELinux

messages. run sealert -l 6c028f77-ddb6-4515-91f4-4e3e719994d4

上面的錯誤訊息可是同一行喔！大綱說的是『SElinux 被用來避免 httpd 讀取到錯誤的安全性本文， 想要查閱完整的資料，請執行 sealert -l 6c02...』沒錯！你注意到了！重點就是 sealert -l 啦！ 上面提供的資訊並不完整，想要更完整的說明得要靠 sealert 配合偵測到的錯誤代碼來處理。 實際處理後會像這樣：

[root@www ~]# sealert -l 6c028f77-ddb6-4515-91f4-4e3e719994d4

Summary:

SELinux is preventing the httpd from using potentially mislabeled files

(/var/www/html/index.html). <==就是剛剛 /var/log/messages 的訊息

Detailed Description:       <==底下是更完整的描述！要看！

SELinux has denied httpd access to potentially mislabeled file(s)

(/var/www/html/index.html). This means that SELinux will not allow httpd to use

these files. It is common for users to edit files in their home directory or tmp

directories and then move (mv) them to system directories. The problem is that

the files end up with the wrong file context which confined applications are not

allowed to access.

Allowing Access:            <==若要允許存取，你需要進行的動作！

If you want httpd to access this files, you need to relabel them using

restorecon -v '/var/www/html/index.html'. You might want to relabel the entire

directory using restorecon -R -v '/var/www/html'.

....(底下省略)....

重點就是上面特殊字體顯示的地方！你只要照著『Allowing Access』裡面的提示去進行處理， 就能夠完成你的 SELinux 類型設定了！比對剛剛我們上個小節提到的 restorecon 與 chcon 你就能夠知道， setroubleshoot 提供的訊息有多有效了吧！

- auditd --> 詳細資料寫入 /var/log/audit/audit.log

audit 是稽核的意思，這個 auditd 會將 SELinux 發生的錯誤資訊寫入 /var/log/audit/audit.log 中！ 與上個服務相同的，你最好在開機時就設定這服務為啟動的模式，因此可以照樣造句：

[root@www ~]# chkconfig --list auditd

auditd      0:off  1:off  2:on   3:on   4:on   5:on   6:off

[root@www ~]# chkconfig auditd on

# 若 3:off 及 5:off 時，才需要進行！

與 setroubleshoot 不同的是， auditd 會將許多的 SELinux 資訊都記錄下來，不只是錯誤訊息而已， 因此登錄檔 /var/log/audit/audit.log 非常的龐大！要直接到這檔案裡面去搜尋資料是挺累人的∼ 還好，SELinux 有提供一個 audit2why 的指令來讓我們查詢錯誤訊息的回報呢！那麼這個指令如何使用呢？ 可以這樣用的：

[root@www ~]# audit2why < /var/log/audit/audit.log

# 意思是，將登錄檔的內容讀進來分析，並輸出分析的結果！結果有點像這樣：

type=AVC msg=audit(1237799959.349:355): avc:  denied  { getattr } for  pid=24094

comm="httpd" path="/var/www/html/index.html" dev=hda2 ino=654685 scontext=root:s

ystem_r:httpd_t:s0 tcontext=root:object_r:user_home_t:s0 tclass=file

Was caused by:

Missing or disabled TE allow rule.

Allow rules may exist but be disabled by boolean settings; check boolean

settings.

You can see the necessary allow rules by running audit2allow with this

audit message as input.

audit2why 的用法與輸出結果如上，比較有趣的是那個 AVC ，AVC 是 access vector cache 的縮寫， 目的是記錄所有與 SELinux 有關的存取統計資料。輸出的資訊當中，會有談到產生錯誤的問題為何，如上表特殊字體部分， 你會發現錯誤訊息主要告知 type 不符，所以導致錯誤的發生啊！不過，就鳥哥來看，我個人覺得 setroubleshoot 比較好用呢！ 這兩個好東西都可以幫助你解決 SELinux 的錯誤，因此，請務必至少要學會其中一項錯誤分析的方法喔！

SELinux 的政策與規則管理

現在你應該知道，一個主體程式能否讀取到目標檔案資源的重點在於 SELinux 的政策以及政策內的各項規則， 然後再透過該規則的定義去處理各目標檔案的安全性本文，尤其是『類型』的部分。現在我們也知道可以透過 sestatus 與 getenforce 去取得目前的 SELinux 狀態。 但是，能不能知道更詳細的政策說明與規則項目呢？底下我們就來瞭解瞭解！

- 政策查閱

CentOS 5.x 預設使使用 targeted 政策，那麼這個政策提供多少相關的規則呢？此時可以透過 seinfo 來查詢喔！

[root@www ~]# seinfo [-Atrub]

選項與參數：

-A  ：列出 SELinux 的狀態、規則布林值、身份識別、角色、類別等所有資訊

-t  ：列出 SELinux 的所有類別 (type) 種類

-r  ：列出 SELinux 的所有角色 (role) 種類

-u  ：列出 SELinux 的所有身份識別 (user) 種類

-b  ：列出所有規則的種類 (布林值)

範例一：列出 SELinux 在此政策下的統計狀態

[root@www ~]# seinfo

Statistics for policy file: /etc/selinux/targeted/policy/policy.21

Policy Version & Type: v.21 (binary, MLS) <==列出政策所在檔與版本

Classes:            61    Permissions:       220

Types:            1521    Attributes:        155

Users:               3    Roles:               6

Booleans:          213    Cond. Expr.:       190

Sensitivities:       1    Categories:       1024

Allow:           86561    Neverallow:          0

Auditallow:         34    Dontaudit:        5460

Role allow:          5    Role trans:          0

....(底下省略)....

# 從上面我們可以看到這個政策是 targeted ，此政策的安全性本文類別有 1521 個；

# 而針對網路服務的規則 (Booleans) 共制訂了 213 條規則！

範例二：列出與 httpd 有關的規則 (booleans) 有哪些？

[root@www ~]# seinfo -b | grep httpd

Rule loading disabled

allow_httpd_mod_auth_pam

allow_httpd_bugzilla_script_anon_write

httpd_enable_ftp_server

....(底下省略)....

# 你可以看到，有非常多的與 httpd 有關的規則訂定呢！

從上面我們可以看到與 httpd 有關的布林值，同樣的，如果你想要找到有 httpd 字樣的安全性本文類別時， 就可以使用『 seinfo -t | grep httpd 』來查詢了！如果查詢到相關的類別或者是布林值後，想要知道詳細的規則時， 就得要使用 sesearch 這個指令了！

[root@www ~]# sesearch [-a] [-s 主體類別] [-t 目標類別] [-b 布林值]

選項與參數：

-a  ：列出該類別或布林值的所有相關資訊

-t  ：後面還要接類別，例如 -t httpd_t

-b  ：後面還要接布林值的規則，例如 -b httpd_enable_ftp_server

範例一：找出目標檔案資源類別為 httpd_sys_content_t 的有關資訊

[root@www ~]# sesearch -a -t httpd_sys_content_t

Found 74 av rules:

allow readahead_t httpd_sys_content_t : file { ioctl read getattr lock };

allow readahead_t httpd_sys_content_t : dir { ioctl read getattr lock search };

....(底下省略)....

# 『 allow  主體程序安全性本文類別  目標檔案安全性本文類別 』

# 如上，說明這個類別可以被那個主題程序的類別所讀取，以及目標檔案資源的格式。

範例二：找出主體程序為 httpd_t 且目標檔案類別為 httpd 相關的所有資訊

[root@www ~]# sesearch -s httpd_t -t httpd_* -a

Found 163 av rules:

....(中間省略)....

allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock };

allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search };

allow httpd_t httpd_sys_content_t : lnk_file { ioctl read getattr lock };

....(後面省略)....

# 從上面的資料就可以看出當程序為 httpd_t 這個類別，是可以讀取

# httpd_sys_content_t 的！

你可以很輕易的查詢到某個主體程序 (subject) 可以讀取的目標檔案資源 (Object) ， 從我們上面的練習，我們也可以很輕鬆的就知道，為何 httpd_t 可以讀取 httpd_sys_content_t 囉！ 那如果是布林值呢？裡面又規範了什麼？讓我們來看看先：

範例三：我知道有個布林值為 httpd_enable_homedirs ，請問該布林值規範多少規則？

[root@www ~]# sesearch -b httpd_enable_homedirs -a

Found 21 av rules:

allow httpd_t user_home_dir_t : dir { getattr search };

allow httpd_t cifs_t : file { ioctl read getattr lock };

allow httpd_t cifs_t : dir { ioctl read getattr lock search };

....(後面省略)....

從這個布林值的設定我們可以看到裡面規範了非常多的主體程序與目標檔案資源的放行與否！ 所以你知道了，實際規範這些規則的，就是布林值的項目啦！那也就是我們之前所說的一堆規則是也！ 你的主體程序能否對某些目標檔案進行存取，與這個布林值非常有關係喔！因為布林值可以將規則設定為啟動 (1) 或者是關閉 (0) 啦！

由 seinfo 與 sesearch 的輸出資訊，我們也會得到實際的政策資料都是放置到 /etc/selinux/targeted/policy/ 底下， 事實上，所有與 targetd 相關的資訊都是放置到 /etc/selinux/targeted 裡面的呢！包括安全性本文相關的資訊。 這部分等一下談到安全性本文的預設值修改時，我們再來討論。

- 布林值的查詢與修改

上面我們透過 sesearch 知道了，其實 Subject 與 Object 能否有存取的權限，是與布林值有關的， 那麼系統有多少布林值可以透過 seinfo -b 來查詢，但，每個布林值是啟動的還是關閉的呢？這就來查詢看看吧：

[root@www ~]# getsebool [-a] [布林值條款]

選項與參數：

-a  ：列出目前系統上面的所有布林值條款設定為開啟或關閉值

範例一：查詢本系統內所有的布林值設定狀況

[root@www ~]# getsebool -a

NetworkManager_disable_trans --> off

allow_console_login --> off

allow_cvs_read_shadow --> off

allow_daemons_dump_core --> on

....(底下省略)....

# 您瞧！這就告訴你目前的布林值狀態囉！

那麼如果查詢到某個布林值，並且以 sesearch 知道該布林值的用途後，想要關閉或啟動他，又該如何處置？

[root@www ~]# setsebool [-P] 布林值=[0|1]

選項與參數：

-P  ：直接將設定值寫入設定檔，該設定資料未來會生效的！

範例一：查詢 httpd_enable_homedirs 是否為關閉，若不為關閉，請關閉他！

[root@www ~]# getsebool httpd_enable_homedirs

httpd_enable_homedirs --> on  <==結果是 on ，依題意給他關閉！

[root@www ~]# setsebool -P httpd_enable_homedirs=0

[root@www ~]# getsebool httpd_enable_homedirs

httpd_enable_homedirs --> off

這個 setsebool 最好記得一定要加上 -P 的選項！因為這樣才能將此設定寫入設定檔！ 這是非常棒的工具組！你一定要知道如何使用 getsebool 與 setsebool 才行！

- 預設目錄的安全性本文查詢與修改

還記得我們在使用 restorecon 時談到每個目錄或檔案都會有預設的安全性本文嗎？ 會制訂目錄的安全性本文，是因為系統的一些服務所放置檔案的目錄已經是確定的，當然有預設的安全性本文管理上較方便。 那你如何查詢這些目錄的預設安全性本文呢？就得要使用 semanage 囉！

[root@www ~]# semanage {login|user|port|interface|fcontext|translation} -l

[root@www ~]# semanage fcontext -{a|d|m} [-frst] file_spec

選項與參數：

fcontext ：主要用在安全性本文方面的用途， -l 為查詢的意思；

-a ：增加的意思，你可以增加一些目錄的預設安全性本文類型設定；

-m ：修改的意思；

-d ：刪除的意思。

範例一：查詢一下 /var/www/html 的預設安全性本文設定為何！

[root@www ~]# semanage fcontext -l

SELinux fcontext    type          Context

....(前面省略)....

/var/www(/.*)?      all files     system_u:object_r:httpd_sys_content_t:s0

....(後面省略)....

從上面的說明，我們知道其實 semanage 可以處理非常多的任務，不過，在這個小節我們主要想瞭解的是每個目錄的預設安全性本文。 如上面範例一所示，我們可以查詢的到每個目錄的安全性本文啦！而目錄的設定可以使用正規表示法去指定一個範圍。那麼如果我們想要增加某些自訂的目錄的安全性本文呢？ 舉例來說，我想要制訂 /srv/samba 成為 public_content_t 的類型時，應該如何指定呢？

範例二：利用 semanage 設定 /srv/samba 目錄的預設安全性本文為 public_content_t

[root@www ~]# mkdir /srv/samba

[root@www ~]# ll -Zd /srv/samba

drwxr-xr-x  root root root:object_r:var_t    /srv/samba

# 如上所示，預設的情況應該是 var_t 這個咚咚的！

[root@www ~]# semanage fcontext -l | grep '/srv'

/srv/.*                     all files   system_u:object_r:var_t:s0

/srv/([^/]*/)?ftp(/.*)?     all files   system_u:object_r:public_content_t:s0

/srv/([^/]*/)?www(/.*)?     all files   system_u:object_r:httpd_sys_content_t:s0

/srv/([^/]*/)?rsync(/.*)?   all files   system_u:object_r:public_content_t:s0

/srv/gallery2(/.*)?         all files   system_u:object_r:httpd_sys_content_t:s0

/srv                        directory   system_u:object_r:var_t:s0 <==看這裡！

# 上面則是預設的 /srv 底下的安全性本文資料，不過，並沒有指定到 /srv/samba 啦

[root@www ~]# semanage fcontext -a -t public_content_t "/srv/samba(/.*)?"

[root@www ~]# semanage fcontext -l | grep '/srv/samba'

/srv/samba(/.*)?            all files   system_u:object_r:public_content_t:s0

[root@www ~]# cat /etc/selinux/targeted/contexts/files/file_contexts.local

# This file is auto-generated by libsemanage

# Please use the semanage command to make changes

/srv/samba(/.*)?    system_u:object_r:public_content_t:s0

# 其實就是寫入這個檔案的囉！ ^_^

[root@www ~]# restorecon -Rv /srv/samba* <==嘗試恢復預設值

[root@www ~]# ll -Zd /srv/samba

drwxr-xr-x  root root system_u:object_r:public_content_t /srv/samba/

# 有預設值，以後用 restorecon 來修改比較簡單！

semanage 的功能很多，不過鳥哥主要用到的僅有 fcontext 這個項目的動作而已。如上所示， 你可以使用 semanage 來查詢所有的目錄預設值，也能夠使用他來增加預設值的設定！如果您學會這些基礎的工具， 那麼 SELinux 對你來說，也不是什麼太難的咚咚囉！

重點回顧

- 程式 (program)：通常為 binary program ，放置在儲存媒體中 (如硬碟、光碟、軟碟、磁帶等)，為實體檔案的型態存在；

- 程序 (process)：程式被觸發後，執行者的權限與屬性、程式的程式碼與所需資料等都會被載入記憶體中， 作業系統並給予這個記憶體內的單元一個識別碼 (PID)，可以說，程序就是一個正在運作中的程式。

- 程式彼此之間是有相關性的，故有父程序與子程序之分。而 Linux 系統所有程序的父程序就是 init 這個 PID 為 1 號的程序。

- 在 Linux 的程序呼叫通常稱為 fork-and-exec 的流程！程序都會藉由父程序以複製 (fork) 的方式產生一個一模一樣的子程序， 然後被複製出來的子程序再以 exec 的方式來執行實際要進行的程式，最終就成為一個子程序的存在。

- 常駐在記憶體當中的程序通常都是負責一些系統所提供的功能以服務使用者各項任務，因此這些常駐程式就會被我們稱為：服務 (daemon)。

- 在工作管理 (job control) 中，可以出現提示字元讓你操作的環境就稱為前景 (foreground)，至於其他工作就可以讓你放入背景 (background) 去暫停或運作。

- 與 job control 有關的按鍵與關鍵字有： &, [ctrl]-z, jobs, fg, bg, kill %n 等；

- 程序管理的觀察指令有： ps, top, pstree 等等；

- 程序之間是可以互相控制的，傳遞的訊息 (signal) 主要透過 kill 這個指令在處理；

- 程序是有優先順序的，該項目為 Priority，但 PRI 是核心動態調整的，使用者只能使用 nice 值去微調 PRI

- nice 的給予可以有： nice, renice, top 等指令；

- vmstat 為相當好用的系統資源使用情況觀察指令；

- SELinux 當初的設計是為了避免使用者資源的誤用，而 SELinux 使用的是 MAC 委任式存取設定；

- SELinux 的運作中，重點在於主體程序 (Subject) 能否存取目標檔案資源 (Object) ，這中間牽涉到政策 (Policy) 內的規則， 以及實際的安全性本文類別 (type)；

- 安全性本文的一般設定為：『Identify:role:type』其中又以 type 最重要；

- SELinux 的模式有： enforcing, permissive, disabled 三種，而啟動的政策 (Policy) 主要是 targeted

- SELinux 啟動與關閉的設定檔在： /etc/selinux/config

- SELinux 的啟動與觀察： getenforce, sestatus 等指令

- 重設 SELinux 的安全性本文可使用 restorecon 與 chcon

- 在 SELinux 有啟動時，必備的服務至少要啟動 setroubleshoot 這個！

- 若要管理預設的 SELinux 布林值，可使用 getsebool, setsebool 來管理！

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：透過一個網路程式 vsftpd 的服務，來瞭解到程序與 SELinux 的相關限制行為：

- 目標：瞭解軟體、程式、程序、優先執行緒、網路程序與 SELinux 的相關性

- 需求：已經知道如何安裝軟體，否則就得要連上 Internet 才能進行 vsftpd 服務的安裝；

底下的流程先看看即可，很多資料如果當初忘記安裝的話，可能會無法進行。沒關係！後續的文章看完後，第二次讀到這裡後， 你就會知道如何處理了。

- 先察看有無安裝 vsftpd 這個軟體，如果有的話那就 OK ∼沒有的話，可能需要線上安裝才行：

[root@www ~]# rpm -q vsftpd

vsftpd-2.0.5-12.el5   <==出現這個才是對的！若沒有出現，就是沒安裝

# 如果沒有安裝的話，你又已經有 IP 可以上網了，那麼就這樣安裝：

[root@www ~]# yum install vsftpd

- 啟動 vsftpd 這個服務：

[root@www ~]# /etc/init.d/vsftpd start

- 假設 vsftpd 這個服務並不是那麼重要，因此我想要在這次啟動期間，讓 vsftpd 的優先執行緒較不優先 10 分， 可以這麼做：

[root@www ~]# pstree -p | grep vsftpd

|-vsftpd(2377)   <==找到了 PID 為 2377 喔！

[root@www ~]# renice 10 2377

[root@www ~]# top -p grep 2377 <==重點是在觀察！

- vsftpd 是個網路服務，他到底是啟動哪個埠口？可以這樣觀察：

[root@www ~]# netstat -tlunp | grep vsftpd

tcp  0 0 0.0.0.0:21     0.0.0.0:*  LISTEN   2377/vsftpd

# 這樣的答案夠明顯了嗎？

- vsftpd 提供網路的 FTP 功能，有個使用者名為 vbird ，他卻無法登入自己的帳號！這是什麼原因呢？ 由於 CentOS 的預設 vsftpd 是能夠允許一般用戶登入自己家目錄的，因此無法登入的可能原因是權限還是 SELinux 呢？ 我們可以這樣測試看看：

# 1. 先用 vbird 的身份登入 vsftpd 看看：

[root@www ~]# ftp localhost

Connected to www.vbird.tsai.

Name (localhost:root): vbird

331 Please specify the password.

Password: <==這裡輸入 vbird 的密碼喔！

500 OOPS: cannot change directory:/home/vbird

Login failed.  <==見鬼了！竟然無法登入自己的家目錄 /home/vbird 哩！

ftp> bye

[root@www ~]# ls -ld /home/vbird

drwx------ 4 vbird vbird 4096  8月 18 18:22 /home/vbird

# 權限明明是對的嘛！怎麼會無法切換？

# 2. 看看登錄檔有沒有什麼重要訊息的說明：

[root@www ~]# tail /var/log/messages

Sep 11 16:57:31 www setroubleshoot: SELinux is preventing the ftp daemon from

reading users home directories (/). For complete SELinux messages. run

sealert -l b8bdaf2d-b083-4e28-9465-91fae8df63b1

# 3. 照著作一下：

[root@www ~]# sealert -l b8bdaf2d-b083-4e28-9465-91fae8df63b1

Summary:

SELinux is preventing the ftp daemon from reading users home directories (/).

....(中間省略)....

The following command will allow this access:

setsebool -P ftp_home_dir=1

....(底下省略)....

- 好了，現在讓我們處理一下上面的 vsftpd 相關的規則吧！因為是規則擋住了用戶的登入了！：

[root@www ~]# setsebool -P ftp_home_dir=1

[root@www ~]# ftp localhost

Connected to www.vbird.tsai.

Name (localhost:root): vbird

331 Please specify the password.

Password:

230 Login successful.  <==看吧！順利登入囉！

Remote system type is UNIX.

Using binary mode to transfer files.

ftp> bye

簡答題部分：

- 簡單說明什麼是程式 (program) 而什麼是程序 (process)？

程式 (program) 是系統上面可以被執行的檔案，由於 Linux 的完整檔名 (由 / 寫起) 僅能有一個， 所以 program 的檔名具有單一性。當程式被執行後，就會啟動成程序 (process)， 一個 program 可以被不同的使用者或者相同的使用者重複的執行成為多個程序， 且該程式所造成的程序還因為不同的使用者，而有不同的權限，且每個 process 幾乎都是獨立的。

- 我今天想要查詢 /etc/crontab 與 crontab 這個程式的用法與寫法，請問我該如何線上查詢？

查詢 crontab 指令可以使用 man crontab 或 info crontab ，至於查詢 /etc/crontab ，則可以使用 man 5 crontab 囉！

- 我要如何查詢 crond 這個 daemon 的 PID 與他的 PRI 值呢？

ps -lA | grep crond 即可查到！

- 我要如何修改 crond 這個 PID 的優先執行序？

先以 ps aux 找到 crond 的 PID 後，再以： renice -n number PID 來調整！

- 我是一般身份使用者，我是否可以調整不屬於我的程序的 nice 值？此外，如果我調整了我自己的程序的 nice 值到 10 ，是否可以將他調回 5 呢？

不行！一般身份使用者僅能調整屬於自己的 PID 程序，並且，只能將 nice 值一再地調高，並不能調低，所以調整為 10 之後，就不能降回 5 囉！

- 我要怎麼知道我的網路卡在開機的過程中有沒有被捉到？

可以使用 dmesg 來視察！

參考資料與延伸閱讀

- 註1：關於 fork-and-exec 的說明可以參考如下網頁與書籍：

吳賢明老師維護的網站：http://nmc.nchu.edu.tw/linux/process.htm

楊振和、作業系統導論、第三章、學貫出版社

- 註2：對 Linux 核心有興趣的話，可以先看看底下的連結：

http://www.linux.org.tw/CLDP/OLD/INFO-SHEET-2.html

http://oreilly.com/catalog/linuxkernel/chapter/ch10.html

- 註3：來自 Linux Journal 的關於 /proc 的說明：http://www.linuxjournal.com/article/177

- 註4：關於 SELinux 相關的網站與文件資料：

美國國家安全局的 SELinux 簡介：http://www.nsa.gov/research/selinux/

小州老師在 SA 的簡報資料：http://kenduest.sayya.org/blog/kenduest-data/2008/10/selinux_sa.pdf

小州老師上課的講義：http://kenduest.sayya.org/blog/kenduest-data/2008/5/kenduest-UNIX-selinux-2008-05-15.pdf

陳永昇、『企業級Linux 系統管理寶典』、學貫行銷股份有限公司

Fedora SELinux 說明：http://fedoraproject.org/wiki/SELinux/SecurityContext

美國國家安全局對 SELinux 的白皮書：http://www.nsa.gov/research/_files/selinux/papers/module/t1.shtml

徐秉義老師的 SELinux 設定範例：http://kate.babyface.com.tw/NetAdmin/24200801SELinux/

2002/06/28：第一次完成

2003/02/10：重新編排與加入 FAQ

2005/09/07：將舊的文章移動到 此處 。

2005/09/18：哈哈，終於將這篇寫完囉。新增了一些簡單的小指令啦。

2009/03/15：將舊的基於 FC4 的文章移動到此處。

2009/03/19：調整 sar 成為 vmstat ，因為 vmstat 是預設有安裝的分析工具！

2009/09/11：加入了 nohup 的說明囉！並加入了情境模擬題

2011/04/14：原本的習題解答為 ps aux ，應該是 ps -lA 才好！感謝網友 redsc 的回報！

2002/04/30以來統計人數

- 使用一般帳號：系統平日操作的好習慣

事實上，為了安全的緣故，一些老人家都會建議你，盡量以一般身份使用者來操作 Linux 的日常作業！等到需要設定系統環境時， 才變換身份成為 root 來進行系統管理，相對比較安全啦！避免作錯一些嚴重的指令，例如恐怖的『 rm -rf / 』(千萬作不得！)

- 用較低權限啟動系統服務

相對於系統安全，有的時候，我們必須要以某些系統帳號來進行程序的執行。 舉例來說， Linux 主機上面的一套軟體，名稱為 apache ，我們可以額外建立一個名為 apache 的使用者來啟動 apache 軟體啊，如此一來，如果這個程序被攻破，至少系統還不至於就損毀了∼

- 軟體本身的限制

在遠古時代的 telnet 程式中，該程式預設是不許使用 root 的身份登入的，telnet 會判斷登入者的 UID， 若 UID 為 0 的話，那就直接拒絕登入了。所以，你只能使用一般使用者來登入 Linux 伺服器。 此外， ssh (註3) 也可以設定拒絕 root 登入喔！那如果你有系統設定需求該如何是好啊？就變換身份啊！

由於上述考量，所以我們都是使用一般帳號登入系統的，等有需要進行系統維護或軟體更新時才轉為 root 的身份來動作。 那如何讓一般使用者轉變身份成為 root 呢？主要有兩種方式喔：

- 以『 su - 』直接將身份變成 root 即可，但是這個指令卻需要 root 的密碼，也就是說，如果你要以 su 變成 root 的話，你的一般使用者就必須要有 root 的密碼才行；

- 以『 sudo 指令 』執行 root 的指令串，由於 sudo 需要事先設定妥當，且 sudo 需要輸入使用者自己的密碼， 因此多人共管同一部主機時， sudo 要比 su 來的好喔！至少 root 密碼不會流出去！

底下我們就來說一說 su 跟 sudo 的用法啦！

su

su 是最簡單的身份切換指令了，他可以進行任何身份的切換唷！方法如下：

[root@www ~]# su [-lm] [-c 指令] [username]

選項與參數：

-   ：單純使用 - 如『 su - 』代表使用 login-shell 的變數檔案讀取方式來登入系統；

若使用者名稱沒有加上去，則代表切換為 root 的身份。

-l  ：與 - 類似，但後面需要加欲切換的使用者帳號！也是 login-shell 的方式。

-m  ：-m 與 -p 是一樣的，表示『使用目前的環境設定，而不讀取新使用者的設定檔』

-c  ：僅進行一次指令，所以 -c 後面可以加上指令喔！

上表的解釋當中有出現之前第十一章談過的 login-shell 設定檔讀取方式，如果你忘記那是啥東西， 請先回去第十一章瞧瞧再回來吧！這個 su 的用法當中，有沒有加上那個減號『 - 』差很多喔！ 因為涉及 login-shell 與 non-login shell 的變數讀取方法。這裡讓我們以一個小例子來說明吧！

範例一：假設你原本是 vbird1 的身份，想要使用 non-login shell 的方式變成 root

[vbird1@www ~]$ su       <==注意提示字元，是 vbird1 的身份喔！

Password:                <==這裡輸入 root 的密碼喔！

[root@www vbird1]# id    <==提示字元的目錄是 vbird1 喔！

uid=0(root) gid=0(root) groups=0(root),1(bin),...   <==確實是 root 的身份！

[root@www vbird1]# env | grep 'vbird1'

USER=vbird1

PATH=/usr/local/bin:/bin:/usr/bin:/home/vbird1/bin  <==這個影響最大！

MAIL=/var/spool/mail/vbird1                         <==收到的 mailbox 是 vbird1

PWD=/home/vbird1                                    <==並非 root 的家目錄

LOGNAME=vbird1

# 雖然你的 UID 已經是具有 root 的身份，但是看到上面的輸出訊息嗎？

# 還是有一堆變數為原本 vbird1 的身份，所以很多資料還是無法直接利用。

[root@www vbird1]# exit   <==這樣可以離開 su 的環境！

單純使用『 su 』切換成為 root 的身份，讀取的變數設定方式為 non-login shell 的方式，這種方式很多原本的變數不會被改變， 尤其是我們之前談過很多次的 PATH 這個變數，由於沒有改變成為 root 的環境 (一堆 /sbin, /usr/sbin 等目錄都沒有被包含進來)， 因此很多 root 慣用的指令就只能使用絕對路徑來執行咯。其他的還有 MAIL 這個變數，你輸入 mail 時， 收到的郵件竟然還是 vbird1 的，而不是 root 本身的郵件！是否覺得很奇怪啊！所以切換身份時，請務必使用如下的範例二：

範例二：使用 login shell 的方式切換為 root 的身份並觀察變數

[vbird1@www ~]$ su -

Password:   <==這裡輸入 root 的密碼喔！

[root@www ~]# env | grep root

USER=root

MAIL=/var/spool/mail/root

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

PWD=/root

HOME=/root

LOGNAME=root

# 瞭解差異了吧？下次變換成為 root 時，記得最好使用 su - 喔！

[root@www ~]# exit   <==這樣可以離開 su 的環境！

上述的作法是讓使用者的身份變成 root 並開始操作系統，如果想要離開 root 的身份則得要利用 exit 離開才行。 那我如果只是想要執行『一個只有 root 才能進行的指令，且執行完畢就恢復原本的身份』呢？那就可以加上 -c 這個選項囉！ 請參考底下範例三！

範例三：vbird1 想要執行『 head -n 3 /etc/shadow 』一次，且已知 root 密碼

[vbird1@www ~]$ head -n 3 /etc/shadow

head: cannot open `/etc/shadow' for reading: Permission denied

[vbird1@www ~]$ su - -c "head -n 3 /etc/shadow"

Password: <==這裡輸入 root 的密碼喔！

root:$1$/30QpEWEBEZXRD0bh6rAABCEQD.BAH0:14126:0:99999:7:::

bin:*:14126:0:99999:7:::

daemon:*:14126:0:99999:7:::

[vbird1@www ~]$ <==注意看，身份還是 vbird1 喔！繼續使用舊的身份進行系統操作！

由於 /etc/shadow 權限的關係，該檔案僅有 root 可以查閱。為了查閱該檔案，所以我們必須要使用 root 的身份工作。 但我只想要進行一次該指令而已，此時就使用類似上面的語法吧！好，那接下來，如果我是 root 或者是其他人， 想要變更成為某些特殊帳號，可以使用如下的方法來切換喔！

範例四：原本是 vbird1 這個使用者，想要變換身份成為 dmtsai 時？

[vbird1@www ~]$ su -l dmtsai

Password: <==這裡輸入 dmtsai 的密碼喔！

[dmtsai@www ~]$ su -

Password: <==這裡輸入 root 的密碼喔！

[root@www ~]# id sshd

uid=74(sshd) gid=74(sshd) groups=74(sshd) ... <==確實有存在此人

[root@www ~]# su -l sshd

This account is currently not available.      <==竟然說此人無法切換？

[root@www ~]# finger sshd

Login: sshd                             Name: Privilege-separated SSH

Directory: /var/empty/sshd              Shell: /sbin/nologin

[root@www ~]# exit    <==離開第二次的 su

[dmtsai@www ~]$ exit  <==離開第一次的 su

[vbird1@www ~]$ exit  <==這才是最初的環境！

su 就這樣簡單的介紹完畢，總結一下他的用法是這樣的：

- 若要完整的切換到新使用者的環境，必須要使用『 su - username 』或『 su -l username 』， 才會連同 PATH/USER/MAIL 等變數都轉成新使用者的環境；

- 如果僅想要執行一次 root 的指令，可以利用『 su - -c "指令串" 』的方式來處理；

- 使用 root 切換成為任何使用者時，並不需要輸入新使用者的密碼；

雖然使用 su 很方便啦，不過缺點是，當我的主機是多人共管的環境時，如果大家都要使用 su 來切換成為 root 的身份，那麼不就每個人都得要知道 root 的密碼，這樣密碼太多人知道可能會流出去， 很不妥當呢！怎辦？透過 sudo 來處理即可！

sudo

相對於 su 需要瞭解新切換的使用者密碼 (常常是需要 root 的密碼)， sudo 的執行則僅需要自己的密碼即可！ 甚至可以設定不需要密碼即可執行 sudo 呢！由於 sudo 可以讓你以其他用戶的身份執行指令 (通常是使用 root 的身份來執行指令)，因此並非所有人都能夠執行 sudo ， 而是僅有規範到 /etc/sudoers 內的用戶才能夠執行 sudo 這個指令喔！說的這麼神奇，底下就來瞧瞧那 sudo 如何使用？

- sudo 的指令用法

由於一開始系統預設僅有 root 可以執行 sudo ，因此底下的範例我們先以 root 的身份來執行，等到談到 visudo 時，再以一般使用者來討論其他 sudo 的用法吧！ sudo 的語法如下：

[root@www ~]# sudo [-b] [-u 新使用者帳號]

選項與參數：

-b  ：將後續的指令放到背景中讓系統自行執行，而不與目前的 shell 產生影響

-u  ：後面可以接欲切換的使用者，若無此項則代表切換身份為 root 。

範例一：你想要以 sshd 的身份在 /tmp 底下建立一個名為 mysshd 的檔案

[root@www ~]# sudo -u sshd touch /tmp/mysshd

[root@www ~]# ll /tmp/mysshd

-rw-r--r-- 1 sshd sshd 0 Feb 28 17:42 /tmp/mysshd

# 特別留意，這個檔案的權限是由 sshd 所建立的情況喔！

範例二：你想要以 vbird1 的身份建立 ~vbird1/www 並於其中建立 index.html 檔案

[root@www ~]# sudo -u vbird1 sh -c "mkdir ~vbird1/www; cd ~vbird1/www; \

>  echo 'This is index.html file' > index.html"

[root@www ~]# ll -a ~vbird1/www

drwxr-xr-x 2 vbird1 vbird1 4096 Feb 28 17:51 .

drwx------ 5 vbird1 vbird1 4096 Feb 28 17:51 ..

-rw-r--r-- 1 vbird1 vbird1   24 Feb 28 17:51 index.html

# 要注意，建立者的身份是 vbird1 ，且我們使用 sh -c "一串指令" 來執行的！

sudo 可以讓你切換身份來進行某項任務，例如上面的兩個範例。範例一中，我們的 root 使用 sshd 的權限去進行某項任務！ 要注意，因為我們無法使用『 su - sshd 』去切換系統帳號 (因為系統帳號的 shell 是 /sbin/nologin)， 這個時候 sudo 真是他 X 的好用了！立刻以 sshd 的權限在 /tmp 底下建立檔案！查閱一下檔案權限你就瞭解意義啦！ 至於範例二則更使用多重指令串 (透過分號 ; 來延續指令進行)，使用 sh -c 的方法來執行一連串的指令， 如此真是好方便！

但是 sudo 預設僅有 root 能使用啊！為什麼呢？因為 sudo 的執行是這樣的流程：

1. 當使用者執行 sudo 時，系統於 /etc/sudoers 檔案中搜尋該使用者是否有執行 sudo 的權限；

2. 若使用者具有可執行 sudo 的權限後，便讓使用者『輸入使用者自己的密碼』來確認；

3. 若密碼輸入成功，便開始進行 sudo 後續接的指令(但 root 執行 sudo 時，不需要輸入密碼)；

4. 若欲切換的身份與執行者身份相同，那也不需要輸入密碼。

所以說，sudo 執行的重點是：『能否使用 sudo 必須要看 /etc/sudoers 的設定值， 而可使用 sudo 者是透過輸入使用者自己的密碼來執行後續的指令串』喔！由於能否使用與 /etc/sudoers 有關， 所以我們當然要去編輯 sudoers 檔案啦！不過，因為該檔案的內容是有一定的規範的，因此直接使用 vi 去編輯是不好的。 此時，我們得要透過 visudo 去修改這個檔案喔！

- visudo 與 /etc/sudoers

從上面的說明我們可以知道，除了 root 之外的其他帳號，若想要使用 sudo 執行屬於 root 的權限指令，則 root 需要先使用 visudo 去修改 /etc/sudoers ，讓該帳號能夠使用全部或部分的 root 指令功能。為什麼要使用 visudo 呢？這是因為 /etc/sudoers 是有設定語法的，如果設定錯誤那會造成無法使用 sudo 指令的不良後果。因此才會使用 visudo 去修改， 並在結束離開修改畫面時，系統會去檢驗 /etc/sudoers 的語法就是了。

一般來說，visudo 的設定方式有幾種簡單的方法喔，底下我們以幾個簡單的例子來分別說明：

1. 單一使用者可進行 root 所有指令，與 sudoers 檔案語法：

假如我們要讓 vbird1 這個帳號可以使用 root 的任何指令，那麼可以簡單的這樣進行修改即可：

[root@www ~]# visudo

....(前面省略)....

root    ALL=(ALL)       ALL  <==找到這一行，大約在 76 行左右

vbird1  ALL=(ALL)       ALL  <==這一行是你要新增的！

....(前面省略)....

有趣吧！其實 visudo 只是利用 vi 將 /etc/sudoers 檔案呼叫出來進行修改而已，所以這個檔案就是 /etc/sudoers 啦！ 這個檔案的設定其實很簡單，如上面所示，如果你找到 76 行 (有 root 設定的那行) 左右，看到的資料就是：

使用者帳號  登入者的來源主機名稱=(可切換的身份)  可下達的指令

root                         ALL=(ALL)           ALL   <==這是預設值

上面這一行的四個元件意義是：

1. 系統的哪個帳號可以使用 sudo 這個指令的意思，預設為 root 這個帳號；

2. 當這個帳號由哪部主機連線到本 Linux 主機，意思是這個帳號可能是由哪一部網路主機連線過來的， 這個設定值可以指定用戶端電腦(信任用戶的意思)。預設值 root 可來自任何一部網路主機

3. 這個帳號可以切換成什麼身份來下達後續的指令，預設 root 可以切換成任何人；

4. 可用該身份下達什麼指令？這個指令請務必使用絕對路徑撰寫。 預設 root 可以切換任何身份且進行任何指令之意。

那個 ALL 是特殊的關鍵字，代表任何身份、主機或指令的意思。所以，我想讓 vbird1 可以進行任何身份的任何指令， 就如同上表特殊字體寫的那樣，其實就是複製上述預設值那一行，再將 root 改成 vbird1 即可啊！ 此時『vbird1 不論來自哪部主機登入，他可以變換身份成為任何人，且可以進行系統上面的任何指令』之意。 修改完請儲存後離開 vi，並以 vbird1 登入系統後，進行如下的測試看看：

[vbird1@www ~]$ tail -n 1 /etc/shadow  <==注意！身份是 vbird1

tail: cannot open `/etc/shadow' for reading: Permission denied

# 因為不是 root 嘛！所以當然不能查詢 /etc/shadow

[vbird1@www ~]$ sudo tail -n 1 /etc/shadow <==透過 sudo

We trust you have received the usual lecture from the local System

Administrator. It usually boils down to these three things:

#1) Respect the privacy of others.  <==這裡僅是一些說明與警示項目

#2) Think before you type.

#3) With great power comes great responsibility.

Password: <==注意啊！這裡輸入的是『 vbird1 自己的密碼 』

pro3:$1$GfinyJgZ$9J8IdrBXXMwZIauANg7tW0:14302:0:99999:7:::

# 看！vbird1 竟然可以查詢 shadow ！

注意到了吧！vbird1 輸入自己的密碼就能夠執行 root 的指令！所以，系統管理員當然要瞭解 vbird1 這個用戶的『操守』才行！否則隨便設定一個使用者，他惡搞系統怎辦？另外，一個一個設定太麻煩了， 能不能使用群組的方式來設定呢？參考底下的方式吧。

1. 利用群組以及免密碼的功能處理 visudo

我們在本章前面曾經建立過 pro1, pro2, pro3 ，這三個用戶能否透過群組的功能讓這三個人可以管理系統？ 可以的，而且很簡單！同樣我們使用實際案例來說明：

[root@www ~]# visudo  <==同樣的，請使用 root 先設定

....(前面省略)....

%wheel     ALL=(ALL)    ALL <==大約在 84 行左右，請將這行的 # 拿掉！

# 在最左邊加上 % ，代表後面接的是一個『群組』之意！改完請儲存後離開

[root@www ~]# usermod -a -G wheel pro1 <==將 pro1 加入 wheel 的支援

上面的設定值會造成『任何加入 wheel 這個群組的使用者，就能夠使用 sudo 切換任何身份來操作任何指令』的意思。 你當然可以將 wheel 換成你自己想要的群組名。接下來，請分別切換身份成為 pro1 及 pro2 試看看 sudo 的運作。

[pro1@www ~]$ sudo tail -n 1 /etc/shadow <==注意身份是 pro1

....(前面省略)....

Password:  <==輸入 pro1 的密碼喔！

pro3:$1$GfinyJgZ$9J8IdrBXXMwZIauANg7tW0:14302:0:99999:7:::

[pro2@www ~]$ sudo tail -n 1 /etc/shadow <==注意身份是 pro2

Password:

pro2 is not in the sudoers file.  This incident will be reported.

# 仔細看錯誤訊息他是說這個 pro2 不在 /etc/sudoers 的設定中！

這樣理解群組了吧？如果你想要讓 pro3 也支援這個 sudo 的話，不需要重新使用 visudo ，只要利用 usermod 去修改 pro3 的群組支援，讓 wheel 也支援 pro3 的話，那他就能夠進行 sudo 囉！ 簡單吧！不過，既然我們都信任這些 sudo 的用戶了，能否提供『不需要密碼即可使用 sudo 』呢？ 就透過如下的方式：

[root@www ~]# visudo  <==同樣的，請使用 root 先設定

....(前面省略)....

%wheel     ALL=(ALL)   NOPASSWD: ALL <==大約在 87 行左右，請將 # 拿掉！

# 在最左邊加上 % ，代表後面接的是一個『群組』之意！改完請儲存後離開

重點是那個 NOPASSWD 啦！該關鍵字是免除密碼輸入的意思喔！

1. 有限制的指令操作：

上面兩點都會讓使用者能夠利用 root 的身份進行任何事情！這樣總是不太好∼如果我想要讓使用者僅能夠進行部分系統任務， 比方說，系統上面的 myuser1 僅能夠幫 root 修改其他使用者的密碼時，亦即『當使用者僅能使用 passwd 這個指令幫忙 root 修改其他用戶的密碼』時，你該如何撰寫呢？可以這樣做：

[root@www ~]# visudo  <==注意是 root 身份

myuser1 ALL=(root)  /usr/bin/passwd  <==最後指令務必用絕對路徑

上面的設定值指的是『myuser1 可以切換成為 root 使用 passwd 這個指令』的意思。其中要注意的是： 指令欄位必須要填寫絕對路徑才行！否則 visudo 會出現語法錯誤的狀況發生！ 此外，上面的設定是有問題的！我們使用底下的指令操作來讓您瞭解：

[myuser1@www ~]$ sudo passwd myuser3  <==注意，身份是 myuser1

Password:  <==輸入 myuser1 的密碼

Changing password for user myuser3. <==底下改的是 myuser3 的密碼喔！這樣是正確的

New UNIX password:

Retype new UNIX password:

passwd: all authentication tokens updated successfully.

[myuser1@www ~]$ sudo passwd

Changing password for user root.  <==見鬼！怎麼會去改 root 的密碼？

恐怖啊！我們竟然讓 root 的密碼被 myuser3 給改變了！下次 root 回來竟無法登入系統...欲哭無淚∼怎辦？ 所以我們必須要限制使用者的指令參數！修改的方法為將上述的那行改一改先：

[root@www ~]# visudo  <==注意是 root 身份

myuser1 ALL=(root)  !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, \

!/usr/bin/passwd root

由於螢幕一行寫不完，我將這行寫成兩行，所以上面第一行最後加上反斜線囉。加上驚嘆號『 ! 』代表『不可執行』的意思。 因此上面這一行會變成：可以執行『 passwd 任意字元』，但是『 passwd 』與『 passwd root 』這兩個指令例外！ 如此一來 myuser1 就無法改變 root 的密碼了！這樣這位使用者可以具有 root 的能力幫助你修改其他用戶的密碼， 而且也不能隨意改變 root 的密碼！很有用處的！

1. 透過別名建置 visudo：

如上述第三點，如果我有 15 個用戶需要加入剛剛的管理員行列，那麼我是否要將上述那長長的設定寫入 15 行啊？ 而且如果想要修改命令或者是新增命令時，那我每行都需要重新設定，很麻煩ㄟ！有沒有更簡單的方式？ 是有的！透過別名即可！我們 visudo 的別名可以是『指令別名、帳號別名、主機別名』等。不過這裡我們僅介紹帳號別名， 其他的設定值有興趣的話，可以自行玩玩！

假設我的 pro1, pro2, pro3 與 myuser1, myuser2 要加入上述的密碼管理員的 sudo 列表中， 那我可以創立一個帳號別名稱為 ADMPW 的名稱，然後將這個名稱處理一下即可。處理的方式如下：

[root@www ~]# visudo  <==注意是 root 身份

User_Alias ADMPW = pro1, pro2, pro3, myuser1, myuser2

Cmnd_Alias ADMPWCOM = !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, \

!/usr/bin/passwd root

ADMPW   ALL=(root)  ADMPWCOM

我透過 User_Alias 建立出一個新帳號，這個帳號名稱一定要使用大寫字元來處理，包括 Cmnd_Alias(命令別名)、Host_Alias(來源主機名稱別名) 都需要使用大寫字元的！這個 ADMPW 代表後面接的那些實際帳號。 而該帳號能夠進行的指令就如同 ADMPWCOM 後面所指定的那樣！上表最後一行則寫入這兩個別名 (帳號與指令別名)， 未來要修改時，我只要修改 User_Alias 以及 Cmnd_Alias 這兩行即可！設定方面會比較簡單有彈性喔！

1. sudo 的時間間隔問題：

或許您已經發現了，那就是，如果我使用同一個帳號在短時間內重複操作 sudo 來運作指令的話， 在第二次執行 sudo 時，並不需要輸入自己的密碼！sudo 還是會正確的運作喔！為什麼呢？ 第一次執行 sudo 需要輸入密碼，是擔心由於使用者暫時離開座位，但有人跑來你的座位使用你的帳號操作系統之故。 所以需要你輸入一次密碼重新確認一次身份。

兩次執行 sudo 的間隔在五分鐘內，那麼再次執行 sudo 時就不需要再次輸入密碼了， 這是因為系統相信你在五分鐘內不會離開你的作業，所以執行 sudo 的是同一個人！呼呼！真是很人性化的設計啊∼ ^_^。不過如果兩次 sudo 操作的間隔超過 5 分鐘，那就得要重新輸入一次你的密碼了 (註4)

另外要注意的是，因為使用一般帳號時，理論上不會使用到 /sbin, /usr/sbin 等目錄內的指令，所以 $PATH 變數不會含有這些目錄，因此很多管理指令需要使用絕對路徑來下達比較妥當喔！

2. sudo 搭配 su 的使用方式：

很多時候我們需要大量執行很多 root 的工作，所以一直使用 sudo 覺得很煩ㄟ！那有沒有辦法使用 sudo 搭配 su ， 一口氣將身份轉為 root ，而且還用使用者自己的密碼來變成 root 呢？是有的！而且方法簡單的會讓你想笑！ 我們建立一個 ADMINS 帳號別名，然後這樣做：

[root@www ~]# visudo

User_Alias  ADMINS = pro1, pro2, pro3, myuser1

ADMINS ALL=(root)  /bin/su -

接下來，上述的 pro1, pro2, pro3, myuser1 這四個人，只要輸入『 sudo su - 』並且輸入『自己的密碼』後， 立刻變成 root 的身份！不但 root 密碼不會外流，使用者的管理也變的非常方便！ 這也是實務上面多人共管一部主機時常常使用的技巧呢！這樣管理確實方便，不過還是要強調一下大前提， 那就是『這些你加入的使用者，全部都是你能夠信任的用戶』！

使用者的特殊 shell 與 PAM 模組

我們前面一直談到的大多是一般身份使用者與系統管理員 (root) 的相關操作， 而且大多是討論關於可登入系統的帳號來說。那麼換個角度想，如果我今天想要建立的， 是一個『僅能使用 mail server 相關郵件服務的帳號，而該帳號並不能登入 Linux 主機』呢？如果不能給予該帳號一個密碼，那麼該帳號就無法使用系統的各項資源，當然也包括 mail 的資源， 而如果給予一個密碼，那麼該帳號就可能可以登入 Linux 主機啊！呵呵∼傷腦筋吧∼ 所以，底下讓我們來談一談這些有趣的話題囉！

另外，在本章之前談到過 /etc/login.defs 檔案中，關於密碼長度應該預設是 5 個字串長度，但是我們上面也談到，該設定值已經被 PAM 模組所取代了，那麼 PAM 是什麼？為什麼他可以影響我們使用者的登入呢？這裡也要來談談的！

特殊的 shell, /sbin/nologin

在本章一開頭的 passwd 檔案結構裡面我們就談過系統帳號這玩意兒，這玩意兒的 shell 就是使用 /sbin/nologin ，重點在於系統帳號是不需要登入的！所以我們就給他這個無法登入的合法 shell。 使用了這個 shell 的用戶即使有了密碼，你想要登入時他也無法登入，因為會出現如下的訊息喔：

This account is currently not available.

我們所謂的『無法登入』指的僅是：『這個使用者無法使用 bash 或其他 shell 來登入系統』而已， 並不是說這個帳號就無法使用其他的系統資源喔！ 舉例來說，各個系統帳號，列印工作由 lp 這個帳號在管理， WWW 服務由 apache 這個帳號在管理， 他們都可以進行系統程序的工作，但是『就是無法登入主機』而已啦！^_^

換個角度來想，如果我的 Linux 主機提供的是郵件服務，所以說，在這部 Linux 主機上面的帳號， 其實大部分都是用來收受主機的信件而已，並不需要登入主機的呢！ 這個時候，我們就可以考慮讓單純使用 mail 的帳號以 /sbin/nologin 做為他們的 shell ， 這樣，最起碼當我的主機被嘗試想要登入系統以取得 shell 環境時，可以拒絕該帳號呢！

另外，如果我想要讓某個具有 /sbin/nologin 的使用者知道，他們不能登入主機時， 其實我可以建立『 /etc/nologin.txt 』這個檔案， 並且在這個檔案內說明不能登入的原因，那麼下次當這個使用者想要登入系統時， 螢幕上出現的就會是 /etc/nologin.txt 這個檔案的內容，而不是預設的內容了！

例題：

當使用者嘗試利用純 mail 帳號 (例如 myuser3) 時，利用 /etc/nologin.txt 告知使用者不要利用該帳號登入系統。

答：

直接以 vi 編輯該檔案，內容可以是這樣：

[root@www ~]# vi /etc/nologin.txt

This account is system account or mail account.

Please DO NOT use this account to login my Linux server.

想要測試時，可以使用 myuser3 (此帳號的 shell 是 /sbin/nologin) 來測試看看！

[root@www ~]# su - myuser3

This account is system account or mail account.

Please DO NOT use this account to login my Linux server.

[root@www ~]#

結果會發現與原本的預設訊息不一樣喔！ ^_^

PAM 模組簡介

在過去，我們想要對一個使用者進行認證 (authentication)，得要要求使用者輸入帳號密碼， 然後透過自行撰寫的程式來判斷該帳號密碼是否正確。也因為如此，我們常常得使用不同的機制來判斷帳號密碼， 所以搞的一部主機上面擁有多個各別的認證系統，也造成帳號密碼可能不同步的驗證問題！ 為了解決這個問題因此有了 PAM (Pluggable Authentication Modules, 嵌入式模組) 的機制！

PAM 可以說是一套應用程式介面 (Application Programming Interface, API)，他提供了一連串的驗證機制，只要使用者將驗證階段的需求告知 PAM 後， PAM 就能夠回報使用者驗證的結果 (成功或失敗)。由於 PAM 僅是一套驗證的機制，又可以提供給其他程式所呼叫引用，因此不論你使用什麼程式，都可以使用 PAM 來進行驗證，如此一來，就能夠讓帳號密碼或者是其他方式的驗證具有一致的結果！也讓程式設計師方便處理驗證的問題喔！ (註5)

圖 5.2.1、 PAM 模組與其他程式的相關性

如上述的圖示， PAM 是一個獨立的 API 存在，只要任何程式有需求時，可以向 PAM 發出驗證要求的通知， PAM 經過一連串的驗證後，將驗證的結果回報給該程式，然後該程式就能夠利用驗證的結果來進行可登入或顯示其他無法使用的訊息。 這也就是說，你可以在寫程式的時候將 PAM 模組的功能加入，就能夠利用 PAM 的驗證功能囉。 因此目前很多程式都會利用 PAM 喔！所以我們才要來學習他啊！

PAM 用來進行驗證的資料稱為模組 (Modules)，每個 PAM 模組的功能都不太相同。舉例來說， 還記得我們在本章使用 passwd 指令時，如果隨便輸入字典上面找的到的字串， passwd 就會回報錯誤資訊了！這是為什麼呢？這就是 PAM 的 pam_cracklib.so 模組的功能！他能夠判斷該密碼是否在字典裡面！ 並回報給密碼修改程式，此時就能夠瞭解你的密碼強度了。

所以，當你有任何需要判斷是否在字典當中的密碼字串時，就可以使用 pam_cracklib.so 這個模組來驗證！ 並根據驗證的回報結果來撰寫你的程式呢！這樣說，可以理解 PAM 的功能了吧？沒錯！ PAM 的模組也是很重要的一環！

PAM 模組設定語法

PAM 藉由一個與程式相同檔名的設定檔來進行一連串的認證分析需求。我們同樣以 passwd 這個指令的呼叫 PAM 來說明好了。 當你執行 passwd 後，這支程式呼叫 PAM 的流程是：

1. 使用者開始執行 /usr/bin/passwd 這支程式，並輸入密碼；

2. passwd 呼叫 PAM 模組進行驗證；

3. PAM 模組會到 /etc/pam.d/ 找尋與程式 (passwd) 同名的設定檔；

4. 依據 /etc/pam.d/passwd 內的設定，引用相關的 PAM 模組逐步進行驗證分析；

5. 將驗證結果 (成功、失敗以及其他訊息) 回傳給 passwd 這支程式；

6. passwd 這支程式會根據 PAM 回傳的結果決定下一個動作 (重新輸入新密碼或者通過驗證！)

從上頭的說明，我們會知道重點其實是 /etc/pam.d/ 裡面的設定檔，以及設定檔所呼叫的 PAM 模組進行的驗證工作！ 既然一直談到 passwd 這個密碼修改指令，那我們就來看看 /etc/pam.d/passwd 這個設定檔的內容是怎樣吧！

[root@www ~]# cat /etc/pam.d/passwd

#%PAM-1.0  <==PAM版本的說明而已！

auth       include      system-auth <==每一行都是一個驗證的過程

account    include      system-auth

password   include      system-auth

驗證類別   控制標準     PAM 模組與該模組的參數

在這個設定檔當中，除了第一行宣告 PAM 版本之外，其他任何『 # 』開頭的都是註解，而每一行都是一個獨立的驗證流程， 每一行可以區分為三個欄位，分別是驗證類別(type)、控制標準(flag)、PAM的模組與該模組的參數。 底下我們先來談談驗證類別與控制標準這兩項資料吧！

Tips:

你會發現在我們上面的表格當中出現的是『 include (包括) 』這個關鍵字，他代表的是『請呼叫後面的檔案來作為這個類別的驗證』， 所以，上述的每一行都要重複呼叫 /etc/pam.d/system-auth 那個檔案來進行驗證的意思！

- 第一個欄位：驗證類別 (Type)

驗證類別主要分為四種，分別說明如下：

- auth

是 authentication (認證) 的縮寫，所以這種類別主要用來檢驗使用者的身份驗證，這種類別通常是需要密碼來檢驗的， 所以後續接的模組是用來檢驗使用者的身份。

- account

account (帳號) 則大部分是在進行 authorization (授權)，這種類別則主要在檢驗使用者是否具有正確的使用權限， 舉例來說，當你使用一個過期的密碼來登入時，當然就無法正確的登入了。

- session

session 是會議期間的意思，所以 session 管理的就是使用者在這次登入 (或使用這個指令) 期間，PAM 所給予的環境設定。 這個類別通常用在記錄使用者登入與登出時的資訊！例如，如果你常常使用 su 或者是 sudo 指令的話， 那麼應該可以在 /var/log/secure 裡面發現很多關於 pam 的說明，而且記載的資料是『session open, session close』的資訊！

- password

password 就是密碼嘛！所以這種類別主要在提供驗證的修訂工作，舉例來說，就是修改/變更密碼啦！

這四個驗證的類型通常是有順序的，不過也有例外就是了。 會有順序的原因是，(1)我們總是得要先驗證身份 (auth) 後， (2)系統才能夠藉由使用者的身份給予適當的授權與權限設定 (account)，而且(3)登入與登出期間的環境才需要設定， 也才需要記錄登入與登出的資訊 (session)。如果在運作期間需要密碼修訂時，(4)才給予 password 的類別。這樣說起來， 自然是需要有點順序吧！

- 第二個欄位：驗證的控制旗標 (control flag)

那麼『驗證的控制旗標(control flag)』又是什麼？簡單的說，他就是『驗證通過的標準』啦！ 這個欄位在管控該驗證的放行方式，主要也分為四種控制方式：

- required

此驗證若成功則帶有 success (成功) 的標誌，若失敗則帶有 failure 的標誌，但不論成功或失敗都會繼續後續的驗證流程。 由於後續的驗證流程可以繼續進行，因此相當有利於資料的登錄 (log) ，這也是 PAM 最常使用 required 的原因。

- requisite

若驗證失敗則立刻回報原程式 failure 的標誌，並終止後續的驗證流程。若驗證成功則帶有 success 的標誌並繼續後續的驗證流程。 這個項目與 required 最大的差異，就在於失敗的時候還要不要繼續驗證下去？由於 requisite 是失敗就終止， 因此失敗時所產生的 PAM 資訊就無法透過後續的模組來記錄了。

- sufficient

若驗證成功則立刻回傳 success 給原程式，並終止後續的驗證流程；若驗證失敗則帶有 failure 標誌並繼續後續的驗證流程。 這玩意兒與 requisits 剛好相反！

- optional

這個模組控制項目大多是在顯示訊息而已，並不是用在驗證方面的。

如果將這些控制旗標以圖示的方式配合成功與否的條件繪圖，會有點像底下這樣：

圖 5.3.1、 PAM 控制旗標所造成的回報流程

程式運作過程中遇到驗證時才會去呼叫 PAM ，而 PAM 驗證又分很多類型與控制，不同的控制旗標所回報的訊息並不相同。 如上圖所示， requisite 失敗就回報了並不會繼續，而 sufficient 則是成功就回報了也不會繼續。 至於驗證結束後所回報的資訊通常是『succes 或 failure 』而已，後續的流程還需要該程式的判斷來繼續執行才行。

常用模組簡介

談完了設定檔的語法後，現在讓我們來查閱一下 CentOS 5.x 提供的 PAM 預設檔案的內容是啥吧！ 由於我們常常需要透過各種方式登入 (login) 系統，因此就來看看登入所需要的 PAM 流程為何：

[root@www ~]# cat /etc/pam.d/login

#%PAM-1.0

auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so

auth       include      system-auth

account    required     pam_nologin.so

account    include      system-auth

password   include      system-auth

# pam_selinux.so close should be the first session rule

session    required     pam_selinux.so close

session    include      system-auth

session    required     pam_loginuid.so

session    optional     pam_console.so

# pam_selinux.so open should only be followed by sessions...

session    required     pam_selinux.so open

session    optional     pam_keyinit.so force revoke

# 我們可以看到，其實 login 也呼叫多次的 system-auth ，所以底下列出該設定檔

[root@www ~]# cat /etc/pam.d/system-auth

#%PAM-1.0

# This file is auto-generated.

# User changes will be destroyed the next time authconfig is run.

auth     required     pam_env.so

auth     sufficient   pam_unix.so nullok try_first_pass

auth     requisite    pam_succeed_if.so uid >= 500 quiet

auth     required     pam_deny.so

account  required     pam_unix.so

account  sufficient   pam_succeed_if.so uid < 500 quiet

account  required     pam_permit.so

password requisite    pam_cracklib.so try_first_pass retry=3

password sufficient   pam_unix.so md5 shadow nullok try_first_pass use_authtok

password required     pam_deny.so

session  optional     pam_keyinit.so revoke

session  required     pam_limits.so

session  [success=1 default=ignore] pam_succeed_if.so service in crond quiet \

use_uid

session  required     pam_unix.so

上面這個表格當中使用到非常多的 PAM 模組，每個模組的功能都不太相同，詳細的模組情報可以在你的系統中找到：

- /etc/pam.d/*：每個程式個別的 PAM 設定檔；

- /lib/security/*：PAM 模組檔案的實際放置目錄；

- /etc/security/*：其他 PAM 環境的設定檔；

- /usr/share/doc/pam-*/：詳細的 PAM 說明文件。

例如鳥哥使用未 update 過的 CentOS 5.2 ，pam_nologin 說明文件檔在： /usr/share/doc/pam-0.99.6.2/txts/README.pam_nologin。你可以自行查閱一下該模組的功能。 鳥哥這裡僅簡單介紹幾個較常使用的模組，詳細的資訊還得要您努力查閱參考書呢！ ^_^

- pam_securetty.so：

限制系統管理員 (root) 只能夠從安全的 (secure) 終端機登入；那什麼是終端機？例如 tty1, tty2 等就是傳統的終端機裝置名稱。那麼安全的終端機設定呢？ 就寫在 /etc/securetty 這個檔案中。你可以查閱一下該檔案， 就知道為什麼 root 可以從 tty1~tty7 登入，但卻無法透過 telnet 登入 Linux 主機了！

- pam_nologin.so：

這個模組可以限制一般使用者是否能夠登入主機之用。當 /etc/nologin 這個檔案存在時，則所有一般使用者均無法再登入系統了！若 /etc/nologin 存在，則一般使用者在登入時， 在他們的終端機上會將該檔案的內容顯示出來！所以，正常的情況下，這個檔案應該是不能存在系統中的。 但這個模組對 root 以及已經登入系統中的一般帳號並沒有影響。

- pam_selinux.so：

SELinux 是個針對程序來進行細部管理權限的功能，SELinux 這玩意兒我們會在第十七章的時候再來詳細談論。由於 SELinux 會影響到使用者執行程式的權限，因此我們利用 PAM 模組，將 SELinux 暫時關閉，等到驗證通過後， 再予以啟動！

- pam_console.so：

當系統出現某些問題，或者是某些時刻你需要使用特殊的終端介面 (例如 RS232 之類的終端連線設備) 登入主機時， 這個模組可以幫助處理一些檔案權限的問題，讓使用者可以透過特殊終端介面 (console) 順利的登入系統。

- pam_loginuid.so：

我們知道系統帳號與一般帳號的 UID 是不同的！一般帳號 UID 均大於 500 才合理。 因此，為了驗證使用者的 UID 真的是我們所需要的數值，可以使用這個模組來進行規範！

- pam_env.so：

用來設定環境變數的一個模組，如果你有需要額外的環境變數設定，可以參考 /etc/security/pam_env.conf 這個檔案的詳細說明。

- pam_unix.so：

這是個很複雜且重要的模組，這個模組可以用在驗證階段的認證功能，可以用在授權階段的帳號授權管理， 可以用在會議階段的登錄檔記錄等，甚至也可以用在密碼更新階段的檢驗！非常豐富的功能！ 這個模組在早期使用得相當頻繁喔！

- pam_cracklib.so：

可以用來檢驗密碼的強度！包括密碼是否在字典中，密碼輸入幾次都失敗就斷掉此次連線等功能，都是這模組提供的！ 這玩意兒很重要！

- pam_limits.so：

還記得我們在十一章談到的 ulimit 嗎？ 其實那就是這個模組提供的能力！還有更多細部的設定可以參考： /etc/security/limits.conf 內的說明。

瞭解了這些模組的大致功能後，言歸正傳，討論一下 login 的 PAM 驗證機制流程是這樣的：

1. 驗證階段 (auth)：首先，(a)會先經過 pam_securetty.so 判斷，如果使用者是 root 時，則會參考 /etc/securetty 的設定； 接下來(b)經過 pam_env.so 設定額外的環境變數；再(c)透過 pam_unix.so 檢驗密碼，若通過則回報 login 程式；若不通過則(d)繼續往下以 pam_succeed_if.so 判斷 UID 是否大於 500 ，若小於 500則回報失敗，否則再往下 (e)以 pam_deny.so 拒絕連線。

2. 授權階段 (account)：(a)先以 pam_nologin.so 判斷 /etc/nologin 是否存在，若存在則不許一般使用者登入； (b)接下來以 pam_unix 進行帳號管理，再以 (c) pam_succeed_if.so 判斷 UID 是否小於 500 ，若小於 500 則不記錄登錄資訊。(d)最後以 pam_permit.so 允許該帳號登入。

3. 密碼階段 (password)：(a)先以 pam_cracklib.so 設定密碼僅能嘗試錯誤 3 次；(b)接下來以 pam_unix.so 透過 md5, shadow 等功能進行密碼檢驗，若通過則回報 login 程式，若不通過則 (c)以 pam_deny.so 拒絕登入。

4. 會議階段 (session)：(a)先以 pam_selinux.so 暫時關閉 SELinux；(b)使用 pam_limits.so 設定好使用者能夠操作的系統資源； (c)登入成功後開始記錄相關資訊在登錄檔中； (d)以 pam_loginuid.so 規範不同的 UID 權限；(e)開啟 pam_selinux.so 的功能。

總之，就是依據驗證類別 (type) 來看，然後先由 login 的設定值去查閱，如果出現『 include system-auth 』 就轉到 system-auth 檔案中的相同類別，去取得額外的驗證流程就是了。然後再到下一個驗證類別，最終將所有的驗證跑完！ 就結束這次的 PAM 驗證啦！

經過這樣的驗證流程，現在你知道為啥 /etc/nologin 存在會有問題，也會知道為何你使用一些遠端連線機制時， 老是無法使用 root 登入的問題了吧？沒錯！這都是 PAM 模組提供的功能啦！

例題：

為什麼 root 無法以 telnet 直接登入系統，但是卻能夠使用 ssh 直接登入？

答：

一般來說， telnet 會引用 login 的 PAM 模組，而 login 的驗證階段會有 /etc/securetty 的限制！ 由於遠端連線屬於 pts/n (n 為數字) 的動態終端機介面裝置名稱，並沒有寫入到 /etc/securetty ， 因此 root 無法以 telnet 登入遠端主機。至於 ssh 使用的是 /etc/pam.d/sshd 這個模組， 你可以查閱一下該模組，由於該模組的驗證階段並沒有加入 pam_securetty ，因此就沒有 /etc/securetty 的限制！故可以從遠端直接連線到伺服器端。

另外，關於 telnet 與 ssh 的細部說明，請參考鳥哥的 Linux 私房菜伺服器篇

其他相關檔案

除了前一小節談到的 /etc/securetty 會影響到 root 可登入的安全終端機， /etc/nologin 會影響到一般使用者是否能夠登入的功能之外，我們也知道 PAM 相關的設定檔在 /etc/pam.d ， 說明文件在 /usr/share/doc/pam-(版本) ，模組實際在 /lib/security/ 。那麼還有沒有相關的 PAM 檔案呢？ 是有的，主要都在 /etc/security 這個目錄內！我們底下介紹幾個可能會用到的設定檔喔！

- limits.conf

我們在第十一章談到的 ulimit 功能中， 除了修改使用者的 ~/.bashrc 設定檔之外，其實系統管理員可以統一藉由 PAM 來管理的！ 那就是 /etc/security/limits.conf 這個檔案的設定了。這個檔案的設定很簡單，你可以自行參考一下該檔案內容。 我們這裡僅作個簡單的介紹：

範例一：vbird1 這個用戶只能建立 100MB 的檔案，且大於 90MB 會警告

[root@www ~]# vi /etc/security/limits.conf

vbird1  soft           fsize           90000

vbird1  hard           fsize          100000

#帳號   限制依據       限制項目       限制值

# 第一欄位為帳號，或者是群組！若為群組則前面需要加上 @ ，例如 @projecta

# 第二欄位為限制的依據，是嚴格(hard)，還是僅為警告(soft)；

# 第三欄位為相關限制，此例中限制檔案容量，

# 第四欄位為限制的值，在此例中單位為 KB。

# 若以 vbird1 登入後，進行如下的操作則會有相關的限制出現！

[vbird1@www ~]$ ulimit -a

....(前面省略)....

file size               (blocks, -f) 90000

....(後面省略)....

[vbird1@www ~]$ dd if=/dev/zero of=test bs=1M count=110

File size limit exceeded

[vbird1@www ~]$ ll -k test

-rw-rw-r-- 1 vbird1 vbird1 90000 Mar  4 11:30 test

# 果然有限制到了

範例二：限制 pro1 這個群組，每次僅能有一個使用者登入系統 (maxlogins)

[root@www ~]# vi /etc/security/limits.conf

@pro1   hard   maxlogins   1

# 如果要使用群組功能的話，這個功能似乎對初始群組才有效喔！

# 而如果你嘗試多個 pro1 的登入時，第二個以後就無法登入了。

# 而且在 /var/log/secure 檔案中還會出現如下的資訊：

# pam_limits(login:session): Too many logins (max 1) for pro1

這個檔案挺有趣的，而且是設定完成就生效了，你不用重新啟動任何服務的！ 但是 PAM 有個特殊的地方，由於他是在程式呼叫時才予以設定的，因此你修改完成的資料， 對於已登入系統中的使用者是沒有效果的，要等他再次登入時才會生效喔！另外， 上述的設定請在測試完成後立刻註解掉，否則下次這兩個使用者登入就會發生些許問題啦！ ^_^

- /var/log/secure, /var/log/messages

如果發生任何無法登入或者是產生一些你無法預期的錯誤時，由於 PAM 模組都會將資料記載在 /var/log/secure 當中，所以發生了問題請務必到該檔案內去查詢一下問題點！舉例來說， 我們在 limits.conf 的介紹內的範例二，就有談到多重登入的錯誤可以到 /var/log/secure 內查閱了！ 這樣你也就知道為何第二個 pro1 無法登入啦！^_^

Linux 主機上的使用者訊息傳遞

談了這麼多的帳號問題，總是該要談一談，那麼如何針對系統上面的使用者進行查詢吧？ 想幾個狀態，如果你在 Linux 上面操作時，剛好有其他的使用者也登入主機，你想要跟他對談，該如何是好？ 你想要知道某個帳號的相關資訊，該如何查閱？呼呼！底下我們就來聊一聊∼

查詢使用者： w, who, last, lastlog

如何查詢一個使用者的相關資料呢？這還不簡單，我們之前就提過了 id, finger 等指令了，都可以讓您瞭解到一個使用者的相關資訊啦！那麼想要知道使用者到底啥時候登入呢？ 最簡單可以使用 last 檢查啊！這個玩意兒我們也在 第十一章 bash 提過了， 您可以自行前往參考啊！簡單的很。

Tips:

早期的 Red Hat 系統的版本中， last 僅會列出當月的登入者資訊，不過在我們的 CentOS 5.x 版以後， last 可以列出從系統建立之後到目前為止的所有登入者資訊！這是因為登錄檔輪替的設定不同所致。 詳細的說明可以參考後續的第十九章登錄檔簡介。

那如果你想要知道目前已登入在系統上面的使用者呢？可以透過 w 或 who 來查詢喔！如下範例所示：

[root@www ~]# w

13:13:56 up 13:00,  1 user,  load average: 0.08, 0.02, 0.01

USER   TTY    FROM            LOGIN@   IDLE   JCPU   PCPU WHAT

root   pts/1  192.168.1.100   11:04    0.00s  0.36s  0.00s -bash

vbird1 pts/2  192.168.1.100   13:15    0.00s  0.06s  0.02s w

# 第一行顯示目前的時間、開機 (up) 多久，幾個使用者在系統上平均負載等；

# 第二行只是各個項目的說明，

# 第三行以後，每行代表一個使用者。如上所示，root 登入並取得終端機名 pts/1 之意。

[root@www ~]# who

root     pts/1        2009-03-04 11:04 (192.168.1.100)

vbird1   pts/2        2009-03-04 13:15 (192.168.1.100)

另外，如果您想要知道每個帳號的最近登入的時間，則可以使用 lastlog 這個指令喔！ lastlog 會去讀取 /var/log/lastlog 檔案，結果將資料輸出如下表：

[root@www ~]# lastlog

Username    Port   From           Latest

root        pts/1  192.168.1.100  Wed Mar  4 11:04:22 +0800 2009

bin                                        **Never logged in**

....(中間省略)....

vbird1      pts/2  192.168.1.100  Wed Mar  4 13:15:56 +0800 2009

....(以下省略)....

這樣就能夠知道每個帳號的最近登入的時間囉∼ ^_^

使用者對談： write, mesg, wall

那麼我是否可以跟系統上面的使用者談天說地呢？當然可以啦！利用 write 這個指令即可。 write 可以直接將訊息傳給接收者囉！舉例來說，我們的 Linux 目前有 vbird1 與 root 兩個人在線上， 我的 root 要跟 vbird1 講話，可以這樣做：

[root@www ~]# write 使用者帳號 [使用者所在終端介面]

[root@www ~]# who

root     pts/1    2009-03-04 11:04 (192.168.1.100)

vbird1   pts/2    2009-03-04 13:15 (192.168.1.100)  <==有看到 vbird1 在線上

[root@www ~]# write vbird1 pts/2

Hello, there:

Please don't do anything wrong...  <==這兩行是 root 寫的資訊！

# 結束時，請按下 [crtl]-d 來結束輸入。此時在 vbird1 的畫面中，會出現：

Message from root@www.vbird.tsai on pts/1 at 13:23 ...

Hello, there:

Please don't do anything wrong...

EOF

怪怪∼立刻會有訊息回應給 vbird1 ！不過......當時 vbird1 正在查資料，哇！ 這些訊息會立刻打斷 vbird1 原本的工作喔！所以，如果 vbird1 這個人不想要接受任何訊息，直接下達這個動作：

[vbird1@www ~]$ mesg n

[vbird1@www ~]$ mesg

is n

不過，這個 mesg 的功能對 root 傳送來的訊息沒有抵擋的能力！所以如果是 root 傳送訊息， vbird1 還是得要收下。 但是如果 root 的 mesg 是 n 的，那麼 vbird1 寫給 root 的資訊會變這樣：

[vbird1@www ~]$ write root

write: root has messages disabled

瞭解乎？如果想要解開的話，再次下達『 mesg y 』就好啦！想要知道目前的 mesg 狀態，直接下達『 mesg 』即可！瞭呼？ 相對於 write 是僅針對一個使用者來傳『簡訊』，我們還可以『對所有系統上面的使用者傳送簡訊 (廣播)』哩∼ 如何下達？用 wall 即可啊！他的語法也是很簡單的喔！

[root@www ~]# wall "I will shutdown my linux server..."

然後你就會發現所有的人都會收到這個簡訊呢！

使用者郵件信箱： mail

使用 wall, write 畢竟要等到使用者在線上才能夠進行，有沒有其他方式來聯絡啊？ 不是說每個 Linux 主機上面的使用者都具有一個 mailbox 嗎？ 我們可否寄信給使用者啊！呵呵！當然可以啊！我們可以寄、收 mailbox 內的信件呢！ 一般來說， mailbox 都會放置在 /var/spool/mail 裡面，一個帳號一個 mailbox (檔案)。 舉例來說，我的 vbird1 就具有 /var/spool/mail/vbird1 這個 mailbox 喔！

那麼我該如何寄出信件呢？就直接使用 mail 這個指令即可！這個指令的用法很簡單的，直接這樣下達：『 mail username@localhost -s "郵件標題" 』即可！ 一般來說，如果是寄給本機上的使用者，基本上，連『 @localhost 』都不用寫啦！ 舉例來說，我以 root 寄信給 vbird1 ，信件標題是『 nice to meet you 』，則：

[root@www ~]# mail vbird1 -s "nice to meet you"

Hello, D.M. Tsai

Nice to meet you in the network.

You are so nice.  byebye!

.    <==這裡很重要喔，結束時，最後一行輸入小數點 . 即可！

Cc:  <==這裡是所謂的『副本』，不需要寄給其他人，所以直接 [Enter]

[root@www ~]#  <==出現提示字元，表示輸入完畢了！

如此一來，你就已經寄出一封信給 vbird1 這位使用者囉，而且，該信件標題為： nice to meet you，信件內容就如同上面提到的。不過，你或許會覺得 mail 這個程式不好用∼ 因為在信件編寫的過程中，如果寫錯字而按下 Enter 進入次行，前一行的資料很難刪除ㄟ！ 那怎麼辦？沒關係啦！我們使用資料流重導向啊！呵呵！利用那個小於的符號 ( < ) 就可以達到取代鍵盤輸入的要求了。也就是說，你可以先用 vi 將信件內容編好， 然後再以 mail vbird1 -s "nice to meet you" < filename 來將檔案內容傳輸即可。

例題：

請將你的家目錄下的環境變數檔 (~/.bashrc) 寄給自己！

答：

mail -s "bashrc file content" vbird < ~/.bashrc

剛剛上面提到的是關於『寄信』的問題，那麼如果是要收信呢？呵呵！同樣的使用 mail 啊！ 假設我以 vbird1 的身份登入主機，然後輸入 mail 後，會得到什麼？

[vbird1@www ~]$ mail

Mail version 8.1 6/6/93.  Type ? for help.

"/var/spool/mail/vbird1": 1 message 1 new

>N  1 root@www.vbird.tsai   Wed Mar  4 13:36  18/663   "nice to meet you"

&  <==這裡可以輸入很多的指令，如果要查閱，輸入 ? 即可！

在 mail 當中的提示字元是 & 符號喔，別搞錯了∼輸入 mail 之後，我可以看到我有一封信件， 這封信件的前面那個 > 代表目前處理的信件，而在大於符號的左邊那個 N 代表該封信件尚未讀過， 如果我想要知道這個 mail 內部的指令有哪些，可以在 & 之後輸入『 ? 』，就可以看到如下的畫面：

& ?

Mail   Commands

t <message list>                type messages

n                               goto and type next message

e <message list>                edit messages

f <message list>                give head lines of messages

d <message list>                delete messages

s <message list> file           append messages to file

u <message list>                undelete messages

R <message list>                reply to message senders

r <message list>                reply to message senders and all recipients

pre <message list>              make messages go back to /usr/spool/mail

m <user list>                   mail to specific users

q                               quit, saving unresolved messages in mbox

x                               quit, do not remove system mailbox

h                               print out active message headers

!                               shell escape

cd [directory]                  chdir to directory or home if none given

<message list> 指的是每封郵件的左邊那個數字啦！而幾個比較常見的指令是：

指令

意義

h

列出信件標頭；如果要查閱 40 封信件左右的信件標頭，可以輸入『 h 40 』

d

刪除後續接的信件號碼，刪除單封是『 d10 』，刪除 20~40 封則為『 d20-40 』。 不過，這個動作要生效的話，必須要配合 q 這個指令才行(參考底下說明)！

s

將信件儲存成檔案。例如我要將第 5 封信件的內容存成 ~/mail.file:『s 5 ~/mail.file』

x

或者輸入 exit 都可以。這個是『不作任何動作離開 mail 程式』的意思。 不論你剛剛刪除了什麼信件，或者讀過什麼，使用 exit 都會直接離開 mail，所以剛剛進行的刪除與閱讀工作都會無效。 如果您只是查閱一下郵件而已的話，一般來說，建議使用這個離開啦！除非你真的要刪除某些信件。

q

相對於 exit 是不動作離開， q 則會進行兩項動作： 1. 將剛剛刪除的信件移出 mailbox 之外； 2. 將剛剛有閱讀過的信件存入 ~/mbox ，且移出 mailbox 之外。鳥哥通常不很喜歡使用 q 離開， 因為，很容易忘記讀過什麼咚咚∼導致信件給他移出 mailbox 說∼

由於讀過的信件若使用『 q 』來離開 mail 時，會將該信件移動到 ~/mbox 中，所以你可以這樣想像： /var/spool/mail/vbird1 為 vbird1 的『新件匣』，而 /home/vbird1/mbox 則為『收件匣』的意思。 那如何讀取 /home/vbird1/mbox 呢？就使用『mail -f /home/vbird1/mbox』即可。

手動新增使用者

一般來說，我們不很建議大家使用手動的方式來新增使用者，為什麼呢？ 因為使用者的建立涉及到 GID/UID 等權限的關係，而且，與檔案/目錄的權限也有關係， 使用 useradd 可以幫我們自動設定好 UID/GID 家目錄以及家目錄相關的權限設定， 但是，手動來增加的時候，有可能會忘東忘西，結果導致一些困擾的發生。

不過，要瞭解整個系統，最好還是手動來修改過比較好，至少我們的帳號問題可以完全依照自己的意思去修訂， 而不必遷就於系統的預設值啊！但是，還是要告誡一下朋友們，要手動設定帳號時， 您必須要真的很瞭解自己在作什麼，尤其是與權限有關的設定方面喔！好吧！底下就讓我們來玩一玩囉∼ ^_^

一些檢查工具

既然要手動修改帳號的相關設定檔，那麼一些檢查群組、帳號相關的指令就不可不知道啊∼ 尤其是那個密碼轉換的 pwconv 及 pwuconv 這兩個玩意∼可重要的很呢！底下我們稍微介紹一下這些指令吧！

- pwck

pwck 這個指令在檢查 /etc/passwd 這個帳號設定檔內的資訊，與實際的家目錄是否存在等資訊， 還可以比對 /etc/passwd /etc/shadow 的資訊是否一致，另外，如果 /etc/passwd 內的資料欄位錯誤時，會提示使用者修訂。 一般來說，我只是利用這個玩意兒來檢查我的輸入是否正確就是了。

[root@www ~]# pwck

user adm: directory /var/adm does not exist

user uucp: directory /var/spool/uucp does not exist

user gopher: directory /var/gopher does not exist

瞧！上面僅是告知我，這些帳號並沒有家目錄，由於那些帳號絕大部分都是系統帳號， 確實也不需要家目錄的，所以，那是『正常的錯誤！』呵呵！不理他。 ^_^。 相對應的群組檢查可以使用 grpck 這個指令的啦！

- pwconv

這個指令主要的目的是在『將 /etc/passwd 內的帳號與密碼，移動到 /etc/shadow 當中！』 早期的 Unix 系統當中並沒有 /etc/shadow 呢，所以，使用者的登入密碼早期是在 /etc/passwd 的第二欄，後來為了系統安全，才將密碼資料移動到 /etc/shadow 內的。使用 pwconv 後，可以：

- 比對 /etc/passwd 及 /etc/shadow ，若 /etc/passwd 內存在的帳號並沒有對應的 /etc/shadow 密碼時，則 pwconv 會去 /etc/login.defs 取用相關的密碼資料，並建立該帳號的 /etc/shadow 資料；

- 若 /etc/passwd 內存在加密後的密碼資料時，則 pwconv 會將該密碼欄移動到 /etc/shadow 內，並將原本的 /etc/passwd 內相對應的密碼欄變成 x ！

一般來說，如果您正常使用 useradd 增加使用者時，使用 pwconv 並不會有任何的動作，因為 /etc/passwd 與 /etc/shadow 並不會有上述兩點問題啊！ ^_^。不過，如果手動設定帳號，這個 pwconv 就很重要囉！

- pwunconv

相對於 pwconv ， pwunconv 則是『將 /etc/shadow 內的密碼欄資料寫回 /etc/passwd 當中， 並且刪除 /etc/shadow 檔案。』這個指令說實在的，最好不要使用啦！ 因為他會將你的 /etc/shadow 刪除喔！如果你忘記備份，又不會使用 pwconv 的話，粉嚴重呢！

- chpasswd

chpasswd 是個挺有趣的指令，他可以『讀入未加密前的密碼，並且經過加密後， 將加密後的密碼寫入 /etc/shadow 當中。』這個指令很常被使用在大量建置帳號的情況中喔！ 他可以由 Standard input 讀入資料，每筆資料的格式是『 username:password 』。 舉例來說，我的系統當中有個使用者帳號為 dmtsai ，我想要更新他的密碼 (update) ， 假如他的密碼是 abcdefg 的話，那麼我可以這樣做：

[root@www ~]# echo "dmtsai:abcdefg" | chpasswd -m

神奇吧！這樣就可以更新了呢！在預設的情況中， chpasswd 使用的是 DES 加密方法來加密， 我們可以使用 chpasswd -m 來使用 CentOS 5.x 預設的 MD5 加密方法。這個指令雖然已經很好用了，不過 CentOS 5.x 其實已經提供了『 passwd --stdin 』的選項，老實說，這個 chpasswd 可以不必使用了。但考慮其他版本不見得會提供 --stdin 給 passwd 這個指令，所以您還是得要瞭解一下這個指令用途！

特殊帳號，如純數字帳號的手工建立

在我們瞭解了 UID/GID 與帳號的關係之後，基本上，您應該瞭解了，為啥我們不建議使用純數字的帳號了！因為很多時候，系統會搞不清楚那組數字是『帳號』還是『 UID 』，這不是很好啦∼也因此，在早期某些版本底下，是沒有辦法使用數字來建立帳號的。例如在 Red Hat 9 的環境中， 使用『 useradd 1234 』他會顯示『 useradd: invalid user name '1234' 』瞭解了嗎？

Tips:

在較新的 distribution 當中，純數字的帳號已經可以被 useradd 建立了。不過鳥哥還是非常不建議使用純數字帳號。 例如在 setfacl 的設定值中，若使用『 setfacl -m u:501:rwx filename 』那個 501 代表的是 UID 還是帳號？ 因為 setfacl 的設定是支援使用 UID 或帳號的，純數字帳號很容易造成系統的誤解！

不過，有的時候，長官的命令難為啊 @_@ 有時還是得要建立這方面的帳號的，那該如何是好？ 呵呵！當然可以手動來建立這樣的帳號啦！不過，為了系統安全起見，鳥哥還是不建議使用純數字的帳號的啦！ 因此，底下的範例當中，我們使用手動的方式來建立一個名為 normaluser 的帳號， 而且這個帳號屬於 normalgroup 這個群組。OK！那麼整個步驟該如何是好呢？ 由前面的說明來看，您應該瞭解了帳號與群組是與 /etc/group, /etc/shadow, /etc/passwd, /etc/gshadow 有關，因此，整個動作是這樣的：

1. 先建立所需要的群組 ( vi /etc/group )；

2. 將 /etc/group 與 /etc/gshadow 同步化 ( grpconv )；

3. 建立帳號的各個屬性 ( vi /etc/passwd )；

4. 將 /etc/passwd 與 /etc/shadow 同步化 ( pwconv )；

5. 建立該帳號的密碼 ( passwd accountname )；

6. 建立使用者家目錄 ( cp -a /etc/skel /home/accountname )；

7. 更改使用者家目錄的屬性 ( chown -R accountname.group /home/accountname )。

夠簡單的咯吧！讓我們來玩一玩囉∼

1. 建立群組 normalgroup ，假設 520 這個 GID 沒有被使用！並且同步化 gshadow

[root@www ~]# vi /etc/group

# 在最後一行加入底下這一行！

normalgroup:x:520:

[root@www ~]# grpconv

[root@www ~]# grep 'normalgroup' /etc/group /etc/gshadow

/etc/group:normalgroup:x:520:

/etc/gshadow:normalgroup:x::

# 最後確定 /etc/group, /etc/gshadow 都存在這個群組才行！搞定群組囉！

2. 建立 normaluser 這個帳號，假設 UID 700 沒被使用掉！

[root@www ~]# vi /etc/passwd

# 在最後一行加入底下這一行！

normaluser:x:700:520::/home/normaluser:/bin/bash

3. 同步化密碼，並且建立該使用者的密碼

[root@www ~]# pwconv

[root@www ~]# grep 'normaluser' /etc/passwd /etc/shadow

/etc/passwd:normaluser:x:700:520::/home/normaluser:/bin/bash

/etc/shadow:normaluser:x:14307:0:99999:7:::

# 確定 /etc/passwd, /etc/shadow 都含有 normaluser 的資訊了！但是密碼還不對∼

[root@www ~]# passwd normaluser

Changing password for user normaluser.

New UNIX password:

Retype new UNIX password:

passwd: all authentication tokens updated successfully.

4. 建立使用者家目錄，並且修訂權限！

[root@www ~]# cp -a /etc/skel /home/normaluser

[root@www ~]# chown -R normaluser:normalgroup /home/normaluser

[root@www ~]# chmod 700 /home/normaluser

別懷疑！這樣就搞定了一個帳號的設定了！ 從此以後，你可以建立任何名稱的帳號囉∼不過，還是不建議您設定一些很怪很怪的帳號名稱啦！

大量建置帳號範本(適用 passwd --stdin 選項)

由於 CentOS 5.x 的 passwd 已經提供了 --stdin 的功能，因此如果我們可以提供帳號密碼的話， 那麼就能夠很簡單的建置起我們的帳號密碼了。底下鳥哥製作一個簡單的 script 來執行新增用戶的功能喔！

[root@www ~]# vi account1.sh

#!/bin/bash

# 這支程式用來建立新增帳號，功能有：

# 1. 檢查 account1.txt 是否存在，並將該檔案內的帳號取出；

# 2. 建立上述檔案的帳號；

# 3. 將上述帳號的密碼修訂成為『強制第一次進入需要修改密碼』的格式。

# 2009/03/04    VBird

export PATH=/bin:/sbin:/usr/bin:/usr/sbin

# 檢查 account1.txt 是否存在

if [ ! -f account1.txt ]; then

echo "所需要的帳號檔案不存在，請建立 account1.txt ，每行一個帳號名稱"

exit 1

fi

usernames=$(cat account1.txt)

for username in $usernames

do

useradd $username                         <==新增帳號

echo $username | passwd --stdin $username <==與帳號相同的密碼

chage -d 0 $username                      <==強制登入修改密碼

done

接下來只要建立 account1.txt 這個檔案即可！鳥哥建立這個檔案裡面共有十行，你可以自行建立該檔案！ 內容每一行一個帳號。注意，最終的結果會是每個帳號具有與帳號相同的密碼，且初次登入後， 必須要重新設定密碼後才能夠再次登入使用系統資源！

[root@www ~]# vi account1.txt

std01

std02

std03

std04

std05

std06

std07

std08

std09

std10

[root@www ~]# sh account1.sh

Changing password for user std01.

passwd: all authentication tokens updated successfully.

....(後面省略)....

這支簡單的腳本你可以在按如下的連結下載：

- http://linux.vbird.org/linux_basic/0410accountmanager/account1.sh

另外，鳥哥的 script 是在 zh_TW.big5 的語系下建立的，如果你需要轉成萬國碼 (utf8) 的編碼格式， 請下載上述檔案後，利用第十章談到的 iconv 來處理語系的問題！

大量建置帳號的範例(適用於連續數字，如學號)

前一小節的內容已經可以滿足很多朋友的帳號建置方法了，不過，某些時候上述的 script 還是很麻煩！ 因為需要手動編輯 account1.txt 嘛！如果是類似學校單位這種學號非常類似的帳號時，有沒有更快的方案？ 此外，如果需要每個班級同屬於一個群組，不同班級的群組不同，又該如何建置？這是比較麻煩啦！

目前很多網站都有提供大量建立帳號的工具，例如台南縣網中心的臥龍大師：

- http://news.ols3.net/techdoc/old/howtouse_cmpwd101.htm

提供的好用的 cmpwd 程式，但是小三大師的程式僅供學術單位使用，一般個人是無權使用的(參考上述連結的授權)。 不過，其實我們也可以利用簡單的 script 來幫我們達成喔！例如底下這支程式， 他的執行結果與小三大師提供的程式差不多啦∼但是因為我是直接以 useradd 來新增的， 所以，即使不瞭解 UID ，也是可以適用的啦∼整支程式的特色是：

- 預設不允許使用純數字方式建立帳號；

- 可加入年級來區分帳號；

- 可設定帳號的起始號碼與帳號數量；

- 有兩種密碼建立方式，可以與帳號相同或程式自行以亂數建立密碼檔。

執行方法也簡單的要命∼請自行參考的啦！不再多說∼使用時請注意，不要在公家使用的主機上面進行測試，因為..... 這支程式會大量建立帳號嘛！^_^

#!/bin/bash

#

# 這支程式主要在幫您建立大量的帳號之用，更多的使用方法請參考：

# Vbird14.htm#manual_amount

#

# 本程式為鳥哥自行開發，在 CentOS 5.x 上使用沒有問題，

# 但不保證絕不會發生錯誤！使用時，請自行負擔風險∼

#

# History:

# 2005/09/05    VBird   剛剛才寫完，使用看看先∼

# 2009/03/04    VBird   加入一些語系的修改與說明，修改密碼產生方式 (用 openssl)

export LANG=zh_TW.big5

export PATH=/sbin:/usr/sbin:/bin:/usr/bin

accountfile="user.passwd"

# 1. 進行帳號相關的輸入先！

echo ""

echo "例如我們崑山四技的學號為： 4960c001 到 4960c060 ，那麼："

echo "帳號開頭代碼為         ：4"

echo "帳號層級或年級為       ：960c"

echo "號碼數字位數為(001~060)：3"

echo "帳號開始號碼為         ：1"

echo "帳號數量為             ：60"

echo ""

read -p "帳號開頭代碼 ( Input title name, ex> std )======> " username_start

read -p "帳號層級或年級 ( Input degree, ex> 1 or enter )=> " username_degree

read -p "號碼部分的數字位數 ( Input \# of digital )======> " nu_nu

read -p "起始號碼 ( Input start number, ex> 520 )========> " nu_start

read -p "帳號數量 ( Input amount of users, ex> 100 )=====> " nu_amount

read -p "密碼標準 1) 與帳號相同 2)亂數自訂 ==============> " pwm

if [ "$username_start" == "" ]; then

echo "沒有輸入開頭的代碼，不給你執行哩！" ; exit 1

fi

# 判斷數字系統

testing0=$(echo $nu_nu     | grep '[^0-9]' )

testing1=$(echo $nu_amount | grep '[^0-9]' )

testing2=$(echo $nu_start  | grep '[^0-9]' )

if [ "$testing0" != "" -o "$testing1" != "" -o "$testing2" != "" ]; then

echo "輸入的號碼不對啦！有非為數字的內容！" ; exit 1

fi

if [ "$pwm" != "1" ]; then

pwm="2"

fi

# 2. 開始輸出帳號與密碼檔案！

[ -f "$accountfile" ] && mv $accountfile "$accountfile"$(date +%Y%m%d)

nu_end=$(($nu_start+$nu_amount-1))

for (( i=$nu_start; i<=$nu_end; i++ ))

do

nu_len=${#i}

if [ $nu_nu -lt $nu_len ]; then

echo "數值的位數($i->$nu_len)已經比你設定的位數($nu_nu)還大！"

echo "程式無法繼續"

exit 1

fi

nu_diff=$(( $nu_nu - $nu_len ))

if [ "$nu_diff" != "0" ]; then

nu_nn=0000000000

nu_nn=${nu_nn:1:$nu_diff}

fi

account=${username_start}${username_degree}${nu_nn}${i}

if [ "$pwm" == "1" ]; then

password="$account"

else

password=$(openssl rand -base64 6)

fi

echo "$account":"$password" | tee -a "$accountfile"

done

# 3. 開始建立帳號與密碼！

cat "$accountfile" | cut -d':' -f1 | xargs -n 1 useradd -m

chpasswd < "$accountfile"

pwconv

echo "OK！建立完成！"

如果有需要建立同一班級具有同一群組的話，可以先使用 groupadd 建立群組後， 將該群組加入『 cat "$accountfile" | cut -d':' -f1 | xargs -n 1 useradd -m -g groupname 』那行！這支腳本可以在底下連結下載：

- http://linux.vbird.org/linux_basic/0410accountmanager/account2.sh

如果僅是測試而已，想要將剛剛建立的使用者整個刪除，則可以使用如下的腳本來進行刪除！

[root@www ~]# vi delaccount2.sh

#!/bin/bash

usernames=$(cat user.passwd | cut -d ':' -f 1)

for username in $usernames

do

echo "userdel -r $username"

userdel -r $username

done

[root@www ~]# sh delaccount2.sh

總之，帳號管理是很重要的！希望上面的說明能夠對大家有點幫助啦！

重點回顧

- Linux 作業系統上面，關於帳號與群組，其實記錄的是 UID/GID 的數字而已；

- 使用者的帳號/群組與 UID/GID 的對應，參考 /etc/passwd 及 /etc/group 兩個檔案

- /etc/passwd 檔案結構以冒號隔開，共分為七個欄位，分別是『帳號名稱、密碼、UID、GID、全名、家目錄、shell』

- UID 只有 0 與非為 0 兩種，非為 0 則為一般帳號。一般帳號又分為系統帳號 (1~499) 即可登入者帳號 (大於 500)

- 帳號的密碼已經移動到 /etc/shadow 檔案中，該檔案權限為僅有 root 可以更動。該檔案分為九個欄位，內容為『 帳號名稱、加密密碼、密碼更動日期、密碼最小可變動日期、密碼最大需變動日期、密碼過期前警告日數、密碼失效天數、 帳號失效日、保留未使用』

- 使用者可以支援多個群組，其中在新建檔案時會影響新檔案群組者，為有效群組。而寫入 /etc/passwd 的第四個欄位者， 稱為初始群組。

- 與使用者建立、更改參數、刪除有關的指令為：useradd, usermod, userdel等，密碼建立則為 passwd；

- 與群組建立、修改、刪除有關的指令為：groupadd, groupmod, groupdel 等；

- 群組的觀察與有效群組的切換分別為：groups 及 newgrp 指令；

- useradd 指令作用參考的檔案有： /etc/default/useradd, /etc/login.defs, /etc/skel/ 等等

- 觀察使用者詳細的密碼參數，可以使用『 chage -l 帳號 』來處理；

- 使用者自行修改參數的指令有： chsh, chfn 等，觀察指令則有： id, finger 等

- ACL 可進行單一個人或群組的權限管理，但 ACL 的啟動需要有檔案系統的支援；

- ACL 的設定可使用 setfacl ，查閱則使用 getfacl ；

- 身份切換可使用 su ，亦可使用 sudo ，但使用 sudo 者，必須先以 visudo 設定可使用的指令；

- PAM 模組可進行某些程式的驗證程序！與 PAM 模組有關的設定檔位於 /etc/pam.d/* 及 /etc/security/*

- 系統上面帳號登入情況的查詢，可使用 w, who, last, lastlog 等；

- 線上與使用者交談可使用 write, wall，離線狀態下可使用 mail 傳送郵件！

本章習題

- 情境模擬題一：想將本伺服器的帳號分開管理，分為單純郵件使用，與可登入系統帳號兩種。其中若為純郵件帳號時， 將該帳號加入 mail 為初始群組，且此帳號不可使用 bash 等 shell 登入系統。若為可登入帳號時， 將該帳號加入 youcan 這個次要群組。

- 目標：瞭解 /sbin/nologin 的用途；

- 前提：可自行觀察使用者是否已經建立等問題；

- 需求：需已瞭解 useradd, groupadd 等指令的用法；

解決方案如下：

- 預先察看一下兩個群組是否存在？

[root@www ~]# grep mail /etc/group

[root@www ~]# grep youcan /etc/group

[root@www ~]# groupadd youcan

可發現 youcan 尚未被建立，因此如上表所示，我們主動去建立這個群組囉。

- 開始建立三個郵件帳號，此帳號名稱為 pop1, pop2, pop3 ，且密碼與帳號相同。可使用如下的程式來處理：

[root@www ~]# vim popuser.sh

#!/bin/bash

for username in pop1 pop2 pop3

do

useradd -g mail -s /sbin/nologin -M $username

echo $username | passwd --stdin $username

done

[root@www ~]# sh popuser.sh

- 開始建立一般帳號，只是這些一般帳號必須要能夠登入，並且需要使用次要群組的支援！所以：

[root@www ~]# vim loginuser.sh

#!/bin/bash

for username in youlog1 youlog2 youlog3

do

useradd -G youcan -s /bin/bash -m $username

echo $username | passwd --stdin $username

done

[root@www ~]# sh loginuser.sh

- 這樣就將帳號分開管理了！非常簡單吧！

簡答題部分

- root 的 UID 與 GID 是多少？而基於這個理由，我要讓 test 這個帳號具有 root 的權限，應該怎麼作？

root 的 UID 與 GID 均為 0 ，所以要讓 test 變成 root 的權限，那麼就將 /etc/passwd 裡面， test 的 UID 與 GID 欄位變成 0 即可！

- 假設我是一個系統管理員，我有一個用戶最近不乖，所以我想暫時將他的帳號停掉， 讓他近期無法進行任何動作，等到未來他乖一點之後，我再將他的帳號啟用，請問：我可以怎麼作比較好？？

由於這個帳號是暫時失效的，所以不能使用 userdel 來刪除，否則很麻煩！那麼應該如何設定呢？再回去瞧一瞧 /etc/shadow 的架構，可以知道有這幾個可使用的方法：

- 將 /etc/passwd 的 shell 欄位寫成 /sbin/nologin ，即可讓該帳號暫時無法登入主機；

- 將 /etc/shadow 內的密碼欄位，增加一個 * 號在最前面，這樣該帳號亦無法登入！

- 將 /etc/shadow 的第八個欄位關於帳號取消日期的那個，設定小於目前日期的數字，那麼他就無法登入系統了！

- 我在使用 useradd 的時候，新增的帳號裡面的 UID, GID 還有其他相關的密碼控制，都是在哪幾個檔案裡面設定的？

在 /etc/login.defs 還有 /etc/default/useradd 裡面規定好的！

- 我希望我在設定每個帳號的時候( 使用 useradd )，預設情況中，他們的家目錄就含有一個名稱為 www 的子目錄，我應該怎麼作比較好？

由於使用 useradd 的時候，會自動以 /etc/skel 做為預設的家目錄，所以，我可以在 /etc/skel 裡面新增加一個名稱為 www 的目錄即可！

- 簡單說明系統帳號與一般使用者帳號的差別？

一般而言，為了讓系統能夠順利以較小的權限運作，系統會有很多帳號， 例如 mail, bin, adm 等等。而為了確保這些帳號能夠在系統上面具有獨一無二的權限， 一般來說 Linux 都會保留一些 UID 給系統使用。在 CentOS 5.x 上面，小於 500 以下的帳號 (UID) 即是所謂的 System account。

- 簡單說明，為何 CentOS 5.x 建立使用者時，他會主動的幫使用者建立一個群組，而不是使用 /etc/default/useradd 的設定？

不同的 linux distributions 對於使用者 group 的建立機制並不相同。主要的機制分為：

- Public group schemes: 使用者將會直接給予一個系統指定的群組，一般來說即是 users ， 可以 SuSE Server 9 為代表；

- Private group schemes: 系統會建立一個與帳號一樣的群組名稱！以 CentOS 5.x 為例！

- 如何建立一個使用者名稱 alex, 他所屬群組為 alexgroup, 預計使用 csh, 他的全名為 "Alex Tsai"， 且他還得要加入 users 群組當中！

groupadd alexgroup

useradd -c "Alex Tsai" -g alexgroup -G users -m alex

務必先建立群組，才能夠建立使用者喔！

- 由於種種因素，導致你的使用者家目錄以後都需要被放置到 /account 這個目錄下。 請問，我該如何作，可以讓使用 useradd 時，預設的家目錄就指向 /account ？

最簡單的方法，編輯 /etc/default/useradd ，將裡頭的 HOME=/home 改成 HOME=/account 即可。

- 我想要讓 dmtsai 這個使用者，加入 vbird1, vbird2, vbird3 這三個群組，且不影響 dmtsai 原本已經支援的次要群組時，該如何動作？

usermod -a -G vbird1,vbird2,vbird3 dmtsai

參考資料與延伸閱讀

- 註1：最完整與詳細的密碼檔說明，可參考各 distribution 內部的 man page。 本文中以 CentOS 5.x 的『 man 5 passwd 』及『 man 5 shadow 』的內容說明；

- 註2：MD5與DES均為加密的機制，詳細的解釋可參考維基百科的說明：

MD5：http://zh.wikipedia.org/wiki/MD5

DES：http://en.wikipedia.org/wiki/Data_Encryption_Standard

在早期的 Linux 版本中，主要使用 DES 加密演算法，近期則使用 MD5 作為預設演算法。

- 註3：telnet 與 ssh 都是可以由遠端用戶主機連線到 Linux 伺服器的一種機制！詳細資料可查詢鳥站文章： 遠端連線伺服器：http://linux.vbird.org/linux_server/0310telnetssh.php

- 註4：詳細的說明請參考 man sudo ，然後以 5 作為關鍵字搜尋看看即可瞭解。

- 註5：詳細的 PAM 說明可以參考如下連結：

維基百科：http://en.wikipedia.org/wiki/Pluggable_Authentication_Modules

Linux-PAM網頁： http://www.kernel.org/pub/linux/libs/pam/

2002/05/15：第一次完成

2003/02/10：重新編排與加入 FAQ

2005/08/25：加入一個大量建置帳號的實例，簡單說明一下而已！

2005/08/29：將原本的舊文放置到 此處

2005/08/31：因為 userconf 已經不再這麼好用了，使用指令模式比較簡單，所以，將他拿掉了∼

2005/09/05：終於將大量建置帳號的那支程式寫完了∼真是高興啊！

2006/03/02：更新使用者 UID 號碼，由 65535 升級到 2^32-1 這麼大！

2007/04/15：原本寫的 /etc/pam.d/limits.conf 錯了！應該是 /etc/security/limits.conf 才對！

2008/04/28：sudo 關於密碼重新輸入的部分寫錯了！已經更新，在這裡查閱看看。感謝網友 superpmo 的告知！

2009/02/18：將基於 FC4 版本的舊文章移動到 此處。

2009/02/26：加入 chage 以及『 chage -d 0 帳號』的功能！

2009/02/27：加入 acl 的控制項目！

2009/03/04：加入一個簡單的帳號新增範例，以及修改原本的帳號新增範例！

2009/04/28：取消 sudo 內的 -c 選項功能說明！之前說的是錯的∼

2009/09/09：加入一些模擬題，修改一些語詞的用法。

2010/04/27：情境模擬第三步驟的程式腳本錯了！原本是：『useradd -G youcan -s -m $username』！感謝 linux_task 兄的說明呢！

2002/05/05以來統計人數

- 依據不同的 UID 規範出 umask 的值；

- 依據不同的 UID 規範出提示字元 (就是 PS1 變數)；

- 呼叫 /etc/profile.d/*.sh 的設定

你要注意的是，這個 /etc/bashrc 是 CentOS 特有的 (其實是 Red Hat 系統特有的)，其他不同的 distributions 可能會放置在不同的檔名就是了。由於這個 ~/.bashrc 會呼叫 /etc/bashrc 及 /etc/profile.d/*.sh ， 所以，萬一你沒有 ~/.bashrc (可能自己不小心將他刪除了)，那麼你會發現你的 bash 提示字元可能會變成這個樣子：

-bash-3.2$

不要太擔心啦！這是正常的，因為你並沒有呼叫 /etc/bashrc 來規範 PS1 變數啦！而且這樣的情況也不會影響你的 bash 使用。 如果你想要將命令提示字元捉回來，那麼可以複製 /etc/skel/.bashrc 到你的家目錄，再修訂一下你所想要的內容， 並使用 source 去呼叫 ~/.bashrc ，那你的命令提示字元就會回來啦！

- 其他相關設定檔

事實上還有一些設定檔可能會影響到你的 bash 操作的，底下就來談一談：

- /etc/man.config

這個檔案乍看之下好像跟 bash 沒相關性，但是對於系統管理員來說， 卻也是很重要的一個檔案！這的檔案的內容『規範了使用 man 的時候， man page 的路徑到哪裡去尋找！』所以說的簡單一點，這個檔案規定了下達 man 的時候，該去哪裡查看資料的路徑設定！

那麼什麼時候要來修改這個檔案呢？如果你是以 tarball 的方式來安裝你的資料，那麼你的 man page 可能會放置在 /usr/local/softpackage/man 裡頭，那個 softpackage 是你的套件名稱， 這個時候你就得以手動的方式將該路徑加到 /etc/man.config 裡頭，否則使用 man 的時候就會找不到相關的說明檔囉。

事實上，這個檔案內最重要的其實是 MANPATH 這個變數設定啦！ 我們搜尋 man page 時，會依據 MANPATH 的路徑去分別搜尋啊！另外，要注意的是， 這個檔案在各大不同版本 Linux distributions 中，檔名都不太相同，例如 CentOS 用的是 /etc/man.config ，而 SuSE 用的則是 /etc/manpath.config ， 可以利用 [tab] 按鍵來進行檔名的補齊啦！

- ~/.bash_history

還記得我們在歷史命令提到過這個檔案吧？預設的情況下， 我們的歷史命令就記錄在這裡啊！而這個檔案能夠記錄幾筆資料，則與 HISTFILESIZE 這個變數有關啊。每次登入 bash 後，bash 會先讀取這個檔案，將所有的歷史指令讀入記憶體， 因此，當我們登入 bash 後就可以查知上次使用過哪些指令囉。至於更多的歷史指令， 請自行回去參考喔！

- ~/.bash_logout

這個檔案則記錄了『當我登出 bash 後，系統再幫我做完什麼動作後才離開』的意思。 你可以去讀取一下這個檔案的內容，預設的情況下，登出時， bash 只是幫我們清掉螢幕的訊息而已。 不過，你也可以將一些備份或者是其他你認為重要的工作寫在這個檔案中 (例如清空暫存檔)， 那麼當你離開 Linux 的時候，就可以解決一些煩人的事情囉！

終端機的環境設定： stty, set

我們在第五章首次登入 Linux 時就提過，可以在 tty1 ~ tty6 這六個文字介面的終端機 (terminal) 環境中登入，登入的時候我們可以取得一些字元設定的功能喔！ 舉例來說，我們可以利用倒退鍵 (backspace，就是那個←符號的按鍵) 來刪除命令列上的字元， 也可以使用 [ctrl]+c 來強制終止一個指令的運行，當輸入錯誤時，就會有聲音跑出來警告。這是怎麼辦到的呢？ 很簡單啊！因為登入終端機的時候，會自動的取得一些終端機的輸入環境的設定啊！

事實上，目前我們使用的 Linux distributions 都幫我們作了最棒的使用者環境了， 所以大家可以不用擔心操作環境的問題。不過，在某些 Unix like 的機器中，還是可能需要動用一些手腳， 才能夠讓我們的輸入比較快樂∼舉例來說，利用 [backspace] 刪除，要比利用 [Del] 按鍵來的順手吧！ 但是某些 Unix 偏偏是以 [del] 來進行字元的刪除啊！所以，這個時候就可以動動手腳囉∼

那麼如何查閱目前的一些按鍵內容呢？可以利用 stty (setting tty 終端機的意思) 呢！ stty 也可以幫助設定終端機的輸入按鍵代表意義喔！

[root@www ~]# stty [-a]

選項與參數：

-a  ：將目前所有的 stty 參數列出來；

範例一：列出所有的按鍵與按鍵內容

[root@www ~]# stty -a

speed 38400 baud; rows 24; columns 80; line = 0;

intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;

eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;

rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;

....(以下省略)....

我們可以利用 stty -a 來列出目前環境中所有的按鍵列表，在上頭的列表當中，需要注意的是特殊字體那幾個， 此外，如果出現 ^ 表示 [Ctrl] 那個按鍵的意思。舉例來說， intr = ^C 表示利用 [ctrl] + c 來達成的。幾個重要的代表意義是：

- eof   : End of file 的意思，代表『結束輸入』。

- erase : 向後刪除字元，

- intr  : 送出一個 interrupt (中斷) 的訊號給目前正在 run 的程序；

- kill  : 刪除在目前指令列上的所有文字；

- quit  : 送出一個 quit 的訊號給目前正在 run 的程序；

- start : 在某個程序停止後，重新啟動他的 output

- stop  : 停止目前螢幕的輸出；

- susp  : 送出一個 terminal stop 的訊號給正在 run 的程序。

記不記得我們在第五章講過幾個 Linux 熱鍵啊？沒錯！ 就是這個 stty 設定值內的 intr / eof 囉∼至於刪除字元，就是 erase 那個設定值啦！ 如果你想要用 [ctrl]+h 來進行字元的刪除，那麼可以下達：

[root@www ~]# stty erase ^h

那麼從此之後，你的刪除字元就得要使用 [ctrl]+h 囉，按下 [backspace] 則會出現 ^? 字樣呢！ 如果想要回復利用 [backspace] ，就下達 stty erase ^? 即可啊！ 至於更多的 stty 說明，記得參考一下 man stty 的內容喔！

除了 stty 之外，其實我們的 bash 還有自己的一些終端機設定值呢！那就是利用 set 來設定的！ 我們之前提到一些變數時，可以利用 set 來顯示，除此之外，其實 set 還可以幫我們設定整個指令輸出/輸入的環境。 例如記錄歷史命令、顯示錯誤內容等等。

[root@www ~]# set [-uvCHhmBx]

選項與參數：

-u  ：預設不啟用。若啟用後，當使用未設定變數時，會顯示錯誤訊息；

-v  ：預設不啟用。若啟用後，在訊息被輸出前，會先顯示訊息的原始內容；

-x  ：預設不啟用。若啟用後，在指令被執行前，會顯示指令內容(前面有 ++ 符號)

-h  ：預設啟用。與歷史命令有關；

-H  ：預設啟用。與歷史命令有關；

-m  ：預設啟用。與工作管理有關；

-B  ：預設啟用。與刮號 [] 的作用有關；

-C  ：預設不啟用。若使用 > 等，則若檔案存在時，該檔案不會被覆蓋。

範例一：顯示目前所有的 set 設定值

[root@www ~]# echo $-

himBH

# 那個 $- 變數內容就是 set 的所有設定啦！ bash 預設是 himBH 喔！

範例二：設定 "若使用未定義變數時，則顯示錯誤訊息"

[root@www ~]# set -u

[root@www ~]# echo $vbirding

-bash: vbirding: unbound variable

# 預設情況下，未設定/未宣告 的變數都會是『空的』，不過，若設定 -u 參數，

# 那麼當使用未設定的變數時，就會有問題啦！很多的 shell 都預設啟用 -u 參數。

# 若要取消這個參數，輸入 set +u 即可！

範例三：執行前，顯示該指令內容。

[root@www ~]# set -x

[root@www ~]# echo $HOME

+ echo /root

/root

++ echo -ne '\033]0;root@www:~'

# 看見否？要輸出的指令都會先被列印到螢幕上喔！前面會多出 + 的符號！

另外，其實我們還有其他的按鍵設定功能呢！就是在前一小節提到的 /etc/inputrc 這個檔案裡面設定。

[root@www ~]# cat /etc/inputrc

# do not bell on tab-completion

#set bell-style none

set meta-flag on

set input-meta on

set convert-meta off

set output-meta on

.....以下省略.....

還有例如 /etc/DIR_COLORS* 與 /etc/termcap 等，也都是與終端機有關的環境設定檔案呢！ 不過，事實上，鳥哥並不建議您修改 tty 的環境呢，這是因為 bash 的環境已經設定的很親和了， 我們不需要額外的設定或者修改，否則反而會產生一些困擾。不過，寫在這裡的資料， 只是希望大家能夠清楚的知道我們的終端機是如何進行設定的喔！ ^_^！ 最後，我們將 bash 預設的組合鍵給他彙整如下：

組合按鍵

執行結果

Ctrl + C

終止目前的命令

Ctrl + D

輸入結束 (EOF)，例如郵件結束的時候；

Ctrl + M

就是 Enter 啦！

Ctrl + S

暫停螢幕的輸出

Ctrl + Q

恢復螢幕的輸出

Ctrl + U

在提示字元下，將整列命令刪除

Ctrl + Z

『暫停』目前的命令

萬用字元與特殊符號

在 bash 的操作環境中還有一個非常有用的功能，那就是萬用字元 (wildcard) ！ 我們利用 bash 處理資料就更方便了！底下我們列出一些常用的萬用字元喔：

符號

意義

*

代表『 0 個到無窮多個』任意字元

?

代表『一定有一個』任意字元

[ ]

同樣代表『一定有一個在括號內』的字元(非任意字元)。例如 [abcd] 代表『一定有一個字元， 可能是 a, b, c, d 這四個任何一個』

[ - ]

若有減號在中括號內時，代表『在編碼順序內的所有字元』。例如 [0-9] 代表 0 到 9 之間的所有數字，因為數字的語系編碼是連續的！

[^ ]

若中括號內的第一個字元為指數符號 (^) ，那表示『反向選擇』，例如 [^abc] 代表 一定有一個字元，只要是非 a, b, c 的其他字元就接受的意思。

接下來讓我們利用萬用字元來玩些東西吧！首先，利用萬用字元配合 ls 找檔名看看：

[root@www ~]# LANG=C              <==由於與編碼有關，先設定語系一下

範例一：找出 /etc/ 底下以 cron 為開頭的檔名

[root@www ~]# ll -d /etc/cron*    <==加上 -d 是為了僅顯示目錄而已

範例二：找出 /etc/ 底下檔名『剛好是五個字母』的檔名

[root@www ~]# ll -d /etc/?????    <==由於 ? 一定有一個，所以五個 ? 就對了

範例三：找出 /etc/ 底下檔名含有數字的檔名

[root@www ~]# ll -d /etc/*[0-9]*  <==記得中括號左右兩邊均需 *

範例四：找出 /etc/ 底下，檔名開頭非為小寫字母的檔名：

[root@www ~]# ll -d /etc/[^a-z]*  <==注意中括號左邊沒有 *

範例五：將範例四找到的檔案複製到 /tmp 中

[root@www ~]# cp -a /etc/[^a-z]* /tmp

除了萬用字元之外，bash 環境中的特殊符號有哪些呢？底下我們先彙整一下：

符號

內容

#

註解符號：這個最常被使用在 script 當中，視為說明！在後的資料均不執行

\

跳脫符號：將『特殊字元或萬用字元』還原成一般字元

|

管線 (pipe)：分隔兩個管線命令的界定(後兩節介紹)；

;

連續指令下達分隔符號：連續性命令的界定 (注意！與管線命令並不相同)

~

使用者的家目錄

$

取用變數前置字元：亦即是變數之前需要加的變數取代值

&

工作控制 (job control)：將指令變成背景下工作

!

邏輯運算意義上的『非』 not 的意思！

/

目錄符號：路徑分隔的符號

>, >>

資料流重導向：輸出導向，分別是『取代』與『累加』

<, <<

資料流重導向：輸入導向 (這兩個留待下節介紹)

' '

單引號，不具有變數置換的功能

" "

具有變數置換的功能！

` `

兩個『 ` 』中間為可以先執行的指令，亦可使用 $( )

( )

在中間為子 shell 的起始與結束

{ }

在中間為命令區塊的組合！

以上為 bash 環境中常見的特殊符號彙整！理論上，你的『檔名』盡量不要使用到上述的字元啦！

資料流重導向

資料流重導向 (redirect) 由字面上的意思來看，好像就是將『資料給他傳導到其他地方去』的樣子？ 沒錯∼資料流重導向就是將某個指令執行後應該要出現在螢幕上的資料， 給他傳輸到其他的地方，例如檔案或者是裝置 (例如印表機之類的)！這玩意兒在 Linux 的文字模式底下可重要的！ 尤其是如果我們想要將某些資料儲存下來時，就更有用了！

什麼是資料流重導向

什麼是資料流重導向啊？這得要由指令的執行結果談起！一般來說，如果你要執行一個指令，通常他會是這樣的：

圖 5.1.1、指令執行過程的資料傳輸情況

我們執行一個指令的時候，這個指令可能會由檔案讀入資料，經過處理之後，再將資料輸出到螢幕上。 在上圖當中， standard output 與 standard error output 分別代表『標準輸出』與『標準錯誤輸出』， 這兩個玩意兒預設都是輸出到螢幕上面來的啊！那麼什麼是標準輸出與標準錯誤輸出呢？

- standard output 與 standard error output

簡單的說，標準輸出指的是『指令執行所回傳的正確的訊息』，而標準錯誤輸出可理解為『 指令執行失敗後，所回傳的錯誤訊息』。舉個簡單例子來說，我們的系統預設有 /etc/crontab 但卻無 /etc/vbirdsay， 此時若下達『 cat /etc/crontab /etc/vbirdsay 』這個指令時，cat 會進行：

- 標準輸出：讀取 /etc/crontab 後，將該檔案內容顯示到螢幕上；

- 標準錯誤輸出：因為無法找到 /etc/vbirdsay，因此在螢幕上顯示錯誤訊息

不管正確或錯誤的資料都是預設輸出到螢幕上，所以螢幕當然是亂亂的！那能不能透過某些機制將這兩股資料分開呢？ 當然可以啊！那就是資料流重導向的功能啊！資料流重導向可以將 standard output (簡稱 stdout) 與 standard error output (簡稱 stderr) 分別傳送到其他的檔案或裝置去，而分別傳送所用的特殊字元則如下所示：

1. 標準輸入　　(stdin) ：代碼為 0 ，使用 < 或 << ；

2. 標準輸出　　(stdout)：代碼為 1 ，使用 > 或 >> ；

3. 標準錯誤輸出(stderr)：代碼為 2 ，使用 2> 或 2>> ；

為了理解 stdout 與 stderr ，我們先來進行一個範例的練習：

範例一：觀察你的系統根目錄 (/) 下各目錄的檔名、權限與屬性，並記錄下來

[root@www ~]# ll /  <==此時螢幕會顯示出檔名資訊

[root@www ~]# ll / > ~/rootfile <==螢幕並無任何資訊

[root@www ~]# ll  ~/rootfile <==有個新檔被建立了！

-rw-r--r-- 1 root root 1089 Feb  6 17:00 /root/rootfile

怪了！螢幕怎麼會完全沒有資料呢？這是因為原本『 ll / 』所顯示的資料已經被重新導向到 ~/rootfile 檔案中了！ 那個 ~/rootfile 的檔名可以隨便你取。如果你下達『 cat ~/rootfile 』那就可以看到原本應該在螢幕上面的資料囉。 如果我再次下達：『 ll /home > ~/rootfile 』後，那個 ~/rootfile 檔案的內容變成什麼？ 他將變成『僅有 ll /home 的資料』而已！咦！原本的『 ll / 』資料就不見了嗎？是的！因為該檔案的建立方式是：

1. 該檔案 (本例中是 ~/rootfile) 若不存在，系統會自動的將他建立起來，但是

2. 當這個檔案存在的時候，那麼系統就會先將這個檔案內容清空，然後再將資料寫入！

3. 也就是若以 > 輸出到一個已存在的檔案中，那個檔案就會被覆蓋掉囉！

那如果我想要將資料累加而不想要將舊的資料刪除，那該如何是好？利用兩個大於的符號 (>>) 就好啦！以上面的範例來說，你應該要改成『 ll / >> ~/rootfile 』即可。 如此一來，當 (1) ~/rootfile 不存在時系統會主動建立這個檔案；(2)若該檔案已存在， 則資料會在該檔案的最下方累加進去！

上面談到的是 standard output 的正確資料，那如果是 standard error output 的錯誤資料呢？那就透過 2> 及 2>> 囉！同樣是覆蓋 (2>) 與累加 (2>>) 的特性！我們在剛剛才談到 stdout 代碼是 1 而 stderr 代碼是 2 ， 所以這個 2> 是很容易理解的，而如果僅存在 > 時，則代表預設的代碼 1 囉！也就是說：

- 1> ：以覆蓋的方法將『正確的資料』輸出到指定的檔案或裝置上；

- 1>>：以累加的方法將『正確的資料』輸出到指定的檔案或裝置上；

- 2> ：以覆蓋的方法將『錯誤的資料』輸出到指定的檔案或裝置上；

- 2>>：以累加的方法將『錯誤的資料』輸出到指定的檔案或裝置上；

要注意喔，『 1>> 』以及『 2>> 』中間是沒有空格的！OK！有些概念之後讓我們繼續聊一聊這傢伙怎麼應用吧！ 當你以一般身份執行 find 這個指令的時候，由於權限的問題可能會產生一些錯誤資訊。例如執行『 find / -name testing 』時，可能會產生類似『 find: /root: Permission denied 』之類的訊息。 例如底下這個範例：

範例二：利用一般身份帳號搜尋 /home 底下是否有名為 .bashrc 的檔案存在

[root@www ~]# su - dmtsai  <==假設我的系統有名為 dmtsai 的帳號

[dmtsai@www ~]$ find /home -name .bashrc <==身份是 dmtsai 喔！

find: /home/lost+found: Permission denied  <== Standard error

find: /home/alex: Permission denied        <== Standard error

find: /home/arod: Permission denied        <== Standard error

/home/dmtsai/.bashrc                       <== Standard output

由於 /home 底下還有我們之前建立的帳號存在，那些帳號的家目錄你當然不能進入啊！所以就會有錯誤及正確資料了。 好了，那麼假如我想要將資料輸出到 list 這個檔案中呢？執行『 find /home -name .bashrc > list 』 會有什麼結果？呵呵，你會發現 list 裡面存了剛剛那個『正確』的輸出資料， 至於螢幕上還是會有錯誤的訊息出現呢！傷腦筋！如果想要將正確的與錯誤的資料分別存入不同的檔案中需要怎麼做？

範例三：承範例二，將 stdout 與 stderr 分存到不同的檔案去

[dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error

注意喔，此時『螢幕上不會出現任何訊息』！因為剛剛執行的結果中，有 Permission 的那幾行錯誤資訊都會跑到 list_error 這個檔案中，至於正確的輸出資料則會存到 list_right 這個檔案中囉！這樣可以瞭解了嗎？ 如果有點混亂的話，去休息一下再來看看吧！

- /dev/null 垃圾桶黑洞裝置與特殊寫法

想像一下，如果我知道錯誤訊息會發生，所以要將錯誤訊息忽略掉而不顯示或儲存呢？ 這個時候黑洞裝置 /dev/null 就很重要了！這個 /dev/null 可以吃掉任何導向這個裝置的資訊喔！將上述的範例修訂一下：

範例四：承範例三，將錯誤的資料丟棄，螢幕上顯示正確的資料

[dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null

/home/dmtsai/.bashrc  <==只有 stdout 會顯示到螢幕上， stderr 被丟棄了

再想像一下，如果我要將正確與錯誤資料通通寫入同一個檔案去呢？這個時候就得要使用特殊的寫法了！ 我們同樣用底下的案例來說明：

範例五：將指令的資料全部寫入名為 list 的檔案中

[dmtsai@www ~]$ find /home -name .bashrc > list 2> list  <==錯誤

[dmtsai@www ~]$ find /home -name .bashrc > list 2>&1     <==正確

[dmtsai@www ~]$ find /home -name .bashrc &> list         <==正確

上述表格第一行錯誤的原因是，由於兩股資料同時寫入一個檔案，又沒有使用特殊的語法， 此時兩股資料可能會交叉寫入該檔案內，造成次序的錯亂。所以雖然最終 list 檔案還是會產生，但是裡面的資料排列就會怪怪的，而不是原本螢幕上的輸出排序。 至於寫入同一個檔案的特殊語法如上表所示，你可以使用 2>&1 也可以使用 &> ！ 一般來說，鳥哥比較習慣使用 2>&1 的語法啦！

- standard input ： < 與 <<

瞭解了 stderr 與 stdout 後，那麼那個 < 又是什麼呀？呵呵！以最簡單的說法來說， 那就是『將原本需要由鍵盤輸入的資料，改由檔案內容來取代』的意思。 我們先由底下的 cat 指令操作來瞭解一下什麼叫做『鍵盤輸入』吧！

範例六：利用 cat 指令來建立一個檔案的簡單流程

[root@www ~]# cat > catfile

testing

cat file test

<==這裡按下 [ctrl]+d 來離開

[root@www ~]# cat catfile

testing

cat file test

由於加入 > 在 cat 後，所以那個 catfile 會被主動的建立，而內容就是剛剛鍵盤上面輸入的那兩行資料了。 唔！那我能不能用純文字檔取代鍵盤的輸入，也就是說，用某個檔案的內容來取代鍵盤的敲擊呢？ 可以的！如下所示：

範例七：用 stdin 取代鍵盤的輸入以建立新檔案的簡單流程

[root@www ~]# cat > catfile < ~/.bashrc

[root@www ~]# ll catfile ~/.bashrc

-rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc

-rw-r--r-- 1 root root 194 Feb  6 18:29 catfile

# 注意看，這兩個檔案的大小會一模一樣！幾乎像是使用 cp 來複製一般！

這東西非常的有幫助！尤其是用在類似 mail 這種指令的使用上。 理解 < 之後，再來則是怪可怕一把的 << 這個連續兩個小於的符號了。 他代表的是『結束的輸入字元』的意思！舉例來講：『我要用 cat 直接將輸入的訊息輸出到 catfile 中， 且當由鍵盤輸入 eof 時，該次輸入就結束』，那我可以這樣做：

[root@www ~]# cat > catfile << "eof"

> This is a test.

> OK now stop

> eof  <==輸入這關鍵字，立刻就結束而不需要輸入 [ctrl]+d

[root@www ~]# cat catfile

This is a test.

OK now stop     <==只有這兩行，不會存在關鍵字那一行！

看到了嗎？利用 << 右側的控制字元，我們可以終止一次輸入， 而不必輸入 [crtl]+d 來結束哩！這對程式寫作很有幫助喔！好了，那麼為何要使用命令輸出重導向呢？我們來說一說吧！

- 螢幕輸出的資訊很重要，而且我們需要將他存下來的時候；

- 背景執行中的程式，不希望他干擾螢幕正常的輸出結果時；

- 一些系統的例行命令 (例如寫在 /etc/crontab 中的檔案) 的執行結果，希望他可以存下來時；

- 一些執行命令的可能已知錯誤訊息時，想以『 2> /dev/null 』將他丟掉時；

- 錯誤訊息與正確訊息需要分別輸出時。

當然還有很多的功能的，最簡單的就是網友們常常問到的：『為何我的 root 都會收到系統 crontab 寄來的錯誤訊息呢』這個咚咚是常見的錯誤， 而如果我們已經知道這個錯誤訊息是可以忽略的時候，嗯！『 2> errorfile 』這個功能就很重要了吧！ 瞭解了嗎？

命令執行的判斷依據： ; , &&, ||

在某些情況下，很多指令我想要一次輸入去執行，而不想要分次執行時，該如何是好？基本上你有兩個選擇， 一個是透過第十三章要介紹的 shell script 撰寫腳本去執行，一種則是透過底下的介紹來一次輸入多重指令喔！

- cmd ; cmd (不考慮指令相關性的連續指令下達)

在某些時候，我們希望可以一次執行多個指令，例如在關機的時候我希望可以先執行兩次 sync 同步化寫入磁碟後才 shutdown 電腦，那麼可以怎麼作呢？這樣做呀：

[root@www ~]# sync; sync; shutdown -h now

在指令與指令中間利用分號 (;) 來隔開，這樣一來，分號前的指令執行完後就會立刻接著執行後面的指令了。 這真是方便啊∼再來，換個角度來想，萬一我想要在某個目錄底下建立一個檔案，也就是說，如果該目錄存在的話， 那我才建立這個檔案，如果不存在，那就算了。也就是說這兩個指令彼此之間是有相關性的， 前一個指令是否成功的執行與後一個指令是否要執行有關！那就得動用到 && 或 || 囉！

- $? (指令回傳值) 與 && 或 ||

如同上面談到的，兩個指令之間有相依性，而這個相依性主要判斷的地方就在於前一個指令執行的結果是否正確。 還記得本章之前我們曾介紹過指令回傳值吧！嘿嘿！沒錯，您真聰明！就是透過這個回傳值啦！ 再複習一次『若前一個指令執行的結果為正確，在 Linux 底下會回傳一個 $? = 0 的值』。 那麼我們怎麼透過這個回傳值來判斷後續的指令是否要執行呢？這就得要藉由『 && 』及『 || 』的幫忙了！ 注意喔，兩個 & 之間是沒有空格的！那個 | 則是 [Shift]+[\] 的按鍵結果。

指令下達情況

說明

cmd1 && cmd2

1. 若 cmd1 執行完畢且正確執行($?=0)，則開始執行 cmd2。

2. 若 cmd1 執行完畢且為錯誤 ($?≠0)，則 cmd2 不執行。

cmd1 || cmd2

1. 若 cmd1 執行完畢且正確執行($?=0)，則 cmd2 不執行。

2. 若 cmd1 執行完畢且為錯誤 ($?≠0)，則開始執行 cmd2。

上述的 cmd1 及 cmd2 都是指令。好了，回到我們剛剛假想的情況，就是想要： (1)先判斷一個目錄是否存在； (2)若存在才在該目錄底下建立一個檔案。由於我們尚未介紹如何判斷式 (test) 的使用，在這裡我們使用 ls 以及回傳值來判斷目錄是否存在啦！ 讓我們進行底下這個練習看看：

範例一：使用 ls 查閱目錄 /tmp/abc 是否存在，若存在則用 touch 建立 /tmp/abc/hehe

[root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe

ls: /tmp/abc: No such file or directory

# ls 很乾脆的說明找不到該目錄，但並沒有 touch 的錯誤，表示 touch 並沒有執行

[root@www ~]# mkdir /tmp/abc

[root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe

[root@www ~]# ll /tmp/abc

-rw-r--r-- 1 root root 0 Feb  7 12:43 hehe

看到了吧？如果 /tmp/abc 不存在時，touch 就不會被執行，若 /tmp/abc 存在的話，那麼 touch 就會開始執行囉！ 很不錯用吧！不過，我們還得手動自行建立目錄，傷腦筋∼能不能自動判斷，如果沒有該目錄就給予建立呢？ 參考一下底下的例子先：

範例二：測試 /tmp/abc 是否存在，若不存在則予以建立，若存在就不作任何事情

[root@www ~]# rm -r /tmp/abc                <==先刪除此目錄以方便測試

[root@www ~]# ls /tmp/abc || mkdir /tmp/abc

ls: /tmp/abc: No such file or directory <==真的不存在喔！

[root@www ~]# ll /tmp/abc

total 0                                 <==結果出現了！有進行 mkdir

如果你一再重複『 ls /tmp/abc || mkdir /tmp/abc 』畫面也不會出現重複 mkdir 的錯誤！這是因為 /tmp/abc 已經存在， 所以後續的 mkdir 就不會進行！這樣理解否？好了，讓我們再次的討論一下，如果我想要建立 /tmp/abc/hehe 這個檔案， 但我並不知道 /tmp/abc 是否存在，那該如何是好？試看看：

範例三：我不清楚 /tmp/abc 是否存在，但就是要建立 /tmp/abc/hehe 檔案

[root@www ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

上面這個範例三總是會建立 /tmp/abc/hehe 的喔！不論 /tmp/abc 是否存在。那麼範例三應該如何解釋呢？ 由於Linux 底下的指令都是由左往右執行的，所以範例三有幾種結果我們來分析一下：

- (1)若 /tmp/abc 不存在故回傳 $?≠0，則 (2)因為 || 遇到非為 0 的 $? 故開始 mkdir /tmp/abc，由於 mkdir /tmp/abc 會成功進行，所以回傳 $?=0 (3)因為 && 遇到 $?=0 故會執行 touch /tmp/abc/hehe，最終 hehe 就被建立了；

- (1)若 /tmp/abc 存在故回傳 $?=0，則 (2)因為 || 遇到 0 的 $? 不會進行，此時 $?=0 繼續向後傳，故 (3)因為 && 遇到 $?=0 就開始建立 /tmp/abc/hehe 了！最終 /tmp/abc/hehe 被建立起來。

整個流程圖示如下：

圖 5.2.1、 指令依序執行的關係示意圖

上面這張圖顯示的兩股資料中，上方的線段為不存在 /tmp/abc 時所進行的指令行為，下方的線段則是存在 /tmp/abc 所在的指令行為。如上所述，下方線段由於存在 /tmp/abc 所以導致 $?=0 ，讓中間的 mkdir 就不執行了！ 並將 $?=0 繼續往後傳給後續的 touch 去利用啦！瞭乎？在任何時刻你都可以拿上面這張圖作為示意！ 讓我們來想想底下這個例題吧！

例題：

以 ls 測試 /tmp/vbirding 是否存在，若存在則顯示 "exist" ，若不存在，則顯示 "not exist"！

答：

這又牽涉到邏輯判斷的問題，如果存在就顯示某個資料，若不存在就顯示其他資料，那我可以這樣做：

ls /tmp/vbirding && echo "exist" || echo "not exist"

意思是說，當 ls /tmp/vbirding 執行後，若正確，就執行 echo "exist" ，若有問題，就執行 echo "not exist" ！那如果寫成如下的狀況會出現什麼？

ls /tmp/vbirding || echo "not exist" && echo "exist"

這其實是有問題的，為什麼呢？由圖 5.2.1 的流程介紹我們知道指令是一個一個往後執行， 因此在上面的例子當中，如果 /tmp/vbirding 不存在時，他會進行如下動作：

1. 若 ls /tmp/vbirding 不存在，因此回傳一個非為 0 的數值；

2. 接下來經過 || 的判斷，發現前一個指令回傳非為 0 的數值，因此，程式開始執行 echo "not exist" ，而 echo "not exist" 程式肯定可以執行成功，因此會回傳一個 0 值給後面的指令；

3. 經過 && 的判斷，咦！是 0 啊！所以就開始執行 echo "exist" 。

所以啊，嘿嘿！第二個例子裡面竟然會同時出現 not exist 與 exist 呢！真神奇∼

經過這個例題的練習，你應該會瞭解，由於指令是一個接著一個去執行的，因此，如果真要使用判斷， 那麼這個 && 與 || 的順序就不能搞錯。一般來說，假設判斷式有三個，也就是：

command1 && command2 || command3

而且順序通常不會變，因為一般來說， command2 與 command3 會放置肯定可以執行成功的指令， 因此，依據上面例題的邏輯分析，您就會曉得為何要如此放置囉∼這很有用的啦！而且.....考試也很常考∼

管線命令 (pipe)

就如同前面所說的， bash 命令執行的時候有輸出的資料會出現！ 那麼如果這群資料必需要經過幾道手續之後才能得到我們所想要的格式，應該如何來設定？ 這就牽涉到管線命令的問題了 (pipe) ，管線命令使用的是『 | 』這個界定符號！ 另外，管線命令與『連續下達命令』是不一樣的呦！ 這點底下我們會再說明。底下我們先舉一個例子來說明一下簡單的管線命令。

假設我們想要知道 /etc/ 底下有多少檔案，那麼可以利用 ls /etc 來查閱，不過， 因為 /etc 底下的檔案太多，導致一口氣就將螢幕塞滿了∼不知道前面輸出的內容是啥？此時，我們可以透過 less 指令的協助，利用：

[root@www ~]# ls -al /etc | less

如此一來，使用 ls 指令輸出後的內容，就能夠被 less 讀取，並且利用 less 的功能，我們就能夠前後翻動相關的資訊了！很方便是吧？我們就來瞭解一下這個管線命令『 | 』的用途吧！ 其實這個管線命令『 | 』僅能處理經由前面一個指令傳來的正確資訊，也就是 standard output 的資訊，對於 stdandard error 並沒有直接處理的能力。那麼整體的管線命令可以使用下圖表示：

圖 6.1.1、 管線命令的處理示意圖

在每個管線後面接的第一個資料必定是『指令』喔！而且這個指令必須要能夠接受 standard input 的資料才行，這樣的指令才可以是為『管線命令』，例如 less, more, head, tail 等都是可以接受 standard input 的管線命令啦。至於例如 ls, cp, mv 等就不是管線命令了！因為 ls, cp, mv 並不會接受來自 stdin 的資料。 也就是說，管線命令主要有兩個比較需要注意的地方：

- 管線命令僅會處理 standard output，對於 standard error output 會予以忽略

- 管線命令必須要能夠接受來自前一個指令的資料成為 standard input 繼續處理才行。

多說無益，讓我們來玩一些管線命令吧！底下的咚咚對系統管理非常有幫助喔！

擷取命令： cut, grep

什麼是擷取命令啊？說穿了，就是將一段資料經過分析後，取出我們所想要的。或者是經由分析關鍵字，取得我們所想要的那一行！ 不過，要注意的是，一般來說，擷取訊息通常是針對『一行一行』來分析的， 並不是整篇訊息分析的喔∼底下我們介紹兩個很常用的訊息擷取命令：

- cut

cut 不就是『切』嗎？沒錯啦！這個指令可以將一段訊息的某一段給他『切』出來∼ 處理的訊息是以『行』為單位喔！底下我們就來談一談：

[root@www ~]# cut -d'分隔字元' -f fields <==用於有特定分隔字元

[root@www ~]# cut -c 字元區間            <==用於排列整齊的訊息

選項與參數：

-d  ：後面接分隔字元。與 -f 一起使用；

-f  ：依據 -d 的分隔字元將一段訊息分割成為數段，用 -f 取出第幾段的意思；

-c  ：以字元 (characters) 的單位取出固定字元區間；

範例一：將 PATH 變數取出，我要找出第五個路徑。

[root@www ~]# echo $PATH

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games:

# 1 |    2   |  3  |    4    |       5      |     6        |    7

[root@www ~]# echo $PATH | cut -d ':' -f 5

# 如同上面的數字顯示，我們是以『 : 』作為分隔，因此會出現 /usr/local/bin

# 那麼如果想要列出第 3 與第 5 呢？，就是這樣：

[root@www ~]# echo $PATH | cut -d ':' -f 3,5

範例二：將 export 輸出的訊息，取得第 12 字元以後的所有字串

[root@www ~]# export

declare -x HISTSIZE="1000"

declare -x INPUTRC="/etc/inputrc"

declare -x KDEDIR="/usr"

declare -x LANG="zh_TW.big5"

.....(其他省略).....

# 注意看，每個資料都是排列整齊的輸出！如果我們不想要『 declare -x 』時，

# 就得這麼做：

[root@www ~]# export | cut -c 12-

HISTSIZE="1000"

INPUTRC="/etc/inputrc"

KDEDIR="/usr"

LANG="zh_TW.big5"

.....(其他省略).....

# 知道怎麼回事了吧？用 -c 可以處理比較具有格式的輸出資料！

# 我們還可以指定某個範圍的值，例如第 12-20 的字元，就是 cut -c 12-20 等等！

範例三：用 last 將顯示的登入者的資訊中，僅留下使用者大名

[root@www ~]# last

root   pts/1    192.168.201.101  Sat Feb  7 12:35   still logged in

root   pts/1    192.168.201.101  Fri Feb  6 12:13 - 18:46  (06:33)

root   pts/1    192.168.201.254  Thu Feb  5 22:37 - 23:53  (01:16)

# last 可以輸出『帳號/終端機/來源/日期時間』的資料，並且是排列整齊的

[root@www ~]# last | cut -d ' ' -f 1

# 由輸出的結果我們可以發現第一個空白分隔的欄位代表帳號，所以使用如上指令：

# 但是因為 root   pts/1 之間空格有好幾個，並非僅有一個，所以，如果要找出

# pts/1 其實不能以 cut -d ' ' -f 1,2 喔！輸出的結果會不是我們想要的。

cut 主要的用途在於將『同一行裡面的資料進行分解！』最常使用在分析一些數據或文字資料的時候！ 這是因為有時候我們會以某些字元當作分割的參數，然後來將資料加以切割，以取得我們所需要的資料。 鳥哥也很常使用這個功能呢！尤其是在分析 log 檔案的時候！不過，cut 在處理多空格相連的資料時，可能會比較吃力一點。

- grep

剛剛的 cut 是將一行訊息當中，取出某部分我們想要的，而 grep 則是分析一行訊息， 若當中有我們所需要的資訊，就將該行拿出來∼簡單的語法是這樣的：

[root@www ~]# grep [-acinv] [--color=auto] '搜尋字串' filename

選項與參數：

-a ：將 binary 檔案以 text 檔案的方式搜尋資料

-c ：計算找到 '搜尋字串' 的次數

-i ：忽略大小寫的不同，所以大小寫視為相同

-n ：順便輸出行號

-v ：反向選擇，亦即顯示出沒有 '搜尋字串' 內容的那一行！

--color=auto ：可以將找到的關鍵字部分加上顏色的顯示喔！

範例一：將 last 當中，有出現 root 的那一行就取出來；

[root@www ~]# last | grep 'root'

範例二：與範例一相反，只要沒有 root 的就取出！

[root@www ~]# last | grep -v 'root'

範例三：在 last 的輸出訊息中，只要有 root 就取出，並且僅取第一欄

[root@www ~]# last | grep 'root' |cut -d ' ' -f1

# 在取出 root 之後，利用上個指令 cut 的處理，就能夠僅取得第一欄囉！

範例四：取出 /etc/man.config 內含 MANPATH 的那幾行

[root@www ~]# grep --color=auto 'MANPATH' /etc/man.config

....(前面省略)....

MANPATH_MAP     /usr/X11R6/bin          /usr/X11R6/man

MANPATH_MAP     /usr/bin/X11            /usr/X11R6/man

MANPATH_MAP     /usr/bin/mh             /usr/share/man

# 神奇的是，如果加上 --color=auto 的選項，找到的關鍵字部分會用特殊顏色顯示喔！

grep 是個很棒的指令喔！他支援的語法實在是太多了∼用在正規表示法裡頭， 能夠處理的資料實在是多的很∼不過，我們這裡先不談正規表示法∼下一章再來說明∼ 您先瞭解一下， grep 可以解析一行文字，取得關鍵字，若該行有存在關鍵字，就會整行列出來！

排序命令： sort, wc, uniq

很多時候，我們都會去計算一次資料裡頭的相同型態的資料總數，舉例來說， 使用 last 可以查得這個月份有登入主機者的身份。那麼我可以針對每個使用者查出他們的總登入次數嗎？ 此時就得要排序與計算之類的指令來輔助了！底下我們介紹幾個好用的排序與統計指令喔！

- sort

sort 是很有趣的指令，他可以幫我們進行排序，而且可以依據不同的資料型態來排序喔！ 例如數字與文字的排序就不一樣。此外，排序的字元與語系的編碼有關，因此， 如果您需要排序時，建議使用 LANG=C 來讓語系統一，資料排序比較好一些。

[root@www ~]# sort [-fbMnrtuk] [file or stdin]

選項與參數：

-f  ：忽略大小寫的差異，例如 A 與 a 視為編碼相同；

-b  ：忽略最前面的空白字元部分；

-M  ：以月份的名字來排序，例如 JAN, DEC 等等的排序方法；

-n  ：使用『純數字』進行排序(預設是以文字型態來排序的)；

-r  ：反向排序；

-u  ：就是 uniq ，相同的資料中，僅出現一行代表；

-t  ：分隔符號，預設是用 [tab] 鍵來分隔；

-k  ：以那個區間 (field) 來進行排序的意思

範例一：個人帳號都記錄在 /etc/passwd 下，請將帳號進行排序。

[root@www ~]# cat /etc/passwd | sort

adm:x:3:4:adm:/var/adm:/sbin/nologin

apache:x:48:48:Apache:/var/www:/sbin/nologin

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

# 鳥哥省略很多的輸出∼由上面的資料看起來， sort 是預設『以第一個』資料來排序，

# 而且預設是以『文字』型態來排序的喔！所以由 a 開始排到最後囉！

範例二：/etc/passwd 內容是以 : 來分隔的，我想以第三欄來排序，該如何？

[root@www ~]# cat /etc/passwd | sort -t ':' -k 3

root:x:0:0:root:/root:/bin/bash

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

bin:x:1:1:bin:/bin:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

# 看到特殊字體的輸出部分了吧？怎麼會這樣排列啊？呵呵！沒錯啦∼

# 如果是以文字型態來排序的話，原本就會是這樣，想要使用數字排序：

# cat /etc/passwd | sort -t ':' -k 3 -n

# 這樣才行啊！用那個 -n 來告知 sort 以數字來排序啊！

範例三：利用 last ，將輸出的資料僅取帳號，並加以排序

[root@www ~]# last | cut -d ' ' -f1 | sort

sort 同樣是很常用的指令呢！因為我們常常需要比較一些資訊啦！ 舉個上面的第二個例子來說好了！今天假設你有很多的帳號，而且你想要知道最大的使用者 ID 目前到哪一號了！呵呵！使用 sort 一下子就可以知道答案咯！當然其使用還不止此啦！ 有空的話不妨玩一玩！

- uniq

如果我排序完成了，想要將重複的資料僅列出一個顯示，可以怎麼做呢？

[root@www ~]# uniq [-ic]

選項與參數：

-i  ：忽略大小寫字元的不同；

-c  ：進行計數

範例一：使用 last 將帳號列出，僅取出帳號欄，進行排序後僅取出一位；

[root@www ~]# last | cut -d ' ' -f1 | sort | uniq

範例二：承上題，如果我還想要知道每個人的登入總次數呢？

[root@www ~]# last | cut -d ' ' -f1 | sort | uniq -c

1

12 reboot

41 root

1 wtmp

# 從上面的結果可以發現 reboot 有 12 次， root 登入則有 41 次！

# wtmp 與第一行的空白都是 last 的預設字元，那兩個可以忽略的！

這個指令用來將『重複的行刪除掉只顯示一個』，舉個例子來說， 你要知道這個月份登入你主機的使用者有誰，而不在乎他的登入次數，那麼就使用上面的範例， (1)先將所有的資料列出；(2)再將人名獨立出來；(3)經過排序；(4)只顯示一個！ 由於這個指令是在將重複的東西減少，所以當然需要『配合排序過的檔案』來處理囉！

- wc

如果我想要知道 /etc/man.config 這個檔案裡面有多少字？多少行？多少字元的話， 可以怎麼做呢？其實可以利用 wc 這個指令來達成喔！他可以幫我們計算輸出的訊息的整體資料！

[root@www ~]# wc [-lwm]

選項與參數：

-l  ：僅列出行；

-w  ：僅列出多少字(英文單字)；

-m  ：多少字元；

範例一：那個 /etc/man.config 裡面到底有多少相關字、行、字元數？

[root@www ~]# cat /etc/man.config | wc

141     722    4617

# 輸出的三個數字中，分別代表： 『行、字數、字元數』

範例二：我知道使用 last 可以輸出登入者，但是 last 最後兩行並非帳號內容，

那麼請問，我該如何以一行指令串取得這個月份登入系統的總人次？

[root@www ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l

# 由於 last 會輸出空白行與 wtmp 字樣在最底下兩行，因此，我利用

# grep 取出非空白行，以及去除 wtmp 那一行，在計算行數，就能夠瞭解囉！

wc 也可以當作指令？這可不是上洗手間的 WC 呢！這是相當有用的計算檔案內容的一個工具組喔！舉個例子來說， 當你要知道目前你的帳號檔案中有多少個帳號時，就使用這個方法：『 cat /etc/passwd | wc -l 』啦！因為 /etc/passwd 裡頭一行代表一個使用者呀！ 所以知道行數就曉得有多少的帳號在裡頭了！而如果要計算一個檔案裡頭有多少個字元時，就使用 wc -m 這個選項吧！

雙向重導向： tee

想個簡單的東西，我們由前一節知道 > 會將資料流整個傳送給檔案或裝置，因此我們除非去讀取該檔案或裝置， 否則就無法繼續利用這個資料流。萬一我想要將這個資料流的處理過程中將某段訊息存下來，應該怎麼做？ 利用 tee 就可以囉∼我們可以這樣簡單的看一下：

圖 6.3.1、tee 的工作流程示意圖

tee 會同時將資料流分送到檔案去與螢幕 (screen)；而輸出到螢幕的，其實就是 stdout ，可以讓下個指令繼續處理喔！

[root@www ~]# tee [-a] file

選項與參數：

-a  ：以累加 (append) 的方式，將資料加入 file 當中！

[root@www ~]# last | tee last.list | cut -d " " -f1

# 這個範例可以讓我們將 last 的輸出存一份到 last.list 檔案中；

[root@www ~]# ls -l /home | tee ~/homefile | more

# 這個範例則是將 ls 的資料存一份到 ~/homefile ，同時螢幕也有輸出訊息！

[root@www ~]# ls -l / | tee -a ~/homefile | more

# 要注意！ tee 後接的檔案會被覆蓋，若加上 -a 這個選項則能將訊息累加。

tee 可以讓 standard output 轉存一份到檔案內並將同樣的資料繼續送到螢幕去處理！ 這樣除了可以讓我們同時分析一份資料並記錄下來之外，還可以作為處理一份資料的中間暫存檔記錄之用！ tee 這傢伙在很多選擇/填充的認證考試中很容易考呢！

字元轉換命令： tr, col, join, paste, expand

我們在 vim 程式編輯器當中，提到過 DOS 斷行字元與 Unix 斷行字元的不同，並且可以使用 dos2unix 與 unix2dos 來完成轉換。好了，那麼思考一下，是否還有其他常用的字元替代？ 舉例來說，要將大寫改成小寫，或者是將資料中的 [tab] 按鍵轉成空白鍵？還有，如何將兩篇訊息整合成一篇？ 底下我們就來介紹一下這些字元轉換命令在管線當中的使用方法：

- tr

tr 可以用來刪除一段訊息當中的文字，或者是進行文字訊息的替換！

[root@www ~]# tr [-ds] SET1 ...

選項與參數：

-d  ：刪除訊息當中的 SET1 這個字串；

-s  ：取代掉重複的字元！

範例一：將 last 輸出的訊息中，所有的小寫變成大寫字元：

[root@www ~]# last | tr '[a-z]' '[A-Z]'

# 事實上，沒有加上單引號也是可以執行的，如：『 last | tr [a-z] [A-Z] 』

範例二：將 /etc/passwd 輸出的訊息中，將冒號 (:) 刪除

[root@www ~]# cat /etc/passwd | tr -d ':'

範例三：將 /etc/passwd 轉存成 dos 斷行到 /root/passwd 中，再將 ^M 符號刪除

[root@www ~]# cp /etc/passwd /root/passwd && unix2dos /root/passwd

[root@www ~]# file /etc/passwd /root/passwd

/etc/passwd:  ASCII text

/root/passwd: ASCII text, with CRLF line terminators <==就是 DOS 斷行

[root@www ~]# cat /root/passwd | tr -d '\r' > /root/passwd.linux

# 那個 \r 指的是 DOS 的斷行字元，關於更多的字符，請參考 man tr

[root@www ~]# ll /etc/passwd /root/passwd*

-rw-r--r-- 1 root root 1986 Feb  6 17:55 /etc/passwd

-rw-r--r-- 1 root root 2030 Feb  7 15:55 /root/passwd

-rw-r--r-- 1 root root 1986 Feb  7 15:57 /root/passwd.linux

# 處理過後，發現檔案大小與原本的 /etc/passwd 就一致了！

其實這個指令也可以寫在『正規表示法』裡頭！因為他也是由正規表示法的方式來取代資料的！ 以上面的例子來說，使用 [] 可以設定一串字呢！也常常用來取代檔案中的怪異符號！ 例如上面第三個例子當中，可以去除 DOS 檔案留下來的 ^M 這個斷行的符號！這東西相當的有用！相信處理 Linux & Windows 系統中的人們最麻煩的一件事就是這個事情啦！亦即是 DOS 底下會自動的在每行行尾加入 ^M 這個斷行符號！這個時候我們可以使用這個 tr 來將 ^M 去除！ ^M 可以使用 \r 來代替之！

- col

[root@www ~]# col [-xb]

選項與參數：

-x  ：將 tab 鍵轉換成對等的空白鍵

-b  ：在文字內有反斜線 (/) 時，僅保留反斜線最後接的那個字元

範例一：利用 cat -A 顯示出所有特殊按鍵，最後以 col 將 [tab] 轉成空白

[root@www ~]# cat -A /etc/man.config  <==此時會看到很多 ^I 的符號，那就是 tab

[root@www ~]# cat /etc/man.config | col -x | cat -A | more

# 嘿嘿！如此一來， [tab] 按鍵會被取代成為空白鍵，輸出就美觀多了！

範例二：將 col 的 man page 轉存成為 /root/col.man 的純文字檔

[root@www ~]# man col > /root/col.man

[root@www ~]# vi /root/col.man

COL(1)          BSD General Commands Manual               COL(1)

N^HNA^HAM^HME^HE

c^Hco^Hol^Hl - filter reverse line feeds from input

S^HSY^HYN^HNO^HOP^HPS^HSI^HIS^HS

c^Hco^Hol^Hl [-^H-b^Hbf^Hfp^Hpx^Hx] [-^H-l^Hl _^Hn_^Hu_^Hm]

# 你沒看錯！由於 man page 內有些特殊按鈕會用來作為類似特殊按鍵與顏色顯示，

# 所以這個檔案內就會出現如上所示的一堆怪異字元(有 ^ 的)

[root@www ~]# man col | col -b > /root/col.man

雖然 col 有他特殊的用途，不過，很多時候，他可以用來簡單的處理將 [tab] 按鍵取代成為空白鍵！ 例如上面的例子當中，如果使用 cat -A 則 [tab] 會以 ^I 來表示。 但經過 col -x 的處理，則會將 [tab] 取代成為對等的空白鍵！此外， col 經常被利用於將 man page 轉存為純文字檔以方便查閱的功能！如上述的範例二！

- join

join 看字面上的意義 (加入/參加) 就可以知道，他是在處理兩個檔案之間的資料， 而且，主要是在處理『兩個檔案當中，有 "相同資料" 的那一行，才將他加在一起』的意思。我們利用底下的簡單例子來說明：

[root@www ~]# join [-ti12] file1 file2

選項與參數：

-t  ：join 預設以空白字元分隔資料，並且比對『第一個欄位』的資料，

如果兩個檔案相同，則將兩筆資料聯成一行，且第一個欄位放在第一個！

-i  ：忽略大小寫的差異；

-1  ：這個是數字的 1 ，代表『第一個檔案要用那個欄位來分析』的意思；

-2  ：代表『第二個檔案要用那個欄位來分析』的意思。

範例一：用 root 的身份，將 /etc/passwd 與 /etc/shadow 相關資料整合成一欄

[root@www ~]# head -n 3 /etc/passwd /etc/shadow

==> /etc/passwd <==

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/shadow <==

root:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7:::

bin:*:14126:0:99999:7:::

daemon:*:14126:0:99999:7:::

# 由輸出的資料可以發現這兩個檔案的最左邊欄位都是帳號！且以 : 分隔

[root@www ~]# join -t ':' /etc/passwd /etc/shadow

root:x:0:0:root:/root:/bin/bash:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7:::

bin:x:1:1:bin:/bin:/sbin/nologin:*:14126:0:99999:7:::

daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:14126:0:99999:7:::

# 透過上面這個動作，我們可以將兩個檔案第一欄位相同者整合成一行！

# 第二個檔案的相同欄位並不會顯示(因為已經在第一行了嘛！)

範例二：我們知道 /etc/passwd 第四個欄位是 GID ，那個 GID 記錄在

/etc/group 當中的第三個欄位，請問如何將兩個檔案整合？

[root@www ~]# head -n 3 /etc/passwd /etc/group

==> /etc/passwd <==

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/group <==

root:x:0:root

bin:x:1:root,bin,daemon

daemon:x:2:root,bin,daemon

# 從上面可以看到，確實有相同的部分喔！趕緊來整合一下！

[root@www ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group

0:root:x:0:root:/root:/bin/bash:root:x:root

1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon

2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon

# 同樣的，相同的欄位部分被移動到最前面了！所以第二個檔案的內容就沒再顯示。

# 請讀者們配合上述顯示兩個檔案的實際內容來比對！

這個 join 在處理兩個相關的資料檔案時，就真的是很有幫助的啦！ 例如上面的案例當中，我的 /etc/passwd, /etc/shadow, /etc/group 都是有相關性的， 其中 /etc/passwd, /etc/shadow 以帳號為相關性，至於 /etc/passwd, /etc/group 則以所謂的 GID (帳號的數字定義) 來作為他的相關性。根據這個相關性， 我們可以將有關係的資料放置在一起！這在處理資料可是相當有幫助的！ 但是上面的例子有點難，希望您可以靜下心好好的看一看原因喔！

此外，需要特別注意的是，在使用 join 之前，你所需要處理的檔案應該要事先經過排序 (sort) 處理！ 否則有些比對的項目會被略過呢！特別注意了！

- paste

這個 paste 就要比 join 簡單多了！相對於 join 必須要比對兩個檔案的資料相關性， paste 就直接『將兩行貼在一起，且中間以 [tab] 鍵隔開』而已！簡單的使用方法：

[root@www ~]# paste [-d] file1 file2

選項與參數：

-d  ：後面可以接分隔字元。預設是以 [tab] 來分隔的！

-   ：如果 file 部分寫成 - ，表示來自 standard input 的資料的意思。

範例一：將 /etc/passwd 與 /etc/shadow 同一行貼在一起

[root@www ~]# paste /etc/passwd /etc/shadow

bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:14126:0:99999:7:::

daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:14126:0:99999:7:::

adm:x:3:4:adm:/var/adm:/sbin/nologin    adm:*:14126:0:99999:7:::

# 注意喔！同一行中間是以 [tab] 按鍵隔開的！

範例二：先將 /etc/group 讀出(用 cat)，然後與範例一貼上一起！且僅取出前三行

[root@www ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3

# 這個例子的重點在那個 - 的使用！那玩意兒常常代表 stdin 喔！

- expand

這玩意兒就是在將 [tab] 按鍵轉成空白鍵啦∼可以這樣玩：

[root@www ~]# expand [-t] file

選項與參數：

-t  ：後面可以接數字。一般來說，一個 tab 按鍵可以用 8 個空白鍵取代。

我們也可以自行定義一個 [tab] 按鍵代表多少個字元呢！

範例一：將 /etc/man.config 內行首為 MANPATH 的字樣就取出；僅取前三行；

[root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3

MANPATH /usr/man

MANPATH /usr/share/man

MANPATH /usr/local/man

# 行首的代表標誌為 ^ ，這個我們留待下節介紹！先有概念即可！

範例二：承上，如果我想要將所有的符號都列出來？(用 cat)

[root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 |cat -A

MANPATH^I/usr/man$

MANPATH^I/usr/share/man$

MANPATH^I/usr/local/man$

# 發現差別了嗎？沒錯∼ [tab] 按鍵可以被 cat -A 顯示成為 ^I

範例三：承上，我將 [tab] 按鍵設定成 6 個字元的話？

[root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 | \

>  expand -t 6 - | cat -A

MANPATH     /usr/man$

MANPATH     /usr/share/man$

MANPATH     /usr/local/man$

123456123456123456.....

# 仔細看一下上面的數字說明，因為我是以 6 個字元來代表一個 [tab] 的長度，所以，

# MAN... 到 /usr 之間會隔 12 (兩個 [tab]) 個字元喔！如果 tab 改成 9 的話，

# 情況就又不同了！這裡也不好理解∼您可以多設定幾個數字來查閱就曉得！

expand 也是挺好玩的∼他會自動將 [tab] 轉成空白鍵∼所以，以上面的例子來說， 使用 cat -A 就會查不到 ^I 的字符囉∼此外，因為 [tab] 最大的功能就是格式排列整齊！ 我們轉成空白鍵後，這個空白鍵也會依據我們自己的定義來增加大小∼ 所以，並不是一個 ^I 就會換成 8 個空白喔！這個地方要特別注意的哩！ 此外，您也可以參考一下 unexpand 這個將空白轉成 [tab] 的指令功能啊！ ^_^

分割命令： split

如果你有檔案太大，導致一些攜帶式裝置無法複製的問題，嘿嘿！找 split 就對了！ 他可以幫你將一個大檔案，依據檔案大小或行數來分割，就可以將大檔案分割成為小檔案了！ 快速又有效啊！真不錯∼

[root@www ~]# split [-bl] file PREFIX

選項與參數：

-b  ：後面可接欲分割成的檔案大小，可加單位，例如 b, k, m 等；

-l  ：以行數來進行分割。

PREFIX ：代表前置字元的意思，可作為分割檔案的前導文字。

範例一：我的 /etc/termcap 有七百多K，若想要分成 300K 一個檔案時？

[root@www ~]# cd /tmp; split -b 300k /etc/termcap termcap

[root@www tmp]# ll -k termcap*

-rw-r--r-- 1 root root 300 Feb  7 16:39 termcapaa

-rw-r--r-- 1 root root 300 Feb  7 16:39 termcapab

-rw-r--r-- 1 root root 189 Feb  7 16:39 termcapac

# 那個檔名可以隨意取的啦！我們只要寫上前導文字，小檔案就會以

# xxxaa, xxxab, xxxac 等方式來建立小檔案的！

範例二：如何將上面的三個小檔案合成一個檔案，檔名為 termcapback

[root@www tmp]# cat termcap* >> termcapback

# 很簡單吧？就用資料流重導向就好啦！簡單！

範例三：使用 ls -al / 輸出的資訊中，每十行記錄成一個檔案

[root@www tmp]# ls -al / | split -l 10 - lsroot

[root@www tmp]# wc -l lsroot*

10 lsrootaa

10 lsrootab

6 lsrootac

26 total

# 重點在那個 - 啦！一般來說，如果需要 stdout/stdin 時，但偏偏又沒有檔案，

# 有的只是 - 時，那麼那個 - 就會被當成 stdin 或 stdout ∼

在 Windows 作業系統下，你要將檔案分割需要如何作？傷腦筋吧！在 Linux 底下就簡單的多了！你要將檔案分割的話，那麼就使用 -b size 來將一個分割的檔案限制其大小，如果是行數的話，那麼就使用 -l line 來分割！好用的很！如此一來，你就可以輕易的將你的檔案分割成軟碟 (floppy) 的大小，方便你 copy 囉！

參數代換： xargs

xargs 是在做什麼的呢？就以字面上的意義來看， x 是加減乘除的乘號，args 則是 arguments (參數) 的意思，所以說，這個玩意兒就是在產生某個指令的參數的意思！ xargs 可以讀入 stdin 的資料，並且以空白字元或斷行字元作為分辨，將 stdin 的資料分隔成為 arguments 。 因為是以空白字元作為分隔，所以，如果有一些檔名或者是其他意義的名詞內含有空白字元的時候， xargs 可能就會誤判了∼他的用法其實也還滿簡單的！就來看一看先！

[root@www ~]# xargs [-0epn] command

選項與參數：

-0  ：如果輸入的 stdin 含有特殊字元，例如 `, \, 空白鍵等等字元時，這個 -0 參數

可以將他還原成一般字元。這個參數可以用於特殊狀態喔！

-e  ：這個是 EOF (end of file) 的意思。後面可以接一個字串，當 xargs 分析到

這個字串時，就會停止繼續工作！

-p  ：在執行每個指令的 argument 時，都會詢問使用者的意思；

-n  ：後面接次數，每次 command 指令執行時，要使用幾個參數的意思。看範例三。

當 xargs 後面沒有接任何的指令時，預設是以 echo 來進行輸出喔！

範例一：將 /etc/passwd 內的第一欄取出，僅取三行，使用 finger 這個指令將每個

帳號內容秀出來

[root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs finger

Login: root                             Name: root

Directory: /root                        Shell: /bin/bash

Never logged in.

No mail.

No Plan.

......底下省略.....

# 由 finger account 可以取得該帳號的相關說明內容，例如上面的輸出就是 finger root

# 後的結果。在這個例子當中，我們利用 cut 取出帳號名稱，用 head 取出三個帳號，

# 最後則是由 xargs 將三個帳號的名稱變成 finger 後面需要的參數！

範例二：同上，但是每次執行 finger 時，都要詢問使用者是否動作？

[root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs -p finger

finger root bin daemon ?...y

.....(底下省略)....

# 呵呵！這個 -p 的選項可以讓使用者的使用過程中，被詢問到每個指令是否執行！

範例三：將所有的 /etc/passwd 內的帳號都以 finger 查閱，但一次僅查閱五個帳號

[root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -n 5 finger

finger root bin daemon adm lp ?...y

.....(中間省略)....

finger uucp operator games gopher ftp ?...y

.....(底下省略)....

# 在這裡鳥哥使用了 -p 這個參數來讓您對於 -n 更有概念。一般來說，某些指令後面

# 可以接的 arguments 是有限制的，不能無限制的累加，此時，我們可以利用 -n

# 來幫助我們將參數分成數個部分，每個部分分別再以指令來執行！這樣就 OK 啦！^_^

範例四：同上，但是當分析到 lp 就結束這串指令？

[root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -e'lp' finger

finger root bin daemon adm ?...

# 仔細與上面的案例做比較。也同時注意，那個 -e'lp' 是連在一起的，中間沒有空白鍵。

# 上個例子當中，第五個參數是 lp 啊，那麼我們下達 -e'lp' 後，則分析到 lp

# 這個字串時，後面的其他 stdin 的內容就會被 xargs 捨棄掉了！

其實，在 man xargs 裡面就有三四個小範例，您可以自行參考一下內容。 此外， xargs 真的是很好用的一個玩意兒！您真的需要好好的參詳參詳！會使用 xargs 的原因是， 很多指令其實並不支援管線命令，因此我們可以透過 xargs 來提供該指令引用 standard input 之用！舉例來說，我們使用如下的範例來說明：

範例五：找出 /sbin 底下具有特殊權限的檔名，並使用 ls -l 列出詳細屬性

[root@www ~]# find /sbin -perm +7000 | ls -l

# 結果竟然僅有列出 root 所在目錄下的檔案！這不是我們要的！

# 因為 ll (ls) 並不是管線命令的原因啊！

[root@www ~]# find /sbin -perm +7000 | xargs ls -l

-rwsr-xr-x 1 root root 70420 May 25  2008 /sbin/mount.nfs

-rwsr-xr-x 1 root root 70424 May 25  2008 /sbin/mount.nfs4

-rwxr-sr-x 1 root root  5920 Jun 15  2008 /sbin/netreport

....(底下省略)....

關於減號 - 的用途

管線命令在 bash 的連續的處理程序中是相當重要的！另外，在 log file 的分析當中也是相當重要的一環， 所以請特別留意！另外，在管線命令當中，常常會使用到前一個指令的 stdout 作為這次的 stdin ， 某些指令需要用到檔案名稱 (例如 tar) 來進行處理時，該 stdin 與 stdout 可以利用減號 "-" 來替代， 舉例來說：

[root@www ~]# tar -cvf - /home | tar -xvf -

上面這個例子是說：『我將 /home 裡面的檔案給他打包，但打包的資料不是紀錄到檔案，而是傳送到 stdout； 經過管線後，將 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個指令的 stdout， 因此，我們就不需要使用 file 了！這是很常見的例子喔！注意注意！

重點回顧

- 由於核心在記憶體中是受保護的區塊，因此我們必須要透過『 Shell 』將我們輸入的指令與 Kernel 溝通，好讓 Kernel 可以控制硬體來正確無誤的工作

- 學習 shell 的原因主要有：文字介面的 shell 在各大 distribution 都一樣；遠端管理時文字介面速度較快； shell 是管理 Linux 系統非常重要的一環，因為 Linux 內很多控制都是以 shell 撰寫的。

- 系統合法的 shell 均寫在 /etc/shells 檔案中；

- 使用者預設登入取得的 shell 記錄於 /etc/passwd 的最後一個欄位；

- bash 的功能主要有：命令編修能力；命令與檔案補全功能；命令別名設定功能；工作控制、前景背景控制；程式化腳本；萬用字元

- type 可以用來找到執行指令為何種類型，亦可用於與 which 相同的功能；

- 變數就是以一組文字或符號等，來取代一些設定或者是一串保留的資料

- 變數主要有環境變數與自訂變數，或稱為全域變數與區域變數

- 使用 env 與 export 可觀察環境變數，其中 export 可以將自訂變數轉成環境變數；

- set 可以觀察目前 bash 環境下的所有變數；

- $? 亦為變數，是前一個指令執行完畢後的回傳值。在 Linux 回傳值為 0 代表執行成功；

- locale 可用於觀察語系資料；

- 可用 read 讓使用者由鍵盤輸入變數的值

- ulimit 可用以限制使用者使用系統的資源情況

- bash 的設定檔主要分為 login shell 與 non-login shell。login shell 主要讀取 /etc/profile 與 ~/.bash_profile， non-login shell 則僅讀取 ~/.bashrc

- 萬用字元主要有： *, ?, [] 等等

- 資料流重導向透過 >, 2>, < 之類的符號將輸出的資訊轉到其他檔案或裝置去；

- 連續命令的下達可透過 ; && || 等符號來處理

- 管線命令的重點是：『管線命令僅會處理 standard output，對於 standard error output 會予以忽略』 『管線命令必須要能夠接受來自前一個指令的資料成為 standard input 繼續處理才行。』

- 本章介紹的管線命令主要有：cut, grep, sort, wc, uniq, tee, tr, col, join, paste, expand, split, xargs 等。

本章習題

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：由於 ~/.bash_history 僅能記錄指令，我想要在每次登出時都記錄時間，並將後續的指令 50 筆記錄下來， 可以如何處理？

- 目標：瞭解 history ，並透過資料流重導向的方式記錄歷史命令；

- 前提：需要瞭解本章的資料流重導向，以及瞭解 bash 的各個環境設定檔資訊。

其實處理的方式非常簡單，我們可以瞭解 date 可以輸出時間，而利用 ~/.myhistory 來記錄所有歷史記錄， 而目前最新的 50 筆歷史記錄可以使用 history 50 來顯示，故可以修改 ~/.bash_logout 成為底下的模樣：

[root@www ~]# vim ~/.bash_logout

date >> ~/.myhistory

history 50 > > ~/.myhistory

clear

簡答題部分：

- 在 Linux 上可以找到哪些 shell(舉出三個) ？那個檔案記錄可用的 shell ？而 Linux 預設的 shell 是？

1) /bin/bash, /bin/tcsh, /bin/csh

2) /etc/shells

3) bash ，亦即是 /bin/bash。

- 在 shell 環境下，有個提示字元 (prompt)，他可以修改嗎？要改什麼？預設的提示字元內容是？

可以修改的，改 PS1 這個變數，這個 PS1 變數的預設內容為：『[\u@\h \W]\$』

- 如何顯示 HOME 這個環境變數？

echo $HOME

- 如何得知目前的所有變數與環境變數的設定值？

環境變數用 env 或 export 而所有變數用 set 即可顯示

- 我是否可以設定一個變數名稱為 3myhome ？

不行！變數不能以數字做為開頭，參考變數設定規則的內容

- 在這樣的練習中『A=B』且『B=C』，若我下達『unset $A』，則取消的變數是 A 還是 B？

被取消的是 B 喔，因為 unset $A 相當於 unset B 所以取消的是 B ，A 會繼續存在！

- 如何取消變數與命令別名的內容？

使用 unset 及 unalias 即可

- 如何設定一個變數名稱為 name 內容為 It's my name ？

name=It\'s\ my\ name 或 name="It's my name"

- bash 環境設定檔主要分為哪兩種類型的讀取？分別讀取哪些重要檔案？

(1)login shell：主要讀取 /etc/profile 及 ~/.bash_profile

(2)non-logni shell：主要讀取 ~/.bashrc 而已。

- CentOS 5.x 的 man page 的路徑設定檔案？

/etc/man.config

- 試說明 ', ", 與 ` 這些符號在變數定義中的用途？

參考變數規則那一章節，其中， " 可以具有變數的內容屬性，' 則僅有一般字元，至於 ` 之內則是可先被執行的指令。

- 跳脫符號 \ 有什麼用途？

可以用來跳脫特殊字元，例如 Enter, $ 等等，使成為一般字元！

- 連續命令中， ;, &&, || 有何不同？

分號可以讓兩個 command 連續運作，不考慮 command1 的輸出狀態， && 則前一個指令必需要沒有錯誤訊息，亦即回傳值需為 0 則 command2 才會被執行， || 則與 && 相反！

- 如何將 last 的結果中，獨立出帳號，並且印出曾經登入過的帳號？

last | cut -d ' ' -f1 | sort | uniq

- 請問 foo1 && foo2 | foo3 > foo4 ，這個指令串當中， foo1/foo2/foo3/foo4 是指令還是檔案？ 整串指令的意義為？

foo1, foo2 與 foo3 都是指令， foo4 是裝置或檔案。整串指令意義為：

(1)當 foo1 執行結果有錯誤時，則該指令串結束；

(2)若 foo1 執行結果沒有錯誤時，則執行 foo2 | foo3 > foo4 ；其中：

(2-1)foo2 將 stdout 輸出的結果傳給 foo3 處理；

(2-2)foo3 將來自 foo2 的 stdout 當成 stdin ，處理完後將資料流重新導向 foo4 這個裝置/檔案

- 如何秀出在 /bin 底下任何以 a 為開頭的檔案檔名的詳細資料？

ls -l /bin/a*

- 如何秀出 /bin 底下，檔名為四個字元的檔案？

ls -l /bin/????

- 如何秀出 /bin 底下，檔名開頭不是 a-d 的檔案？

ls -l /bin/[^a-d]*

- 我想要讓終端機介面的登入提示字元修改成我自己喜好的模樣，應該要改哪裡？(filename)

/etc/issue

- 承上題，如果我是想要讓使用者登入後，才顯示歡迎訊息，又應該要改哪裡？

/etc/motd

參考資料與延伸閱讀

- 註1：Webmin 的官方網站：http://www.webmin.com/

- 註2：關於 shell 的相關歷史可以參考網路農夫兄所整理的優秀文章。不過由於網路農夫兄所建置的網站暫時關閉， 因此底下的連結為鳥哥到網路上找到的片段文章連結。若有任何侵權事宜，請來信告知，謝謝：

http://linux.vbird.org/linux_basic/0320bash/csh/

- 註3：使用 man bash，再以 PS1 為關鍵字去查詢，按下數次 n 往後查詢後，可以得到 PS1 的變數說明。

- 註4：i18n 是由一些 Linux distribution 貢獻者共同發起的大型計畫，目的在於讓眾多的 Linux distributions 能夠有良好的萬國碼 (Unicode) 語系的支援。詳細的資料可以參考：

i18n 的官方網站：http://www.openi18n.org/

康橋大學 Dr Markus Kuhn 的文獻：http://www.cl.cam.ac.uk/~mgk25/unicode.html

Debian 社群所寫的文件：http://www.debian.org/doc/manuals/intro-i18n/

- 臥龍小三的教學文件：http://linux.tnc.edu.tw/techdoc/shell/book1.html

- GNU 計畫的 BASH 說明：http://www.gnu.org/manual/bash-2.05a/html_mono/bashref.html

鳥哥的備份：http://linux.vbird.org/linux_basic/0320bash/0320bash_reference.php

- man bash

2002/06/27：第一次完成

2003/02/10：重新編排與加入 FAQ

2005/08/17：將舊的資料放置到 這裡

2005/08/17：終於稍微搞定了∼花了半個多月不眠不休∼呼∼補充了較多的管線命令與資料流重導向！

2005/08/18：加入額外的變數設定部分！

2005/08/30：加入了 login 與 non-login shell 的簡單說明！

2006/03/19：原先在 col 的說明當中，原本指令『cat -A /etc/man.config | col -x | cat -A | more』不該有 -A！

2006/10/05：感謝小州兄的告知，修正了原本 ~/.bashrc 說明當中的錯誤。

2007/04/05：原本的 cut 範例說明有誤，原本是『我要找出第三個』應該改為『我要找出第五個』才對！

2007/04/11：原本的 join 說明沒有加上排序，應該需要排序後再處理才對！

2007/07/15：原本的額外的變數功能表格有誤，在 var=${str+expr} 與var=${str:+expr} 需要修改，請參考 此處

2009/01/13：將原本基於 FC4 寫作的舊文章移動到此處

2009/02/03：拿掉了原本的『變數的用途』部分，改以案例說明

2009/02/05：多加了變數刪除、取代與替代部分的範例，看起來應該不會像前一版那樣不容易理解！

2009/08/25：加入了情境模擬，並且進行一些說明的細部修改而已。

2010/04/16：感謝wenyenyang兄的告知， wc -c 錯誤，是 wc -m 才是！

2002/05/20以來統計人數

第一章、Linux是什麼

切換解析度為 800x600

最近更新日期：2009/08/05

眾所皆知的，Linux的核心原型是1991年由托瓦茲(Linus Torvalds)寫出來的，但是托瓦茲為何可以寫出Linux這個作業系統？ 為什麼他要選擇386的電腦來開發？為什麼Linux的發展可以這麼迅速？又為什麼Linux是免費的？ 以及目前為何有這麼多的Linux版本(distributions)呢？瞭解這些東西後，才能夠知道為何Linux可以免除專利軟體之爭， 並且瞭解到Linux為何可以同時在個人電腦與大型主機上面大放異彩！ 所以，在實際進入Linux的世界前，就讓我們來談一談這些有趣的歷史故事吧！ ^_^

1. Linux是什麼

1.1 Linux是什麼

1.2 Linux之前，Unix的歷史

1.3 關於GNU計畫

2. Torvalds的Linux發展

2.1 與Minix之間

2.2 對386硬體的多工測試

2.3 初次釋出Linux 0.02

2.4 Linux的發展：虛擬團隊的產生

2.5 Linux 的核心版本

2.6 Linux distributions

3. Linux的特色

3.1 Linux的特色

3.2 Linux的優缺點

3.3 關於授權

4. 重點回顧

5. 本章習題

6. 參考資料與延伸閱讀

7. 針對本文的建議：http://phorum.vbird.org/viewtopic.php?t=23871

Linux是什麼

我們知道Linux這玩意兒是在電腦上面運作的，所以說Linux就是一組軟體。問題是這個軟體是作業系統還是應用程式？ 且Linux可以在哪些種類的電腦上面運作？而Linux源自哪裡？為什麼 Linux 還不用錢？這些我們都得來談一談先！

Linux是什麼

我們在第零章、計算機概論裡面有提到過整個電腦系統的概念， 電腦是由一堆硬體所組成的，為了有效率的控制這些硬體資源，於是乎就有作業系統的產生了。 作業系統除了有效率的控制這些硬體資源的分配，並提供電腦運作所需要的功能(如網路功能)之外， 為了要提供程式設計師更容易開發軟體的環境，所以作業系統也會提供一整組系統呼叫介面來給軟體設計師開發用喔！

知道為什麼要講這些了嗎？嘿嘿！沒錯，因為Linux就是一套作業系統！如同下圖所示， Linux就是核心與系統呼叫介面那兩層。至於應用程式算不算Linux呢？當然不算啦！這點要特別注意喔！

圖1.1.1、作業系統的角色

由上圖中我們可以看到其實核心與硬體的關係非常的強烈。早期的Linux是針對386來開發的， 由於Linux只是一套作業系統並不含有其他的應用程式，因此很多工程師在下載了 Linux 核心並且實際安裝之後，就只能看著電腦開始運作了！ 接下來這些高級工程師為了自己的需求，再在Linux上面安裝他們所需要的軟體就是了。

Tips:

Torvalds先生在寫出Linux的時候，其實該核心僅能『驅動386所有的硬體』而已， 所謂的『讓386電腦開始運作，並且等待使用者指令輸入』而已，事實上， 當時能夠在Linux上面跑的軟體還很少呢！

由於不同的硬體他的功能函數並不相同，例如IBM的Power CPU與Intel的x86架構就是不一樣！ 所以同一套作業系統是無法在不同的硬體平台上面運作的！舉例來說，如果你想要讓x86上面跑的那套作業系統也能夠在Power CPU上運作時，就得要將該作業系統進行修改才行。如果能夠參考硬體的功能函數並據以修改你的作業系統程式碼， 那經過改版後的作業系統就能夠在另一個硬體平台上面運作了。 這個動作我們通常就稱為『軟體移植』了！

例題：

請問Windows作業系統能否在蘋果公司的麥金塔電腦(MAC)上面安裝與運作？

答：

由上面的說明中，我們知道硬體是由『核心』來控制的，而每種作業系統都有他自己的核心。 在2006年以前的蘋果電腦公司是請IBM公司幫忙開發硬體(所謂的Power CPU)， 而蘋果電腦公司則在該硬體架構上發展自家的作業系統(就是俗稱的麥金塔，MAC是也)。Windows則是開發在x86架構上的作業系統之一， 因此Windows是沒有辦法安裝到麥金塔電腦硬體上面的。

不過，在2006年以後，蘋果電腦轉而請Intel設計其硬體架構，亦即其硬體架構已經轉為x86系統， 因此在2006年以後的蘋果電腦若使用x86架構時，其硬體則『可能』可以安裝Windows作業系統了。 不過，你可能需要自己想些方式來處理該硬體的相容性囉！

Tips:

Windows作業系統本來就是針對個人電腦x86架構的硬體去設計的，所以他當然只能在x86的個人電腦上面運作， 在不同的平台當然就無法運行了。也就是說，每種作業系統都是在他專門的機器上面運行的喔！這點得要先瞭解。 不過，Linux由於是Open Source的作業系統，所以他的程式碼可以被修改成適合在各種機器上面運行的， 也就是說，Linux是具有『可移植性』，這可是很重要的一個功能喔！ ^_^

Linux提供了一個完整的作業系統當中最底層的硬體控制與資源管理的完整架構， 這個架構是沿襲Unix良好的傳統來的，所以相當的穩定而功能強大！此外， 由於這個優良的架構可以在目前的個人電腦(x86系統)上面跑， 所以很多的軟體開發者漸漸的將他們的工作心血移轉到這個架構上面，所以 Linux 作業系統也有很多的應用軟體啦！

雖然Linux僅是其核心與核心提供的工具，不過由於核心、核心工具與這些軟體開發者提供的軟體的整合， 使得Linux成為一個更完整的、功能強大的作業系統囉！約略瞭解Linux是何物之後，接下來，我們要談一談， 『為什麼說Linux是很穩定的作業系統呢？他是如何來的？』

Linux之前，Unix的歷史

早在Linux出現之前的二十年(大約在1970 年代)，就有一個相當穩定而成熟的作業系統存在了！ 那就是Linux的老大哥『Unix』是也！怎麼這麼說呢？他們這兩個傢伙有什麼關係呀？這裡就給他說一說囉！

眾所皆知的，Linux的核心是由Linus Torvalds在1991年的時候給他開發出來的， 並且丟到網路上提供大家下載，後來大家覺得這個小東西(Linux Kernel)相當的小而精巧， 所以慢慢的就有相當多的朋友投入這個小東西的研究領域裡面去了！ 但是為什麼這個小東西這麼棒呢？又為什麼大家都可以免費的下載這個東西呢？ 嗯！等鳥哥慢慢的唬xx....喔不！聽我慢慢的道來！

- 1969年以前：一個偉大的夢想--Bell,MIT與GE的『Multics』系統

早期的電腦並不像現在的個人電腦一樣普遍，他可不是一般人碰的起的呢∼ 除非是軍事或者是高科技用途，或者是學術單位的學術研究，否則真的很難接觸到。 非但如此，早期的電腦架構還很難使用，除了運算速度並不快之外，操作介面也很困擾的！ 因為那個時候的輸入設備只有讀卡機、輸出設備只有印表機， 使用者也無法與作業系統互動(批次型作業系統)。

在那個時候，寫程式是件很可憐的事情，因為程式設計者，必須要將程式相關的資訊在讀卡紙上面打洞， 然後再將讀卡紙插入讀卡機來將資訊讀入主機中運算。光是這樣就很麻煩了，如果程式有個小地方寫錯， 哈哈！光是重新打卡就很慘，加上主機少，使用者眾多，光是等待，就耗去很多的時間了！

在那之後，由於硬體與作業系統的改良，使得後來可以使用鍵盤來進行資訊的輸入。 不過，在一間學校裡面，主機畢竟可能只有一部，如果多人等待使用，那怎麼辦？大家還是得要等待啊！ 好在1960年代初期麻省理工學院(MIT)發展了所謂的： 『相容分時系統(Compatible Time-Sharing System, CTSS)』， 它可以讓大型主機透過提供數個終端機(terminal)以連線進入主機，來利用主機的資源進行運算工作。 架構有點像這樣：

圖1.2.1、早期主機與終端機的相關性圖示

Tips:

這個相容分時系統可以說是近代作業系統的始祖呢！他可以讓多個使用者在某一段時間內分別使用CPU的資源， 感覺上你會覺得大家是同時使用該主機的資源！事實上，是CPU在每個使用者的工作之間進行切換， 在當時，這可是個劃時代的技術喔！

如此一來，無論主機在哪裡，只要在終端機前面進行輸入輸出的作業，就可利用主機提供的功能了。 不過，需要注意的是，此時終端機只具有輸入/輸出的功能，本身完全不具任何運算或者軟體安裝的能力。 而且，比較先進的主機大概也只能提供30個不到的終端機而已。

為了更加強化大型主機的功能，以讓主機的資源可以提供更多使用者來利用，所以在1965年前後， 由貝爾實驗室(Bell)、麻省理工學院(MIT)及奇異公司(GE, 或稱為通用電器)共同發起了Multics的計畫， Multics計畫的目的是想要讓大型主機可以達成提供300個以上的終端機連線使用的目標。 不過，到了1969年前後，計畫進度落後，資金也短缺，所以該計畫雖然繼續在研究，但貝爾實驗室還是退出了該計畫的研究工作。 (註：Multics有複雜、多數的意思存在。)

Tips:

最終Multics還是有成功的發展出他們的系統，完整的歷史說明可以參考： http://www.multicians.org/網站內容。 Multics計畫雖然後來沒有受到很大的重視，但是他培養出來的人材是相當優秀的！ ^_^

- 1969年：Ken Thompson的小型file server system

在認為Multics計畫不可能成功之後，貝爾研究室就退出該計畫。不過，原本參與Multics計畫的人員中，已經從該計畫當中獲得一些點子， Ken Thompson 就是其中一位！

Thompson因為自己的需要，希望開發一個小小的作業系統以提供自己的需求。 在開發時，有一部DEC(Digital Equipment Corporation)公司推出的PDP-7剛好沒人使用， 於是他就準備針對這部主機進行作業系統核心程式的撰寫。本來Thompson應該是沒時間的(有家有小孩的宿命？)， 無巧不巧的是，在1969年八月份左右，剛好Thompson的妻兒去了美西探親， 於是他有了額外的一個月的時間好好的待在家將一些構想實現出來！

經過四個星期的奮鬥，他終於以組合語言(Assembler)寫出了一組核心程式，同時包括一些核心工具程式， 以及一個小小的檔案系統。那個系統就是Unix的原型！ 當時Thompson將Multics龐大的複雜系統簡化了不少，於是同實驗室的朋友都戲稱這個系統為：Unics。(當時尚未有Unix的名稱)

Thompson 的這個檔案系統有兩個重要的概念，分別是：

- 所有的程式或系統裝置都是檔案

- 不管建構編輯器還是附屬檔案，所寫的程式只有一個目的，且要有效的完成目標。

這些概念在後來對於Linux的發展有相當重要的影響喔！

Tips:

套一句常聽到的廣告詞：『科技始終來自於人性』，當初Thompson會寫這套Unix核心程式， 卻是想要移植一套名為『太空旅遊』的遊戲呢！ ^_^

- 1973年：Unix的正式誕生，Ritchie等人以C語言寫出第一個正式Unix核心

由於Thompson寫的那個作業系統實在太好用了，所以在貝爾實驗室內部廣為流傳，並且數度經過改版。 但是因為Unics本來是以組合語言寫成的，而如第零章計算機概論談到的， 組合語言具有專一性，加上當時的電腦機器架構都不太相同，所以每次要安裝到不同的機器都得要重新編寫組合語言，真不方便！

後來Thompson與Ritchie合作想將Unics改以高階程式語言來撰寫。當時現成的高階程式語言有B語言。 但是由B語言所編譯出來的核心效能不是很好。後來Dennis Ritchie將B語言重新改寫成C語言，再以C語言重新改寫與編譯Unics的核心， 最後正名與發行出Unix的正式版本！

Tips:

這群高級駭客實在很厲害！因為自己的需求來開發出這麼多好用的工具！ C程式語言開發成功後，甚至一直沿用至今呢！你說厲不厲害啊！這個故事也告訴我們，不要小看自己的潛能喔！ 你想作的，但是現實生活中沒有的，就動手自己搞一個來玩玩吧！

由於貝爾實驗室是隸屬於美國電信大廠AT&T公司的， 只是AT&T當時忙於其他商業活動，對於Unix並不支持也不排斥。此外，Unix在這個時期的發展者都是貝爾實驗室的工程師， 這些工程師對於程式當然相當有研究，所以，Unix在此時當然是不容易被一般人所接受的！不過對於學術界的學者來說， 這個 Unix 真是學者們進行研究的福音！因為程式碼可改寫並且可作為學術研究之用嘛！

需要特別強調的是，由於Unix是以較高階的C語言寫的，相對於組合語言需要與硬體有密切的配合， 高階的C語言與硬體的相關性就沒有這麼大了！所以，這個改變也使得Unix很容易被移植到不同的機器上面喔！

- 1977年：重要的Unix分支--BSD的誕生

雖然貝爾屬於AT&T，但是AT&T此時對於Unix是採取較開放的態度，此外，Unix是以高階的C語言寫成的， 理論上是具有可移植性的！亦即只要取得Unix的原始碼，並且針對大型主機的特性加以修訂原有的原始碼(Source Code)， 就可能將Unix移植到另一部不同的主機上頭了。所以在1973年以後，Unix便得以與學術界合作開發！ 最重要的接觸就是與加州柏克萊(Berkeley)大學的合作了。

柏克萊大學的Bill Joy在取得了Unix的核心原始碼後，著手修改成適合自己機器的版本， 並且同時增加了很多工具軟體與編譯程式，最終將它命名為Berkeley Software Distribution (BSD)。這個BSD是Unix很重要的一個分支，Bill Joy也是Unix業者『Sun(昇陽)』這家公司的創辦者！ Sun公司即是以BSD發展的核心進行自己的商業Unix版本的發展的。 (後來可以安裝在x86硬體架構上面FreeBSD即是BSD改版而來！)

- 1979年：重要的 System V 架構與版權宣告

由於Unix的高度可移植性與強大的效能，加上當時並沒有版權的糾紛， 所以讓很多商業公司開始了Unix作業系統的發展，例如AT&T自家的System V、IBM的AIX以及HP與DEC等公司， 都有推出自家的主機搭配自己的Unix作業系統。

但是，如同我們前面提到的，作業系統的核心(Kernel)必須要跟硬體配合， 以提供及控制硬體的資源進行良好的工作！而在早期每一家生產電腦硬體的公司還沒有所謂的『協定』的概念， 所以每一個電腦公司出產的硬體自然就不相同囉！因此他們必須要為自己的電腦硬體開發合適的Unix系統。 例如在學術機構相當有名的Sun、Cray與HP就是這一種情況。 他們開發出來的Unix作業系統以及內含的相關軟體並沒有辦法在其他的硬體架構下工作的！ 另外，由於沒有廠商針對個人電腦設計Unix系統，因此，在早期並沒有支援個人電腦的Unix作業系統的出現。

Tips:

如同相容分時系統的功能一般，Unix強調的是多人多工的環境！ 但早期的286個人電腦架構下的CPU是沒有能力達到多工的作業，因此，並沒有人對移植Unix到x86的電腦上有興趣。

每一家公司自己出的Unix雖然在架構上面大同小異，但是卻真的僅能支援自身的硬體， 所以囉，早先的Unix只能與伺服器(Server)或者是大型工作站(Workstation)劃上等號！ 但到了 1979 年時，AT&T推出 System V 第七版 Unix 後，這個情況就有點改善了。 這一版最重要的特色是可以支援x86架構的個人電腦系統，也就是說 System V 可以在個人電腦上面安裝與運作了。

不過因為AT&T由於商業的考量，以及在當時現實環境下的思考，於是想將Unix的版權收回去。因此， AT&T在1979年發行的第七版Unix中，特別提到了 『不可對學生提供原始碼』的嚴格限制！ 同時，也造成Unix業界之間的緊張氣氛，並且也引爆了很多的商業糾紛∼

Tips:

目前被稱為純種的Unix指的就是System V以及BSD這兩套囉！

- 1984年之一：x86架構的Minix作業系統誕生

關於1979年的版權聲明中，影響最大的當然就是學校教Unix核心原始碼相關學問的教授了！ 想一想，如果沒有核心原始碼，那麼如何教導學生認識Unix呢？這問題對於Andrew Tanenbaum(譚寧邦)教授來說，實在是很傷腦筋的！不過，學校的課程還是得繼續啊！那怎麼辦？

既然1979年的Unix第七版可以在Intel的x86架構上面進行移植， 那麼是否意味著可以將Unix改寫並移植到x86上面了呢？在這個想法上， 譚寧邦教授於是乎自己動手寫了Minix這個Unix Like的核心程式！ 在撰寫的過程中，為了避免版權糾紛，譚寧邦完全不看Unix核心原始碼！ 並且強調他的Minix必須能夠與Unix相容才行！譚寧邦在1984年開始撰寫核心程式， 到了1986年終於完成，並於次年出版Minix相關書籍，同時與新聞群組(BBS及News)相結合∼

Tips:

之所以稱為Minix的原因，是因為他是個Mini的Unix系統囉！^_^

這個Minix版本比較有趣的地方是，他並不是完全免費的，無法在網路上提供下載！ 必須要透過磁片/磁帶購買才行！雖然真的很便宜∼不過，畢竟因為沒有在網路上流傳， 所以Minix的傳遞速度並沒有很快速！此外，購買時，隨磁片還會附上Minix的原始碼！ 這意味著使用者可以學習Minix的核心程式設計概念喔！ (這個特色對於Linux的啟始開發階段，可是有很大的關係喔！)

此外，Minix作業系統的開發者僅有譚寧邦教授，因為學者很忙啊！加上譚寧邦始終認為Minix主要用在教育用途上面， 所以對於Minix是點到為止！沒錯，Minix是很受歡迎，不過，使用者的要求/需求的聲音可能就比較沒有辦法上升到比較高的地方了！ 這樣說，你明白吧？^_^

- 1984年之二：GNU計畫與FSF基金會的成立

Richard Mathew Stallman(史托曼)在1984年發起的GNU計畫，對於現今的自由軟體風潮， 真有不可磨滅的地位！目前我們所使用得很多自由軟體，幾乎均直接或間接受益於GNU這個計畫呢！ 那麼史托曼是何許人也？為何他會發起這個GNU計畫呢？

- 一個分享的環境：

Richard Mathew Stallman(生於1953年， 網路上自稱的ID為RMS)從小就很聰明！他在1971年的時候，進入駭客圈中相當出名的人工智慧實驗室(AI Lab.)， 這個時候的駭客專指電腦功力很強的人，而非破壞電腦的怪客(cracker)喔！

當時的駭客圈對於軟體的著眼點幾乎都是在『分享』，所以並沒有專利方面的困擾！ 這個特色對於史托曼的影響很大！不過，後來由於管理階層的問題，導致實驗室的優秀駭客離開該實驗室， 並且進入其他商業公司繼續發展優秀的軟體。但史托曼並不服輸，仍然持續在原來的實驗室開發新的程式與軟體。 後來，他發現到，自己一個人並無法完成所有的工作，於是想要成立一個開放的團體來共同努力！

- 使用Unix開發階段：

1983年以後，因為實驗室硬體的更換，使得史托曼無法繼續以原有的硬體與作業系統繼續自由程式的撰寫∼ 而且他進一步發現到，過去他所使用的Lisp作業系統，是麻省理工學院的專利軟體， 是無法共享的，這對於想要成立一個開放團體的史托曼是個阻礙。於是他便放棄了Lisp這個系統。 後來，他接觸到Unix這個系統，並且發現，Unix在理論與實際上，都可以在不同的機器間進行移植。雖然 Unix 依舊是專利軟體， 但至少 Unix 架構上還是比較開放的！於是他開始轉而使用Unix系統。

因為Lisp與Unix是不同的系統，所以，他原本已經撰寫完畢的軟體是無法在Unix上面運行的！為此， 他就開始將軟體移植到Unix上面。並且，為了讓軟體可以在不同的平台上運作， 因此，史托曼將他發展的軟體均撰寫成可以移植的型態！也就是他都會將程式的原始碼公佈出來！

- GNU計畫的推展：

1984年，史托曼開始GNU計畫， 這個計畫的目的是：建立一個自由、開放的Unix作業系統(Free Unix)。 但是建立一個作業系統談何容易啊！而且在當時的GNU是僅有自己一個人單打獨鬥的史托曼∼ 這實在太麻煩，但又不想放棄這個計畫，那可怎麼辦啊？

聰明的史托曼乾脆反其道而行∼『既然作業系統太複雜，我就先寫可以在Unix上面運行的小程式，這總可以了吧？』在這個想法上， 史托曼開始參考Unix上面現有的軟體，並依據這些軟體的作用開發出功能相同的軟體，且開發期間史托曼絕不看其他軟體的原始碼， 以避免吃上官司。後來一堆人知道免費的GNU軟體，並且實際使用後發現與原有的專利軟體也差不了太多，於是便轉而使用GNU軟體， 於是GNU計畫逐漸打開知名度。

雖然GNU計畫漸漸打開知名度，但是能見度還是不夠。這時史托曼又想：不論是什麼軟體， 都得要進行編譯成為二進位檔案(binary program)後才能夠執行，如果能夠寫出一個不錯的編譯器，那不就是大家都需要的軟體了嗎？ 因此他便開始撰寫C語言的編譯器，那就是現在相當有名的GNU C Compiler(gcc)！ 這個點相當的重要！這是因為C語言編譯器版本眾多，但都是專利軟體， 如果他寫的C編譯器夠棒，效能夠佳，那麼將會大大的讓GNU計畫出現在眾人眼前！如果忘記啥是編譯器， 請回到第零章去瞧瞧編譯程式吧！

但開始撰寫GCC時並不順利，為此，他先轉而將他原先就已經寫過的Emacs編輯器寫成可以在Unix上面跑的軟體，並公布原始碼。 Emacs是一種程式編輯器，他可以在使用者撰寫程式的過程中就進行程式語法的檢驗，此一功能可以減少程式設計師除錯的時間！ 因為Emacs太優秀了，因此，很多人便直接向他購買。

此時網際網路尚未流行，所以，史托曼便藉著Emacs以磁帶(tape)出售，賺了一點錢 ，進而開始全力撰寫其他軟體。並且成立自由軟體基金會(FSF, Free Software Foundation)，請更多工程師與志工撰寫軟體。終於還是完成了GCC，這比Emacs還更有幫助！ 此外，他還撰寫了更多可以被呼叫的C函式庫(GNU C library)，以及可以被使用來操作作業系統的基本介面BASH shell！ 這些都在1990年左右完成了！

Tips:

如果純粹使用文字編輯器來編輯程式的話，那麼程式語法如果寫錯時，只能利用編譯時發生的錯誤訊息來修訂了，這樣實在很沒有效率。 Emacs則是一個很棒的編輯器！注意！是編輯(editor)而非編譯(compiler)！ 他可以很快的立刻顯示出你寫入的語法可能有錯誤的地方，這對於程式設計師來說， 實在是一個好到不能再好的工具了！所以才會這麼的受到歡迎啊！

- GNU的通用公共許可證：

到了1985年，為了避免GNU所開發的自由軟體被其他人所利用而成為專利軟體， 所以他與律師草擬了有名的通用公共許可證(General Public License, GPL)， 並且稱呼他為copyleft(相對於專利軟體的copyright！)。 關於GPL的相關內容我們在下一個小節繼續談論，在這裡，必須要說明的是， 由於有GNU所開發的幾個重要軟體，如：

- Emacs

- GNU C (GCC)

- GNU C Library (glibc)

- Bash shell

造成後來很多的軟體開發者可以藉由這些基礎的工具來進行程式開發！ 進一步壯大了自由軟體團體！這是很重要的！不過，對於GNU的最初構想 『建立一個自由的Unix作業系統』來說，有這些優秀的程式是仍無法滿足， 因為，當下並沒有『自由的Unix核心』存在...所以這些軟體仍只能在那些有專利的 Unix平台上工作∼∼一直到Linux的出現...更多的FSF開發的軟體可以參考如下網頁：

- https://www.fsf.org/resources

- 1988年：圖形介面XFree86計畫

有鑑於圖形使用者介面(Graphical User Interface, GUI) 的需求日益加重，在1984年由MIT與其他協力廠商首次發表了X Window System ，並且更在1988年成立了非營利性質的XFree86這個組織。所謂的XFree86其實是 X Window System + Free + x86的整合名稱呢！ 而這個XFree86的GUI介面更在Linux的核心1.0版於1994年釋出時，整合於Linux作業系統當中！

Tips:

為什麼稱圖形使用者介面為X呢？因為由英文單字來看，Window的W接的就是X啦！意指Window的下一版就是了！ 需注意的是，X Window並不是X Windows喔！

- 1991年：芬蘭大學生Linus Torvalds的一則簡訊

到了1991年，芬蘭的赫爾辛基大學的Linus Torvalds在BBS上面貼了一則消息， 宣稱他以bash, gcc等工具寫了一個小小的核心程式，這個核心程式可以在Intel的386機器上面運作， 讓很多人很感興趣！從此開始了Linux不平凡的路程！

關於GNU計畫

GNU計畫對於整個自由軟體來說是佔有非常重要的角色！底下我們就來談談這咚咚吧！

- 自由軟體的活動：

1984年創立GNU計畫與FSF基金會的Stallman先生認為，寫程式最大的快樂就是讓自己發展的良好的軟體讓大家來使用了！ 而既然程式是想要分享給大家使用的，不過，每個人所使用的電腦軟硬體並不相同， 既然如此的話，那麼該程式的原始碼(Source code)就應該要同時釋出， 這樣才能方便大家修改而適用於每個人的電腦中呢！這個將原始碼連同軟體程式釋出的舉動， 就稱為自由軟體(Free Software)運動！

此外，史托曼同時認為，如果你將你程式的Source code分享出來時，若該程式是很優秀的，那麼將會有很多人使用， 而每個人對於該程式都可以查閱source code，無形之中，就會有一票人幫你除錯囉！ 你的這支程式將會越來越壯大！越來越優秀呢！

- 自由軟體的版權GNU GPL：

而為了避免自己的開發出來的Open source自由軟體被拿去做成專利軟體， 於是Stallman同時將GNU與FSF發展出來的軟體，都掛上GPL的版權宣告∼ 這個FSF的核心觀念是『版權制度是促進社會進步的手段， 版權本身不是自然權力。』對於FSF有興趣或者對於GNU想要更深入的瞭解時，請參考朝陽科技大學洪朝貴教授的網站 http://people.ofset.org/~ckhung/a/c_83.php，或直接到GNU去： http://www.gnu.org 裡面有更為深入的解說！

Tips:

為什麼要稱為GNU呢？其實GNU是GNU's Not Unix的縮寫，意思是說，GNU並不是Unix啊！那麼GNU又是什麼呢？ 就是GNU's Not Unix嘛！.....如果你寫過程式就會知道，這個GNU = GNU's Not Unix可是無窮迴圈啊！忙碌∼

另外，什麼是Open Source呢？所謂的source是程式發展者寫出的原始程式碼， Open Source就是，軟體在發佈時，同時將作者的原始碼一起公布的意思！

- 自由(Free)的真諦：

那麼這個GPL(GNU General Public License, GPL)是什麼玩意兒？ 為什麼要將自由軟體掛上GPL的『版權宣告』呢？這個版權宣告對於作者有何好處？ 首先，Stallman對GPL一直是強調Free的，這個Free的意思是這樣的：

"Free software" is a matter of liberty, not price. To understand the concept, you should think of "free speech", not "free beer". "Free software" refers to the users' freedom to run, copy, distribute, study, change, and improve the software

大意是說，Free Software(自由軟體)是一種自由的權力，並非是『價格！』 舉例來說，你可以擁有自由呼吸的權力、你擁有自由發表言論的權力， 但是，這並不代表你可以到處喝『免費的啤酒！(free beer)』，也就是說， 自由軟體的重點並不是指『免費』的，而是指具有『自由度, freedom』的軟體， 史托曼進一步說明了自由度的意義是： 使用者可以自由的執行、複製、再發行、學習、修改與強化自由軟體。

這無疑是個好消息！因為如此一來，你所拿到的軟體可能原先只能在Unix上面跑， 但是經過原始碼的修改之後，你將可以拿他在Linux或者是Windows上面來跑！總之， 一個軟體掛上了GPL版權宣告之後，他自然就成了自由軟體！這個軟體就具有底下的特色：

- 取得軟體與原始碼：你可以根據自己的需求來執行這個自由軟體；

- 複製：你可以自由的複製該軟體；

- 修改：你可以將取得的原始碼進行程式修改工作，使之適合你的工作；

- 再發行：你可以將你修改過的程式，再度的自由發行，而不會與原先的撰寫者衝突；

- 回饋：你應該將你修改過的程式碼回饋於社群！

但請特別留意，你所修改的任何一個自由軟體都不應該也不能這樣：

- 修改授權：你不能將一個GPL授權的自由軟體，在你修改後而將他取消GPL授權∼

- 單純販賣：你不能單純的販賣自由軟體。

也就是說，既然GPL是站在互助互利的角度上去開發的，你自然不應該將大家的成果佔為己有， 對吧！因此你當然不可以將一個GPL軟體的授權取消，即使你已經對該軟體進行大幅度的修改！ 那麼自由軟體也不能販賣嗎？當然不是！還記得上一個小節裡面， 我們提到史托曼藉由販賣Emacs取得一些經費，讓自己生活不至於匱乏吧？是的！ 自由軟體是可以販售的，不過，不可僅販售該軟體，應同時搭配售後服務與相關手冊∼ 這些可就需要工本費了呢！

- 自由軟體與商業行為：

很多人還是有疑問，目前不是有很多Linux開發商嗎？為何他們可以販售Linux這個GPL授權的軟體？ 原因很簡單，因為他們大多都是販售『售後服務！』所以，他們所使用的自由軟體， 都可以在他們的網站上面下載！(當然，每個廠商他們自己開發的工具軟體就不是GPL的授權軟體了！) 但是，你可以購買他們的Linux光碟，如果你購買了光碟，他們會提供相關的手冊說明文件， 同時也會提供你數年不等的諮詢、售後服務、軟體升級與其他協力工作等等的附加價值！

所以說，目前自由軟體工作者，他們所賴以維生的，幾乎都是在『服務』這個領域呢！ 畢竟自由軟體並不是每個人都會撰寫，有人有需要你的自由軟體時，他就會請求你的協助， 此時，你就可以透過服務來收費了！這樣來說， 自由軟體確實還是具有商業空間的喔！

Tips:

很多人對於GPL授權一直很疑惑，對於GPL的商業行為更是無法接受！ 關於這一點，鳥哥在這裡還是要再次的申明，GPL是可以從事商業行為的！ 而很多的作者也是藉由這些商業行為來得以取得生活所需，更進一步去發展更優秀的自由軟體！ 千萬不要聽到『商業』就排斥！這對於發展優良軟體的朋友來說，是不禮貌的！

上面提到的大多是與使用者有關的項目，那麼 GPL 對於自由軟體的作者有何優點呢？大致的優點有這些：

- 軟體安全性較佳；

- 軟體執行效能較佳；

- 軟體除錯時間較短；

- 貢獻的原始碼永遠都存在。

這是因為既然是Open Source的自由軟體，那麼你的程式碼將會有很多人幫你查閱， 如此一來，程式的漏洞與程式的優化將會進展的很快！所以，在安全性與效能上面， 自由軟體一點都不輸給商業軟體喔！此外，因為GPL授權當中，修改者並不能修改授權， 因此，你如果曾經貢獻過程式碼，嘿嘿！你將名留青史呢！不錯吧！ ^_^

對於程式開發者來說，GPL實在是一個非常好的授權，因為大家可以互相學習對方的程式撰寫技巧， 而且自己寫的程式也有人可以幫忙除錯。那你會問啊，對於我們這些廣大的終端用戶，GPL有沒有什麼好處啊？有啊！當然有！ 雖然終端用戶或許不會自己編譯程式碼或者是幫人家除錯，但是終端用戶使用的軟體絕大部分就是GPL的軟體， 全世界有一大票的工程師在幫你維護你的系統，這難道不是一件非常棒的事嗎？ ^_^

Torvalds的Linux發展

我們前面一節當中，提到了Unix的歷史，也提到了Linux是由Torvalds這個芬蘭人所發明的。那麼為何托瓦茲可以發明Linux呢？ 憑空想像而來的？還是有什麼淵源？這裡我們就來談一談囉！

與Minix之間

Linus Torvalds(托瓦茲, 1969年出生)的外祖父是赫爾辛基大學的統計學家， 他的外祖父為了讓自己的小孫子能夠學點東西，所以從小就將托瓦茲帶到身邊來管理一些微電腦。 在這個時期，托瓦茲接觸了組合語言(Assembly Language)，那是一種直接與晶片對談的程式語言，也就是所謂的低階語言。 必須要很瞭解硬體的架構，否則很難以組合語言撰寫程式的。

在1988年間，托瓦茲順利的進入了赫爾辛基大學，並選讀了電腦科學系。在就學期間，因為學業的需要與自己的興趣， 托瓦茲接觸到了Unix這個作業系統。當時整個赫爾辛基只有一部最新的Unix系統，同時僅提供16個終端機(terminal)。 還記得我們上一節剛剛提過的，早期的電腦僅有主機具有運算功能，terminal僅負責提供Input/Output而已。在這種情況下， 實在很難滿足托瓦茲的需求，因為.....光是等待使用Unix的時間，就很耗時∼為此，他不禁想到： 『我何不自己搞一部Unix來玩？』不過，就如同Stallman當初的GNU計畫一樣，要寫核心程式，談何容易∼

不過，幸運之神並未背離托瓦茲，因為不久之後，他就知道有一個類似Unix的系統， 並且與Unix完全相容，還可以在Intel 386機器上面跑的作業系統， 那就是我們上一節提過的，譚寧邦教授為了教育需要而撰寫的Minix系統！ 他在購買了最新的Intel 386的個人電腦後，就立即安裝了Minix這個作業系統。 另外，上個小節當中也談到，Minix這個作業系統是有附上原始碼的， 所以托瓦茲也經由這個原始碼學習到了很多的核心程式設計的設計概念喔！

對386硬體的多工測試

事實上，托瓦茲對於個人電腦的CPU其實並不滿意，因為他之前碰的電腦都是工作站型的電腦， 這類電腦的CPU特色就是可以進行『多工處理』的能力。什麼是多工呢？理論上， 一個CPU在一個時間內僅能進行一個程式， 那如果有兩個以上的程式同時出現到系統中呢？舉例來說， 你可以在現今的電腦中同時開啟兩個以上的辦公軟體，例如電子試算表與文書處理軟體。 這個同時開啟的動作代表著這兩個程式同時要交給CPU來處理∼

啊！CPU一個時間點內僅能處理一個程式，那怎麼辦？沒關係，這個時候如果具有多工能力的CPU就會在不同的程式間切換∼ 還記得前一章談到的CPU時脈吧？假設CPU時脈為1GHz的話，那表示CPU一秒鐘可以進行10^9次工作。 假設CPU對每個程式都只進行1000次運作週期，然後就得要切換到下個程式的話，那麼CPU一秒鐘就能夠切換10^6次呢！ (當然啦，切換工作這件事情也會花去一些CPU時間，不過這裡暫不討論)。這麼快的處理速度下，你會發現， 兩個程式感覺上幾乎是同步在進行啦！

Tips:

為什麼有的時候我同時開兩個檔案(假設為A, B檔案)所花的時間， 要比開完A再去開B檔案的時間還要多？現在是否稍微可以理解？ 因為如果同時開啟的話，CPU就必須要在兩個工作之間不停的切換∼ 而切換的動作還是會耗去一些CPU時間的！所以囉，同時啟用兩個以上的工作在一個CPU上， 要比一個一個的執行還要耗時一點。這也是為何現在CPU開發商要整合兩個CPU於一個晶片中！ 也是為何在運作情況比較複雜的伺服器上，需要比較多的CPU負責的原因！

早期Intel x86架構電腦不是很受重視的原因，就是因為x86的晶片對於多工的處理不佳， CPU在不同的工作之間切換不是很順暢。但是這個情況在386電腦推出後，有很大的改善。 托瓦茲在得知新的386晶片的相關資訊後，他認為，以性能價格比的觀點來看， Intel的386相當的便宜，所以在性能上也就稍微可以將就將就 ^_^。最終他就貸款去買了一部Intel的386來玩。

早期的電腦效能沒有現在這麼好，所以壓榨電腦效能就成了工程師的一項癖好！ 托瓦茲本人早期是玩組合語言的，組合語言對於硬體有很密切的關係，托瓦茲自己也說：『我始終是個性能癖』^_^。 為了徹底發揮386的效能，於是托瓦茲花了不少時間在測試386機器上！ 他的重要測試就是在測試386的多功效能。首先，他寫了三個小程式，一個程式會持續輸出A、一個會持續輸出B， 最後一個會將兩個程式進行切換。他將三個程式同時執行，結果，他看到螢幕上很順利的一直出現ABABAB...... 他知道，他成功了！ ^_^

圖2.2.1、386電腦的多工測試

Tips:

要達到多工(multitasking)的環境，除了硬體(主要是CPU)需要能夠具有多工的特性外，作業系統也需要支援這個功能喔！ 一些不具有多工特性的作業系統，想要同時執行兩個程式是不可能的。除非先被執行的程式執行完畢，否則， 後面的程式不可能被主動執行。

至於多工的作業系統中，每個程式被執行時，都會有一個最大CPU使用時間，若該工作運作的時間超過這個CPU使用時間時， 該工作就會先被丟出CPU的運作中，而再度的進入核心工作排程中等待下一次被CPU取用來運作。

這有點像在開記者會啦，主持人(CPU)會問『誰要發問』？一群記者(工作程式) 就會舉手(看誰的工作重要！)，先舉手的自然就被允許發問，問完之後， 主持人又會問一次誰要發問，當然，所有人(包括剛剛那個記者)都可以舉手！ 如此一次一次的將工作給他完成啊！ ^_^ 多工的環境對於複雜的工作情況，幫助很大喔！

初次釋出Linux 0.02

探索完了386的硬體之後，終於拿到Minix並且安裝在托瓦茲的386電腦上之後，托瓦茲跟BBS上面一堆工程師一樣， 他發現Minix雖然真的很棒，但是譚寧邦教授就是不願意進行功能的加強，導致一堆工程師在作業系統功能上面的欲求不滿！ 這個時候年輕的托瓦茲就想：『既然如此，那我何不自己來改寫一個我想要的作業系統？』 於是他就開始了核心程式的撰寫了。

撰寫程式需要什麼呢？首先需要的是能夠進行工作的環境，再來則是可以將原始碼編譯成為可執行檔的編譯器。 好在有GNU計畫提供的bash工作環境軟體以及gcc編譯器等自由軟體， 讓托瓦茲得以順利的撰寫核心程式。他參考Minix的設計理念與書上的程式碼，然後仔細研究出386個人電腦的效能最佳化， 然後使用GNU的自由軟體將核心程式碼與386緊緊的結合在一起，最終寫出他所需要的核心程式。 而這個小玩意竟然真的可以在386上面順利的跑起來∼還可以讀取Minix的檔案系統。 真是太好了！不過還不夠，他希望這個程式可以獲得大家的一些修改建議， 於是他便將這個核心放置在網路上提供大家下載，同時在BBS上面貼了一則消息：

Hello everybody out there using minix-

I'm doing a (free) operation system (just a hobby,

won't be big and professional like gnu) for 386(486) AT clones.

I've currently ported bash (1.08) and gcc (1.40),

and things seem to work. This implies that i'll get

something practical within a few months, and I'd like to know

what features most people want. Any suggestions are welcome,

but I won't promise I'll implement them :-)

他說，他完成了一個小小的作業系統，這個核心是用在386機器上的， 同時，他真的僅是好玩，並不是想要做一個跟GNU一樣大的計畫！ 另外，他希望能夠得到更多人的建議與回饋來發展這個作業系統！這個概念跟Minix剛好背道而馳呢！ 這則新聞引起很多人的注意，他們也去托瓦茲提供的網站上下載了這個核心來安裝。 有趣的是，因為托瓦茲放置核心的那個FTP網站的目錄為：Linux， 從此，大家便稱這個核心為Linux了。(請注意，此時的Linux就是那個kernel喔！ 另外，托瓦茲所丟到該目錄下的第一個核心版本為0.02呢！)

同時，為了讓自己的Linux能夠相容於Unix系統，於是托瓦茲開始將一些能夠在Unix上面運作的軟體拿來在Linux上面跑。 不過，他發現到有很多的軟體無法在Linux這個核心上運作。這個時候他有兩種作法， 一種是修改軟體，讓該軟體可以在Linux上跑， 另一種則是修改Linux，讓Linux符合軟體能夠運作的規範！ 由於Linux希望能夠相容於Unix，於是托瓦茲選擇了第二個作法『修改Linux』！ 為了讓所有的軟體都可以在Linux上執行，於是托瓦茲開始參考標準的POSIX規範。

Tips:

POSIX是可攜式作業系統介面(Portable Operating System Interface)的縮寫，重點在規範核心與應用程式之間的介面， 這是由美國電器與電子工程師學會(IEEE)所發佈的一項標準喔！

這個正確的決定讓Linux在起步的時候體質就比別人優良∼因為POSIX標準主要是針對Unix與一些軟體運行時候的標準規範， 只要依據這些標準規範來設計的核心與軟體，理論上，就可以搭配在一起執行了。 而Linux的發展就是依據這個POSIX的標準規範，Unix上面的軟體也是遵循這個規範來設計的， 如此一來，讓Linux很容易就與Unix相容共享互有的軟體了！同時，因為Linux直接放置在網路下，提供大家下載， 所以在流通的速度上相當的快！導致Linux的使用率大增！這些都是造成Linux大受歡迎的幾個重要因素呢！

Linux 的發展：虛擬團隊的產生

Linux能夠成功除了托瓦茲個人的理念與力量之外，其實還有個最重要的團隊！

- 單一個人維護階段

Linux雖然是托瓦茲發明的，而且內容還絕不會涉及專利軟體的版權問題。 不過，如果單靠托瓦茲自己一個人的話，那麼Linux要茁壯實在很困難∼ 因為一個人的力量是很有限的。好在托瓦茲選擇Linux的開發方式相當的務實！ 首先，他將釋出的Linux核心放置在FTP上面，並請告知大家新的版本資訊， 等到使用者下載了這個核心並且安裝之後，如果發生問題， 或者是由於特殊需求亟需某些硬體的驅動程式，那麼這些使用者就會主動回報給托瓦茲。 在托瓦茲能夠解決的問題範圍內，他都能很快速的進行Linux核心的更新與除錯。

- 廣大駭客志工加入階段

不過，托瓦茲總是有些硬體無法取得的啊，那麼他當然無法幫助進行驅動程式的撰寫與相關軟體的改良。 這個時候，就會有些志工跳出來說：『這個硬體我有，我來幫忙寫相關的驅動程式。』 因為Linux的核心是Open Source的，駭客志工們很容易就能夠跟隨Linux的原本設計架構， 並且寫出相容的驅動程式或者軟體。志工們寫完的驅動程式與軟體托瓦茲是如何看待的呢？ 首先，他將該驅動程式/軟體帶入核心中，並且加以測試。 只要測試可以運行，並且沒有什麼主要的大問題，那麼他就會很樂意的將志工們寫的程式碼加入核心中！

總之，托瓦茲是個很務實的人，對於Linux核心所欠缺的項目，他總是『先求有且能跑， 再求進一步改良』的心態！這讓Linux使用者與志工得到相當大的鼓勵！ 因為Linux的進步太快了！使用者要求虛擬記憶體，結果不到一個星期推出的新版Linux就有了！ 這不得不讓人佩服啊！

另外，為因應這種隨時都有程式碼加入的狀況，於是Linux便逐漸發展成具有模組的功能！ 亦即是將某些功能獨立出於核心外，在需要的時候才載入到核心中。如此一來， 如果有新的硬體驅動程式或者其他協定的程式碼進來時，就可以模組化， 大大的增加了Linux核心的可維護能力！

Tips:

核心是一組程式，如果這組程式每次加入新的功能都得要重新編譯與改版的話會變成如何？ 想像一下，如果你只是換了顯示卡就得要重新安裝新的Windows作業系統，會不會傻眼？ 模組化之後，原本的核心程式不需要更動，你可以直接將他想成是『驅動程式』即可！ ^_^

- 核心功能細部分工發展階段

後來，因為Linux核心加入了太多的功能，光靠托瓦茲一個人進行核心的實際測試並加入核心原始程式實在太費力∼ 結果，就有很多的朋友跳出來幫忙這個前置作業！例如考克斯(Alan Cox)、與崔迪(Stephen Tweedie)等等， 這些重要的副手會先將來自志工們的修補程式或者新功能的程式碼進行測試， 並且結果上傳給托瓦茲看，讓托瓦茲作最後核心加入的原始碼的選擇與整併！ 這個分層負責的結果，讓Linux的發展更加的容易！

特別值得注意的是，這些托瓦茲的Linux發展副手，以及自願傳送修補程式的駭客志工， 其實都沒有見過面，而且彼此在地球的各個角落，大家群策群力的共同發展出現今的Linux， 我們稱這群人為虛擬團隊！而為了虛擬團隊資料的傳輸，於是Linux便成立的核心網站： http://www.kernel.org！

而這群素未謀面的虛擬團隊們，在1994年終於完成的Linux的核心正式版！version 1.0。 這一版同時還加入了X Window System的支援呢！更於1996年完成了2.0版。此外，托瓦茲指明了企鵝為Linux的吉祥物。

Tips:

奇怪的是，托瓦茲是因為小時候去動物園被企鵝咬了一口念念不忘， 而正式的2.0推出時，大家要他想一個吉祥物。他在想也想不到什麼動物的情況下， 就將這個念念不忘的企鵝當成了Linux的吉祥物了......

Linux由於托瓦茲是針對386寫的，跟386硬體的相關性很強，所以， 早期的Linux確實是不具有移植性的。不過，大家知道Open source的好處就是， 可以修改程式碼去適合作業的環境。因此，在1994年以後，Linux便被開發到很多的硬體上面去了！ 目前除了x86之外，IBM、HP、Sun等等公司出的硬體也都有被Linux所支援呢！

Linux的核心版本

Linux的核心版本編號有點類似如下的樣子：

2.6.18-92.el5

主版本.次版本.釋出版本-修改版本

如前所述，因為對於Linux核心的開發者太多了，以致於造成Linux核心經常性的變動。 但對於一般家用電腦或企業關鍵應用的話，常變動的核心並不適合的。因此托瓦茲便將核心的發展趨勢分為兩股， 並根據這兩股核心的發展分別給予不同的核心編號，那就是：

- 主、次版本為奇數：發展中版本(development)

如2.5.xx，這種核心版本主要用在測試與發展新功能，所以通常這種版本僅有核心開發工程師會使用。 如果有新增的核心程式碼，會加到這種版本當中，等到眾多工程師測試沒問題後，才加入下一版的穩定核心中；

- 主、次版本為偶數：穩定版本(stable)

如2.6.xx，等到核心功能發展成熟後會加到這類的版本中，主要用在一般家用電腦以及企業版本中。 重點在於提供使用者一個相對穩定的Linux作業環境平台。

至於釋出版本則是在主、次版本架構不變的情況下，新增的功能累積到一定的程度後所新釋出的核心版本。 而由於Linux核心是使用GPL的授權，因此大家都能夠進行核心程式碼的修改。因此，如果你有針對某個版本的核心修改過部分的程式碼， 那麼那個被修改過的新的核心版本就可以加上所謂的修改版本了。

Linux核心版本與distribution (下個小節會談到) 的版本並不相同，很多朋友常常上網問到：『我的Linux是9.x版，請問....』之類的留言， 這是不對的提問方式，因為所謂的Linux版本指的應該是核心版本， 而目前最新的核心版本應該是2.6.30(2009/08) 才對，並不會有9.x的版本出現的。

妳常用的Linux系統則應該說明為distribution才對！因此，如果以CentOS這個distribution來說， 妳應該說：『我用的Linux是CentOS這個 distribution，版本為5.x 版，請問....』才對喔！

Tips:

當妳有任何問題想要在Linux論壇發言時，請務必仔細的說明妳的distribution版本， 因為雖然各家distributions使用的都是Linux核心，不過每家distributions所選用的軟體以及他們自己發展的工具並不相同， 多少還是有點差異，所以留言時得要先聲明distribution的版本才行喔！ ^_^

Linux distributions

好了，經過上面的說明，我們知道了Linux其實就是一個作業系統最底層的核心及其提供的核心工具。 他是GNU GPL授權模式，所以，任何人均可取得原始碼與可執行這個核心程式，並且可以修改。 此外，因為Linux參考POSIX設計規範，於是相容於Unix作業系統，故亦可稱之為Unix Like的一種。

Tips:

鳥哥曾在上課的時候問過同學：『什麼是Unix Like啊』？可愛的同學們回答的答案是：『就是很喜歡(like)Unix啦！』 囧rz...那個like是『很像』啦！所以Unix like是『很像Unix的作業系統』哩！

- 可完整安裝的Linux發佈套件

Linux的出現讓GNU計畫放下了心裡的一塊大石頭，因為GNU一直以來就是缺乏了核心程式， 導致他們的GNU自由軟體只能在其他的Unix上面跑。既然目前有Linux出現了，且 Linux也用了很多的GNU相關軟體，所以Stallman認為Linux的全名應該稱之為GNU/Linux呢！ 不管怎麼說，Linux實在很不錯，讓GNU軟體大多以Linux為主要作業系統來進行開發， 此外，很多其他的自由軟體團隊，例如sendmail, wu-ftp, apache等等也都有以Linux 為開發測試平台的計畫出現！如此一來，Linux除了主要的核心程式外，可以在Linux 上面運行的軟體也越來越多，如果有心，就能夠將一個完整的Linux作業系統搞定了！

雖然由Torvalds負責開發的Linux僅具有Kernel與Kernel提供的工具， 不過，如上所述，很多的軟體已經可以在Linux上面運作了，因此， 『Linux + 各種軟體』就可以完成一個相當完整的作業系統了。 不過，要完成這樣的作業系統......還真難∼ 因為Linux早期都是由駭客工程師所開發維護的，他們並沒有考慮到一般使用者的能力......

為了讓使用者能夠接觸到Linux，於是很多的商業公司或非營利團體， 就將Linux Kernel(含tools)與可運行的軟體整合起來，加上自己具有創意的工具程式， 這個工具程式可以讓使用者以光碟/DVD或者透過網路直接安裝/管理Linux系統。 這個『Kernel + Softwares + Tools的可完整安裝』的咚咚，我們稱之為Linux distribution， 一般中文翻譯成可完整安裝套件，或者Linux發佈商套件等。

圖2.5.1、Linux可完整安裝發佈套件

Tips:

由於Linux核心是由駭客工程師寫的，要由原始碼安裝到x86電腦上面成為可以執行的binary檔案， 這個過程可不是人人都會的∼所以早期確實只有工程師對Linux有興趣。 一直到一些社群與商業公司將Linux核心配合自由軟體，並提供完整的安裝程序， 且製成光碟/DVD後，對於一般使用者來說，Linux才越來越具有吸引力！ 因為只要一直『下一步』就可以將Linux安裝完成啊！ ^_^

由於GNU的GPL授權並非不能從事商業行為，於是很多商業公司便成立來販售Linux distribution。 而由於Linux的GPL版權宣告，因此，商業公司所販售的Linux distributions通常也都可以從Internet上面來下載的！ 此外，如果你想要其他商業公司的服務，那麼直接向該公司購買光碟來安裝，也是一個很不錯的方式的！

- 各大Linux Distributions的主要異同：支援標準！

不過，由於發展Linux distributions的社群與公司實在太多了，例如在台灣有名的Red Hat, SuSE, Ubuntu, Fedora, Debian等等，所以很多人都很擔心，如此一來每個distribution是否都不相同呢？ 這就不需要擔心了，因為每個Linux distributions使用的kernel都是http://www.kernel.org所釋出的，而他們所選擇的軟體，幾乎都是目前很知名的軟體，重複性相當的高， 例如網頁伺服器的Apache，電子郵件伺服器的Postfix/sendmail，檔案伺服器的Samba等等。

此外，為了讓所有的Linux distributions開發不致於差異太大，且讓這些開發商在開發的時候有所依據，還有Linux Standard Base (LSB)等標準來規範開發者，以及目錄架構的File system Hierarchy Standard (FHS)標準規範！ 唯一差別的，可能就是該開發者自家所開發出來的管理工具，以及套件管理的模式吧！ 所以說，基本上，每個Linux distributions除了架構的嚴謹度與選擇的套件內容外， 其實差異並不太大啦！ ^_^ 。大家可以選擇自己喜好的distribution來安裝即可！

- FHS: http://www.pathname.com/fhs/

- LSB: http://www.linuxbase.org/

Tips:

事實上鳥哥認為distributions主要分為兩大系統，一種是使用RPM方式安裝軟體的系統，包括Red Hat, Fedora, SuSE等都是這類； 一種則是使用Debian的dpkg方式安裝軟體的系統，包括Debian, Ubuntu, B2D等等。

底下列出幾個主要的Linux distributions發行者網址：

- Red Hat: http://www.redhat.com

- Fedora: http://fedoraproject.org/

- Mandriva: http://www.mandriva.com

- Novell SuSE: http://www.novell.com/linux/

- Debian: http://www.debian.org/

- Slackware: http://www.slackware.com/

- Gentoo: http://www.gentoo.org/

- Ubuntu: http://www.ubuntu.com/

- CentOS: http://www.centos.org/

Tips:

到底是要買商業版還是社群版的Linux distribution呢？如果是要裝在個人電腦上面做為桌上型電腦用的，建議使用社群版， 包括Fedora, Ubuntu, OpenSuSE等等。如果是用在伺服器上面的，建議使用商業版本，包括Red Hat, SuSE等。 這是因為社群版通常開發者會加入最新的軟體，這些軟體可能會有一些bug存在。至於商業版則是經過一段時間的磨合後， 才將穩定的軟體放進去。

舉例來說，Fedora兜出來的軟體套件經過一段時間的維護後，等到該軟體穩定到不容易發生錯誤後， Red Hat才將該軟體放到他們最新的釋出版本中。所以，Fedora的軟體比較經常改版，Red Hat的軟體就較少更版。

- Linux在台灣

當然發行套件者不僅於此。但是值得大書特書的，是中文Linux的延伸計畫：CLE這個套件！ 早期的Linux因為是工程師發展的，而這些工程師大多以英文語系的國家為主， 所以Linux對於國人的學習是比較困擾一點。後來由國人發起的CLE計畫： http://cle.linux.org.tw/ 開發很多的中文套件及翻譯了很多的英文文件，使得我們目前得以使用中文的Linux呢！ 另外，目前正在開發中的還有台南縣臥龍小三等老師們發起的眾多自由軟體計畫， 真是造福很多的朋友啊！

- 自由軟體技術交流網： http://freesf.tw/

- B2D: http://b2d-linux.com/

此外，如果只想看看Linux的話，還可以選擇所謂的可光碟開機進入Linux的Live CD版本， 亦即是KNOPPIX這個Linux distributions呢！台灣也有阿里巴巴兄維護的中文Live CD喔！

- http://www.knoppix.net/

- 洪老師解釋 KNOPPIX: http://people.ofset.org/~ckhung/b/sa/knoppix.php

Tips:

對於沒有額外的硬碟或者是沒有額外的主機的朋友來說，KNOPPIX這個可以利用光碟開機而進入Linux作業系統的Live CD 真的是一個不錯的選擇！你只要下載了KNOPPIX的映象檔，然後將他燒錄成為CD， 放入你主機的光碟機，並在BIOS內設定光碟為第一個開機選項，就可以使用Linux系統了呢！

如果你還想要知道更多的Linux distributions的下載與使用資訊，可以參考：

- http://distrowatch.com/

- 選擇適合你的Linux distribution

那我到底應該要選擇哪一個distributions？就如同我們上面提到的，其實每個distributions差異性並不大！ 不過，由於套件管理的方式主要分為Debian的dpkg及Red Hat系統的RPM方式， 目前鳥哥的建議是，先學習以RPM套件管理為主的RHEL/Fedora/SuSE/CentOS等台灣使用者較多的版本， 這樣一來，發生問題時，可以提供解決的管道比較多。如果你已經接觸過Linux了， 還想要探討更嚴謹的Linux版本，那可以考慮使用Debian，如果你是以效能至上來考量， 那麼或許Gentoo是不錯的建議！

總之，版本很多，但是各版本差異其實不大，建議你一定要先選定一個版本後， 先徹頭徹尾的瞭解他，那再繼續玩其他的版本時，就可以很快的進入狀況。 鳥哥的網站僅提供一個版本，不過是以比較基礎的方式來介紹的， 因此，如果能夠熟練俺這個網站的話，呵呵！哪一個distributions對你來說，都不成問題啦！

不過，如果依據電腦主機的用途來分的話，在台灣鳥哥會這樣建議：

- 用於企業環境：建議使用商業版本，例如Red Hat的RHEL或者是Novell的SuSE都是很不錯的選擇！ 畢竟企業的環境強調的是永續的經營，你可不希望網管人員走了之後整個機房的主機都沒有人管理吧！ 由於商業版本都會提供客戶服務，所以可以降低企業的風險喔！

- 用於個人或教學的伺服器環境：要是你的伺服器所在環境如果當機還不會造成太大的問題的話， 加上你的環境是在教學的場合當中時(就是說，唔！經費不足的環境啦！)那麼可以使用『號稱』完全相容商業版RHEL的CentOS。 因為CentOS是抓RHEL的原始碼來重新兜起來的一個Linux distribution，所以號稱相容於RHEL。 這一版的軟體完全與RHEL相同，在改版的幅度較小，適合於伺服器系統的環境；

- 用於個人的桌上型電腦：想要嘗鮮嗎？建議使用很炫的Fedora/Ubuntu等Desktop(桌面環境)使用的版本！ 如果不想要安裝Linux的話，那麼Fedora或CentOS也有推出Live CD了！也很容易學習喔！

Linux的特色

Linux是Torvalds先生所開發出來的，基於GPL的版權宣告之下，可以在x86的架構下運作，也可以被移植到其他的大型主機上面。 由於開發的相關理念與相容的問題，因此，我們也可以稱Linux為Unix Like作業系統的一種。

Tips:

其實Unix-Like可以說是目前伺服器類型的作業系統的統稱啦！ 因為，不論是FreeBSD, BSD, Sun Unix, HP Unix, Red Hat Linux, Mandrake Linux等等，都是由同一個祖先Thompson所寫的『Unix』來的， 因此，這些咚咚都被統稱為Unix-Like的作業系統囉！

Linux的特色

那麼這個系統有什麼特異功能呢？簡單的說：

- 自由與開放的使用與學習環境：

由於Linux是基於GPL的授權之下，因此他是自由軟體， 也就是任何人都可以自由的使用或者是修改其中的原始碼的意思！ 這種開放性架構對科學界來說是相當重要的！ 因為很多的工程師由於特殊的需求，常常需要修改系統的原始碼， 使該系統可以符合自己的需求！而這個開放性的架構將可以滿足各不同需求的工程師！ 因此當然就有可能越來越流行囉！以鳥哥來說，目前環境工程界的空氣品質模式最新版 Models-3/CMAQ 就是以Linux為基準平台設計的呢！

- 配備需求低廉：

Linux可以支援個人電腦的x86架構，系統資源不必像早先的Unix系統那般，僅適合於單一公司所出產的設備！ 單就這一點來看，就可以造成很大的流行囉！不過，如果你想要在Linux下執行X Window系統， 那麼硬體的等級就不能太低了！

- 核心功能強大而穩定：

而且由於Linux功能並不會輸給一些大型的Unix工作站，因此，近年來越來越多的公司或者是團體、 個人投入這一個作業系統的開發與整合工作！例如IBM與昇陽公司都有推出x86的Linux伺服器呢！

- 獨立作業：

另外，由於很多的軟體套件逐漸被這套作業系統拿來使用，而很多套件軟體也都在 Linux這個作業系統上面進行發展與測試，因此，Linux近來已經可以獨力完成幾乎所有的工作站或伺服器的服務了，例如 Web, Mail, Proxy, FTP.....。

目前Linux已經是相當成熟的一套作業系統囉！而且不耗資源又可以自由取得！呵呵， 可以說造成微軟相當大的壓力呀！此外，由於他的系統硬體要求很低， 加上目前很多的人由於『Intel 的陰謀』而造成手邊有相當多的淘汰掉的硬體配備， Linux在這些被淘汰的硬體中就可以執行的相當的順暢與穩定！因此也造成相當多朋友的關注囉！

Tips:

呵呵！開玩笑的，因為Tom的硬體評論 (http://www.big5.tomshardware.com/) 網站常常這樣取笑Intel的說！呵！很好笑！

這也是造成Linux成為最近幾年來最受矚目的作業系統之一，如前所述， 他會受到矚目的原因主要是因為他是『free』的，就是可以自由取得的作業系統啦！ 然後他是開放性的系統，也就是你可以隨時的取得程式的原始碼，這對於程式開發工程師是很重要的！ 而且，雖然他是Free的自由軟體，不過功能卻很強大！另外， Linux對於硬體的需求是很低的，這一點更造成它流行的主因，因為硬體的汰換率太快了， 所以很多人手邊都有一些很少在用的零件，這些零件組一組就可以用來跑Linux了， 反正做一個工作站又不用使用到螢幕(只要主機就可以囉)，因此Linux就越來越流行囉！

Tips:

也就是因為Linux具有 1.硬體需求低、 2.架構開放、 3.系統穩定性及保密性功能夠強、 4.完全免費，所以造成一些所謂『反微軟聯盟』的程式設計高手不斷的開發新軟體！以與Microsoft進行抗衡！

Linux的優缺點

那幹嘛要使用Linux做為我們的主機系統呢？這是因為Linux有底下這些優點：

- 穩定的系統：

Linux本來就是基於Unix概念而發展出來的作業系統，因此，Linux具有與Unix系統相似的程式介面跟操作方式， 當然也繼承了Unix穩定並且有效率的特點。常聽到安裝Linux的主機連續運做一年以上而不曾當機、 不必關機是稀鬆平常的事；

- 免費或少許費用：

由於Linux是基於GPL授權下的產物，因此任何人皆可以自由取得Linux， 至於一些『安裝套件』的發行者， 他們發行的安裝光碟也僅需要些許費用即可獲得！不同於Unix需要負擔龐大的版權費用，當然也不同於微軟需要一而再、 再而三的更新你的系統，並且繳納大量費用囉！

- 安全性、漏洞的快速修補：

如果你常玩網路的話，那麼你最常聽到的應該是『沒有絕對安全的主機』！ 沒錯！不過Linux由於支援者日眾，有相當多的熱心團體、個人參與其中的開發， 因此可以隨時獲得最新的安全資訊，並給予隨時的更新，亦即是具有相對的較安全！

- 多工、多使用者：

與Windows系統不同的，Linux主機上可以同時允許多人上線來工作， 並且資源的分配較為公平，比起Windows的單人多工系統要穩定的多囉！ 這個多人多工可是Unix-Like上面相當好的一個功能，怎麼說呢？你可以在一部 Linux主機上面規劃出不同等級的使用者，而且每個使用者登入系統時的工作環境都可以不相同， 此外，還可以允許不同的使用者在同一個時間登入主機，同時使用主機的資源。

- 使用者與群組的規劃：

在Linux的機器中，檔案的屬性可以分為『可讀、可寫、可執行』 等參數來定義一個檔案的適用性，此外，這些屬性還可以分為三個種類， 分別是『檔案擁有者、檔案所屬群組、其他非擁有者與群組者』。 這對於專案計畫或者其他計畫開發者具有相當良好的系統保密性。

- 相對比較不耗資源的系統：

Linux只要一部P-III以上等級的電腦就可以安裝並且使用愉快囉！還不需要到P-4或AMD K8 等級的電腦呢！不過，如果你要架設的是屬於大型的主機（服務上百人以上的主機系統）， 那麼就需要比較好一點的機器了。不過，目前市面上任何一款個人電腦均可以達到這一個要求囉！

- 適合需要小核心程式的嵌入式系統：

由於Linux只要幾百K不到的程式碼就可以完整的驅動整個電腦硬體並成為一個完整的作業系統， 因此相當適合於目前家電或者是小電子用品的作業系統呢！那就是當紅炸子雞『嵌入式』系統啦！ Linux真的是很適合例如手機、數位相機、PDA、家電用品等等的微電腦作業系統呢！ ^_^

- 整合度佳且多樣的圖形使用者介面(GUI)：

自從1994年Linux 1.0後就加入的X Window系統，在眾多駭客的努力之下終於與Linux有高度整合， 且主要的繪圖卡公司(Intel, NVidia, ATI等)都有針對Linux推出最新的驅動程式， 因此Linux的GUI已經有長足的進步了！另外，Linux環境下的圖形介面不只有一種呢！ 包括大家耳熟能詳的KDE(http://www.kde.org/)以及GNOME(http://www.gnome.org)都是很常見的！

反正Linux好處說不完啦！不過雖然Linux具有這樣多的好處，但是他先天上有一個足以致命的地方， 使他的普及率受到很大的限制，就是Linux需要使用『指令列』的終端機模式進行系統的管理！ 雖然近年來有很多的圖形介面開發使用在Linux上面，但畢竟要熟悉Linux還是以指令列來使用是比較好的， 因此要接受Linux的玩家必須比較要能熟悉對電腦下指令的行為，而不是用滑鼠點一點icon就行了！ Linux 還可以改進的地方：

- 沒有特定的支援廠商：

因為在Linux上面的所有套件幾乎都是自由軟體，而每個自由軟體的開發者可能並不是公司團體， 而是非營利性質的團體。如此一來，在你Linux主機上面的軟體若發生問題，該如何是好？ 好在由於目前Linux商業界的整合還不錯，目前在台灣比較具名的Red Hat與SuSE 均有設立了服務點。你可以經由這個服務點來直接向他們購買/諮詢相關的軟硬體問題呢！ 不過，如果你並非選擇有專門商業公司的Linux distributions時？怎麼辦？ 沒有專人到府服務呢∼這點倒是還不需要太擔心， 因為拜網路風行之賜，你要問的問題幾乎在網路上都可以找到答案喔！看你有沒有用心去找就是了！

- 遊戲的支援度不足：

在現代這個時候，敢說你們家的桌上型電腦裡面完全沒有遊戲的小朋友應該不多了！ 遊戲軟體也是個應用程式，所以它與作業系統的關係就相當密切了。 可惜的是目前很多遊戲開發商並沒有在Linux平台上面開發大型遊戲，這間接導致Linux無法進入一般家庭說。

- 專業軟體的支援度不足：

這是鳥哥到學校教書後才發現的一件事，目前很多專業繪圖軟體公司所推出的專業軟體並不支援Linux作業系統， 這讓同學很難在不同的平台上面操作相同的軟體！唉！很傷腦筋∼

- 教育訓練作的還不夠好：

如果能夠在國小就教導小朋友使用自由軟體，那麼長大自然就會使用自由軟體了！ 在台灣目前政策方面還是相當的搖擺不定，希望未來能夠給自由軟體一些機會。

老實說，這些缺點絕大部分都不是Linux本身的問題，倒是一些政策面與商業方面的考量，才是最大的困擾。 不過，Linux與其他的作業系統一樣，就是一個工具而已！希望大家能夠在快樂中學習到Linux的精髓啦！^_^

關於授權

現在市面上有好多的軟體，有的是自由軟體，有的是專利軟體。有的專利軟體免費，有的自由軟體要錢∼ 啊！好煩啊！怎麼分辨這些東西？其實，鳥哥並不是律師，對於法律也不十分懂，不過， 還是有幾個授權模式可以來談一談∼

- Open Source (開放源碼)

軟體以Open Source的方式釋出時，表示除了可執行的軟體本身外，一定伴隨著原始碼的釋出喔！通常Open Source的軟體有幾個好處：

1. 程式設計師通常會等到程式成熟之後才會釋出(免得被笑, ^_^)，所以通常程式在雛形的時候，就已經具有相當的優良體質；

2. Open Source的精神，相信當程式原設計人將程式原始碼釋出之後，其他的程式設計師接受這份原始碼之後， 由於需要將程式改成自己所需的樣式，所以會經由本身的所學來加以改良，並從中加以改良與除蟲， 所以程式的debug功能會比傳統的close source來的快！

3. 由於程式是伴隨原始碼的，因此，系統將會不易存在鮮為人知的木馬程式或一些安全漏洞， 相對而言，會比較更加的安全！

Open source的代表授權為GNU的GPL授權及BSD等等，底下列出知名的Open Source授權網頁：

- GNU General Public License：

http://www.gnu.org/licenses/licenses.html#GPL

目前有version 2, version 3兩種版本，Linux使用的是version 2這一版。 鳥哥也有收集一份GPL version 2 的中文化條文，您可以參考：appendix_A.htm

- Berkeley Software Distribution (BSD)：

http://en.wikipedia.org/wiki/BSD_license

使用BSD source code最常接觸到的就是BSD授權模式了！這個授權模式其實與GPL很類似， 而其精神也與Open Source相呼應呢！

- Apache License, Version 2.0：

http://www.apache.org/licenses/LICENSE-2.0

Apache是一種網頁伺服器軟體，這個軟體的發佈方式也是使用Open source的。只是在apache的授權中規定， 如果想要重新發佈此軟體時(如果你有修改過該軟體)，軟體的名稱依舊需要定名為Apache才行！

- Close Source

相對於Open Source的軟體會釋出原始碼，Close source的程式則僅推出可執行的二進位程式(binary program)而已。 這種軟體的優點是有專人維護，你不需要去更動他；缺點則是靈活度大打折扣，使用者無法變更該程式成為自己想要的樣式！ 此外，若有木馬程式或者安全漏洞，將會花上相當長的一段時間來除錯！這也是所謂專利軟體(copyright)常見的軟體出售方式。

雖然專利軟體常常代表就是需要花錢去購買，不過有些專利軟體還是可以免費提供大眾使用的！ 免費的專利軟體代表的授權模式有：

- Freeware：

http://en.wikipedia.org/wiki/Freeware

不同於Free software，Freeware為『免費軟體』而非『自由軟體！』雖然它是免費的軟體，但是不見得要公布其原始碼， 端看釋出者的意見囉！這個東西與Open Source畢竟是不太相同的東西喔！此外，目前很多標榜免費軟體的程式很多都有小問題！ 例如假藉免費軟體的名義，實施使用者資料竊取的目的！ 所以『來路不明的軟體請勿安裝！』

- Shareware：

http://en.wikipedia.org/wiki/Shareware

共享軟體這個名詞就有趣了！與免費軟體有點類似的是，Shareware在使用初期，它也是免費的，但是， 到了所謂的『試用期限』之後，你就必須要選擇『付費後繼續使用』或者『將它移除』的宿命∼ 通常，這些共享軟體都會自行撰寫失效程式，讓你在試用期限之後就無法使用該軟體。

重點回顧

- 電腦主要以二進位作為單位，而目前常用的磁碟容量單位為bytes，其單位換算為1Byte = 8bits， 其他的以1024為其倍數，如 1GByte=1024MBytes等等。

- 作業系統(Operation System)主要在管理與驅動硬體，因此必須要能夠管理記憶體、管理裝置、 負責行程管理以及系統呼叫等等。因此，只要能夠讓硬體準備妥當(Ready)的情況， 就是一個陽春的作業系統了。

- 最陽春的作業系統僅在驅動與管理硬體，而要使用硬體時，就得需要透過應用軟體或者是殼程式(shell) 的功能，來呼叫作業系統操縱硬體工作。因此，目前稱為作業系統的， 除了上述功能外，通常已經包含了日常工作所需要的應用軟體在內了。

- Unix的前身是由貝爾實驗室(Bell lab.)的Ken Thompson利用組合語言寫成的， 後來在1971-1973年間由Dennis Ritchie以C程式語言進行改寫，才稱為Unix。

- 1977年由Bill Joy釋出BSD (Berkeley Software Distribution)，這些稱為Unix-like的作業系統。

- 1984年由Andrew Tanenbaum製作出Minix作業系統，該系統可以提供原始碼以及軟體；

- 1984年由Richard Stallman提倡GNU計畫，倡導自由軟體(Free software)， 強調其軟體可以『自由的取得、複製、修改與再發行』，並規範出GPL授權模式， 任何GPL(General Public License)軟體均不可單純僅販賣其軟體，也不可修改軟體授權。

- 1991年由芬蘭人Linus Torvalds開發出Linux作業系統。簡而言之，Linux成功的地方主要在於： Minix(Unix), GNU, Internet, POSIX 及虛擬團隊的產生。

- Linux本身就是個最陽春的作業系統，其開發網站設立在http://www.kernel.org，我們亦稱Linux作業系統最底層的資料為『核心(Kernel)』。

- 目前Linux核心的發展分為兩種版本，分別是穩定版本的偶數版，如2.6.X，適合於商業與家用環境使用； 一種是發展中版本的奇數版如2.5.X 版，適合開發特殊功能的環境。

- Linux distributions的組成含有：『Linux Kernel + Free Software + Documentations(Tools) + 可完整安裝的程序』所製成的一套完整的系統。

本章習題

(要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看)

實作題部分：

- 請依據本章內容的說明，下載 Fedora 最新版本的 Live CD ，並將該 Live CD 燒錄成為光碟 (或 DVD) 後， 調整你的主機 BIOS 成為使用光碟機開機，在開機時放入剛剛燒錄的 Live CD ，使用該光碟機開機。在開機後你應該能夠進入系統。 請進入該系統，嘗試打開終端機、瀏覽器等，並嘗試操作一下該系統。由於該系統並不會影響到你的硬碟資料， 請儘量玩玩！

- 承上題，打開終端機並且輸入『 uname -r 』這個指令，出現的核心版本為何？是穩定還是發展中版本？

- 請上網找出目前 Linux 核心的最新穩定版與發展中版本的版本號碼，請註明查詢的日期與版本的對應。

- 請上網找出 Linux 的吉祥物企鵝的名字，以及最原始的圖檔畫面。(提示：請前往 http://www.linux.org 查閱)

簡答題部分：

- 你在你的主機上面安裝了一張網路卡，但是開機之後，系統卻無法使用，你確定網路卡是好的，那麼可能的問題出在哪裡？該如何解決？

因為所有的硬體都沒有問題，所以，可能出問題的地方在於系統的核心(kernel) 不支援這張網路卡。解決的方法，(1)到網路卡的開發商網站，(2)下載支援你主機作業系統的驅動程式， (3)安裝網路卡驅動程式後，就可以使用了。

- 我在一部主機上面安裝Windows作業系統時，並且安裝了顯示卡的驅動程式，他是沒有問題的。但是安裝Linux時，卻無法完整的顯示整個X Window。請問，我可不可以將Windows上面的顯示卡驅動程式拿來安裝在Linux上？

不行！因為核心不同，針對硬體所寫的驅動程式也會不相同，編譯器也不同，當然，驅動程式也無法在兩個作業系統間相容。 這也是為何開發商在他們的網站上面，都會同時提供許多不同作業系統的驅動程式之故。

- 一個作業系統至少要能夠完整的控制整個硬體，請問，作業系統應該要控制硬體的哪些單元？

根據硬體的運作，以及資料在主機上面的運算情況與寫入/讀取情況，我們知道至少要能夠控制： (1)input/output control, (2)device control, (3)process management, (4)file management. 等等！

- 一個GBytes的硬碟空間，等於幾個KBytes？

1GBytes = 1024 MBytes * 1024 KBytes/MBytes = 1048576 KBytes

- 我在Windows上面玩的遊戲，可不可以拿到Linux去玩？

當然不行！因為遊戲也是一個應用程式 (application)，他必須要使用到核心所提供的工具來開發他的遊戲， 所以這個遊戲是不可在不同的平台間運作的。除非這個遊戲已經進行了移植。

- Linux本身僅是一個核心與相關的核心工具而已，不過，他已經可以驅動所有的硬體， 所以，可以算是一個很陽春的作業系統了。經過其他應用程式的開發之後，被整合成為Linux distribitions。請問眾多的distributions之間，有何異同？

相同：(1)同樣使用 http://www.kernel.org 所釋出的核心； (2)支援同樣的標準，如 FHS、LSB 等； (3)使用幾乎相同的自由軟體 (例如 GNU 裡面的 gcc/glibc/vi/apache/bind/sendmail... )； (4)幾乎相同的操作介面 (例如均使用 bash/KDE/GNOME 等等)。

不同：使用的 kernel 與各軟體的版本可能會不同；各開發商加入的應用工具不同，使用的套件管理模式不同(dpkg 與 RPM)

- Unix 是誰寫出來的？ GNU 計畫是誰發起的？

Unix 是 Ken Thompson 寫的，1973 年再由 Dennis Ritchie 以 C 語言改寫成功。 至於 GNU 與 FSF 則是 Richard Stallman 發起的。

- GNU 的全名為何？他主要由那個基金會支持？

GNU 是 GNU is Not Unix 的簡寫，是個無窮迴圈！ 另外，這個計畫是由自由軟體基金會 (Free Software Foundation, FSF) 所支持的！ 兩者都是由 Stallman 先生所發起的！

- 何謂多人 ( Multi-user ) 多工 ( Multitask )？

Multiuser 指的是 Linux 允許多人同時連上主機之外，每個使用者皆有其各人的使用環境，並且可以同時使用系統的資源！

Multitask 指的是多工環境，在 Linux 系統下， CPU 與其他例如網路資源可以同時進行多項工作， Linux 最大的特色之一即在於其多工時，資源分配較為平均！

- 簡單說明 GNU General Public License ( GPL ) 與 Open Source 的精神：

1. GPL 的授權之軟體，乃為自由軟體（Free software），任何人皆可擁有他； 2. 開發 GPL 的團體(或商業企業)可以經由該軟體的服務來取得服務的費用； 3. 經過 GPL 授權的軟體，其屬於 Open source 的情況，所以應該公布其原始碼； 4. 任何人皆可修改經由 GPL 授權過的軟體，使符合自己的需求； 5. 經過修改過後 Open source 應該回饋給 Linux 社群。

- 什麼是 POSIX ?為何說 Linux 使用 POSIX 對於發展有很好的影響？

POSIX 是一種標準規範，主要針對在 Unix 作業系統上面跑的程式來進行規範。 若你的作業系統符合 POSIX ，則符合 POSIX 的程式就可以在你的作業系統上面運作。 Linux 由於支援 POSIX ，因此很多 Unix 上的程式可以直接在 Linux 上運作， 因此程式的移植相當簡易！也讓大家容易轉換平台，提升 Linux 的使用率。

- Linux 的發展主要分為哪兩種核心版本？

主要分為奇數的發展中版本(develop)，如 2.5 ，及偶數的穩定版本，如 2.6 。

- 簡單說明 Linux 成功的因素？

1. 藉由 Minix 作業系統開發的 Unix like ，沒有版權的糾紛；

2. 藉助於 GNU 計畫所提供的各項工具軟體， gcc/bash 等；

3. 藉由 Internet 廣為流傳；

4. 藉由支持 POSIX 標準，讓核心能夠適合所有軟體的開發；

5. 托瓦茲強調務實，虛擬團隊的自然形成！

參考資料與延伸閱讀

- Multics計畫網站：http://www.multicians.org/。

- 葛林穆迪著，杜默譯，『Linux傳奇』，時報文化出版企業。

書本介紹：http://findbook.tw/book/9789571333632/basic

- 網路農夫，2001，Unix簡史：

http://netlab.cse.yzu.edu.tw/~statue/freebsd/docs/csh/

- Ken Thompson的個人網站：http://plan9.bell-labs.com/cm/cs/who/ken/index.html

- Dennis Ritchie的個人網站： http://cm.bell-labs.com/cm/cs/who/dmr/

- Richard Stallman的個人網站： http://www.stallman.org/

- GNU計畫： http://www.gnu.org

- XFree86的網站：http://www.xfree86.org/

- 洪朝貴老師的GNU/FSF介紹： http://people.ofset.org/~ckhung/a/c_83.php

- 維基百科對Linus Torvalds的介紹：http://en.wikipedia.org/wiki/Linus_Torvalds。

- POSIX的相關說明：

維基百科：http://en.wikipedia.org/wiki/POSIX

IEEE POSIX標準：http://standards.ieee.org/regauth/posix/

2002/06/25：第一次完成

2003/01/26：重新修訂，加入一些歷史事件、重新編排與加入 FAQ

2003/02/28：加入百資以及 distrowatch 兩個網站的推薦！

2005/05/31：舊有的資料放於 此處

2005/06/02：做了大幅度的改版，很多資料參考了網路農夫及 Linux 傳奇等書籍，建議大家要多看看網路農夫的大作喔！

2005/06/08：將原本的 binary / compiler / Emacs 的地方再說明一下！比較容易瞭解那是什麼！順便加入習題

2005/07/21：網路農夫的網站結束了∼真傷心∼只好提供網路農夫之前發表的文章連結了！

2005/08/03：感謝網友 babab 的來信告知，修訂了國家高速網路中心網址：http://www.nchc.org.tw

2005/10/24：經由網友的回報，洪朝貴老師已經調職到樹德大學，因此整個連結內容已作修訂。

2006/05/31：加入了重點回顧的項目啦！

2006/06/06：感謝網友 "Warren Hsieh" 兄的提醒，由於麥金塔在 2006 年後使用 Intel 的 x86 硬體架構，故 Windows 是可能可以在上面安裝的！

2008/07/23：因為加入了計算機概論的章節，所以本文做了挺大幅度的修改！原本針對FC4的版本請點選這裡。

2007/07/26：將整份文章重新校閱過，修訂一些文辭，也將格式調整為適合的XHTML了！

2007/07/29：將主、次核心版本加強說明！

2009/08/05：移除最後一小節的標準，將FHS與LSB向前挪到distribution解釋中。拿掉伺服器、工作站、終端機的說明。

2012/02/20：更新了 Linux 在台灣的相關連結資訊

2002/02/03以來統計人數

- 掛載Ext2/Ext3檔案系統

範例一：用預設的方式，將剛剛建立的 /dev/hdc6 掛載到 /mnt/hdc6 上面！

[root@www ~]# mkdir /mnt/hdc6

[root@www ~]# mount /dev/hdc6 /mnt/hdc6

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

.....中間省略.....

/dev/hdc6              1976312     42072   1833836   3% /mnt/hdc6

# 看起來，真的有掛載！且檔案大小約為 2GB 左右啦！

瞎密？竟然這麼簡單！利用『mount 裝置檔名 掛載點』就能夠順利的掛載了！真是方便啊！ 為什麼可以這麼方便呢(甚至不需要使用 -t 這個選項)？由於檔案系統幾乎都有 superblock ， 我們的 Linux 可以透過分析 superblock 搭配 Linux 自己的驅動程式去測試掛載， 如果成功的套和了，就立刻自動的使用該類型的檔案系統掛載起來啊！ 那麼系統有沒有指定哪些類型的 filesystem 才需要進行上述的掛載測試呢？ 主要是參考底下這兩個檔案：

- /etc/filesystems：系統指定的測試掛載檔案系統類型；

- /proc/filesystems：Linux系統已經載入的檔案系統類型。

那我怎麼知道我的 Linux 有沒有相關檔案系統類型的驅動程式呢？我們 Linux 支援的檔案系統之驅動程式都寫在如下的目錄中：

- /lib/modules/$(uname -r)/kernel/fs/

例如 vfat 的驅動程式就寫在『/lib/modules/$(uname -r)/kernel/fs/vfat/』這個目錄下啦！ 簡單的測試掛載後，接下來讓我們檢查看看目前已掛載的檔案系統狀況吧！

範例二：觀察目前『已掛載』的檔案系統，包含各檔案系統的Label名稱

[root@www ~]# mount -l

/dev/hdc2 on / type ext3 (rw) [/1]

proc on /proc type proc (rw)

sysfs on /sys type sysfs (rw)

devpts on /dev/pts type devpts (rw,gid=5,mode=620)

/dev/hdc3 on /home type ext3 (rw) [/home]

/dev/hdc1 on /boot type ext3 (rw) [/boot]

tmpfs on /dev/shm type tmpfs (rw)

none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)

sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)

/dev/hdc6 on /mnt/hdc6 type ext3 (rw) [vbird_logical]

# 除了實際的檔案系統外，很多特殊的檔案系統(proc/sysfs...)也會被顯示出來！

# 值得注意的是，加上 -l 選項可以列出如上特殊字體的標頭(label)喔

這個指令輸出的結果可以讓我們看到非常多資訊，以 /dev/hdc2 這個裝置來說好了(上面表格的第一行)， 他的意義是：『/dev/hdc2 是掛載到 / 目錄，檔案系統類型為 ext3 ，且掛載為可讀寫 (rw) ，另外，這個 filesystem 有標頭，名字(label)為 /1 』 這樣，你會解釋上述表格中的最後一行輸出結果了嗎？自己解釋一下先。^_^。 接下來請拿出你的 CentOS DVD 放入光碟機中，並拿 FAT 格式的 USB 隨身碟(不要用 NTFS 的)插入 USB 插槽中，我們來測試掛載一下！

- 掛載 CD 或 DVD 光碟

範例三：將你用來安裝 Linux 的 CentOS 原版光碟拿出來掛載！

[root@www ~]# mkdir /media/cdrom

[root@www ~]# mount -t iso9660 /dev/cdrom /media/cdrom

[root@www ~]# mount /dev/cdrom /media/cdrom

# 你可以指定 -t iso9660 這個光碟片的格式來掛載，也可以讓系統自己去測試掛載！

# 所以上述的指令只要做一個就夠了！但是目錄的建立初次掛載時必須要進行喔！

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

.....中間省略.....

/dev/hdd               4493152   4493152         0 100% /media/cdrom

# 因為我的光碟機使用的是 /dev/hdd 的 IDE 介面之故！

光碟機一掛載之後就無法退出光碟片了！除非你將他卸載才能夠退出！ 從上面的資料你也可以發現，因為是光碟嘛！所以磁碟使用率達到 100% ，因為你無法直接寫入任何資料到光碟當中ㄇㄟ！ 另外，其實 /dev/cdrom 是個連結檔，正確的磁碟檔名得要看你的光碟機是什麼連接介面的環境。 以鳥哥為例，我的光碟機接在 /dev/hdd，所以正確的掛載應該是『mount /dev/hdd /media/cdrom』比較正確喔！

Tips:

話說當時年紀小 (其實是剛接觸 Linux 的那一年)，摸 Linux 到處碰壁！連將 CDROM 掛載後， 光碟機竟然都不讓我退片！那個時候難過的要死！解決的方法竟然是『重新開機！』囧的可以啊！

- 格式化與掛載軟碟

軟碟的格式化可以直接使用 mkfs 即可。但是軟碟也是可以格式化成為 ext3 或 vfat 格式的。 掛載的時候我們同樣的使用系統自動測試掛載即可！真是粉簡單！如果你有軟碟片的話(很少人有了吧？)， 請先放置到軟碟機當中囉！底下來測試看看(軟碟片請勿放置任何資料，且將防寫打開！)。

範例四：格式化後掛載軟碟到 /media/floppy/ 目錄中。

[root@www ~]# mkfs -t vfat /dev/fd0

# 我們格式化軟碟成為 Windows/Linux 可共同使用的 FAT 格式吧！

[root@www ~]# mkdir /media/floppy

[root@www ~]# mount -t vfat /dev/fd0 /media/floppy

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

.....中間省略.....

/dev/fd0                  1424       164      1260  12% /media/floppy

與光碟機不同的是，你掛載了軟碟後竟然還是可以退出軟碟喔！不過，如此一來你的檔案系統將會有莫名奇妙的問題發生！ 整個 Linux 最重要的就是檔案系統，而檔案系統是直接掛載到目錄樹上頭， 幾乎任何指令都會或多或少使用到目錄樹的資料，因此你當然不可以隨意的將光碟/軟碟拿出來！ 所以，軟碟也請卸載之後再退出！很重要的一點！

- 掛載隨身碟

請拿出你的隨身碟並插入 Linux 主機的 USB 槽中！注意，你的這個隨身碟不能夠是 NTFS 的檔案系統喔！ 接下來讓我們測試測試吧！

範例五：找出你的隨身碟裝置檔名，並掛載到 /mnt/flash 目錄中

[root@www ~]# fdisk -l

.....中間省略.....

Disk /dev/sda: 8313 MB, 8313110528 bytes

59 heads, 58 sectors/track, 4744 cylinders

Units = cylinders of 3422 * 512 = 1752064 bytes

Device Boot      Start         End      Blocks   Id  System

/dev/sda1               1        4745     8118260    b  W95 FAT32

# 從上的特殊字體，可得知磁碟的大小以及裝置檔名，知道是 /dev/sda1

[root@www ~]# mkdir /mnt/flash

[root@www ~]# mount -t vfat -o iocharset=cp950 /dev/sda1 /mnt/flash

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

.....中間省略.....

/dev/sda1              8102416   4986228   3116188  62% /mnt/flash

如果帶有中文檔名的資料，那麼可以在掛載時指定一下掛載檔案系統所使用的語系資料。 在 man mount 找到 vfat 檔案格式當中可以使用 iocharset 來指定語系，而中文語系是 cp950 ， 所以也就有了上述的掛載指令項目囉。

萬一你使用的是隨身硬碟，也就是利用筆記型電腦所做出來的USB磁碟時，通常這樣的硬碟都使用 NTFS 格式的∼ 怎辦？沒關係，可以參考底下這個網站：(註8)

- NTFS 檔案系統官網：Linux-NTFS Project: http://www.linux-ntfs.org/

- CentOS 5.x 版的相關驅動程式下載頁面：http://www.linux-ntfs.org/doku.php?id=redhat:rhel5

將她們提供的驅動程式捉下來並且安裝之後，就能夠使用 NTFS 的檔案系統了！ 只是由於檔案系統與 Linux 核心有很大的關係，因此以後如果你的 Linux 系統有升級 (update) 時， 你就得要重新下載一次相對應的驅動程式版本喔！

- 重新掛載根目錄與掛載不特定目錄

整個目錄樹最重要的地方就是根目錄了，所以根目錄根本就不能夠被卸載的！問題是，如果你的掛載參數要改變， 或者是根目錄出現『唯讀』狀態時，如何重新掛載呢？最可能的處理方式就是重新開機 (reboot)！ 不過你也可以這樣做：

範例六：將 / 重新掛載，並加入參數為 rw 與 auto

[root@www ~]# mount -o remount,rw,auto /

重點是那個『 -o remount,xx 』的選項與參數！請注意，要重新掛載 (remount) 時， 這是個非常重要的機制！尤其是當你進入單人維護模式時，你的根目錄常會被系統掛載為唯讀，這個時候這個指令就太重要了！

另外，我們也可以利用 mount 來將某個目錄掛載到另外一個目錄去喔！這並不是掛載檔案系統，而是額外掛載某個目錄的方法！ 雖然底下的方法也可以使用 symbolic link 來連結，不過在某些不支援符號連結的程式運作中，還是得要透過這樣的方法才行。

範例七：將 /home 這個目錄暫時掛載到 /mnt/home 底下：

[root@www ~]# mkdir /mnt/home

[root@www ~]# mount --bind /home /mnt/home

[root@www ~]# ls -lid /home/ /mnt/home

2 drwxr-xr-x 6 root root 4096 Sep 29 02:21 /home/

2 drwxr-xr-x 6 root root 4096 Sep 29 02:21 /mnt/home

[root@www ~]# mount -l

/home on /mnt/home type none (rw,bind)

看起來，其實兩者連結到同一個 inode 嘛！ ^_^ 沒錯啦！透過這個 mount --bind 的功能， 您可以將某個目錄掛載到其他目錄去喔！而並不是整塊 filesystem 的啦！所以從此進入 /mnt/home 就是進入 /home 的意思喔！

- umount (將裝置檔案卸載)

[root@www ~]# umount [-fn] 裝置檔名或掛載點

選項與參數：

-f ：強制卸載！可用在類似網路檔案系統 (NFS) 無法讀取到的情況下；

-n ：不更新 /etc/mtab 情況下卸載。

就是直接將已掛載的檔案系統給他卸載即是！卸載之後，可以使用 df 或 mount -l 看看是否還存在目錄樹中？ 卸載的方式，可以下達裝置檔名或掛載點，均可接受啦！底下的範例做看看吧！

範例八：將本章之前自行掛載的檔案系統全部卸載：

[root@www ~]# mount

.....前面省略.....

/dev/hdc6 on /mnt/hdc6 type ext3 (rw)

/dev/hdd on /media/cdrom type iso9660 (rw)

/dev/sda1 on /mnt/flash type vfat (rw,iocharset=cp950)

/home on /mnt/home type none (rw,bind)

# 先找一下已經掛載的檔案系統，如上所示，特殊字體即為剛剛掛載的裝置囉！

[root@www ~]# umount /dev/hdc6      <==用裝置檔名來卸載

[root@www ~]# umount /media/cdrom   <==用掛載點來卸載

[root@www ~]# umount /mnt/flash     <==因為掛載點比較好記憶！

[root@www ~]# umount /dev/fd0       <==用裝置檔名較好記！

[root@www ~]# umount /mnt/home      <==一定要用掛載點！因為掛載的是目錄

由於通通卸載了，此時你才可以退出光碟片、軟碟片、USB隨身碟等設備喔！如果你遇到這樣的情況：

[root@www ~]# mount /dev/cdrom /media/cdrom

[root@www ~]# cd /media/cdrom

[root@www cdrom]# umount /media/cdrom

umount: /media/cdrom: device is busy

umount: /media/cdrom: device is busy

由於你目前正在 /media/cdrom/ 的目錄內，也就是說其實『你正在使用該檔案系統』的意思！ 所以自然無法卸載這個裝置！那該如何是好？就『離開該檔案系統的掛載點』即可。以上述的案例來說， 你可以使用『 cd / 』回到根目錄，就能夠卸載 /media/cdrom 囉！簡單吧！

- 使用 Label name 進行掛載的方法

除了磁碟的裝置檔名之外，其實我們可以使用檔案系統的標頭(label)名稱來掛載喔！ 舉例來說，我們剛剛卸載的 /dev/hdc6 標頭名稱是『vbird_logical』，你也可以使用 dumpe2fs 這個指令來查詢一下啦！然後就這樣做即可：

範例九：找出 /dev/hdc6 的 label name，並用 label 掛載到 /mnt/hdc6

[root@www ~]# dumpe2fs -h /dev/hdc6

Filesystem volume name:   vbird_logical

.....底下省略.....

# 找到啦！標頭名稱為 vbird_logical 囉！

[root@www ~]# mount -L "vbird_logical" /mnt/hdc6

這種掛載的方法有一個很大的好處：『系統不必知道該檔案系統所在的介面與磁碟檔名！』 更詳細的說明我們會在下一小節當中的 e2label 介紹的！

磁碟參數修訂

某些時刻，你可能會希望修改一下目前檔案系統的一些相關資訊，舉例來說，你可能要修改 Label name ， 或者是 journal 的參數，或者是其他硬碟運作時的相關參數 (例如 DMA 啟動與否∼)。 這個時候，就得需要底下這些相關的指令功能囉∼

- mknod

還記得我們說過，在 Linux 底下所有的裝置都以檔案來代表吧！但是那個檔案如何代表該裝置呢？ 很簡單！就是透過檔案的 major 與 minor 數值來替代的∼所以，那個 major 與 minor 數值是有特殊意義的，不是隨意設定的喔！舉例來說，在鳥哥的這個測試機當中， 那個用到的磁碟 /dev/hdc 的相關裝置代碼如下：

[root@www ~]# ll /dev/hdc*

brw-r----- 1 root disk 22, 0 Oct 24 15:55 /dev/hdc

brw-r----- 1 root disk 22, 1 Oct 20 08:47 /dev/hdc1

brw-r----- 1 root disk 22, 2 Oct 20 08:47 /dev/hdc2

brw-r----- 1 root disk 22, 3 Oct 20 08:47 /dev/hdc3

brw-r----- 1 root disk 22, 4 Oct 24 16:02 /dev/hdc4

brw-r----- 1 root disk 22, 5 Oct 20 16:46 /dev/hdc5

brw-r----- 1 root disk 22, 6 Oct 25 01:33 /dev/hdc6

上表當中 22 為主要裝置代碼 (Major) 而 0~6 則為次要裝置代碼 (Minor)。 我們的 Linux 核心認識的裝置資料就是透過這兩個數值來決定的！舉例來說，常見的硬碟檔名 /dev/hda 與 /dev/sda 裝置代碼如下所示：

磁碟檔名

Major

Minor

/dev/hda

3

0~63

/dev/hdb

3

64~127

/dev/sda

8

0-15

/dev/sdb

8

16-31

如果你想要知道更多核心支援的硬體裝置代碼 (major, minor) 請參考官網的連結(註9)：

- http://www.kernel.org/pub/linux/docs/device-list/devices.txt

基本上，Linux 核心 2.6 版以後，硬體檔名已經都可以被系統自動的即時產生了，我們根本不需要手動建立裝置檔案。 不過某些情況底下我們可能還是得要手動處理裝置檔案的，例如在某些服務被關到特定目錄下時(chroot)， 就需要這樣做了。此時這個 mknod 就得要知道如何操作才行！

[root@www ~]# mknod 裝置檔名 [bcp] [Major] [Minor]

選項與參數：

裝置種類：

b  ：設定裝置名稱成為一個周邊儲存設備檔案，例如硬碟等；

c  ：設定裝置名稱成為一個周邊輸入設備檔案，例如滑鼠/鍵盤等；

p  ：設定裝置名稱成為一個 FIFO 檔案；

Major ：主要裝置代碼；

Minor ：次要裝置代碼；

範例一：由上述的介紹我們知道 /dev/hdc10 裝置代碼 22, 10，請建立並查閱此裝置

[root@www ~]# mknod /dev/hdc10 b 22 10

[root@www ~]# ll /dev/hdc10

brw-r--r-- 1 root root 22, 10 Oct 26 23:57 /dev/hdc10

# 上面那個 22 與 10 是有意義的，不要隨意設定啊！

範例二：建立一個 FIFO 檔案，檔名為 /tmp/testpipe

[root@www ~]# mknod /tmp/testpipe p

[root@www ~]# ll /tmp/testpipe

prw-r--r-- 1 root root 0 Oct 27 00:00 /tmp/testpipe

# 注意啊！這個檔案可不是一般檔案，不可以隨便就放在這裡！

# 測試完畢之後請刪除這個檔案吧！看一下這個檔案的類型！是 p 喔！^_^

- e2label

我們在 mkfs 指令介紹時有談到設定檔案系統標頭 (Label) 的方法。 那如果格式化完畢後想要修改標頭呢？就用這個 e2label 來修改了。那什麼是 Label 呢？ 我們拿你曾用過的 Windows 系統來說明。當你打開『檔案總管』時，C/D等槽不是都會有個名稱嗎？ 那就是 label (如果沒有設定名稱，就會顯示『本機磁碟機』的字樣)

這個東西除了有趣且可以讓你知道磁碟的內容是啥玩意兒之外，也會被使用到一些設定檔案當中！ 舉例來說，剛剛我們聊到的磁碟的掛載時，不就有用到 Label name 來進行掛載嗎？ 目前 CentOS 的設定檔，也就是那個 /etc/fstab 檔案的設定都預設使用 Label name 呢！ 那這樣做有什麼好處與缺點呢？

- 優點：不論磁碟檔名怎麼變，不論你將硬碟插在哪個 IDE / SATA 介面，由於系統是透過 Label ，所以，磁碟插在哪個介面將不會有影響；

- 缺點：如果插了兩顆硬碟，剛好兩顆硬碟的 Label 有重複的，那就慘了∼ 因為系統可能會無法判斷哪個磁碟分割槽才是正確的！

鳥哥一直是個比較『硬派』作風，所以我還是比較喜歡直接利用磁碟檔名來掛載啦！ 不過，如果沒有特殊需求的話，那麼利用 Label 來掛載也成！ 但是你就不可以隨意修改 Label 的名稱了！

[root@www ~]# e2label 裝置名稱  新的Label名稱

範例一：將 /dev/hdc6 的標頭改成 my_test 並觀察是否修改成功？

[root@www ~]# dumpe2fs -h /dev/hdc6

Filesystem volume name:   vbird_logical  <==原本的標頭名稱

.....底下省略.....

[root@www ~]# e2label /dev/hdc6 "my_test"

[root@www ~]# dumpe2fs -h /dev/hdc6

Filesystem volume name:   my_test        <==改過來啦！

.....底下省略.....

- tune2fs

[root@www ~]# tune2fs [-jlL] 裝置代號

選項與參數：

-l  ：類似 dumpe2fs -h 的功能∼將 superblock 內的資料讀出來∼

-j  ：將 ext2 的 filesystem 轉換為 ext3 的檔案系統；

-L  ：類似 e2label 的功能，可以修改 filesystem 的 Label 喔！

範例一：列出 /dev/hdc6 的 superblock 內容

[root@www ~]# tune2fs -l /dev/hdc6

這個指令的功能其實很廣泛啦∼上面鳥哥僅列出很簡單的一些參數而已， 更多的用法請自行參考 man tune2fs 。比較有趣的是，如果你的某個 partition 原本是 ext2 的檔案系統，如果想要將他更新成為 ext3 檔案系統的話，利用 tune2fs 就可以很簡單的轉換過來囉∼

- hdparm

如果你的硬碟是 IDE 介面的，那麼這個指令可以幫助你設定一些進階參數！如果你是使用 SATA 介面的， 那麼這個指令就沒有多大用途了！另外，目前的 Linux 系統都已經稍微最佳化過，所以這個指令最多是用來測試效能啦！ 而且建議你不要隨便調整硬碟參數，檔案系統容易出問題喔！除非你真的知道你調整的資料是啥！

[root@www ~]# hdparm [-icdmXTt] 裝置名稱

選項與參數：

-i  ：將核心偵測到的硬碟參數顯示出來！

-c  ：設定 32-bit (32位元)存取模式。這個 32 位元存取模式指的是在硬碟在與

PCI 介面之間傳輸的模式，而硬碟本身是依舊以 16 位元模式在跑的！

預設的情況下，這個設定值都會被打開，建議直接使用 c1 即可！

-d  ：設定是否啟用 dma 模式， -d1 為啟動， -d0 為取消；

-m  ：設定同步讀取多個 sector 的模式。一般來說，設定此模式，可降低系統因為

讀取磁碟而損耗的效能∼不過， WD 的硬碟則不怎麼建議設定此值∼

一般來說，設定為 16/32 是最佳化，不過，WD 硬碟建議值則是 4/8 。

這個值的最大值，可以利用 hdparm -i /dev/hda 輸出的 MaxMultSect

來設定喔！一般如果不曉得，設定 16 是合理的！

-X  ：設定 UtraDMA 的模式，一般來說， UDMA 的模式值加 64 即為設定值。

並且，硬碟與主機板晶片必須要同步，所以，取最小的那個。一般來說：

33 MHz DMA mode 0~2 (X64~X66)

66 MHz DMA mode 3~4 (X67~X68)

100MHz DMA mode 5   (X69)

如果您的硬碟上面顯示的是 UATA 100 以上的，那麼設定 X69 也不錯！

-T  ：測試暫存區 cache 的存取效能

-t  ：測試硬碟的實際存取效能 （較正確！）

範例一：取得我硬碟的最大同步存取 sector 值與目前的 UDMA 模式

[root@www ~]# hdparm -i /dev/hdc

Model=IC35L040AVER07-0, FwRev=ER4OA41A, SerialNo=SX0SXL98406 <==硬碟的廠牌型號

Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs }

RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=40

BuffType=DualPortCache, BuffSize=1916kB, MaxMultSect=16, MultSect=16

CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=80418240

IORDY=on/off, tPIO={min:240,w/IORDY:120}, tDMA={min:120,rec:120}

PIO modes:  pio0 pio1 pio2 pio3 pio4

DMA modes:  mdma0 mdma1 mdma2

UDMA modes: udma0 udma1 udma2 udma3 udma4 *udma5 <==有 * 為目前的值

AdvancedPM=yes: disabled (255) WriteCache=enabled

Drive conforms to: ATA/ATAPI-5 T13 1321D revision 1:

ATA/ATAPI-2 ATA/ATAPI-3 ATA/ATAPI-4 ATA/ATAPI-5

# 這顆硬碟緩衝記憶體只有 2MB(BuffSize)，但使用的是 udma5 ！還可以。

範例二：由上個範例知道最大 16 位元/UDMA 為 mode 5，所以可以設定為：

[root@www ~]# hdparm -d1 -c1 -X69 /dev/hdc

範例三：測試這顆硬碟的讀取效能

[root@www ~]# hdparm -Tt /dev/hdc

/dev/hdc:

Timing cached reads:   428 MB in  2.00 seconds = 213.50 MB/sec

Timing buffered disk reads:  114 MB in  3.00 seconds =  38.00 MB/sec

# 鳥哥的這部測試機沒有很好啦∼這樣的速度.....差強人意∼

如果你是使用 SATA 硬碟的話，這個指令唯一可以做的，就是最後面那個測試的功能而已囉！ 雖然這樣的測試不是很準確，至少是一個可以比較的基準。鳥哥在我的 cluster 機器上面測試的 SATA (/dev/sda) 與 RAID (/dev/sdb) 結果如下，可以提供給你參考看看。

[root@www ~]# hdparm -Tt /dev/sda /dev/sdb

/dev/sda:

Timing cached reads:   4152 MB in  2.00 seconds = 2075.28 MB/sec

Timing buffered disk reads:  304 MB in  3.01 seconds = 100.91 MB/sec

/dev/sdb:

Timing cached reads:   4072 MB in  2.00 seconds = 2036.31 MB/sec

Timing buffered disk reads:  278 MB in  3.00 seconds =  92.59 MB/sec

設定開機掛載：

手動處理 mount 不是很人性化，我們總是需要讓系統『自動』在開機時進行掛載的！本小節就是在談這玩意兒！ 另外，從 FTP 伺服器捉下來的映像檔能否不用燒錄就可以讀取內容？我們也需要談談先！

開機掛載 /etc/fstab 及 /etc/mtab

剛剛上面說了許多，那麼可不可以在開機的時候就將我要的檔案系統都掛好呢？這樣我就不需要每次進入 Linux 系統都還要在掛載一次呀！當然可以囉！那就直接到 /etc/fstab 裡面去修修就行囉！不過，在開始說明前，這裡要先跟大家說一說系統掛載的一些限制：

- 根目錄 / 是必須掛載的﹐而且一定要先於其它 mount point 被掛載進來。

- 其它 mount point 必須為已建立的目錄﹐可任意指定﹐但一定要遵守必須的系統目錄架構原則

- 所有 mount point 在同一時間之內﹐只能掛載一次。

- 所有 partition 在同一時間之內﹐只能掛載一次。

- 如若進行卸載﹐您必須先將工作目錄移到 mount point(及其子目錄) 之外。

讓我們直接查閱一下 /etc/fstab 這個檔案的內容吧！

[root@www ~]# cat /etc/fstab

# Device        Mount point   filesystem parameters    dump fsck

LABEL=/1          /           ext3       defaults        1 1

LABEL=/home       /home       ext3       defaults        1 2

LABEL=/boot       /boot       ext3       defaults        1 2

tmpfs             /dev/shm    tmpfs      defaults        0 0

devpts            /dev/pts    devpts     gid=5,mode=620  0 0

sysfs             /sys        sysfs      defaults        0 0

proc              /proc       proc       defaults        0 0

LABEL=SWAP-hdc5   swap        swap       defaults        0 0

# 上述特殊字體的部分與實際磁碟有關！其他則是虛擬檔案系統或

# 與記憶體置換空間 (swap) 有關。

其實 /etc/fstab (filesystem table) 就是將我們利用 mount 指令進行掛載時， 將所有的選項與參數寫入到這個檔案中就是了。除此之外， /etc/fstab 還加入了 dump 這個備份用指令的支援！ 與開機時是否進行檔案系統檢驗 fsck 等指令有關。

這個檔案的內容共有六個欄位，這六個欄位非常的重要！你『一定要背起來』才好！ 各個欄位的詳細資料如下：

Tips:

鳥哥比較龜毛一點，因為某些 distributions 的 /etc/fstab 檔案排列方式蠻醜的， 雖然每一欄之間只要以空白字元分開即可，但就是覺得醜，所以通常鳥哥就會自己排列整齊， 並加上註解符號(就是 # )，來幫我記憶這些資訊！

- 第一欄：磁碟裝置檔名或該裝置的 Label：

這個欄位請填入檔案系統的裝置檔名。但是由上面表格的預設值我們知道系統預設使用的是 Label 名稱！ 在鳥哥的這個測試系統中 /dev/hdc2 標頭名稱為 /1，所以上述表格中的『LABEL=/1』也可以被取代成為『/dev/hdc2』的意思。 至於Label可以使用 dumpe2fs 指令來查閱的。

Tips:

記得有一次有個網友寫信給鳥哥，他說，依照 e2label 的設定去練習修改自己的 partition 的 Label name 之後，卻發現，再也無法順利開機成功！ 後來才發現，原來他的 /etc/fstab 就是以 Label name 去掛載的。但是因為在練習的時候， 將 Label name 改名字過了，導致在開機的過程當中再也找不到相關的Label name了。

所以啦，這裡再次的強調，利用裝置名稱 (ex> /dev/hda1) 來掛載 partition 時， 雖然是被固定死的，所以您的硬碟不可以隨意插在任意的插槽，不過他還是有好處的。 而使用 Label name 來掛載，雖然就沒有插槽方面的問題，不過，您就得要隨時注意您的 Label name 喔！尤其是新增硬碟的時候！ ^_^

- 第二欄：掛載點 (mount point)：：

就是掛載點啊！掛載點是什麼？一定是目錄啊∼要知道啊！

- 第三欄：磁碟分割槽的檔案系統：

在手動掛載時可以讓系統自動測試掛載，但在這個檔案當中我們必須要手動寫入檔案系統才行！ 包括 ext3, reiserfs, nfs, vfat 等等。

- 第四欄：檔案系統參數：

記不記得我們在 mount 這個指令中談到很多特殊的檔案系統參數？ 還有我們使用過的『-o iocharset=cp950』？這些特殊的參數就是寫入在這個欄位啦！ 雖然之前在 mount 已經提過一次，這裡我們利用表格的方式再彙整一下：

參數

內容意義

async/sync

非同步/同步

設定磁碟是否以非同步方式運作！預設為 async(效能較佳)

auto/noauto

自動/非自動

當下達 mount -a 時，此檔案系統是否會被主動測試掛載。預設為 auto。

rw/ro

可讀寫/唯讀

讓該分割槽以可讀寫或者是唯讀的型態掛載上來，如果你想要分享的資料是不給使用者隨意變更的， 這裡也能夠設定為唯讀。則不論在此檔案系統的檔案是否設定 w 權限，都無法寫入喔！

exec/noexec

可執行/不可執行

限制在此檔案系統內是否可以進行『執行』的工作？如果是純粹用來儲存資料的， 那麼可以設定為 noexec 會比較安全，相對的，會比較麻煩！

user/nouser

允許/不允許使用者掛載

是否允許使用者使用 mount 指令來掛載呢？一般而言，我們當然不希望一般身份的 user 能使用 mount 囉，因為太不安全了，因此這裡應該要設定為 nouser 囉！

suid/nosuid

具有/不具有 suid 權限

該檔案系統是否允許 SUID 的存在？如果不是執行檔放置目錄，也可以設定為 nosuid 來取消這個功能！

usrquota

注意名稱是『 usrquota 』不要拼錯了！這個是在啟動 filesystem 支援磁碟配額模式，更多資料我們在第四篇再談。

grpquota

注意名稱是『grpquota』，啟動 filesystem 對群組磁碟配額模式的支援。

defaults

同時具有 rw, suid, dev, exec, auto, nouser, async 等參數。 基本上，預設情況使用 defaults 設定即可！

- 第五欄：能否被 dump 備份指令作用：

dump 是一個用來做為備份的指令(我們會在第二十五章備份策略中談到這個指令)， 我們可以透過 fstab 指定哪個檔案系統必須要進行 dump 備份！ 0 代表不要做 dump 備份， 1 代表要每天進行 dump 的動作。 2 也代表其他不定日期的 dump 備份動作， 通常這個數值不是 0 就是 1 啦！

- 第六欄：是否以 fsck 檢驗磁區：

開機的過程中，系統預設會以 fsck 檢驗我們的 filesystem 是否完整 (clean)。 不過，某些 filesystem 是不需要檢驗的，例如記憶體置換空間 (swap) ，或者是特殊檔案系統例如 /proc 與 /sys 等等。所以，在這個欄位中，我們可以設定是否要以 fsck 檢驗該 filesystem 喔。 0 是不要檢驗， 1 表示最早檢驗(一般只有根目錄會設定為 1)， 2 也是要檢驗，不過 1 會比較早被檢驗啦！ 一般來說，根目錄設定為 1 ，其他的要檢驗的 filesystem 都設定為 2 就好了。

例題：

假設我們要將 /dev/hdc6 每次開機都自動掛載到 /mnt/hdc6 ，該如何進行？

答：

首先，請用 nano 將底下這一行寫入 /etc/fstab 當中；

[root@www ~]# nano /etc/fstab

/dev/hdc6  /mnt/hdc6    ext3    defaults   1 2

再來看看 /dev/hdc6 是否已經掛載，如果掛載了，請務必卸載再說！

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/dev/hdc6              1976312     42072   1833836   3% /mnt/hdc6

# 竟然不知道何時被掛載了？趕緊給他卸載先！

[root@www ~]# umount /dev/hdc6

最後測試一下剛剛我們寫入 /etc/fstab 的語法有沒有錯誤！這點很重要！因為這個檔案如果寫錯了， 則你的 Linux 很可能將無法順利開機完成！所以請務必要測試測試喔！

[root@www ~]# mount -a

[root@www ~]# df

最終有看到 /dev/hdc6 被掛載起來的資訊才是成功的掛載了！而且以後每次開機都會順利的將此檔案系統掛載起來的！ 由於這個範例僅是測試而已，請務必回到 /etc/fstab 當中，將上述這行給他註解或者是刪除掉！

[root@www ~]# nano /etc/fstab

# /dev/hdc6  /mnt/hdc6    ext3    defaults   1 2

/etc/fstab 是開機時的設定檔，不過，實際 filesystem 的掛載是記錄到 /etc/mtab 與 /proc/mounts 這兩個檔案當中的。每次我們在更動 filesystem 的掛載時，也會同時更動這兩個檔案喔！但是，萬一發生您在 /etc/fstab 輸入的資料錯誤，導致無法順利開機成功，而進入單人維護模式當中，那時候的 / 可是 read only 的狀態，當然您就無法修改 /etc/fstab ，也無法更新 /etc/mtab 囉∼那怎麼辦？ 沒關係，可以利用底下這一招：

[root@www ~]# mount -n -o remount,rw /

特殊裝置 loop 掛載 (映象檔不燒錄就掛載使用)

- 掛載光碟/DVD映象檔

想像一下如果今天我們從國家高速網路中心(http://ftp.twaren.net)或者是義守大學(http://ftp.isu.edu.tw)下載了 Linux 或者是其他所需光碟/DVD的映象檔後， 難道一定需要燒錄成為光碟才能夠使用該檔案裡面的資料嗎？當然不是啦！我們可以透過 loop 裝置來掛載的！

那要如何掛載呢？鳥哥將整個 CentOS 5.2 的 DVD 映象檔捉到測試機上面，然後利用這個檔案來掛載給大家參考看看囉！

[root@www ~]# ll -h /root/centos5.2_x86_64.iso

-rw-r--r-- 1 root root 4.3G Oct 27 17:34 /root/centos5.2_x86_64.iso

# 看到上面的結果吧！這個檔案就是映象檔，檔案非常的大吧！

[root@www ~]# mkdir /mnt/centos_dvd

[root@www ~]# mount -o loop /root/centos5.2_x86_64.iso /mnt/centos_dvd

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/root/centos5.2_x86_64.iso

4493152   4493152         0 100% /mnt/centos_dvd

# 就是這個項目！ .iso 映象檔內的所有資料可以在 /mnt/centos_dvd 看到！

[root@www ~]# ll /mnt/centos_dvd

total 584

drwxr-xr-x 2 root root 522240 Jun 24 00:57 CentOS <==瞧！就是DVD的內容啊！

-rw-r--r-- 8 root root    212 Nov 21  2007 EULA

-rw-r--r-- 8 root root  18009 Nov 21  2007 GPL

drwxr-xr-x 4 root root   2048 Jun 24 00:57 images

.....底下省略.....

[root@www ~]# umount /mnt/centos_dvd/

# 測試完成！記得將資料給他卸載！

非常方便吧！如此一來我們不需要將這個檔案燒錄成為光碟或者是 DVD 就能夠讀取內部的資料了！ 換句話說，你也可以在這個檔案內『動手腳』去修改檔案的！這也是為什麼很多映象檔提供後，還得要提供驗證碼 (MD5) 給使用者確認該映象檔沒有問題！

- 建立大檔案以製作 loop 裝置檔案！

想一想，既然能夠掛載 DVD 的映象檔，那麼我能不能製作出一個大檔案，然後將這個檔案格式化後掛載呢？ 好問題！這是個有趣的動作！而且還能夠幫助我們解決很多系統的分割不良的情況呢！舉例來說，如果當初在分割時， 你只有分割出一個根目錄，假設你已經沒有多餘的容量可以進行額外的分割的！偏偏根目錄的容量還很大！ 此時你就能夠製作出一個大檔案，然後將這個檔案掛載！如此一來感覺上你就多了一個分割槽囉！ 用途非常的廣泛啦！

底下我們在 /home 下建立一個 512MB 左右的大檔案，然後將這個大檔案格式化並且實際掛載來玩一玩！ 這樣你會比較清楚鳥哥在講啥！

- 建立大型檔案

首先，我們得先有一個大的檔案吧！怎麼建立這個大檔案呢？在 Linux 底下我們有一支很好用的程式 dd ！他可以用來建立空的檔案喔！詳細的說明請先翻到下一章 壓縮指令的運用 來查閱，這裡鳥哥僅作一個簡單的範例而已。 假設我要建立一個空的檔案在 /home/loopdev ，那可以這樣做：

[root@www ~]# dd if=/dev/zero of=/home/loopdev bs=1M count=512

512+0 records in   <==讀入 512 筆資料

512+0 records out  <==輸出 512 筆資料

536870912 bytes (537 MB) copied, 12.3484 seconds, 43.5 MB/s

# 這個指令的簡單意義如下：

# if 是 input file ，輸入檔案。那個 /dev/zero 是會一直輸出 0 的裝置！

# of 是 output file ，將一堆零寫入到後面接的檔案中。

# bs 是每個 block 大小，就像檔案系統那樣的 block 意義；

# count 則是總共幾個 bs 的意思。

[root@www ~]# ll -h /home/loopdev

-rw-r--r-- 1 root root 512M Oct 28 02:29 /home/loopdev

dd 就好像在疊磚塊一樣，將 512 塊，每塊 1MB 的磚塊堆疊成為一個大檔案 (/home/loopdev) ！ 最終就會出現一個 512MB 的檔案！粉簡單吧！

- 格式化

很簡單就建立起一個 512MB 的檔案了吶！接下來當然是格式化囉！

[root@www ~]# mkfs -t ext3 /home/loopdev

mke2fs 1.39 (29-May-2006)

/home/loopdev is not a block special device.

Proceed anyway? (y,n) y  <==由於不是正常的裝置，所以這裡會提示你！

Filesystem label=

OS type: Linux

Block size=1024 (log=0)

Fragment size=1024 (log=0)

131072 inodes, 524288 blocks

26214 blocks (5.00%) reserved for the super user

.....以下省略.....

- 掛載

那要如何掛載啊？利用 mount 的特殊參數，那個 -o loop 的參數來處理！

[root@www ~]# mount -o loop /home/loopdev /media/cdrom/

[root@www ~]# df

Filesystem           1K-blocks      Used Available Use% Mounted on

/home/loopdev           507748     18768    462766   4% /media/cdrom

透過這個簡單的方法，感覺上你就可以在原本的分割槽在不更動原有的環境下製作出你想要的分割槽就是了！ 這東西很好用的！尤其是想要玩 Linux 上面的『虛擬機器』的話， 也就是以一部 Linux 主機再切割成為數個獨立的主機系統時，類似 VMware 這類的軟體， 在 Linux 上使用 xen 這個軟體，他就可以配合這種 loop device 的檔案類型來進行根目錄的掛載， 真的非常有用的喔！ ^_^

記憶體置換空間(swap)之建置

還記得在安裝 Linux 之前大家常常會告訴你的話吧！就是安裝時一定需要的兩個 partition 囉！ 一個是根目錄，另外一個就是 swap(記憶體置換空間)。關於記憶體置換空間的解釋在第四章安裝 Linux 內的磁碟分割時有約略提過， swap 的功能就是在應付實體記憶體不足的情況下所造成的記憶體延伸記錄的功能。

一般來說，如果硬體的配備足夠的話，那麼 swap 應該不會被我們的系統所使用到， swap 會被利用到的時刻通常就是實體記憶體不足的情況了。從第零章的計算機概論當中，我們知道 CPU 所讀取的資料都來自於記憶體， 那當記憶體不足的時候，為了讓後續的程式可以順利的運作，因此在記憶體中暫不使用的程式與資料就會被挪到 swap 中了。 此時記憶體就會空出來給需要執行的程式載入。由於 swap 是用硬碟來暫時放置記憶體中的資訊， 所以用到 swap 時，你的主機硬碟燈就會開始閃個不停啊！

雖然目前(2009)主機的記憶體都很大，至少都有 1GB 以上囉！因此在個人使用上你不要設定 swap 應該也沒有什麼太大的問題。 不過伺服器可就不這麼想了∼由於你不會知道何時會有大量來自網路的要求，因此你最好能夠預留一些 swap 來緩衝一下系統的記憶體用量！ 至少達到『備而不用』的地步啊！

現在想像一個情況，你已經將系統建立起來了，此時卻才發現你沒有建置 swap ∼那該如何是好呢？ 透過本章上面談到的方法，你可以使用如下的方式來建立你的 swap 囉！

- 設定一個 swap partition

- 建立一個虛擬記憶體的檔案

不囉唆，就立刻來處理處理吧！

使用實體分割槽建置swap

建立 swap 分割槽的方式也是非常的簡單的！透過底下幾個步驟就搞定囉：

1. 分割：先使用 fdisk 在你的磁碟中分割出一個分割槽給系統作為 swap 。由於 Linux 的 fdisk 預設會將分割槽的 ID 設定為 Linux 的檔案系統，所以你可能還得要設定一下 system ID 就是了。

2. 格式化：利用建立 swap 格式的『mkswap 裝置檔名』就能夠格式化該分割槽成為 swap 格式囉

3. 使用：最後將該 swap 裝置啟動，方法為：『swapon 裝置檔名』。

4. 觀察：最終透過 free 這個指令來觀察一下記憶體的用量吧！

不囉唆，立刻來實作看看！既然我們還有多餘的磁碟容量可以分割，那麼讓我們繼續分割出 256MB 的磁碟分割槽吧！ 然後將這個磁碟分割槽做成 swap 吧！

- 1. 先進行分割的行為囉！

[root@www ~]# fdisk /dev/hdc

Command (m for help): n

First cylinder (2303-5005, default 2303):  <==這裡按[enter]

Using default value 2303

Last cylinder or +size or +sizeM or +sizeK (2303-5005, default 5005): +256M

Command (m for help): p

Device Boot      Start         End      Blocks   Id  System

.....中間省略.....

/dev/hdc6            2053        2302     2008093+  83  Linux

/dev/hdc7            2303        2334      257008+  83  Linux <==新增的項目

Command (m for help): t             <==修改系統 ID

Partition number (1-7): 7           <==從上結果看到的，七號partition

Hex code (type L to list codes): 82 <==改成 swap 的 ID

Changed system type of partition 7 to 82 (Linux swap / Solaris)

Command (m for help): p

Device Boot      Start         End      Blocks   Id  System

.....中間省略.....

/dev/hdc6            2053        2302     2008093+  83  Linux

/dev/hdc7            2303        2334      257008+  82  Linux swap / Solaris

Command (m for help): w

# 此時就將 partition table 更新了！

[root@www ~]# partprobe

# 這個玩意兒很重要的啦！不要忘記讓核心更新 partition table 喔！

- 2. 開始建置 swap 格式

[root@www ~]# mkswap /dev/hdc7

Setting up swapspace version 1, size = 263172 kB  <==非常快速！

- 3. 開始觀察與載入看看吧！

[root@www ~]# free

total       used       free     shared    buffers     cached

Mem:        742664     684592      58072          0      43820     497144

-/+ buffers/cache:     143628     599036

Swap:      1020088         96    1019992

# 我有 742664K 的實體記憶體，使用 684592K 剩餘 58072K ，使用掉的記憶體有

# 43820K / 497144K 用在緩衝/快取的用途中。

# 至於 swap 已經存在了 1020088K 囉！這樣會看了吧？！

[root@www ~]# swapon /dev/hdc7

[root@www ~]# free

total       used       free     shared    buffers     cached

Mem:        742664     684712      57952          0      43872     497180

-/+ buffers/cache:     143660     599004

Swap:      1277088         96    1276992  <==有增加囉！看到否？

[root@www ~]# swapon -s

Filename                 Type            Size    Used    Priority

/dev/hdc5                partition       1020088 96      -1

/dev/hdc7                partition       257000  0       -2

# 上面列出目前使用的 swap 裝置有哪些的意思！

使用檔案建置swap

如果是在實體分割槽無法支援的環境下，此時前一小節提到的 loop 裝置建置方法就派的上用場啦！ 與實體分割槽不一樣的只是利用 dd 去建置一個大檔案而已。多說無益，我們就再透過檔案建置的方法建立一個 128 MB 的記憶體置換空間吧！

- 1. 使用 dd 這個指令來新增一個 128MB 的檔案在 /tmp 底下：

[root@www ~]# dd if=/dev/zero of=/tmp/swap bs=1M count=128

128+0 records in

128+0 records out

134217728 bytes (134 MB) copied, 1.7066 seconds, 78.6 MB/s

[root@www ~]# ll -h /tmp/swap

-rw-r--r-- 1 root root 128M Oct 28 15:33 /tmp/swap

這樣一個 128MB 的檔案就建置妥當。若忘記上述的各項參數的意義，請回前一小節查閱一下囉！

- 2. 使用 mkswap 將 /tmp/swap 這個檔案格式化為 swap 的檔案格式：

[root@www ~]# mkswap /tmp/swap

Setting up swapspace version 1, size = 134213 kB

# 這個指令下達時請『特別小心』，因為下錯字元控制，將可能使您的檔案系統掛掉！

- 3. 使用 swapon 來將 /tmp/swap 啟動囉！

[root@www ~]# free

total       used       free     shared    buffers     cached

Mem:        742664     450860     291804          0      45584     261284

-/+ buffers/cache:     143992     598672

Swap:      1277088         96    1276992

[root@www ~]# swapon /tmp/swap

[root@www ~]# free

total       used       free     shared    buffers     cached

Mem:        742664     450860     291804          0      45604     261284

-/+ buffers/cache:     143972     598692

Swap:      1408152         96    1408056

[root@www ~]# swapon -s

Filename                 Type            Size    Used    Priority

/dev/hdc5                partition       1020088 96      -1

/dev/hdc7                partition       257000  0       -2

/tmp/swap                file            131064  0       -3

- 4. 使用 swapoff 關掉 swap file

[root@www ~]# swapoff /tmp/swap

[root@www ~]# swapoff /dev/hdc7

[root@www ~]# free

total       used       free     shared    buffers     cached

Mem:        742664     450860     291804          0      45660     261284

-/+ buffers/cache:     143916     598748

Swap:      1020088         96    1019992  <==回復成最原始的樣子了！

swap使用上的限制

說實話，swap 在目前的桌上型電腦來講，存在的意義已經不大了！這是因為目前的 x86 主機所含的記憶體實在都太大了 (一般入門級至少也都有 512MB 了)，所以，我們的 Linux 系統大概都用不到 swap 這個玩意兒的。不過， 如果是針對伺服器或者是工作站這些常年上線的系統來說的話，那麼，無論如何，swap 還是需要建立的。

因為 swap 主要的功能是當實體記憶體不夠時，則某些在記憶體當中所佔的程式會暫時被移動到 swap 當中，讓實體記憶體可以被需要的程式來使用。另外，如果你的主機支援電源管理模式， 也就是說，你的 Linux 主機系統可以進入『休眠』模式的話，那麼， 運作當中的程式狀態則會被紀錄到 swap 去，以作為『喚醒』主機的狀態依據！ 另外，有某些程式在運作時，本來就會利用 swap 的特性來存放一些資料段， 所以， swap 來是需要建立的！只是不需要太大！

不過， swap 在被建立時，是有限制的喔！

- 在核心 2.4.10 版本以後，單一 swap 量已經沒有 2GB 的限制了，

- 但是，最多還是僅能建立到 32 個 swap 的數量！

- 而且，由於目前 x86_64 (64位元) 最大記憶體定址到 64GB， 因此， swap 總量最大也是僅能達 64GB 就是了！

檔案系統的特殊觀察與操作

檔案系統實在是非常有趣的東西，鳥哥學了好幾年還是很多東西不很懂呢！ 在學習的過程中很多朋友在討論區都有提供一些想法！這些想法將他歸納起來有底下幾點可以參考的資料呢！

boot sector 與 superblock 的關係

在過去非常多的文章都寫到開機管理程式是安裝到 superblock 內的，但是我們由官方的 How to 文件知道，圖解(圖 1.3.1)的結果是將可安裝開機資訊的 boot sector (開機磁區) 獨立出來，並非放置到 superblock 當中的！ 那麼也就是說過去的文章寫錯了？這其實還是可以討論討論的！

經過一些搜尋，鳥哥找到幾篇文章(非官方文件)的說明，大多是網友分析的結果啦！如下所示：(註10)

- The Second Extended File System: http://www.nongnu.org/ext2-doc/ext2.html

- Rob's ext2 documentation: http://www.landley.net/code/toybox/ext2.html

- Life is different blog: ext2文件系統分析： http://www.qdhedu.com/blog/post/7.html

這幾篇文章有幾個重點，歸納一下如下：

- superblock 的大小為 1024 bytes；

- superblock 前面需要保留 1024 bytes 下來，以讓開機管理程式可以安裝。

分析上述兩點我們知道 boot sector 應該會佔有 1024 bytes 的大小吧！但是整個檔案系統主要是依據 block 大小來決定的啊！ 因此要討論 boot sector 與 superblock 的關係時，不得不將 block 的大小拿出來討論討論喔！

- block 為 1024 bytes (1K) 時：

如果 block 大小剛好是 1024 的話，那麼 boot sector 與 superblock 各會佔用掉一個 block ， 所以整個檔案系統圖示就會如同圖 1.3.1 所顯示的那樣，boot sector 是獨立於 superblock 外面的！ 由於鳥哥在基礎篇安裝的環境中有個 /boot 的獨立檔案系統在 /dev/hdc1 中，使用 dumpe2fs 觀察的結果有點像底下這樣(如果你是按照鳥哥的教學安裝你的 CentOS 時，可以發現相同的情況喔！)：

[root@www ~]# dumpe2fs /dev/hdc1

dumpe2fs 1.39 (29-May-2006)

Filesystem volume name:   /boot

....(中間省略)....

First block:              1

Block size:               1024

....(中間省略)....

Group 0: (Blocks 1-8192)

Primary superblock at 1, Group descriptors at 2-2

Reserved GDT blocks at 3-258

Block bitmap at 259 (+258), Inode bitmap at 260 (+259)

Inode table at 261-511 (+260)

511 free blocks, 1991 free inodes, 2 directories

Free blocks: 5619-6129

Free inodes: 18-2008

# 看到最後一個特殊字體的地方嗎？ Group0 的 superblock 是由 1  號 block 開始喔！

由上表我們可以確實的發現 0 號 block 是保留下來的，那就是留給 boot sector 用的囉！ 所以整個分割槽的檔案系統分區有點像底下這樣的圖示：

圖 6.1.1、1K block 的 boot sector 示意圖

- block 大於 1024 bytes (2K, 4K) 時：

如果 block 大於 1024 的話，那麼 superblock 將會在 0 號！我們擷取本章一開始介紹 dumpe2fs 時的內容來說明一下好了！

[root@www ~]# dumpe2fs /dev/hdc2

dumpe2fs 1.39 (29-May-2006)

....(中間省略)....

Filesystem volume name:   /1

....(中間省略)....

Block size:               4096

....(中間省略)....

Group 0: (Blocks 0-32767)

Primary superblock at 0, Group descriptors at 1-1

Reserved GDT blocks at 2-626

Block bitmap at 627 (+627), Inode bitmap at 628 (+628)

Inode table at 629-1641 (+629)

0 free blocks, 32405 free inodes, 2 directories

Free blocks:

Free inodes: 12-32416

我們可以發現 superblock 就在第一個 block (第 0 號) 上頭！但是 superblock 其實就只有 1024bytes 嘛！ 為了怕浪費更多空間，因此第一個 block 內就含有 boot sector 與 superblock 兩者 ！舉上頭的表格來說，因為每個 block 佔有 4K ，因此在第一個 block 內 superblock 僅佔有 1024-2047 ( 由 0 號起算的話)之間的咚咚，至於 2048bytes 以後的空間就真的是保留啦！而 0-1023 就保留給 boot sector 來使用。

圖 6.1.2、4K block 的 boot sector 示意圖

因為上述的情況，如果在比較大的 block 尺寸(size)中，我們可能可以說你能夠將開機管理程式安裝到 superblock 所在的 block 號碼中！就是上表的 0 號囉！但事實上還是安裝到 boot sector 的保留區域中啦！所以說， 以前的文章說開機管理程式可以安裝到 superblock 內也不能算全錯∼但比較正確的說法，應該是安裝到該 filesystem 最前面的 1024 bytes 內的區域，就是 boot sector 這樣比較好！

磁碟空間之浪費問題

我們在前面的 block 介紹中談到了一個 block 只能放置一個檔案， 因此太多小檔案將會浪費非常多的磁碟容量。但你有沒有注意到，整個檔案系統中包括 superblock, inode table 與其他中介資料等其實都會浪費磁碟容量喔！所以當我們在 /dev/hdc6 建立起 ext3 檔案系統時， 一掛載就立刻有很多容量被用掉了！

另外，不知道你有沒有發現到，當你使用 ls -l 去查詢某個目錄下的資料時，第一行都會出現一個『total』的字樣！ 那是啥東西？其實那就是該目錄下的所有資料所耗用的實際 block 數量 * block 大小的值。 我們可以透過 ll -s 來觀察看看上述的意義：

[root@www ~]# ll -s

total 104

8 -rw------- 1 root root  1474 Sep  4 18:27 anaconda-ks.cfg

8 -rw-r--r-- 2 root root   255 Jan  6  2007 crontab

4 lrwxrwxrwx 1 root root    12 Oct 22 13:58 crontab2 -> /etc/crontab

48 -rw-r--r-- 1 root root 42304 Sep  4 18:26 install.log

12 -rw-r--r-- 1 root root  5661 Sep  4 18:25 install.log.syslog

4 -rw-r--r-- 1 root root     0 Sep 27 00:25 test1

8 drwxr-xr-x 2 root root  4096 Sep 27 00:25 test2

4 -rw-rw-r-- 1 root root     0 Sep 27 00:36 test3

8 drwxrwxr-x 2 root root  4096 Sep 27 00:36 test4

從上面的特殊字體部分，那就是每個檔案所使用掉 block 的容量！舉例來說，那個 crontab 雖然僅有 255bytes ， 不過他卻佔用了兩個 block (每個 block 為 4K)，將所有的 block 加總就得到 104Kbytes 那個數值了。 如果計算每個檔案實際容量的加總結果，其實只有 56.5K 而已∼所以囉，這樣就耗費掉好多容量了！

如果想要查詢某個目錄所耗用的所有容量時，那就使用 du 吧！不過 du 如果加上 -s 這個選項時， 還可以依據不同的規範去找出檔案系統所消耗的容量喔！舉例來說，我們就來看看 /etc/ 這個目錄的容量狀態吧！

[root@www ~]# du -sb /etc

108360494       /etc   <==單位是 bytes 喔！

[root@www ~]# du -sm /etc

118     /etc           <==單位是 Mbytes 喔！

使用 bytes 去分析時，發現到實際的資料佔用約 103.3Mbytes，但是使用 block 去測試，就發現其實耗用了 118Mbytes， 此時檔案系統就耗費了約 15Mbytes 囉！這樣看的懂我們在講的資料了吧？

利用 GNU 的 parted 進行分割行為

雖然你可以使用 fdisk 很快速的將你的分割槽切割妥當，不過 fdisk 卻無法支援到高於 2TB 以上的分割槽！ 此時就得需要 parted 來處理了。不要覺得 2TB 你用不著！ 2009 年的現在已經有單顆硬碟高達 2TB 的容量了！ 如果再搭配主機系統有內建磁碟陣列裝置，要使用數個 TB 的單一磁碟裝置也不是不可能的！ 所以，還是得要學一下這個重要的工具！ parted ！

parted 可以直接在一行指令列就完成分割，是一個非常好用的指令！他的語法有點像這樣：

[root@www ~]# parted [裝置] [指令 [參數]]

選項與參數：

指令功能：

新增分割：mkpart [primary|logical|extended] [ext3|vfat] 開始 結束

分割表  ：print

刪除分割：rm [partition]

範例一：以 parted 列出目前本機的分割表資料

[root@www ~]# parted /dev/hdc print

Model: IC35L040AVER07-0 (ide)              <==硬碟介面與型號

Disk /dev/hdc: 41.2GB                      <==磁碟檔名與容量

Sector size (logical/physical): 512B/512B  <==每個磁區的大小

Partition Table: msdos                     <==分割表形式

Number  Start   End     Size    Type      File system  Flags

1      32.3kB  107MB   107MB   primary   ext3         boot

2      107MB   10.6GB  10.5GB  primary   ext3

3      10.6GB  15.8GB  5240MB  primary   ext3

4      15.8GB  41.2GB  25.3GB  extended

5      15.8GB  16.9GB  1045MB  logical   linux-swap

6      16.9GB  18.9GB  2056MB  logical   ext3

7      18.9GB  19.2GB  263MB   logical   linux-swap

[  1 ]  [  2 ]  [  3  ] [  4  ] [  5  ]   [  6  ]

上面是最簡單的 parted 指令功能簡介，你可以使用『 man parted 』，或者是『 parted /dev/hdc help mkpart 』去查詢更詳細的資料。比較有趣的地方在於分割表的輸出。我們將上述的分割表示意拆成六部分來說明：

1. Number：這個就是分割槽的號碼啦！舉例來說，1號代表的是 /dev/hdc1 的意思；

2. Start：起始的磁柱位置在這顆磁碟的多少 MB 處？有趣吧！他以容量作為單位喔！

3. End：結束的磁柱位置在這顆磁碟的多少 MB 處？

4. Size：由上述兩者的分析，得到這個分割槽有多少容量；

5. Type：就是分割槽的類型，有primary, extended, logical等類型；

6. File system：就如同 fdisk 的 System ID 之意。

接下來我們嘗試來建立一個全新的分割槽吧！因為我們僅剩下邏輯分割槽可用，所以等一下底下我們選擇的會是 logical 的分割類型喔！

範例二：建立一個約為 512MB 容量的邏輯分割槽

[root@www ~]# parted /dev/hdc mkpart logical ext3 19.2GB 19.7GB

# 請參考前一表格的指令介紹，因為我們的 /dev/hdc7 在 19.2GB  位置結束，

# 所以我們當然要由 19.2GB 位置處繼續下一個分割，這樣懂了吧？

[root@www ~]# parted /dev/hdc print

.....前面省略.....

7      18.9GB  19.2GB  263MB   logical   linux-swap

8      19.2GB  19.7GB  502MB   logical  <==就是剛剛建立的啦！

範例三：將剛剛建立的第八號磁碟分割槽刪除掉吧！

[root@www ~]# parted /dev/hdc rm 8

# 這樣就刪除了！實在很厲害！所以這個指令的下達要特別注意！

# 因為...指令一下去就立即生效了∼如果寫錯的話，會哭死∼

關於 parted 的介紹我們就到這裡啦！除非你有使用到大於 2TB 以上的磁碟， 否則請愛用 fdisk 這個程式來進行分割喔！拜託拜託！

重點回顧

- 基本上 Linux 的正統檔案系統為 Ext2 ，該檔案系統內的資訊主要有：

- superblock：記錄此 filesystem 的整體資訊，包括inode/block的總量、使用量、剩餘量， 以及檔案系統的格式與相關資訊等；

- inode：記錄檔案的屬性，一個檔案佔用一個inode，同時記錄此檔案的資料所在的 block 號碼；

- block：實際記錄檔案的內容，若檔案太大時，會佔用多個 block 。

- Ext2 檔案系統的資料存取為索引式檔案系統(indexed allocation)

- 需要磁碟重組的原因就是檔案寫入的 block 太過於離散了，此時檔案讀取的效能將會變的很差所致。 這個時候可以透過磁碟重組將同一個檔案所屬的 blocks 彙整在一起。

- Ext2檔案系統主要有：boot sector, superblock, inode bitmap, block bitmap, inode table, data block 等六大部分。

- data block 是用來放置檔案內容資料地方，在 Ext2 檔案系統中所支援的 block 大小有 1K, 2K 及 4K 三種而已

- inode 記錄檔案的屬性/權限等資料，其他重要項目為： 每個 inode 大小均固定為 128 bytes； 每個檔案都僅會佔用一個 inode 而已； 因此檔案系統能夠建立的檔案數量與 inode 的數量有關；

- 檔案的 block 在記錄檔案的實際資料，目錄的 block 則在記錄該目錄底下檔名與其 inode 號碼的對照表；

- 日誌式檔案系統 (journal) 會多出一塊記錄區，隨時記載檔案系統的主要活動，可加快系統復原時間；

- Linux 檔案系統為增加效能，會讓主記憶體作為大量的磁碟快取；

- 實體連結只是多了一個檔名對該 inode 號碼的連結而已；

- 符號連結就類似Windows的捷徑功能。

- 磁碟的使用必需要經過：分割、格式化與掛載，分別慣用的指令為：fdisk, mkfs, mount三個指令

- 開機自動掛載可參考/etc/fstab之設定，設定完畢務必使用 mount -a 測試語法正確否；

本章習題：

( 要看答案請將滑鼠移動到『答：』底下的空白處，按下左鍵圈選空白處即可察看 )

- 情境模擬題一：復原本章的各例題練習，本章新增非常多 partition ，請將這些 partition 刪除，恢復到原本剛安裝好時的狀態。

- 目標：瞭解到刪除分割槽需要注意的各項資訊；

- 前提：本章的各項範例練習你都必須要做過，才會擁有 /dev/hdc6, /dev/hdc7 出現；

- 需求：熟悉 fdisk, umount, swapoff 等指令。

由於本章處理完畢後，將會有 /dev/hdc6 與 /dev/hdc7 這兩個新增的 partition ，所以請刪除掉這兩個 partition 。 刪除的過程需要注意的是：

- 需先以 free / swapon -s / mount 等指令查閱， /dev/hdc6, /dev/hdc7 不可以被使用！ 如果有被使用，則你必須要使用 umount 卸載檔案系統。如果是記憶體置換空間，則需使用 swapon -s 找出被使用的分割槽， 再以 swapoff 去卸載他！

- 觀察 /etc/fstab ，該檔案不能存在這兩個 partition；

- 使用『 fdisk /dev/hdc 』刪除，注意，由於是邏輯分割槽，這些分割槽一定從 5 號開始連續編號，因此你最好不要從 6 號刪除！否則原本的 7 號在你刪除 6 號後，將會變成 6 號！因此，你應該由 7 號刪除掉，再刪除 6 號。

- 情境模擬題二：由於我的系統原本分割的不夠好，我的用戶希望能夠獨立一個 filesystem 附掛在 /srv/myproject 目錄下。 那你該如何建立新的 filesystem ，並且讓這個 filesystem 每次開機都能夠自動的掛載到 /srv/myproject ， 且該目錄是給 project 這個群組共用的，其他人不可具有任何權限。且該 filesystem 具有 5GB 的容量。

- 目標：理解檔案系統的建置、自動掛載檔案系統與專案開發必須要的權限；

- 前提：你需要進行過第七章的情境模擬才可以繼續本章；

- 需求：本章的所有概念必須要清楚！

那就讓我們開始來處理這個流程吧！

- 首先，我們必須要使用 fdisk /dev/hdc 來建立新的 partition ，由於本章之前範例的 partition 已經在上一個練習中刪除， 因此你應該會多出一個 /dev/hdc6 才對：『fdisk /dev/hdc』，然後按下『 n 』，按下『Enter』選擇預設的啟始磁柱， 按下『+5000M』建立 5GB 的磁碟分割槽，可以多按一次『p 』看看是否正確，若無問題則按下『w』寫入分割表；

- 避免重新開機，因此使用『 partprobe 』強制核心更新分割表；如果螢幕出現類似：『 end_request: I/O error dev fd0, sector 0 』的錯誤時，不要擔心啊！這個說明的是『找不到軟碟』，我們本來就沒有軟碟， 所以這個錯誤是可以忽略的。

- 建立完畢後，開始進行格式化的動作如下：『mkfs -t ext3 /dev/hdc6』，這樣就 OK 了！

- 開始建立掛載點，利用：『 mkdir /srv/myproject 』來建立即可；

- 編寫自動掛載的設定檔：『 nano /etc/fstab 』，這個檔案最底下新增一行，內容如下：

/dev/hdc6 /srv/myproject ext3 defaults 1 2

- 測試自動掛載：『 mount -a 』，然後使用『 df 』觀察看看有無掛載即可！

- 設定最後的權限，使用：『 chgrp project /srv/myproject 』以及『 chmod 2770 /srv/myproject 』即可。

簡答題部分：

- 如果由於你的主機磁碟容量不夠大，你想要增加一顆新磁碟，並將該磁碟全部分割成單一分割槽，且將該分割槽掛載到 /home 目錄， 你該如何處置？

詳細的流程可以分為硬體組裝、磁碟分割、格式化、資料搬移與掛載等。

- 安裝硬碟：關掉 Linux 主機電源，若為 IDE 介面時，需要處理跳針 (jump) ，放入主機後插好硬碟的排線與電源線，重新啟動電源；

- 磁碟分割：透過類似上述情境模擬二的動作，將整顆磁碟分割成單一主要分割槽，類似 /dev/sdb1 佔有全部容量；

- 格式化：透過 mkfs -t ext3 來格式化；

- 資料搬移：由於原本的 /home 還會有資料存在，因此你可以 mount /dev/sdb1 /mnt ，再將 /home 的資料複製到 /mnt/ 中，例如：『 cp -a /home/* /mnt 』即可。複製完畢後卸載 /home 以及 /mnt

- 重新掛載：編輯 /etc/fstab ，將 /home 所在的 filesystem 裝置改為 /dev/sdb1 之類的新分割槽，然後 mount -a 測試看看是否正確，如果正確的話，才是順利結束了這次的動作。

- 如果磁區 /dev/hda3 有問題，偏偏他是被掛載上的，請問我要如何修理此一磁區？

umount /dev/hda3

fsck /dev/hda3

- 我們常常說，開機的時候，『發現硬碟有問題』，請問，這個問題的產生是『filesystem 的損毀』，還是『硬碟的損毀』？

特別需要注意的是，如果您某個 filesystem 裡面，由於操作不當，可能會造成 Superblock 資料的損毀， 或者是 inode 的架構損毀，或者是 block area 的記錄遺失等等，這些問題當中，其實您的『硬碟』還是好好的， 不過，在硬碟上面的『檔案系統』則已經無法再利用！一般來說，我們的 Linux 很少會造成 filesystem 的損毀， 所以，發生問題時，很可能整個硬碟都損毀了。但是，如果您的主機常常不正常斷電，那麼， 很可能硬碟是沒問題的，但是，檔案系統則有損毀之虞。此時，重建檔案系統 (reinstall) 即可！ 不需要換掉硬碟啦！ ^_^

- 當我有兩個檔案，分別是 file1 與 file2 ，這兩個檔案互為 hard link 的檔案，請問， 若我將 file1 刪除，然後再以類似 vi 的方式重新建立一個名為 file1 的檔案， 則 file2 的內容是否會被更動？

這是來自網友的疑問。當我刪除 file1 之後， file2 則為一個正規檔案，並不會與他人共同分享同一個 inode 與 block ，因此，當我重新建立一個檔名為 file1 時，他所利用的 inode 與 block 都是由我們的 filesystem 主動去搜尋 meta data ，找到空的 inode 與 block 來建立的， 與原本的 file1 並沒有任何關連性喔！所以，新建的 file1 並不會影響 file2 呢！

參考資料與延伸閱讀

- 註1：根據The Linux Document Project的文件所繪製的圖示，詳細的參考文獻可以參考如下連結：

Filesystem How-To: http://tldp.org/HOWTO/Filesystems-HOWTO-6.html

- 註2：參考維基百科所得資料，連結網址如下：

條目： Ext2 介紹 http://en.wikipedia.org/wiki/Ext2

- 註3：PAVE為一套秀圖軟體，常應用於數值模式的輸出檔案之再處理：

PAVE 使用手冊： http://www.ie.unc.edu/cempd/EDSS/pave_doc/index.shtml

- 註4：詳細的 inode 表格所定義的旗標可以參考如下連結：

John's spec of the second extended filesystem: http://uranus.it.swin.edu.au/~jn/explore2fs/es2fs.htm

- 註5：參考 Ext2 官網提供的解說文件，這份文件非常值得參考的！

文章名稱：『Design and Implementation of the Second Extended Filesystem 』

http://e2fsprogs.sourceforge.net/ext2intro.html

- 註6：Red Hat 自己推出的白皮書內容：

文章名稱：Whitepaper: Red Hat's New Journaling File System: ext3

http://www.redhat.com/support/wpapers/redhat/ext3/

- 註7：其他值得參考的 Ext2 相關檔案系統文章之連結如下：

The Second Extended File System - An introduction: http://www.freeos.com/articles/3912/

ext3 or ReiserFS? Hans Reiser Says Red Hat's Move Is Understandable

http://www.linuxplanet.com/linuxplanet/reports/3726/1/ 檔案系統的比較：維基百科：http://en.wikipedia.org/wiki/Comparison_of_file_systems

- 註8：NTFS 檔案系統官網：Linux-NTFS Project: http://www.linux-ntfs.org/

- 註9： Linux 核心所支援的硬體之裝置代號(Major, Minor)查詢：

http://www.kernel.org/pub/linux/docs/device-list/devices.txt

- 註10：與 Boot sector 及 Superblock 的探討有關的討論文章：

The Second Extended File System: http://www.nongnu.org/ext2-doc/ext2.html

Rob's ext2 documentation: http://www.landley.net/code/toybox/ext2.html

Life is different blog: ext2文件系統分析： http://www.qdhedu.com/blog/post/7.html

2002/07/15：第一次完成

2003/02/07：重新編排與加入 FAQ

2004/03/15：修改 inode 的說明，並且將連結檔的說明移動至這個章節當中！

2005/07/20：將舊的文章移動到 這裡 。

2005/07/22：將原本的附錄一與附錄二移動成為附錄 B 啦！

2005/07/26：做了一個比較完整的修訂，加入較完整的 ext3 的說明∼

2005/09/08：看到了一篇討論，說明 FC4 在預設的環境中，使用 mkswap 會有問題。

2005/10/11：新增加了一個目錄的 link 數量說明！

2005/11/11：增加了一個 fsck 的 -f 參數在裡頭！

2006/03/02：參考：這裡的說明，將 ext2/ext3 最大檔案系統由 16TB 改為 32TB。

2006/03/31：增加了虛擬記憶體的相關說明在 這裡

2006/05/01：將硬碟磁區的圖做個修正，感謝網友 LiaoLiang 兄提供的資訊！並加入參考文獻！

2006/06/09：增加 hard link 不能連結到目錄的原因，詳情參考：http://phorum.study-area.org/viewtopic.php?t=12235

2006/06/28：增加關於 loop device 的相關說明吶！

2006/09/08：加入 mknod 內的裝置代號說明 ，以及列出 Linux 核心網站的裝置代號查詢。

2008/09/29：原本的FC4系列文章移動到此處

2008/10/24：由於軟碟的使用已經越來越少了，所以將 fdformat 及 mkbootdisk 拿掉了！

2008/10/31：這個月事情好多∼花了一個月才將資料整理完畢！修改幅度非常的大喔！

2008/11/01：最後一節的利用 GNU 的 parted 進行分割行為誤植為 GUN ！感謝網友阿賢的來信告知！

2008/12/05：感謝網友 ian_chen 的告知，之前將 flash 當成 flush 了！真抱歉！已更新！

2009/04/01：感謝討論區網友提供的說明， 鳥哥之前 superblock 這裡寫得不夠好，有訂正說明，請幫忙看看。

2009/08/19：加入兩題情境模擬，重新修訂一題簡答題。

2009/08/30：加入 du 的 -S 說明中。

2002/06/26以來統計人數

Table of Contents

第零章、計算機概論

第一章、Linux是什麼

第二章、Linux如何學習

第三章、主機規劃與磁碟分割

第四章、安裝CentOS5.x與多重開機小技巧

第五章、首次登入與線上求助manpage

第六章、Linux的檔案權限與目錄配置

第七章、Linux檔案與目錄管理

第八章、Linux磁碟與檔案系統管理

第九章、檔案與檔案系統的壓縮與打包

第十章、vim 程式編輯器

第十一章、認識與學習 BASH

第十二章、正規表示法與文件格式化處理

第十三章、學習 Shell Scripts

第十四章、Linux 帳號管理與 ACL 權限設定

第十五章、磁碟配額(Quota)與進階檔案系統管理

第十六章、例行性工作排程 (crontab)

第十七章、程序管理與 SELinux 初探

第十八章、認識系統服務 (daemons)

第十九章、認識與分析登錄檔

第二十章、開機流程、模組管理與 Loader

第二十一章、系統設定工具(網路與印表機)與硬體偵測

第二十二章、軟體安裝：原始碼與 Tarball

第二十三章、軟體安裝： RPM, SRPM 與 YUM 功能

第二十四章、 X Window 設定介紹

第二十五章、 Linux 備份策略

第二十六章、Linux 核心編譯與管理

基礎學習篇快速索引

附錄A:GPL條文

附錄B:ext2/ext3

一個簡單的 SPFdisk 分割實例

電腦：輔助人腦的好工具

電腦硬體的五大單元

CPU的種類

周邊設備

運作流程

電腦分類

電腦上面常用的計算單位 (容量、速度等)

個人電腦架構與周邊設備

CPU

CPU的外頻與倍頻

32位元與64位元

CPU等級

記憶體

顯示卡

硬碟與儲存設備

PCI介面卡

主機板

電源供應器