Linux 基礎學習篇 - Mandrake 9

第十章、認識 BASH Shell - for Mandrake 9

鳥哥的第一本書籍的主要內容,內容稍微與書籍不太一樣了!

最近更新時間: 2003/02/10

鳥哥的第一本書大約是在 2002 年的年底左右出版的,內容幾乎都是 Linux 基礎學習,一點也沒有談到伺服器的部份!這也是後來的雛型! 不過內容錯誤的地方很多,導致在 2003 年的年底推出了『基礎學習篇增訂版』的內容,大致上就是處理掉一些比較有嚴重錯誤的部份。 不過,因為 Linux 的版本變化非常快速,因此,寫完了這些文件之後,鳥哥還是持續在網站上更新文件內容,導致原本書籍內容的資料與網站資料差異太大! 這個問題直到鳥哥在 2008 年左右才發現!糟糕了!舊版的文件資料已經遺失~覺得相當扼腕~

因此,在底下的文件內容與當初的書籍內容雖然大同小異,不過章節的編排卻是有所不同!再花時間去一個一個處理,似乎也不太符合成本效益! 鳥哥僅是想要將自己以前的文件記錄下來而已,同時將過時的 big5 編碼改回 utf8 編碼,再加上可以支援 RWD 的樣式而已啦! 內容已經不多做編排~因此,如果內容文件你看不懂,那也是應該的! ^_^

建議您前往本站查詢最新版本的 Linux distribution 文章來閱讀,比較不會浪費時間。最新文章請前往鳥站首頁查閱囉!

什麼是 Shell

這應該是個蠻有趣的話題:『什麼是 Shell ?』相信只要摸過電腦,對於作業系統(不論是 Linux 、 Unix 或者是 Windows )有點概念的朋友們大多聽過這個名詞,因為只要有『作業系統』那麼就離不開 Shell 這個東西。不過,在討論 Shell 之前,我們先來瞭解一下電腦的運作狀況吧!舉個例子來說:當你要電腦傳輸出來『音樂』的時候,你的電腦需要什麼東西呢
  1. 當然就是需要你的硬體有『音效卡晶片』這個硬體配備,否則怎麼會有聲音;
  2. 作業系統的核心可以支援這個晶片組,當然還需要提供晶片的驅動程式囉;
  3. 需要使用者(就是你)輸入發生聲音的指令囉!
這就是基本的一個輸出聲音的需要的步驟!那麼也就是說,你必須要『輸入』一個指令之後,『硬體』才會透過你下達的指令來工作!嘿嘿!那麼硬體如何知道你下達的指令呢?那就是 kernel (核心)的控制工作了!瞭解了嗎?沒錯!也就是說,我們必須要透過『 Shell 』將我們輸入的指令與 Kernel 溝通,好讓 Kernel 可以控制硬體來正確無誤的工作!基本上,我們可以透過底下這兩張圖來說明一下:

基本上,替我們工作的是『硬體』,而控制硬體的是『核心』,再來,我們使用者乃是利用『Shell』控制一些 kernel 提供的 『工具 Utility』來操控硬體替我們正確的工作。再進一步來說,由於 kernel 聽不懂人類的語言,而人類也沒有辦法直接記得 kernel 的語言,所以兩者的溝通就得藉由 shell 來支援了!(其實早期的 DOS 的文字介面也是使用 shell 來溝通呀!那個 shell 的名稱就叫做 command.com ,還記得嗎? ^_^)
 
以字面上的意思來說, kernel 是『核心』的意思,而 Shell 是『殼』的意思,呵呵!也就是說, shell 是最外頭的咚咚!而 kernel 乃是最內層的的咚咚啦!核心是作業系統的最底層的東西!這個核心裡頭包括了各種的支援硬體的工具!當然囉,如果你的硬體太新,而你的 kernel 並沒有支援的話,那麼很抱歉,你的 Shell 能力再怎麼強,也沒有辦法使硬體工作的!這樣可以瞭解了嗎?呵呵!沒錯!使電腦主機工作的正是核心的任務,但是操作核心來替使用者工作的,卻是 shell 喔!因此,有時候你的 shell 搞了老半天,硬體卻不能工作的時候,請注意,您的『核心』是否正確呢?阿!扯遠了!這是 kernel 章節才要說的東西??
  • 我幹嘛要學習 Shell 呢?

  • 常常聽到這個問題:『我幹嘛要學習 shell 呢?不是已經有很多的工具可以提供我設定我的主機了?我為何要花這麼多時間去學指令呢?不是以 X-Window 按一按幾個按鈕就可以搞定了嗎?為什麼要這麼麻煩?』唉?還是得一再地強調,X-Window 還有 Web 介面的設定工具例如 webmin 是真的好用的傢伙,他真的可以幫助我們很簡易的設定好我們的主機,甚至是一些很進階的設定都可以幫我們搞定。但是 VBird 在序章裡面也已經提到過相當多次了, X-Window 的介面雖然親善,功能雖然強大,而 web 介面的工具也可以提供我們很友善的服務,但是畢竟他是整合的一個套件而已,並非是一個完整的套件,所以某些時候當你升級或者是使用其他套件管理模組( 例如 tarball 而非 rpm 檔案等等 )時,就會造成設定的困擾了,此外,遠端連線時,文字介面的傳輸速度一定比較快,而且,較不容易出現斷線或者是資訊外流的問題,因此, shell 真的是得學習的一項工具。而且,他可以讓您更深入 Linux ,更瞭解他,而不是只會按一按滑鼠而已!所謂『天助自助者!』多摸一點文字模式的東西,會讓你與 Linux 更親近呢!
     
    有些朋友也很可愛,常會說:『我學這麼多幹什麼?又不常用,也用不到!』嘿嘿!有沒有聽過『書到用時方恨少?』當你的主機一切安然無恙的時候,您當然會覺得好像學這麼多的東西一點幫助也沒有呀!萬一,某一天真的不幸給他中標了,您該如何是好?是直接重新安裝?還是先追蹤入侵來源後進行漏洞的修補?或者是乾脆就關站好了?這當然涉及很多的考量,但就以 VBird 的觀點來看,多學一點總是好的,尤其我們可以有備而無患嘛!甚至學的不精也沒有關係,瞭解概念也就 OK 啦!畢竟沒有人要您一定要被這麼多的內容啦!瞭解概念就很了不起了!
     
    此外,如果您真的有心想要將您的主機管理的好,那麼良好的 shell 程式編寫是一定需要的啦!就 VBird 來說,我管理的主機雖然還不算多,只有區區不到十部,但是如果每部主機都要花上幾十分鐘來查閱他的 log file 以及相關的資訊,那麼我可能會瘋掉!基本上,也太沒有效率了!這個時候,如果能夠藉由 shell 提供的命令重導向( 或稱資料流重導向 ),以及管線命令,呵呵!那麼我分析 log file 只要花費不到十分鐘就可以看完所有的主機之重要資訊了!相當的好用呢!
     
    由於學習 shell 的好處真的是多多啦!所以,如果您是個系統管理員,或者有心想要管理系統的話,那麼 shell 這個東西與 shell scripts 這個東西,真的真的有必要看一看!

BASH Shell

知道什麼是 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 的簡單歷史吧:第一個流行的 shell 是由 Steven Bourne 發展出來的,為了紀念他所以就稱為 Bourne shell ,或直接簡稱為 sh !而後來另一個廣為流傳的 shell 是由柏克萊大學的 Bill Joy 設計依附於 BSD 版的 Unix 系統中的 shell ,這個 shell 的語法有點類似 C 語言,所以才得名為 C shell ,簡稱為 csh !由於在學術界 Sun 主機勢力相當的龐大,而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一個很重要而且流傳很廣的 shell 之一(因為太多的程式設計師使用的就是 C 語言啦!)!

好了,那麼 BASH 是怎麼一回事呢?這個 shell 是 GNU 計畫中重要的工具軟體之一,目前也是 GNU 作業系統中標準的 shell ,他主要相容於 sh ,並且依據一些使用者需求,而加強的 shell 版本,可以說目前幾乎所有的 Linux distribution 都是使用 bash 作為管理核心的主要 shell !因此,不論您使用的是那個 distribution ,你都難逃需要學習 bash 的宿命啦!那麼這個 shell 有什麼好處,幹嘛 Linux 要使用他作為預設的 shell 呢? BASH 主要的優點有底下幾個:

  • 命令編修能力(類似 DOS 的 doskey 功能):

  • 使用 bash 裡頭,個人認為相當棒的一個功能就是『他能記憶使用過的指令!』這功能真的相當的棒!因為我只要在指令列按『上下鍵』就可以找到前一個輸入的指令!而在 Mandrake 9.0 預設的指令記憶功能可以到達 1000 個!也就是說,你曾經下達過的指令都被記錄下來了,記錄的檔案在你的家目錄內的 .bash_history !不過,需要留意的是, ~/.bash_history 記錄的是前一次登入以前所執行過的指令,而至於這一次登入所執行的指令都被暫存在暫記憶體中,當您成功的登出系統後,該指令記憶才會記錄到 .bash_history 當中!這有什麼功能呢?最大的好處就是可以『查詢曾經做過的舉動!』,如此可以知道你的執行步驟,那麼就可以追蹤您曾下達的指令,以作為除錯的工具!但如此一來也有個煩惱,就是如果被駭客入侵了,那麼他只要翻你曾經執行過的指令,剛好你的指令又跟系統有關(例如直接輸入 MySQL 的密碼在指令列上面)那麼很容易就被破解你的 Linux 主機!所以,最好是將記錄的指令數目減小一點較好
  • 檔案比對補全功能(比對資料正確性):

  • 這個功能也相當的棒!主要分為指令補全與檔案名稱補全:
    • 指令補全:如果在執行命令的時候不想按下太多的按鍵,例如指令 pcprofiledump 夠長吧!好了,那麼如果你輸入了 pcprofile 之後,再按下 [Tab] 按鍵的話,那麼 bash 馬上會自動的將後面的 dump 接上來!那如果有重複的指令呢?那麼按下兩次 [Tab] 將會把所有重複的指令給他列出來囉!那麼就有個特殊的案例啦,就是『直接在提示字元後面連按兩次 <tab> 鍵,則系統會將所有可以使用的指令都列出來!』那麼如果我想要知道目前系統裡面,所以 b 開頭的指令呢?呵呵!就是按下 b 之後,連按兩次 <tab> 就可以知道啦!
    • 檔案名稱補全:此外,如果你用 vi 來讀取某個檔案時,例如 /etc/man.config 這個檔案好了,那麼您可以輸入 vi /etc/man. 之後,直接按下 <tab> 按鍵,那麼該檔案名稱就會被自動的補齊囉!呵呵!很方便,而且對於檔案名稱或者指令名稱的正確性上面,幫助還蠻大的吧!是的!真的是很方便的功能,所以,有事沒事,在 bash shell 底下,多按幾次 <tab> 是一個不錯的習慣啦
  • 命令別名(alias)設定功能:

  • 假如我需要知道這個目錄底下的所有檔案(包含隱藏檔)及所有的檔案屬性,那麼我就必須要下達 ls -al 這樣的指令列,唉!真麻煩,有沒有更快的取代方式?呵呵!就使用命令別名呀!例如我最喜歡直接以 lm 這個自訂的命令來取代上面的命令,也就是說, lm 會等於 ls -al 這樣的一個功能,嘿!那麼要如何作呢?就使用 alias 即可!你可以在指令列輸入 alias 就可以知道目前的命令別名有哪些了!也可以直接下達命令來設定別名呦:
      alias lm='ls -al'
  • 工作控制(jobs)、前景背景控制:

  • 這部分我們在之後的資源管理章節中會再提及!使用前、背景的控制可以讓工作進行的更為順利!至於工作控制(jobs)的用途則更廣,可以讓我們隨時將工作丟到背景中執行!而不怕不小心使用了 [Ctrl] + C 來停掉該程序!真是好樣的!此外,也可以在單一登入的環境中,達到多工的目的呢!
  • Shell scripts 的強大功能:

  • 在 DOS 年代還記得將一堆指令寫在一起的所謂的『批次檔』吧?在 Linux 底下的 shell scripts 則發揮的更為強大的功能,可以將您日常生活當中常需要下達的連續指令寫成一個檔案,該檔案並且可以透過對談互動式的方式來進行主機的偵測工作!也可以藉由 shell 提供的環境變數及相關指令來進行設計,哇!整個設計下來幾乎就是一個小型的程式語言了!該 scripts 的功能真的是超乎我的想像之外!以前在 DOS 底下需要程式語言才能寫的東西,在 Linux 底下使用簡單的 shell scripts 就可以幫你達成了!真的利害!!這部分我們在後續章節再來談!
在瞭解了 BASH 的優點之後,再來我們要來討論的是:那如何在 Shell 提供的環境中下達指令呢?其實很簡單的,下達指令的方式為:
[root@test /root]# command [-options] parameter1 parameter2 ...
                     指令     選項      參數(1)    參數(2)

1. command 為指令的名稱,例如變換路徑的指令為 cd 等等;
2. 中刮號[]並不存在於實際的指令中,而加入參數設定時,通常為 - 號,有時候完整名稱會輸入 -- 符號;
3. parameter1 parameter2.. 為依附在 option 後面的參數,或者是 command 的參數;
4. command, -options, parameter1.. 這幾個咚咚中間以空格來區分,不論空幾格 shell 都視為一格;
5. 指令太長的時候,可以使用 \ 符號來跳脫 [Enter] 符號,使指令連續到下一行。

實例:
[root@test /root]# ls -al /root   <==以 ls 列出 /root 這個目錄中的隱藏檔與相關的屬性參數;
[root@test /root]# ./configure --prefix=/usr/local --with-tcp_wrappers \
> --with-pam     <==這兩行實際上是同一行的指令,但是加上 \ 跳脫符號後,指令可以連續到下一行!
[root@test /root]# ls           -al   /root  <==這個指令與第一個相同,空白字元不論幾個,僅視為一個來處理。

很簡單吧!OK!那麼再來一個問題:『Shell 是什麼時候開始接管 Linux 主機的!?』我們在後面會再提到『開機流程』的介紹,這裡先跳過去,假設你的機器已經開機成功了,那麼主機便進入等待使用者 login 的狀態。當使用者輸入了帳號與密碼,並且順利的 pass 之後,經過了 shell 的環境變數檔案讀取功能,最後,使用者進入自己的『家目錄』之後,例如 root 的家目錄在 /root 底下,一般使用者的家目錄則在 /etc/passwd 這個檔案裡面規定,那麼主機就已經丟了一個程序稱為 bash 的給你操作囉!

變數與變數的設定:echo, env, set, 變數設定規則, export, unset

再繼續研究 BASH 之前,我們要就變數這個東西來討論一番,因為在主機裡面有太多的資料需要進行存取了,而這些資料都是一些服務所必須的,例如 mail 的存取路徑在 /var/spool/mail 、家目錄預設在 /home/useraccount 等等,當然我們可以改變這些個變數,但是如果該變數是直接深植於套件當中,那麼當你修改了某些參數之後,嘿嘿!你的套件就必須要『由原始碼直接更新再編譯』才行!這樣似乎很麻煩,所以囉,就會有變數這個好東西出來了!
 
舉個簡單的例子來說, sendmail 的 smtp 存放 mail 路徑是經由 /etc/profile 裡頭的
MAIL="/var/spool/mail/$USER"
來設定的,而當我修改了上面這一個咚咚,然後重新開機之後,嘿嘿嘿嘿!我的郵件就可以存放到不同的路徑去了!而且不會有問題!可以順利的『在 Linux 主機上面』收發。然而問題發生在 pop3 這個服務上面,由於 pop3 的預設路徑是在 source code 裡頭,而且就正是 /var/spool/mail 這個路徑,也就是說,不論我怎麼修正我的『變數』, pop3 都不為所動!唉~真慘,所以就無法直接以 pop3 來收信了(例如 OutLook 就不能工作了)!會發生密碼不接受的問題呢!
此外,例如我們在執行程式的時候,系統怎麼知道你的 ls 這個指令放在哪裡?原來是有 PATH 這個變數,系統會透過這個變數裡面所設定的路徑去依序尋找該指令系統,如果找不到的話,那麼才在螢幕上顯示『 command not found 』字樣!這些還都只是系統預設的變數的目的,如果是個人的設定方面:例如你要寫一個大型的 script (批次檔)時,有些資料因為可能由於使用者習慣的不同而有差異,比如說路徑好了,由於該路徑在 script 被使用在相當多的地方,如果下次換了一部主機,都要修改 script 裡面的所有路徑,那麼我一定會瘋掉!這個時候如果使用變數,而將該變數的定義寫在最前面,後面相關的路徑名稱都以變數來取代,嘿嘿!那麼你只要修改一行就等於修改整篇 script 了!方便的很!所以,良好的程式設計師都會善用變數的定義!(這個部分我們在底下還會再提到!)
 
如果說的學理一點,那麼由於在 Linux System 下面,所有的執行續都是需要一個執行碼,而就如同上面提到的,你『真正以 shell 來跟 Linux 溝通,是在正確的登入 Linux 之後!』這個時候你就有一個 bash 的執行程序,也才可以真正的經由 bash 來跟系統溝通囉!而在進入 shell 之前,也正如同上面提到的,由於系統需要一些變數來提供他資料的存取(或者是一些環境的設定參數值,例如是否要顯示彩色等等的),所以就有一些所謂的『環境變數』需要來讀入系統中了!這些環境變數例如 PATH、HOME、MAIL、SHELL等等,都是很重要的,為了區別與自訂變數的不同,環境變數通常以大寫字元來表示呢!
 
說了那麼久,那麼到底『什麼是變數』呢?簡單的說,『變數就是以一組文字或符號等,來取代一些設定或者是一串保留的資料!』,例如:『VBird』就是『鳥哥』,所以當你讀取 VBird 的時候,系統自然就會知道!哈!那就是鳥哥!最簡單的例子可以取 PATH 來說明!如果你對於『相對路徑與絕對路徑』還有點印象的話,那麼應該曉得『要下達正確的指令,應該需要指定路徑與檔名』才行!例如你的 ls 指令應該需要以『/bin/ls』來下達指令才對,那麼為何你在任意的路徑下都可以執行 ls 呢?而不需要指定路徑呢?這是因為系統已經預設了一些『搜尋路徑(PATH)』了,所以當你需要執行一些指令的時候,系統就會依照該 PATH 的設定來進行指令的搜尋!而這個 PATH 就是所謂的變數了!那麼如何『顯示變數』呢?這就需要使用到 echo 這個指令啦!

  • echo

  • 顯示變數內容
    語法
    [test @test test]# echo $variable
    參數說明:
    範例:
    [test @test test]# echo $PATH
    /bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/loc
    al/bin:/bin:/usr/bin:/usr/X11R6/bin
    就如同上面的範例,當我們要顯示目前的 PATH 這個變數時,使用了 echo ,而為了要分辨是否為變數,那麼 Linux 系統預設變數名稱前面會加上一個『 $ 』符號,所以就必須要寫成 echo $PATH 囉!
    例題:請在螢幕上面顯示出您的環境變數 PATH, HOME 與 MAIL:
    答:
    [root@test root]# echo $PATH
    /sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
    [root@test root]# echo $HOME
    /root
    [root@test root]# echo $MAIL
    /var/spool/mail/root



    有多少的環境變數呀?使用 env 與 set 來看看:
    嗯!既然環境變數是挺重要的,那麼到底有多少的環境變數在 Linux 系統中呢?呵呵!你可以簡單的使用 env 就可以知道囉!『基本上,在 Linux 預設的情況中,使用{大寫的字母}來設定的變數一般為系統內定需要的變數』,底下列出 Linux 系統中 預設的變數內容:

  • env

  • 顯示目前系統中主要的預設變數內容
    語法
    [test @test test]# env
    ENV=/root/.bashrc             <==使用者自訂環境變數的設定檔案
    HISTSIZE=1000                 <==目前的指令記憶數量
    HOME=/home/test               <==登入者的家目錄
    HOSTNAME=test.adsldns.org  <==這部主機的主機名稱
    HOSTTYPE=i386              <==這部主機的硬體等級大致狀態(i386, i686..)
    INPUTRC=/etc/inputrc          <==一些 shell 載入的資料檔案設定處
    LANGUAGE=C                    <==預設語系的資料
    LANG=zh_TW.Big5 
    與 LANGUAGE 類似,這個則是各個 linux distribution 常用的預設語系變數,由於我的 Mandrake 使用中文安裝,所以預設語系是中文,亦即 zh_TW.Big5 ,如果我要修改這個變數,可以到 /etc/sysconfig/i18n 去修改!底下的 LC_xxx 均是與預設的表示語系有關的變數,其中比較有趣的是 LC_TIME ,如果在文字介面下,最好將 LC_TIME 改成美規日期的顯示方式,才不會有亂碼!
    LC_COLLATE=zh_TW.Big5
    LC_CTYPE=zh_TW.Big5
    LC_MESSAGES=zh_TW.Big5
    LC_MONETARY=zh_TW.Big5
    LC_NUMERIC=zh_TW.Big5
    LC_TIME=en
    LESSOPEN=|/usr/bin/lesspipe.sh %s <==用來設定 less 使用的一支 script 檔案
    LOGNAME=test                  <==登入者的帳號

    MACHTYPE=i586-mandrake-linux-gnu 
    主機的硬體配備等級 i586 為 P MMX 等級,至於 K7 及 PIII 之後的,就是 i686 等級囉!

    MAIL=/var/spool/mail/test     <==登入者的郵件預設放置地點
    OSTYPE=linux-gnu              <==作業系統的形式(linux-gnu)
    PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/test/bin
    PWD=/home/test                <==目前登入者所在的目錄(當下的目錄)
    SHELL=/bin/bash               <==登入者使用的 shell 類型
    USER=test                  <==目前這個登入者的使用者名稱

    env environment 的簡寫,所以說,這個指令主要在將目前系統中的主要變數讀出來!但是,不是說我們還可以自訂變數嗎?因此,除了 env 這個讀取環境變數的指令之外,還有一個可以將目前系統中所有的變數資料都讀出來的指令,稱為 set !set 除了會將上面的資料都給他讀出來之外,還會有額外的這些資訊也一起讀入(通常都與使用者的設定有關!)
     

  • set

  • 顯示目前系統中全部的變數內容
    語法
    [test @test test]# set
    BASH=/bin/bash                         <==BASH 的主程式放置路徑
    BASH_VERSINFO=([0]="2" [1]="05" [2]="8" [3]="1" [4]="release" [5]="i386-redhat-linux-gnu") <==BASH 版本資訊
    BASH_VERSION=$'2.05.8(1)-release'      <==BASH 的版本
    COLORS=/etc/DIR_COLORS                 <==使用顏色
    COLUMNS=100                         <==目前這個終端機使用的欄位有幾個字元距離
    HISTFILE=/home/vbird/.bash_history  <==目前用來存過往指令的檔案,為一個隱藏檔
    HISTFILESIZE=1000                   <==存起來的檔案中,指令的最大數(只紀錄 1000 個指令)
    IFS=$' \t\n'                        <==預設的分隔符號
    langfile=/home/vbird/.i18n             <==語系選擇的檔案
    LINES=40                               <==目前游標所在的位置為第幾行
    MAILCHECK=60                           <==每隔多久檢查一次有無新信件(秒數)
    PPID=24572                             <==目前 bash 這個父程序的 ID !
    PROMPT_COMMAND=$'echo -ne "\\033]0;${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\\007"'      <==提示字元顯示的內容
    SHELLOPTS=braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs
    SUPPORTED=zh_TW.Big5:zh_TW:zh:en_US:en      <==支援的語系
    TERM=xterm                                  <==終端機形式
    UID=500                                 <==登入者的使用者 ID (UID)
    $                                           <==目前 shell 的 PID 

    最後一個命令的回傳值,若之前的命令被正確的執行會傳回 0 ,否則會傳為 1 或其他錯誤代碼。
    set 的輸入就是直接輸入 set 即可!他除了會顯示出目前的『環境變數』之外,也會顯示出您的『自訂變數』呢!那麼有哪些與使用者較有相關性的自訂變數呢?我們上面僅列出部分常見的變數值囉!
     
    使用 set 除了會將系統的預設值秀出來之外,連帶的所有的你自己設定的變數也會被秀出來!同時需要注意的是,若當時有相當多人同時在線上的話,那麼你的變數只能給自己使用(除非改的是系統的預設參數檔,如 /etc/profile ),而不會干擾到別人的!就如同前面所說的,由於你登入 Linux 之後會取得一個 PID ,而你的設定將只對這個 PID 與子程序有關!此外,這次登入所進行的變數設定,如果沒有更動到設定檔,那麼這次設定的變數在下次登入時將被取消掉(因為程序 PID 不見囉!)!所以囉,如果你想要你的變數每次都能在你登入的時候自動就設定好了,那麼就必須將你的設定寫入登入時載入的設定檔
     
    上面的變數中,比較有趣的是 $ 與 ? 這兩個咚咚,尤其是 ? 這個變數,如果您上一個命令執行的過程中沒有錯誤,那麼這個變數就會被設定為 0 ,如果您的上個命令有錯誤訊息,那麼這個變數會變成 1 或其他的錯誤代碼!現在馬上動手試看看您的上個指令執行成果為何?
     
      echo $?
       

  • 變數設定規則:

  • 好了,我們知道了一些系統的預設變數了,但是如果是我自己想要設定一些我自己的變數,該如何設定呢?有什麼規則需要遵守?呵呵!在說明之前,可能要來讓大家瞭解一下為什麼自己會想來設定變數?
      我的案例:最簡單的例子就是『路徑名稱』囉!以鳥哥為例,我的工作在 Unix 系統之下進行一些數值模式的模擬工作,偏偏由於資料量太大,為了怕日後忘記這個目錄的內容與主要的意義,所以我的檔名都取的很長,偏偏在執行模式的過程中,常常會切換目錄!我哩ㄌㄟ,光是打那幾行路徑名稱就快要瘋掉了!所以我就設定那幾行目錄名稱成為一個四個字元的變數,如此一來我只要輸入『 cd $VARI 』這個指令,嘿嘿!馬上就移動到該路徑下了!很方便吧!當然變數的意義還不止於此,不過這是最簡單的實例說明囉!
      我的案例二:另外一個常常需要變數的咚咚是在 scripts 裡面,例如我寫的一個偵測登錄檔的小程式 logfile.sh 這個咚咚,由於裡頭常常需要用到『儲存路徑』,偏偏可能每個人的存取路徑都不太一樣,而如果要修改存取路徑的話,嘿嘿!好幾十行要同時修改呢!還可能會改錯!那麼我只要定義一個變數,然後後續的所有資料都使用這個變數的內容!嘿嘿!那麼只要大家修改了這個變數的內容(只要一行),後續的動作就不需要修正了!這個動作常在程式或者是 script 當中看到的!
      所以囉,有很多的時候為了方便或者是使用於 scripts 的意義,我們必須要設定變數!然而在 bash 底下的變數設定是有一定規則的,必須要來遵守才行:
      1. 變數與變數內容以等號『=』來連結;
      2. 等號兩邊不能直接接空白字元;
      3. 變數名稱只能是英文字母與數字,但是數字不能是開頭字元;
      4. 若有空白字元可以使用雙引號『 " 』或單引號『 ' 』來將變數內容結合起來,但須要特別留意,雙引號內的特殊字元可以保有變數特性,但是單引號內的特殊字元則僅為一般字元;
      5. 必要時需要以跳脫字元『 \ 』來將特殊符號(如Enter, $, \, 空白字元, '等)變成一般符號;
      6. 在一串指令中,還需要藉由其他的指令提供的資訊,可以使用 quote 『 ` command` 』;(特別特別注意,那個 ` 是數字鍵 1 左邊那個按鍵,而不是單引號!)
      7. 若該變數為擴增變數內容時,則需以雙引號及 $變數名稱 如:『 "$PATH":/home』繼續累加內容;
      8. 若該變數需要在其他子程序執行,則需要以 export 來使變數可以動作,如『export PATH』;
      9. 通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷(純粹依照使用者興趣與嗜好);
      10. 取消變數的方法為:『unset 變數名稱』。


      底下我們舉幾個例子來說明一下:
       

      一般變數設定:
      [tets @test test]# 12name=VBrid           <==錯誤的!因為變數開頭不能是數字!
      [test @test test]# name = VBird                  <==錯誤的!因為等號兩邊不能直接接空白!
      [test @test test]# name=VBird                    <==正確的!echo $name 顯示 VBird
      [test @test test]# name=VBird name           <==錯誤的!需要加上雙引號!不然會顯示錯誤!
      [test @test test]# name="VBird name"             <==正確的!echo $name 顯示 VBird name
      [test @test test]# name="VBird's name"          <==正確的!

      變數累加設定:
      [test @test test]# name=$nameisme         <==錯誤的!需要以雙引號將原變數圈起來
      [test @test test]# name="$name"isme       <==正確的!echo $name 顯示 VBird's nameisme
      [test @test test]# PATH="$PATH":/home/test       <==正確的!echo $PATH 將多了後面一句話!
      [test @test test]# PATH="$PATH:/home/test"       <==正確的!這個形式對於 PATH 來說也是正確的格式!

      變數延伸到下一個子程序:
      [test @test test]# name="VBird's name"     <==設定 name 這個變數
      [test @tset test]# echo $name                 <==顯示 name 變數的指令
      [test @test test]# VBird's name
      [test @test test]# /bin/bash                  <==另開一個 bash 的子程序
      [test @tset test]# echo $name                 <==顯示 name 這個變數
      [test @tset test]#                        <==會顯示空字串因為 name 這個變數不能使用在子程序
      [test @test test]# exit                       <==退出子程序 bash shell !
      [test @test test]# export name                <==正確的!如此則 $name 可以用於下一個子程序中!

      指令中的指令:
      [test @test test]# cd /lib/modules/`uname –r`/kernel
      上式中,會先執行 `uname –r` 這個內含指令,然後輸出的結果附加在 /lib/module… 裡面,所以執行這個指令,可以完成幾個附指令程序!

      取消變數設定:
      [test @test test]# unset name

       
      根據上面的案例你可以試試看!就可以瞭解變數的設定囉!這個是很重要的呦!請勤加練習!!其中,較為重要的一些特殊符號的使用囉!例如單引號、雙引號、跳脫字元、錢字號、quote 符號等等,底下的例題想一想吧!
       
      例題:在變數的設定中,單引號與雙引號有什麼不同呢?
      答:
      單引號與雙引號的最大不同在於雙引號仍然可以保有變數的內容,但單引號內僅能是一般字元,而不會有特殊符號。我們以底下的例子做說明:假設您定義了一個變數, name=VBird ,現在想以 name 這個變數定義出 myname 顯示 VBird its me 這個內容,要如何訂定呢?
      [root @test root]# name=VBird
      [root @test root]# echo $name
      VBird
      [root @test root]# myname="$name its me"
      [root @test root]# echo $myname
      VBird its me
      [root @test root]# myname='$name its me'
      [root @test root]# echo $myname
      $name its me
      發現了嗎?沒錯!使用了單引號的時候,那麼 $name 將失去原有的變數內容,僅為一般字元的顯示型態而已!這裡必需要特別小心在意!
       
      例題:在指令下達的過程中, quote ( ` ) 這個符號代表的意義為何?
      答:
      在一串指令中,在 ` 之內的指令將會被先執行,而其執行出來的結果將做為外部的輸入資訊!例如 uname –r 會顯示出目前的核心版本,而我們的核心版本在 /lib/modules 裡面,因此,你可以先執行 uname –r 找出核心版本,然後再以『 cd 目錄』到該目錄下,當然也可以執行
      cd /lib/modules/`uname –r`
      直接到該目錄下去!
       
      底下我們來談一談 export 的用途吧!

  • export

  • 當你取得一個 bash 之後,亦即得到了一個程序了,但是若你再次的執行一次 bash ,那麼你將進入『子程序』,這個程序的概念我們在資源管理章節中再詳談,這裡您先有個概念即可。那麼由於您已經進入了該子程序,所以在父程序中的變數設定將不再繼續的存在。如您想要讓該變數內容繼續的在子程序中使用,那麼就請執行:
     
      export 變數
     
    !這個東西用在『引用他人的檔案或者其他程序』時,相當的重要的!尤其像我常常兩三個檔案互相引用來引用去的,如果忘記設定 export 的話,那麼不同的檔案中的相同變數值,將需要一再地重複設定才行!所以,我只要在頭一個檔案使用 export 的話,那麼後續的檔案引用時,將會把該變數內容讀進來!好用的很?而,如果僅下達 export 而沒有接變數時,那麼此時將會把所有的『環境變數』秀出來喔!也就是說, export 可以將一般自訂的變數變成環境變數
     
    [root @test root]# export
    declare -x BASH_ENV="/root/.bashrc"
    declare -x CVSROOT="/usr/local/cvs/src/master"
    declare -x HISTSIZE="50"
    declare -x HOME="/root"
    declare -x HOSTNAME="test.adsldns.org"
    declare -x HOSTTYPE="i386"
    declare -x INPUTRC="/etc/inputrc"
    declare -x LANG="en_US"
    declare -x LESSOPEN="|/usr/bin/lesspipe.sh %s"
    declare -x LOGNAME="root"
    declare -x LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:
    bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=
    01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh
    =01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.z
    ip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;
    31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=
    01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"
    declare -x MACHTYPE="i386-redhat-linux-gnu"
    declare -x MAIL="/var/spool/mail/root"
    declare -x MANPATH=":/usr/local/netcdf/man"
    declare -x OSTYPE="linux-gnu"
    declare -x PATH="/usr/local/pgi/linux86/bin:/bin:/sbin:/usr/sbin:/usr/bin:
    /usr/local/sbin:/usr/local/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin
    :/usr/local/netcdf/bin"
    declare -x PGI="/usr/local/pgi"
    declare -x PWD="/root"
    declare -x SHELL="/bin/bash"
    declare -x SHLVL="1"
    declare -x SSH_TTY="/dev/pts/0"
    declare -x TERM="xterm"
    declare -x USER="root"
     

  • unset

  • 就是直接將該變數的內容拿掉:
     
      unset 變數
     

  • 變數的有效範圍:

  • 由前面的 export 以及相關的說明,你可以很清楚的知道一件事情,那就是,『變數的設定只在目前這個 shell 環境當中存在,在下個或者是在子程序中 ( 子 shell ) 將不會存在!』要讓變數在下個程序也可以繼續的使用,大概就是使用 export 這個咚咚啦!此外,其實除了 shell 的父、子程序外,在腳本( scripts )的編寫當中,由於有的軟體會使用到 2 個以上的 scripts 做為一個完整的套件!也就是說,假如你有兩支程式,一支為 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 會去引用 scripts1.sh 的變數,這個時候,嘿嘿!你在 scripts1.sh 當中設定的變數請『千萬記得以 export 設定』,否則你的變數將無法在兩個 scripts 之間互相被引用喔!當這個 scripts 執行完畢之後,剛剛在 scripts 當中設定的變數也就『失效了!』。
     

  • 其他的注意事項:

  • 乍看之下變數似乎沒有什麼值得我們來留意的地方,其實不然,變數可以讓我們的系統管理變的更加的簡單,舉個例子來說,剛剛我們提到 HISTSIZE 可以控制歷史指令的多寡,那麼太多的話,可能會有安全的顧慮之虞,那麼是否需要改小一點呢?當然需要~此外,關於路徑的設定方面,當您使用一般身份使用者登入系統,再以 su 轉換成 root 身份時,基本上,一堆環境變數仍是以當初的一般身份者為主的,因此,您常常會發現 root 使用的指令會『找不到!』那就是環境變數的錯誤設定啦!這個時候,如果您能夠將該一般身份使用者的路徑設定成為 root 能用的指令的樣子,嗯!那麼轉換身份的時候,將可以免除相當多的困擾呢!提供給你做為參考了!
     

  • read:

  • 上面我們談到的『變數』都是由『指令列』直接設定好的!那麼可不可以隨時來提供使用只以鍵盤隨時輸入變數內容?也就是說,變數內容是由使用者由鍵盤輸入的哩!呵呵!可以使用 read 來達成喔!這個東西在『 script 』裡面比較重要啦!所以我們在 shell script 裡面會再次的提到喔!
    語法
    [test @test test]# read name
    testing <==這個時候螢幕會等待使用者由鍵盤輸入喔!
    [test @test test]# echo $name
    testing <==剛剛輸入的資料變成了變數的內容啦!
     

  • array:

  • 談完了一些基本的變數之後,再接下來我們可以聊一聊關於『陣列, Array』這東西了!學過數學應該知道有所謂的陣列吧!他可以使用一個『函數』來包含一些內容!例如 A(1)=1, A(2)=4, A(3)=8 等等的樣子,那個 A(n) 就是函數, n 就是 index(索引),而在等號的右邊就是這個函數對應索引所得到的『內容』啦!在 Bash 裡頭提供了『一維陣列』給大家來使用,他的設定格式是:
    語法
    [test @test test]# a[索引]=內容
    [test @test test]# echo ${a[索引]}
    例:
    [test @test test]# a[1]=4
    [test @test test]# a[2]=8
    [test @test test]# echo ${a[1]} ${a[2]}
    4 8
    注意一下喔!在設定陣列的時候,他主要是以 『字母及中刮號, abc[]』的樣式來設定的!其他的規則則與 變數設定規則 相同!不過,在讀取陣列的時候就需要比較注意了!讀取的時候,是以 ${陣列函數} 的方式來讀取的!這部份特別容易搞錯!請大家特別留意呢!當然啦,陣列不止可以進行數字的型態,也可以是字串的類型喔!都可以的啦!
     

  • $RANDOM:

  • 有聽過『隨機取亂數』這個玩意兒吧!?呵呵!那麼在 BASH 裡面的亂數是那個變數來的?亂數在英文的寫法為 RANDOM 啦,所以囉, BASH 當中針對亂數的變數名稱就是 $RANDOM 囉!來給他秀一下吧!
    語法
    [test @test test]# echo $RANDOM
    xxxx <==每次都會出現不同的數字喔!
    亂數對於程式設計師比較重要,對於我們一般使用者,重要性就沒有這麼大啦!只是提出來讓大家知道一下就是了!
     

  • eval:

  • 語法
    [test @test test]# eval variable
    例題:
    [test @test test]# days=365
    [test @test test]# year=days
    [test @test test]# echo \$$year
    $days  <==第一個 $ 被 \ 改變成為一般字元,而 \$ 後面接的 $year 就成為 days 啦!
    [test @test test]# eval echo \$$year
    365
    加上 eval 之後, \$$year 變成的 $days 的『變數內容』會顯現出來喔!
    這個指令也是頗有趣的!他主要是用來做為變數的『疊代』用的!以上面的例子來看,起先, \$$year 會變成為 $days ,而這個 $days 其實是一般字元喔!並不是變數!不過,加上了 eval 之後,這個字串就會被變成變數內容咯!所以說, eval 是用來做為『二次疊代』的功能的!

命令別名與歷史命令

  • 命令別名:

  • 命令別名是一個很有趣的東西,特別是你的慣用指令特別長的時候!還有,增設預設的屬性在一些慣用的指令上面,可以預防一些不小心誤殺檔案的情況發生的時候!舉個例子來說,如果你要查詢隱藏檔,並且需要長的列出與一頁一頁翻看,那麼需要下達『 ls -al | more 』這個指令,我是覺得很煩啦!要輸入好幾個單字!那可不可以使用 lm 來簡化呢?!當然可以,你可以在命令列下面下達:
     
    [test @tset test]# alias lm='ls -al | more'

    要注意的是:『alias 的定義規則與變數定義規則幾乎相同』,所以你只要在 alias 後面加上你的{『別名』='指令 參數'},以後你只要輸入 lm 就相當於輸入了 ls -al|more 這一串指令!很方便吧!另外,我們知道 root 可以移除( rm )任何資料!所以當你以 root 的身份在進行工作時,需要特別小心,但是總有失手的時候,那麼 rm 提供了一個參數來讓我們確認是否要移除該檔案,那就是 -i 這個參數!所以,你可以這樣做:
     

    [test @tset test]# alias rm='rm -i'
     
    嘿嘿!那麼以後使用 rm 的時候,就不用太擔心會有錯誤刪除的情況了!這也是命令別名的優點囉!那麼如何知道目前有哪些的命令別名呢?就使用 alias 呀!
     
    [test @tset test]# alias
    alias l.='ls -d .[a-zA-Z]* --color=tty'
    alias ll='ls -l'
    alias lm='ls -al'
    alias ls='ls --color=tty'
    alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

    至於如果要取消命令別名的話,那麼就使用 unalias 吧!
     
    那麼命令別名與變數有什麼不同呢?基本上,他們的意義就不太一樣了! alias 這種命令別名,你可以將他想成是建立一個新的指令名稱,至於變數則僅是將一個數值或者字串存在某個代表意義當中!舉個例子好了,我們知道以前的 DOS 年代,列出目錄與檔案就是 dir ,而清除螢幕就是 cls ,那麼如果我想要在 linux 裡面也使用相同的指令呢?那就以 alias 來進行指令的別名設定:
     

        alias cls=’clear’
        alias dir=’ls –l’
     
    只要加入這兩行,以後你輸入 cls 及 dir 就可以執行了!很方便吧!

  • 歷史指令記錄資料:

  • 前面我們提過 bash 有提供指令歷史的服務!那麼如何查詢我們曾經下達過的指令呢?就使用 history 囉!當然,如果覺得 histsory 太麻煩,可以使用命令別名來設定呢!不要跟我說還不會設定呦!
     
      alias h=’history’
     
    如此則輸入 h 等於輸入 history 囉!好了,我們來談一談 history 的用法吧!

    • history, !command

    • 顯示歷史指令記錄內容, 下達歷史紀錄中的指令
      語法
      [test @test test]# history
      [test @test test]# [!number]  [!command] [!!]
      參數說明:
      number   :第幾個指令的意思;
      command  :指令的開頭幾個字母
      !        :上一個指令的意思!
      範例:
      [test @test test]# history          <==底下列出的就是(1)歷史指令的編號;(2)指令的內容
         66  man rm
         67  alias
         68  man history
         69  history
      [test @test test]# !66       <==執行第 66 個歷史指令
      [test @test test]# !!               <==執行上一個指令(在本例中,就是 !66 那一個指令!)
      [test @test test]# !al              <==執行最近一次以 al 為開頭的指令內容,就是第 67 個指令囉!
      說明:
      history 這個指令配合 ! 這個用法就多了!如果我想要執行上一個指令,除了使用上下鍵之外,我可以直接以 !! 來下達上個指令的內容,此外,我也可以直接選擇下達第 n 個指令, !n 來執行,也可以使用指令標頭,例如 !vi 來執行最近指令開頭是 vi 的指令列!相當的方便而好用!基本上 history 的用途很大的!但是需要小心安全的問題!尤其是 root 的歷史紀錄檔案,這是 Cracker 的最愛!因為不小心的 root 會將很多的重要資料在執行的過程中會被紀錄在 ~/.bash_history 當中,如果這個檔案被解析的話,後果不堪吶!無論如何,使用 history 配合『 ! 』曾經使用過的指令下達是很有效率的一個指令方法!

bash shell 的設定檔案:

    終於來到 bash 的設定檔案囉!這部份我們預計分成『系統設定值』與『一般各人喜好設定值』來說明,除非您是 root ,並且對於大家的喜好有共同的認知,否則只要設定您的『個人設定值』(在每個人的家目錄內)也就可以囉!要注意的是,在指令列輸入的變數也好、命令別名也罷,都是針對該次登入的設定而已,所以只要您一登出,那麼上次的設定值就會不見去!因此,我們需要有幾個檔案來幫助我們,每次登入的時候,就已經幫我們搞定了環境的設定囉!

  • 系統設定值:

  • 所謂的系統設定值,也就是說每個使用者進入到 bash shell 之後,會先讀取的設定檔案!預設的設定檔案有下列幾個:
    • /etc/profile:這個檔案設定了幾個重要的變數,例如:『PATH、USER、MAIL、HOSTNAME、HISTSIZE、umask』等等,也同時規劃出 /etc/inputrc 這個針對鍵盤熱建設定的檔案的資料內容。你可以在這裡設定總體的 PATH 等等的資訊!同時,這個 file 也規劃出 /etc/profile.d 及 /etc/inputrc 這兩個檔案,其中, inputrc 是用在 history (歷史指令)的作用上的!總之,你可以瞭解到剛剛我們學會的變數設定方式,在這個檔案中也可以設定呢!但是設定上需要特別小心,因為所有的使用者皆會使用到這個檔案的資訊。註:通常我都喜歡將 /usr/local/bin 這個路徑加成最前面,這是因為通常自己安裝的套件自己最喜歡,所以當然是最先收尋囉! ^_^!此外,請注意一下,可以將 HISTSIZE 的大小改變一下,改成 50 就可以啦!比較安全!( 註:這個檔案不論在那個 Linux distribution 當中均存在 /etc/profile 當中,所以,請特別留意此一檔案即可! )。

    •  
    • /etc/bashrc:這個檔案在規劃 umask 的功能,也同時規劃出提示字元的內容(就是裡頭那個 PS1 啦!)。特別留意的是,這個檔案在不同的 Linux distribution 裡面,擺放的位置可能不太一樣呢!所以需要查詢一下才行呦

    •  
    • /etc/man.config:這個檔案或許跟 bash shell 較沒相關性,但是對於系統管理員來說,卻也是很重要的一個檔案!這的檔案的內容『規範了使用 man 的時候, man page 的路徑到哪裡去尋找!』所以說的簡單一點,這個檔案規定了下達 man 的時候,該去哪裡查看資料的路徑設定!那麼什麼時候要來修改這個檔案呢?如果你是以 tarball 的方式來安裝你的資料,那麼你的 man page(指令說明檔案)可能會放置在 /usr/local/softpackage/man 裡頭,那個 softpackage 是你的套件名稱,這個時候你就得以手動的方式將該路徑加到 /etc/man.config 裡頭,否則使用 man 的時候就會找不到相關的說明檔囉
    這就是系統在設定的時候常常會使用的檔案!需要特別留意的是,通常設定完了這幾個檔案之後,都需要先 logout 在 login 之後才會將設定整個啟動起來!

  • 個人設定值

  • 那麼個人的喜好設定在哪裡?嘿嘿嘿嘿!那就是在個人家目錄的幾個隱藏檔當中囉!分別會使用到底下的幾個檔案啦! ( 注意!底下的檔案都是隱藏檔,需要使用 ls -al 方能顯示出來 ) ,另外,注意一下囉!底下那個『 ~ 』代表的是『家目錄』的意思:
    • ~/.bash_profile:裡面定義了個人化的路徑(PATH)與環境變數的檔案名稱!你可以在這裡修改你的個人路徑呦!當然囉!也可以在 ~/.bashrc 這個個人設定的變數裡頭修改!有的時候會有 ~/.profile 或 ~/.bash_login 等檔案來取代這個檔案!

    •  
    • ~/.bashrc:這個檔案對於個人喜好的 bash 設定來說,是最重要的啦!因為我都是在這裡設定我的個人化變數!例如命令別名的設定!路徑的重新定義等等,都是在這裡完成的!

    •  
    • ~/.bash_history:這個檔案的用途在於將你曾經使用過的命令記錄下來,而當你再次的以上下鍵搜尋或者直接以 history 搜尋的時候,就可以找到曾經使用過的指令囉!需要注意的是

    •  
      1. 在這一次的執行過程中的指令,將在你離開 shell 之後才會被紀錄到這個檔案中,否則將只會先被寫到暫存記憶體中(Cache);
      2. 可以藉由 history 這個指令來將裡頭的紀錄搜尋出來;
      3. 這個檔案的指令記錄筆數,與 HISTFILE 有關,你可以自行在 ~/.bashrc 裡頭設定,或者直接由 root 在 /etc/profile 裡面統一設定大小!
       
    • ~/.bash_logout:這個檔案則是在『你登出 shell 的時候, BASH 會為你所做的事情!』通常預設是只有 clear 清除螢幕這件事情而已,不過,你也可以將一些備份或者是其他你認為重要的工作寫在這個檔案中(例如清空暫存檔),那麼當你離開 Linux 的時候,就可以解決一些煩人的事情囉!
    大致上的個人設定就是如同上面說的!不過,我個人覺得比較重要的是 ~/.bashrc 這一個檔案!我喜歡將自己的相關設定寫在裡頭!這樣可以很輕易的將個人的設定寫好!尤其是命令別名與變數的設定等等!我個人喜好的 ~/.bashrc 設定如下:
     
    [test @test test]# more .bashrc
    # User specific aliases and functions 
    PATH="/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/sbin:/usr/bin:$PATH" 
    Export PATH 

    Alias rm='rm -i' 
    Alias cp='cp -i' 
    Alias mv='mv -i' 
    Alias ll='ls -l' 
    Alias lm='ls -al|more' 
    Alias h='history' 

    # Source global definitions 
    if [ -f /etc/bashrc ]; then 
            . /etc/bashrc 
    fi 


  • source:

  • 前面提過了,如果我需要將目前的設定檔的內容讀入一次,需要重新 logout 再 login 才能夠讀入,那麼有沒有辦法不登出而直接讀入變數設定檔呢?當然可以,就使用 source 即可!
     
    [test @test test]# source 變數設定檔

    這個使用的情況在什麼時候呢?最常發生在一個人的工作環境分為多重的時候了!舉個例子來說,在我的大型主機中,我常常需要負責兩到三個不同的案子,每個案子所需要處理的環境變數訂定並不相同,那麼我就將這兩三個案子分別編寫屬於該案子的環境變數設定檔案,當我需要該環境時,就直接 source 變數檔,如此一來,環境變數的設定就變的更簡便而靈活了!

萬用字元與特殊符號

    由於在 bash 當中常會使用到一些萬用字元,與搭配特殊符號來將指令做更好的利用(例如最常提到的正規表示法 Regulare Express )!底下我們列出一些常用的萬用字元與特殊符號:
     
    符號
    內容
    *
    萬用字元,代表一個或多個字元(或數字)
    ?
    萬用字元,代表一個字母
    #
    註解,這個最常被使用在 script 當中,視為說明!
    \
    跳脫符號,將『特殊字元或萬用字元』還原成一般字元
    |
    分隔兩個管線命令的界定
    ;
    連續性命令的界定(注意!與管線命令並不相同)
    ~
    使用者的家目錄
    $
    亦即是變數之前需要加的變數取代值
    &
    將指令變成背景下工作
    !
    邏輯運算意義上的『非』 not 的意思!
    /
    路徑分隔的符號
    >, >>
    輸出導向,分別是『取代』與『累加』
    '
    單引號,不具有變數置換的功能
    "
    具有變數置換的功能!
    ` `
    兩個『 ` 』中間為可以先執行的指令!
    (   )
    在中間為子 shell 的起始與結束
    [  ]
    在中間為字元的組合
    {   }
    在中間為命令區塊的組合!
    組合按鍵
    執行結果
    Ctrl + C
    終止目前的命令
    Ctrl + D
    輸入結束(EOF),例如郵件結束的時候;
    Ctrl + M
    就是 Enter 啦!
    Ctrl + S
    暫停螢幕的輸出
    Ctrl + Q
    恢復螢幕的輸出
    Ctrl + U
    在提示字元下,將整列命令刪除
    Ctrl + Z
    『暫停』目前的命令

    上面的萬用字元當中,最常用的就屬 *, ?, [] 及 ` 了!我們提幾個簡單的例子:
     

    [test @test test]# ls test*  <==那個 * 代表後面不論接幾個字元都予以接受(沒有字元也接受!)
    [test @test test]# ls test?  <==那個 ? 代表後面『一定』要接『一個』字元
    [test @test test]# ls test???  <==那個 ??? 代表『一定要接三個』字元!
    [test @test test]# cp test[1-5] /tmp  <==將 test1, test2, test3, test4, test5 若存在的話,就拷貝到 /tmp 下
    [test @test test]# cd /lib/modules/`uname -r`/kernel/drivers  <==被 ` ` 括起來的內容『會先執行』!
    上面幾個例子相當的有趣!尤其是最後面兩個!需要注意的是, [] 裡面『代表只有一個字元』但是範圍可以由 1-5 ,這樣來說的話,那麼我們如果允許『只要檔名裡面含有至少一個大寫字元』時,就可以將檔案 copy 出來的話,可以這樣做:
     
      cp *[A-Z]* /tmp
     
    很有趣吧?! ^_^
    此外,那個 `` 裡面的『指令』會先被執行,也就是說:
     
    1. 系統先執行 uname -r 找出輸出的結果;
    2. 將結果累加在目錄上面,來執行 cd 的功能!
     
    很棒吧!!這些基本的功能需要特別來瞭解一下才行呦!

  • 連續指令的下達方式:

  • 這裡需要再提幾個重要的資訊,我們剛剛上面提過說,兩個指令先後寫在一起,可以這樣寫:
     
      command1; command2
     
    利用分號『 ; 』來分隔,這個分號的意思,代表不論 command1 執行結果為何,command2 都會被執行!那麼如果我是兩個相關的指令,第一個 command1 如果執行結果有錯誤,第二個就不被執行,可以這樣做嗎?當然可以,就使用下面兩個連結的咚咚:
     
      command1 && command2
      command1 || command2
     
    還記得我們之前的變數內容中,那個 ? 代表什麼嗎?沒錯,就是代表前一個執行的指令內容有沒有錯誤,如果有錯誤就回傳為 1 ,沒有錯誤就回傳為 0 ,你可以經由 echo $? 來查詢得知!那麼 && 就是代表,當 command1 執行結果傳回值為 0 的時候,也就是沒有錯誤訊息時,則 command2 才會開始執行,而 || 恰恰相反,當 command1 有錯誤訊息時, command2 才會執行!舉個例子來說,我的系統中並沒有 /vbird 這個目錄,所以執行 ls /vbird 應該會有錯誤訊息才對,所以,底下三個指令串會顯示什麼呢?
     
    [root @test root]# ls /vbird  ; ls /
    [root @test root]# ls /vbird && ls /
    [root @test root]# ls /vbird || ls /

    試看看呦!

絕對路徑與相對路徑

    其實,在使用 bash 還有另一個困擾,就是當你的 PATH 沒有設定完整的時候,下達指令都是要以『一長列的指令連帶根目錄都要列出來』,呵呵那就是絕對路徑的設定法啦!基本上,這個『絕對路徑』與『相對路徑』的觀念是很重要的!否則你將常常會找不到檔案說!所謂的『絕對路徑』就是以根目錄開始寫入到檔案的一種命令寫定方法,舉例來說,我目前在 /home/test 這個 test 使用者的家目錄中,我想要看看裡面的 .bashrc 這個檔案的資料,使用的是 more 這個指令,而這個指令在 /bin/more 當中,則正確的下達指令的方法為:
     
    [test @tset test]# /bin/more .bashrc<==我在的目錄為 /home/test !這是絕對路徑寫法!
     
    我在的目錄為 /home/test !這是絕對路徑寫法! 而如果你還記得我們在 檔案系統指令 那一篇文章中提到的觀念的話,那麼應該記得使用 ls -al 時會出現兩個一定存在的目錄,分別是『.』與『..』,分別代表是『這個路徑』,與『上一層路徑』!
     
    [test @tset test]# ls -al
    total 728
    drwx------    3 vbird    vbird        4096 May 19 14:53 .      <==這一層路徑的屬性說明
    drwxr-xr-x    3 root     root         4096 May  5 16:50 ..     <==上一層路徑的屬性說明
    以下略!
     
    所以說,要執行上一層目錄中的命令,可以下達『../command 』那個 command 指的是存在的可執行檔!那麼我因為在 /home/test 裡面,距離 /bin 有兩層上層目錄,所以我要使用 /bin/more 這個執行檔,並且使用相對路徑的方法,就必須使用:
     
    [test @tset test]# ../../bin/more .bashrc    <==一層一層回到根目錄,在進入 /bin 的寫法!相對路徑
     
    這種相對路徑的方法相當廣泛的被運用於 script 當中,這是因為如前面提到的,每個人的安裝預設的目錄都不相同,則使用相對路徑的話,很容易就可以找到套件之間相依軟體或者是設定檔案的相關性!
       
      關於路徑搜尋的問題!為何不執行目前所在目錄下的檔案?
      咦!剛剛不是提到『.』與『..』嗎?那麼那個『 . 』是幹嘛用的?!眼尖的朋友應該已經發現了,就是『我在執行檔案的時候,基本上,並不會主動搜尋目前目錄下的檔案』舉個例子來說,我安裝的 squid 這個執行檔在 /usr/local/squid/bin/squid 這個檔案,然而我在 /usr/local/squid/bin 下達 squid 的時候,系統會告訴你『查不到這個檔案!』真是見鬼了!明明有這個檔案的呀!這是因為系統預設的 PATH (路徑)並沒有執行目前目錄下的設定,也就是『.』這個路徑!你可以使用『 echo $PATH 』看看,就可以知道為什麼了!那麼為何不要設定這個路徑呢?這是因為『安全』的考量。由於系統預設是允許任何人在 /tmp 底下寫入任何檔案的,那麼萬一有居心不良的使用者或者是 Cracker 入侵你的電腦,並在你的 /tmp 裡頭埋了一個小木馬,並取名為 ls ,好了,改天你以 root 身份登入後,到 /tmp 底下,並執行 ls ,你看會有什麼結果?!這個 /tmp/ls 由其他身份的人來執行或許沒有問題,但是由 root 來執行卻可能會導致 Cracker 所樂意見到的結果!那曉得為何了吧?!
      當然囉!您還是可以選擇在 ~/.bashrc 當中設定你的 . 在你的 PATH 當中,不過並不這麼建議就是了!
    好了,由於系統預設並不主動搜尋目前目錄下的執行檔,那麼你應該如何執行『目前目錄下的執行檔』呢?很簡單呀!就是以相對路徑的觀念,由於『 .. 』是上層,而『 . 』是這一層,所以要執行這一層目錄的命令就使用『 ./command 』即可!例如你的 /usr/local/squid/bin 底下執行 squid 則可以寫成:
     
    [test @tset bin]# ./squid       <==以相對路徑的觀念來看!在本目錄下達的指令寫法!
     
    請特別留意這方面的問題!『新手特別容易犯這個錯誤呢

命令重導向

    基本上,這個子題是 bash 相當重要的觀念,這裡可得花點心思才行呦!
    • 什麼是『重導向, redirect ?』:簡單的說,就是將你目前的所得資料轉到其他地方去就是了!例如我們常用的,將目前的螢幕輸出資料轉到檔案中去,就可以這麼寫:『ls -l / > test 』,那個大於的符號『 > 』就是將輸出結果導向到 test 這個檔案中的意思囉!這個時候:
      • 如果你執行『 ls -l / 』而已的話,螢幕會將根目錄的檔案與目錄都列出在螢幕上;
      • 但是當使用 > 導向到 test 這個檔案中時,則螢幕不會顯示任何訊息,但是會將剛剛你執行的結果輸出到 test 這個檔案中。
      所以囉,你只要『 vi test 』一下,就會知道 test 這個檔案中記錄了剛剛我們執行的資料結果囉!不過,這裡需要特別留意的是,當你使用 > 符號將資料由螢幕導向到檔案中時,則:
      • 該檔案(就是 test )若不存在,系統會自動的將他建立起來,但是,
      • 當這個檔案存在的時候,那麼系統就會先將這個檔案內容清空,然後再將資料寫入!
      • 也就是若以 > 輸出到一個既存檔案中,呵呵,那個檔案就會被覆蓋掉囉
    除了這個 > 的符號之外,在 bash 命令執行的過程中,主要有三種輸出入的狀況,分別是:
    1. 標準輸入;代碼為 0 ;或稱為 stdin ;使用的方式為 <
    2. 標準輸出:代碼為 1 ;或稱為 stdout;使用的方式為 1>
    3. 錯誤輸出:代碼為 2 ;或稱為 stderr;使用的方式為 2>
    基本的指令書寫方式為:
     
    指令
    1>
    1>>
    2>
    2>>
    <
    裝置或檔案

    左邊一定是指令,至於右邊則可能是裝置或者是檔案!注意了!那個 1> 與 2> 之間並沒有空白字元!而相關的使用說明可以舉例如下:
     

    [test @test test]# ls -al >  list.txt 
    將顯示的結果輸出到 list.txt 檔案中,若該檔案以存在則予以取代!
    [test @test test]# ls -al >> list.txt 
    將顯示的結果累加到 list.txt 檔案中,該檔案為累加的,舊資料保留!
    [test @test test]# ls -al 1> list.txt 2> list.err 
    將顯示的資料,正確的輸出到 list.txt 錯誤的資料輸出到 list.err
    [test @test test]# ls -al 1> list.txt 2>&1 
    將顯示的資料,不論正確或錯誤均輸出到 list.txt 當中!
    [test @test test]# ls -al 1> list.txt 2> /dev/null
    將顯示的資料,正確的輸出到 list.txt 錯誤的資料則予以丟棄!
    注意!錯誤與正確檔案輸出到同一個檔案中,則必須以上面的方法來寫!
    不能寫成其他格式!

    這個觀念相當的重要,尤其是在 /etc/crontab 當中執行的時候,如果我們已經知道錯誤的訊息為何,又不想要讓錯誤的訊息一直填滿 root 的信箱,就必須以 2> 搭配 /dev/null 這個垃圾桶黑洞裝置,來將資料丟棄!這個相當的重要!

    這裡我們來說明一下命令重導向裡面幾個常用的符號與裝置:
    • <  :由 < 的右邊讀入參數檔案;
    • >  :將原本由螢幕輸出的正確資料輸出到 > 右邊的 file ( 檔案名稱 ) 或 device ( 裝置,如 printer )去;
    • >> :將原本由螢幕輸出的正確資料輸出到 >> 右邊,與 > 不同的是,該檔案將不會被覆蓋,而新的資料將以『增加的方式』增加到該檔案的最後面;
    • 2> :將原本應該由螢幕輸出的錯誤資料輸出到 2> 的右邊去。
    • /dev/null :可以說成是黑洞裝置!
好了,對於『 > , >> 』這兩個東西有一定的概念之後,我們來深入的談一談『命令輸出重導向』的觀念吧!如前所述,基本上, Linux 執行的結果中,可以約略的分成『正確輸出』與『錯誤輸出』兩種方式。例如,當你以一般身份執行 find 這個指令時,例如執行『 find / -name testing 』時,由於你是一般身份,又有些資料夾是不允許一般身份者進入的,所以囉,當你使用 find 時,就會有錯誤訊息發生了!但同時如果有 testing 這個檔案在你可以進入的資料夾當中,那麼螢幕也會輸出到給你看!因此,就具有正確的與錯誤的輸出兩種囉!(分別稱為 Stdout 與 Stderror)例如下面為執行結果:裡面的『 find: /home/root: Permission denied 』就告訴你該資料夾你沒有權限進入,這就是錯誤的輸出了,那麼『 /home/test/tseting 』就是正確的輸出了!
 
[test @test test]# find / -name testing
find: /home/test1: Permission denied    <==這是錯誤的輸出
find: /home/root: Permission denied       <==這是錯誤的輸出
find: /home/masda: Permission denied      <==這是錯誤的輸出
/home/test/testing                        <==這是『正確』的輸出
[test @test test]# 

好了,那麼假如我們想要將資料輸出到 list 這個檔案中呢?執行『 find / -name testing > list 』會有什麼結果?呵呵,你會發現 list 裡面存了剛剛那個『正確』的輸出資料,至於螢幕上還是會有錯誤的訊息出現呢!傷腦筋!如果想要將正確的與錯誤的資料分別存入不同的檔案中需要怎麼做?!呵呵!其實在資料的重導向方面,正確的寫法應該是『 1> 』與『 2> 』才對!但是如果只有 > 則預設是以 1> 來進行資料的!那個 1> 是輸出正確資料, 2> 則是錯誤資料輸出項目。也就是說:

  • 1> :是將正確的資料輸出到指定的地方去
  • 2> :是將錯誤的資料輸出到指定的地方去
好了,那麼上面的例子中,我們如何將資料輸出到不同的地方去呢?可以這麼寫:
 
[test @test test]# find / -name testing 1> list_right 2> list_error

這樣一來,剛剛執行的結果中,有 Permission 的那幾行錯誤資訊都會跑到 list_error 這個檔案中,至於正確的輸出資料則會存到 list_right 這個檔案中囉!這樣可以瞭解了嗎?如果有點混亂的話,去休息一下再來看看吧!!

    再來,如果我只要正確的資料,錯誤的資訊我不要了呢?呵呵,這個時候 /dev/null 這個垃圾桶就很重要了!/dev/null 是什麼呢?基本上,那就有點像是一個『黑洞』的垃圾桶功能!當你輸入的任何東西導向到這個虛擬的垃圾桶裝置時,『他就會憑空消失不見了~~』,這個東西有用的很!例如上面的例子中,我們可以這麼做,來將錯誤的資訊丟掉!
     
    [test @test test]# find / -name testing 1> list_right 2> /dev/null

    很神奇呦! error message 就會『不見了!』呵呵!真高興!另外,如果我要將資料都寫到同一個檔案中呢?這個時候寫法需要用到特殊寫法,請注意底下的寫法呦!
     

    [test @test test]# find / -name testing 1> list 2> list<==錯誤寫法
    [test @test tset]# find / -name testing 1> list 2>&1   <==正確寫法

    請特別留意這一點呢!同時寫入同一個檔案需要使用 2>&1 才對呦!

    OK!瞭解了 >, 2>, >> 與 /dev/null 之後,那麼那個 < 又是什麼呀!?呵呵!以最簡單的說法來說,那就是『將原本需要由鍵盤輸入的資料經由檔案來讀入』的意思,最明顯的例子就是 mail 這個東西了!我們以 root 的身份來寄信給 root 好了,可以這樣做:
     
    1. 完全由鍵盤輸入資料:
    [root @test test]# mail -s "test" root <== -s 表示標題, root 為收件者
    I am root! <==以下的資料都是由鍵盤輸入的
    That's OK
    .       <==要結束鍵盤的輸入時,需要在一行的最前面加上 . 即可!
    CC.     <==是否需要有密件副本?不需要的話,直接按下 Enter !
    EOF     <==表示送出的提示字元而已!

    2. 由檔案代替輸入
    [test @test tset]# mail -s "test" root < /root/.bashrc <==將 .bashrc 內容寄給 root !

    很有趣吧! ^_^ 這樣就可以將信寄出去囉!所以說,熟悉命令重導像的話,對您可是相當的有幫助的呦!

    好了,那麼為何要使用命令輸出重導向呢?這個問題一定會困擾你一下下的,如果你從來都沒有寫過 script 的話!好了,我們來說一說吧!
    • 當螢幕輸出的資訊很重要,而且我們需要將他存下來的時候;
    • 背景執行中的程式,不希望他干擾螢幕正常的輸出結果時;
    • 一些系統的例行命令(例如寫在 /etc/crontab 中的檔案)的執行結果,希望他可以存下來時;
    • 一些執行命令,我們已經知道他可能的錯誤訊息,所以想以『 2> /dev/null 』將他丟掉時;
    • 錯誤訊息與正確訊息需要分別輸出時。
    當然還有很多很多的功能的,最簡單的就是網友們常常問到的:『為何我的 root 都會收到系統 crontab 寄來的錯誤訊息呢』這個咚咚是常見的錯誤,而如果我們已經知道這個錯誤訊息是可以忽略的時候,嗯!『 2> errorfile 』這個功能就很重要了吧!瞭解了嗎??

管線命令 ( pipe )

    就如同前面所說的, bash 命令執行的時候有輸出的資料會出現!那麼如果這群資料必需要經過幾道手續之後才能得到我們所想要的格式,應該如何來設定?這就牽涉到管線命令的問題了( pipe ),管線命令使用的是『 | 』這個界定符號!另外,管線命令與『連續下達命令』是不一樣的呦!這點底下我們會再說明。底下我們先舉一個例子來說明一下簡單的管線命令。
    假設我們要讀取 last 這個指令中,那個 root 登入的『次數』應該怎麼作?注意呦!我們只需要『次數』。那麼我所進行的步驟是:
    1. 執行 last ,將所有這個月的所有人登入資料取出來;
    2. 使用 grep 將上面的輸出資料(stdout)當中的 root 擷取出來,其他的不要;
    3. 使用 wc 這個可以計算行數的指令將上一步的資料計算行數!
    由於 last 的輸出是一行代表一次登入,所以只要計算幾行就代表登入幾次的意思,所以囉!經由上面三個步驟,將 last 資料逐步的篩選,就可以得到我們的資料了!整個命令可以寫成如下:
     
    [test @test bin]# last
    [test @test bin]# last | grep root
    [test @test bin]# last | grep root | wc -l 
     
    你可以分別執行『 last 』然後再逐步增加為『 last | grep root 』,最後到上面那一行,那麼就馬上可以清楚的知道為何會這麼做囉!這個管線命令『 | 』僅能處理經由前面一個指令傳來的正確資訊,也就是 standard output ( STDOUT ) 的資訊,對於 stdandard error 並沒有直接處理的能力,請記得。那麼整體的管線命令可以使用下圖表示之:
      
    在每個管線的部分都是『指令』呢!而後一個指令的輸入乃是由前一個指令的輸出而來的!底下我們來談一談一些基本的管線命令指令介紹:

  • cut

  • 語法
    [root @test /root ]# cut -d "分隔字元" [-cf] fields
    參數說明:
    -d  :後面接的是用來分隔的字元,預設是『空白字元』
    -c  :後面接的是『第幾個字元』
    -f  :後面接的是第幾個區塊?
    範例:
    [root @test /root]# cat /etc/passwd | cut -d ":" -f 1 
    將 passwd 這個檔案裡面,每一行裡頭的 : 用來作為分隔號,
    而列出第一個區塊!也就是姓名所在啦!

    [root @test /root]# last | cut -d " " -f1 
    以空白字元為分隔,並列出第一個區間!

    [root @test /root]# last | cut -c1-20
    將 last 之後的資料,每一行的 1-20 個字元取出來!

    說明
    這個 cut 實在很好用!不過,說真的,除非你常常在分析 log 檔案,否則使用到 cut 的機會並不多!好了! cut 主要的用途在於將『同一行裡面的資料進行分解!』,最常使用在分析一些數據或文字資料的時候!這是因為有時候我們會以某些字元當作分割的參數,然後來將資料加以切割,以取得我們所需要的資料。我也很常使用這個功能呢!尤其是在分析 log 檔案的時候!

  • sort

  • 語法
    [root @test /root ]# sort [-t 分隔符號] [(+起始)(-結束)] [-nru]
    參數說明:
    -t 分隔符號:使用分隔符號來隔開不同區間,預設是 tab
    +start -end:由第 start 區間排序到 end 區間
    -n         :使用『純數字』排序(否則就會以文字型態來排序)
    -r         :反向排序
    -u         :相同出現的一行,只列出一次!
    範例:
    [root @test /root]# cat /etc/passwd | sort
    將列出來的個人帳號排序!

    [root @test /root]# cat /etc/passwd | sort -t: +2n
    將個人帳號中,以使用者 ID 來排序(以 : 來分隔,第三個為 ID ,
    但第一個代號為 0 之故)

    [root @test /root]# cat /etc/passwd | sort -t: +2nr
    反相排序囉!

    說明
    sort 同樣是很常用的指令呢!因為我們常常需要比較一些資訊啦!舉個上面的第二個例子來說好了!今天假設你有很多的帳號,而且你想要知道最大的使用者 ID 目前到哪一號了!呵呵!使用 sort 一下子就可以知道答案咯!當然其使用還不止此啦!有空的話不妨玩一玩!

  • wc

  • 語法
    [root @test /root ]# wc [-lmw]
    參數說明:
    -l   :多少行
    -m   :多少字元
    -w   :多少字?
    範例:
    [root @test /root]# cat /etc/passwd | wc -l
    這個檔案裡頭有多少行?

    [root @test /root]# cat /etc/passwd | wc -w 
    這個檔案裡頭有多少字!?

    說明
    wc 也可以當作指令?呵呵!這可不是上洗手間的 WC 呢!這是相當有用的計算檔案內容的一個工具組喔!舉個例子來說,當你要知道目前你的帳號檔案中有多少個帳號時,就使用上面的 wc -l 啦!因為 /etc/passwd 裡頭一行代表一個使用者呀!所以知道行數就曉得有多少的帳號在裡頭了!而如果要計算一個檔案裡頭有多少個字元時,呵呵!就使用 wc -w 這個參數吧!

    • uniq

    • 語法
      [root @test /root ]# uniq
      參數說明:
      範例:
      [root @test /root]# last | cut -d" " -f1 | sort | uniq
      說明
      這個指令用來將『重複的行刪除掉只顯示一個』,舉個例子來說,你要知道這個月份登入你主機的使用者有誰,而不在乎他的登入次數,那麼就使用上面的範例,(1)先將所有的資料列出;(2)再將人名獨立出來;(3)經過排序;(4)只顯示一個!由於這個指令是在將重複的東西減少,所以當然需要『配合排序過的檔案』來處理囉!

    • tee

    • 語法
      [root @test /root ]# last | tee last.list | cut -d " " -f1
      參數說明:
      範例:
      [root @test /root]# last | tee last.list | cut -d " " -f1
      說明
      有沒有發現在命令重導向的時候,如果我們要將資料送出到檔案的時候,螢幕上就不會出現任何的資料!那麼如果我們需要將資料同時顯示在螢幕上跟檔案中呢?呵呵!這個時候就需要 tee 這個指令囉!使用 last 可以查看到這個月份的登入資料,而使用了 tee 之後,會將資料同時傳給下一個命令去執行,也會將資料寫入 last.list 這個檔案中!也是個好幫手!

    • tr

    • 語法
      [root @test /root ]# tr [-ds] SET1
      參數說明:
      -d  :刪除 SET1 這個字串
      -s  :取代掉重複的字元!
      範例:
      [root @test /root]# last | tr '[a-z]' '[A-Z]'         <==將小寫改成大寫
      [root @test /root]# cat /etc/passwd | tr -d :       <==嘿嘿! : 這個符號在 /etc/passwd 中不見了!
      [root @test /root]# cat /home/test/dostxt | tr -d '\r' > dostxt-noM   <==將 DOS 檔案的字尾符號 ^M 的符號去除!
      說明
      其實這個指令也可以寫在『正規表示法』裡頭!因為他也是由正規表示法的方式來取代資料的!以上面的例子來說,使用 [] 可以設定一串字呢!也常常用來取代檔案中的怪異符號!例如上面第三個例子當中,可以去除 DOS 檔案留下來的 ^M 這個斷行的符號!這東西相當的有用!相信處理 Linux & Windows 系統中的人們最麻煩的一件事就是這個事情啦!亦即是 DOS 底下會自動的在每行行尾加入 ^M 這個斷行符號!這個時候我們可以使用這個 tr 來將 ^M 去除! ^M 可以使用 \r 來代替之!

    • split

    • 語法
      [root @test /root ]# split [-bl] 輸入檔案 輸出檔案前導字元
      參數說明:
      -b  :以檔案 size 來分
      -l  :以行數來分
      範例:
      [root @test /root]# split -l 5 /etc/passwd test   <==會產生 testaa, testab, testac... 等等的檔案
      說明
      在 Windows 的情況下,你要將檔案分割需要如何作?!傷腦筋吧!呵呵!在 Linux 底下就簡單的多了!你要將檔案分割的話,那麼就使用 -b size 來將一個分割的檔案限制其大小,如果是行數的話,那麼就使用 -l line 來分割!好用的很!如此一來,你就可以輕易的將你的檔案分割成 floppy 的大小,方便你 copy 囉!
    管線命令在 bash 的連續的處理程序中是相當重要的!另外,在 log file 的分析當中也是相當重要的一環,所以請特別留意!好嘛!?

本章習題練習 ( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看)

  • 如何顯示 HOME 這個環境變數?

  • 答:
      echo $HOME
       
  • 如何得知目前的所有變數與環境變數的設定值?

  • 答:
      環境變數用 env 而所有變數用 set 即可顯示
     
  • 我是否可以設定一個變數名稱為 3myhome ?

  • 答:  
  • 如何取消變數與命令別名的內容?

  • 答:
      使用 unset 及 unalias 即可
       
  • 如何設定一個變數名稱為 name 內容為 It’s my name ?

  • 答:
      name=It\’s\ my\ name 或 name=”It’s my name”
       
  • 環境變數檔案的載入順序?

  • 答:
      先由 /etc/passwd 取得 bash 這個 shell ,再到 /etc/profile 讀取主要的環境變數,同時亦會將 /etc/inputrc 及 /etc/profile.d 內容均讀入。之後,再到個人的家目錄讀取 ~/.bash_profile 及 ~/.bashrc 等檔案!
       
  • man page 的路徑設定檔案?

  • 答:
      /etc/man.config 或 /etc/man.conf
     
  • 試說明 ‘, “, 與 ` 這些符號在變數定義中的用途?

  • 答:
      參考變數規則那一章節,其中, “ 可以具有變數的內容屬性, ‘ 則僅有一般字元,至於 ` 之內則是可先被執行的指令。
       
  • 跳脫符號 \ 有什麼用途?

  • 答:
      可以用來跳脫特殊字元,例如 Enter, $ 等等,使成為一般字元!
     
  • 連續命令中, ;, &&, || 有何不同?

  • 答:
      分號可以讓兩個 command 連續運作,不考慮 command1 的輸出狀態, && 則前一個指令必需要沒有錯誤訊息,亦即回傳值需為 0 則 command2 才會被執行, || 則與 && 相反!
       
  • 如何將 last 的結果中,獨立出帳號,並且印出本月份曾經登入過的帳號?

  • 答:
       last | cut –d “ “ –f1 | sort | uniq

參考文章:
修改歷史:
  • 2002/06/27:第一次完成
  • 2003/02/10:重新編排與加入 FAQ
伺服器篇文件
各版本彙整說明
CentOS 6.x