鳥哥的 Linux 私房菜
為取得較佳瀏覽結果,請愛用 firefox 瀏覽本網頁
前往鳥哥的 Linux 私房菜館首頁 前往 Linux 基礎文件,新手請從頭學起 前往 Linux 架站文件,網路基礎那章節請務必參考! 前往『網路安全』相關文件網頁 前往 Linux 新手討論區,發問前務必查閱發文規則 前往『ADSL連線分享』相關文件網頁 前往 Study Area 網站
     
 
最近更新日期:2007/07/15
文字模式 (command line) 這種指令下達的方式,在 Linux 裡面,其實就相當於是 bash 的工具與介面! 因為 Linux 就是以 bash 為預設的 shell 的!那麼前幾章我們都已經很快樂的進行了很多的指令下達囉∼ 所以說, bash shell 根本就不難吧∼是啦!只要能夠熟悉的話,那麼確實他也不是這麼不可親近的一項工具啊∼ 這個章節中,鳥哥會由變數談起,先講到環境變數的功能與修改的問題, 然後會繼續提到歷史指令的運用。接下來,就會談一下『資料流重導向』這個重要概念, 最後就是管線命令的利用啦!好好清一清腦門,準備用功去囉∼ ^_^ 這個章節幾乎是所有 command line 與未來主機維護與管理的重要基礎,一定要好好仔細的閱讀喔!

1. Bash shell
  1.1 什麼是 shell ?
  1.2 系統的 shell 與 /etc/shells 功能
  1.3 Bash shell 的功能
  1.4 Bash shell 的內建命令: type
  1.5 指令的下達
2. Shell 的變數功能
  2.1 變數的取用與設定echo, 變數設定規則, unset
  2.2 變數的用途?
  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 登錄訊息顯示資料: /etc/issue, /etc/motd
  4.3 環境設定檔: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source
  4.4 終端機的環境設定: stty, set
  4.5 萬用字元與特殊符號:
5. 資料流重導向 (redirecte)
  5.1 何謂資料流重導向?
  5.2 命令執行的判斷依據: ; , &&, ||
6. 管線命令 (pipe):
  6.1 擷取命令: cut, grep
  6.2 排序命令: sort, wc, uniq
  6.3 雙向重導向: tee
  6.4 字元轉換命令: tr, col, join, paste, expand
  6.5 分割命令: split
  6.6 參數代換: xargs
  6.7 關於減號 - 的用途
7. 本章習題練習
8. 針對本文的建議:http://phorum.vbird.org/viewtopic.php?t=23884

大標題的圖示Bash shell
我們在前面的 什麼是 Linux 那個章節當中,提到了, 管理整個硬體的其實是核心 (kernel),那我們一般使用者 (user) 則是以 shell 來跟核心溝通∼ 讓核心達到我們所想要達到的工作目的。那麼系統有多少 shell 可用呢? 為什麼我們要使用 bash 啊?!底下分別來談一談喔!


小標題的圖示什麼是 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 其實是比較狹隘的定義,一般來說,在 Linux 裡頭,所謂的 shell 就是指 BASH 這個文字模式的 shell 囉。但是,廣義的 shell 也可以是 KDE 之類的圖形介面控制軟體呢! 因為他也可以幫我們與 kernel 進行溝通啊!不過,在鳥哥的 Linux 私房菜裡面, 如果沒有特別說明的話,那麼我們的 shell 指的是比較狹義的,也就是文字模式的 shell 喔!

    另外,鳥哥常常聽到這個問題:『我幹嘛要學習 shell 呢? 不是已經有很多的工具可以提供我設定我的主機了?我為何要花這麼多時間去學指令呢?不是以 X Window 按一按幾個按鈕就可以搞定了嗎?為什麼要這麼麻煩?』唉∼還是得一再地強調, X Window 還有 Web 介面的設定工具例如 webmin 是真的好用的傢伙, 他真的可以幫助我們很簡易的設定好我們的主機,甚至是一些很進階的設定都可以幫我們搞定。

    但是鳥哥在序章裡面也已經提到過相當多次了, X Window 的介面雖然親善,功能雖然強大,而 web 介面的工具也可以提供我們很友善的服務,但是畢竟他是將所有利用到的套件都整合在一起的一個套件而已, 並非是一個完整的套件,所以某些時候當你升級或者是使用其他套件管理模組( 例如 tarball 而非 rpm 檔案等等 )時,就會造成設定的困擾了。

    此外,遠端連線時,文字介面的傳輸速度一定比較快, 而且,較不容易出現斷線或者是資訊外流的問題,因此, shell 真的是得學習的一項工具。而且,他可以讓您更深入 Linux ,更瞭解他, 而不是只會按一按滑鼠而已!所謂『天助自助者!』多摸一點文字模式的東西,會讓你與 Linux 更親近呢!

    有些朋友也很可愛,常會說:『我學這麼多幹什麼? 又不常用,也用不到!』嘿嘿!有沒有聽過『書到用時方恨少?』 當你的主機一切安然無恙的時候,您當然會覺得好像學這麼多的東西一點幫助也沒有呀! 萬一,某一天真的不幸給他中標了,您該如何是好?是直接重新安裝? 還是先追蹤入侵來源後進行漏洞的修補?或者是乾脆就關站好了?這當然涉及很多的考量, 但就以鳥哥的觀點來看,多學一點總是好的,尤其我們可以有備而無患嘛!甚至學的不精也沒有關係,瞭解概念也就 OK 啦!畢竟沒有人要您一定要背這麼多的內容啦!瞭解概念就很了不起了!

    此外,如果您真的有心想要將您的主機管理的好,那麼良好的 shell 程式編寫是一定需要的啦!就鳥哥自己來說,我管理的主機雖然還不算多, 只有區區不到十部,但是如果每部主機都要花上幾十分鐘來查閱他的 log file 以及相關的資訊,那麼我可能會瘋掉!基本上,也太沒有效率了!這個時候,如果能夠藉由 shell 提供的命令重導向( 或稱資料流重導向 ),以及管線命令,呵呵!那麼我分析 log file 只要花費不到十分鐘就可以看完所有的主機之重要資訊了!相當的好用呢!

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

    那麼目前我們的 Linux (以 FC4 為例) 有多少我們可以使用的 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 的功能都差不多, 有的只是語法上面的不同而已。目前一般的使用者使用習慣上,似乎是以 bash 及 csh 為主要的兩個 shell 。OK!這麼多的 shell 我要使用哪一個啊?呵呵!使用 Linux 支援最廣泛的 bash 就好了! 不要想太多!另外,咦!為什麼我們系統上的 shell 要寫入 /etc/shells 這個檔案啊? 這是因為系統某些服務在運行過程中, 會去檢查使用者能夠使用的 shells ,而這些 shell 的查詢就是藉由 /etc/shells 這個檔案囉!

    舉例來說,某些 FTP 網站會去檢查使用者的可用 shell ,而如果你不想要讓這些使用者使用 FTP 以外的主機資源時,可能會給予該使用者一些怪怪的 shell,讓使用者無法以其他服務登入主機。 這個時候,你就得將那些怪怪的 shell 寫到 /etc/shells 當中了。舉例來說,我們的 FC4 的 /etc/shells 裡頭就有個 /sbin/nologin 檔案的存在,這個就是我們說的怪怪的 shell 囉∼

    那麼,再想一想,我這個使用者什麼時候可以取得 shell 來工作呢?還有, 我這個使用者預設會取得哪一個 shell 啊?!還記得我們在 首次進入 Linux -- 以文字方式登入 那個章節當中提到的登入動作吧?當我登入的時候,系統就會給我一個 shell 讓我來工作了。 而這個登入取得的 shell 就記錄在 /etc/passwd 這個檔案內!這個檔案的內容是啥?
    [root@linux ~]# 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 是怎麼一回事呢?這個 shell 是 GNU 計畫中重要的工具軟體之一,目前也是 GNU 作業系統中標準的 shell ,他主要相容於 sh ,並且依據一些使用者需求,而加強的 shell 版本,可以說目前幾乎所有的 Linux distribution 都是使用 bash 作為管理核心的主要 shell !因此,不論您使用的是那個 distribution ,你都難逃需要學習 bash 的宿命啦!那麼這個 shell 有什麼好處,幹嘛 Linux 要使用他作為預設的 shell 呢? BASH 主要的優點有底下幾個:

  • 命令編修能力(類似 DOS 的 doskey 功能):
  • 使用 bash 裡頭,個人認為相當棒的一個功能就是『他能記憶使用過的指令!』 這功能真的相當的棒!因為我只要在指令列按『上下鍵』就可以找到前一個輸入的指令!而在很多 distribution 裡頭,預設的指令記憶功能可以到達 1000 個!也就是說, 你曾經下達過的指令都被記錄下來了,記錄的檔案在你的家目錄內的 .bash_history !不過,需要留意的是, ~/.bash_history 記錄的是前一次登入以前所執行過的指令, 而至於這一次登入所執行的指令都被暫存在暫記憶體中,當您成功的登出系統後,該指令記憶才會記錄到 .bash_history 當中

    這有什麼功能呢?最大的好處就是可以『查詢曾經做過的舉動!』, 如此可以知道你的執行步驟,那麼就可以追蹤您曾下達的指令,以作為除錯的工具! 但如此一來也有個煩惱,就是如果被駭客入侵了,那麼他只要翻你曾經執行過的指令, 剛好你的指令又跟系統有關(例如直接輸入 MySQL 的密碼在指令列上面)那麼很容易就被破解你的 Linux 主機!所以,最好是將記錄的指令數目減小一點較好

  • 命令與檔案補全功能:
  • 還記得我們在 首次進入 Linux 的熱門按鍵 一節當中提到的 [tab] 這個按鍵嗎?!這個按鍵的功能就是在 bash 裡頭才有的啦!常常在 bash 環境中使用 [tab] 是個很棒的習慣喔!因為至少可以讓你 1)少打很多字; 2)確定輸入的資料是正確的! 使用 [tab] 按鍵的時機依據 [tab] 接在指令後或參數後而有所不同。我們再複習一次:
    • [Tab] 接在一串指令的第一個字的後面,則為命令補全;
    • [Tab] 接在一串指令的第二個字以後時,則為『檔案補齊』!
    所以說,如果我想要知道我的環境中,所有可以執行的指令有幾個? 就直接在 bash 的提示字元後面輸入兩個 [tab][tab] 就能夠輸出所有的可執行指令了。 那如果想要知道系統當中所有以 c 為開頭的指令呢?就按下 c[tab][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 還支援許多的萬用字元來幫助使用者查詢與指令下達。 舉例來說,想要知道 /usr/X11R6/bin 底下有多少以 xt 為開頭的檔案嗎?使用: ls -l /usr/X11R6/bin/xt* 就能夠知道囉∼此外,還有其他可供利用的萬用字元, 這些都能夠加快使用者的操作呢!

    小標題的圖示Bash shell 的內建命令: type
    我們在首次進入 Linux 章節當中,提到關於 Linux 的線上說明文件 部分,也就是 man page 的內容,那麼 bash 有沒有什麼說明文件啊?開玩笑∼ 這麼棒的東西怎麼可能沒有說明文件!請您在 shell 的環境下,直接輸入 man bash 瞧一瞧, 嘿嘿!不是蓋的吧!讓您看個幾天幾夜也無法看完的 bash 說明文件,可是很詳盡的資料啊! ^_^

    不過,在這個 man bash 所出現的 man page 當中,不知道您是否有察覺到,咦! 怎麼這個說明文件裡面有其他的檔案說明啊?舉例來說,那個 cd 指令的說明就在這個 man page 內? 然後我直接輸入 man cd 時,怎麼出現的畫面中,最上方竟然出現一堆指令的介紹??這是怎麼回事? 為了方便 shell 的操作,其實 bash 已經『內建』了很多指令了,例如上面提到的 cd , 還有例如 umask 等等的指令,都是內建在 bash 當中的呢!

    那我怎麼知道這個指令是來自於外部指令(指的是其他非 bash 套件所提供的指令) 或是內建在 bash 當中的呢? 嘿嘿!利用 type 這個指令來觀察即可!舉例來說:
    [root@linux ~]# type [-tpa] name
    參數:
        :不加任何參數時,則 type 會顯示出那個 name 是外部指令還是 bash 內建的指令!
    -t  :當加入 -t 參數時,type 會將 name 以底下這些字眼顯示出他的意義:
          file    :表示為外部指令;
          alias   :表示該指令為命令別名所設定的名稱;
          builtin :表示該指令為 bash 內建的指令功能;
    -p  :如果後面接的 name 為指令時,會顯示完整檔名(外部指令)或顯示為內建指令;
    -a  :會將由 PATH 變數定義的路徑中,將所有含有 name 的指令都列出來,包含 alias
    範例:
    範例一:查詢一下 ls 這個指令是否為 bash 內建?
    [root@linux ~]# type ls
    ls is aliased to `ls --color=tty'
    # 沒有加上任何參數,僅列出 ls 這個指令的最主要使用情況
    [root@linux ~]# type -t ls
    alias
    # -t 參數則僅列出 ls 這個指令的最主要使用情況說明
    [root@linux ~]# type -a ls
    ls is aliased to `ls --color=tty'
    ls is /bin/ls
    # 利用所有方法找出來的 ls 相關資訊都會被列出來!
    
    範例二:那麼 cd 呢?
    [root@linux ~]# type cd
    cd is a shell builtin
    
    透過 type 這個指令的用途,我們可以知道每個指令是否為 bash 的內建指令。 此外,由於利用 type 搜尋後面的名稱時,如果後面接的名稱並不能以執行檔的狀態被找到, 那麼該名稱是不會被顯示出來的。舉例來說,您的 FC4 應該不會有 vbird 這個指令吧?! 輸入 type -p vbird 看一下,果然沒有輸出任何資料!而如果您輸入的是 type -p touch 呢? 則會出現 /bin/touch !呵呵!所以,這個 type 也可以用來作為類似 which 指令的用途啦!找指令用的!


    小標題的圖示指令的下達
    我們在 首次進入 Linux 一節當中,已經提到過在 shell 環境下的指令下達方式,不過,因為這個部分實在很重要,所以,我們還是再次的提醒一次!
    [root@linux ~]# command [-options] parameter1 parameter2 ...
                      指令     選項      參數(1)    參數(2)
    說明:
    0. 一行指令中第一個輸入的絕對是『指令(command)』或『可執行檔案』
    1. command 為指令的名稱,例如變換路徑的指令為 cd 等等;
    2. 中刮號[]並不存在於實際的指令中,而加入參數設定時,通常為 - 號,例如 -h;
       有時候完整參數名稱會輸入 -- 符號,例如 --help;
    3. parameter1 parameter2.. 為依附在 option 後面的參數,
       或者是 command 的參數; 
    4. command, -options, parameter1.. 這幾個咚咚中間以空格來區分,
       不論空幾格 shell 都視為一格; 
    5. 按下 [Enter] 按鍵後,該指令就立即執行。[Enter] 按鍵為 <CR> 字符,
       他代表著一行指令的開始啟動。
    6. 指令太長的時候,可以使用 \ 符號來跳脫 [Enter] 符號,
       使指令連續到下一行。注意! \ 後就立刻接特殊字符。
    7. 在 Linux 系統中,英文大小寫字母是不一樣的。舉例來說, cd 與 CD 並不同。
    範例:
    
    範例一:列出 /root 底下的各檔案名稱
    [root@linux ~]# ls -al /root
    [root@linux ~]# ls     -al      /root
    # 不論指令與參數中間空幾格,都是可以接受的!
    
    範例二:如果指令太長的話,如何使用兩行來輸出?
    [root@linux ~]# cp /var/spool/mail/root /etc/crontab \
    > /etc/fstab /root
    # 上面這個指令,就是將三個檔案複製到 /root 這個目錄下而已。不過,因為指令太長,
    # 於是鳥哥就利用 \[Enter] 來將 [Enter] 這個按鍵『跳脫!』開來,讓
    # [Enter] 按鍵不再具有上述說明的第 5 點功能!好讓指令繼續在下一行輸入。
    # 需要特別留意, [Enter] 按鍵是緊接著反斜線 (\) 的,兩者中間沒有其他字元。
    # 因為 \ 僅跳脫『緊接著的下一個字符』而已!所以,萬一我寫成:
    # \ [Enter] ,亦即 [Enter] 與反斜線中間有一個空格時,則 \ 跳脫的是『空白鍵』
    # 而不是 [Enter] 按鍵!這個地方請在仔細的看一遍!很重要!
    # 如果順利跳脫 [Enter] 後,下一行最前面就會主動出現 > 的符號,
    # 您可以繼續輸入指令囉!也就是說,那個 > 是系統自動出現的,你不需要輸入。
    
    總之,當我們順利的在終端機 (tty) 上面登入後, Linux 就會依據 /etc/passwd 檔案的設定給我們一個 shell ,預設就是 bash ,然後我們就可以依據上面的指令下達方式來操作 shell, 之後,我們就可以透過 man 這個線上查詢來查詢指令的使用方式與參數說明, 很不錯吧!那麼我們就趕緊更進一步來操作 bash 這個好玩的東西囉!

    大標題的圖示Shell 的變數功能
    在繼續研究 BASH 之前,我們得要先就 變數 這個東西來討論一番。 為什麼要討論變數呢?又,變數是啥玩意兒啊?!先來談一談國中數學好了,您是否依稀記得, 我們國中時候學過所謂的『 y = ax + b 』這東西?其中, y 是變數, x 則是這個變數的內容啊! 講的更簡單一點,我們可以『用一個簡單的 "字眼" 來取代另一個比較複雜或者是容易變動的資料』。這有什麼好處啊?最大的好處就是『方便!』。

    如果以 Linux 主機的運作來說明好了,因為在主機裡面有太多的資料需要進行存取了, 而這些資料都是一些服務所必須的,例如某個名為 dmtsai 的帳號,他的 mail 的存取路徑預設是在 /var/spool/mail/dmtsai 、家目錄預設在 /home/dmtsai 等等。那如果換了另外一個帳號呢? 假設另一個帳號名稱為 vbird ,你猜他的郵件與家目錄在哪?應該是在 /var/spool/mail/vbird 與 /home/vbird 對吧! 那麼我們主機的郵件服務是否要記錄好幾個不同的路徑啊?會不會太麻煩?這當然很麻煩囉∼ 所以為了簡化整個運作流程,我們就可以透過某個變數功能,讓這個變數可以依據不同的使用者而變更內容, 如此一來,系統的郵件服務只要依據那個變數去取得所需要的資料即可,就不需要記錄不同的路徑囉。

    舉例來說,我們每個帳號的郵件信箱預設是以 MAIL 這個變數來進行存取的, 當 dmtsai 這個使用者登入時,他便會取得 MAIL 這個變數,而這個變數的內容其實就是 /var/spool/mail/dmtsai, 那如果 vbird 登入呢?他取得的 MAIL 這個變數的內容其實就是 /var/spool/mail/vbird 。 而我們使用信件讀取指令 mail 來讀取自己的郵件信箱時,嘿嘿,這支程式可以直接讀取 MAIL 這個變數的內容, 就能夠自動的分辨出屬於自己的信箱信件囉!這樣一來,設計程式的設計師就真的很方便的啦!

    當然我們可以改變這些個變數,但是如果該變數是直接深植於套件當中, 那麼當你修改了某些參數之後,嘿嘿!你的套件就必須要『由原始碼直接更新再編譯』 才行!這樣似乎很麻煩,所以囉,變數真的是很方便的啦!
    Tips:
    舉個簡單的例子來說, sendmail 的 smtp 存放 mail 路徑是經由 /etc/profile 裡頭的:
      MAIL="/var/spool/mail/$USER"
    來設定的,而當我修改了上面這一個咚咚,然後重新開機之後,嘿嘿嘿嘿! 我的郵件就可以存放到不同的路徑去了!而且不會有問題!可以順利的『在 Linux 主機上面』收發。然而問題發生在 pop3 這個服務上面,由於 pop3 的預設路徑是在 source code 裡頭,而且就正是 /var/spool/mail 這個路徑,也就是說,不論我怎麼修正我的『變數』, pop3 都不為所動!唉∼真慘,所以就無法直接以 pop3 來收信了(例如 OutLook 就不能工作了)!會發生密碼不接受的問題呢!
    再來繼續講到其他的變數功能好了,我們前面已經提到過很多次,能不能執行某個指令, 與 PATH 這個變數也有很大的關係的。舉例來說,我們在任何地方下達 ls 這個指令時,系統就是透過 PATH 這個變數裡面的內容所記錄的路徑順序來搜尋指令的呢!如果在搜尋完 PATH 變數內的路徑還找不到 ls 這個指令時, 就會在螢幕上顯示『 command not found 』的錯誤訊息了。

    這些還都只是系統預設的變數的目的,如果是個人的設定方面的應用呢:例如你要寫一個大型的 script (批次檔)時,有些資料因為可能由於使用者習慣的不同而有差異,比如說路徑好了,由於該路徑在 script 被使用在相當多的地方,如果下次換了一部主機,都要修改 script 裡面的所有路徑,那麼我一定會瘋掉! 這個時候如果使用變數,而將該變數的定義寫在最前面,後面相關的路徑名稱都以變數來取代, 嘿嘿!那麼你只要修改一行就等於修改整篇 script 了!方便的很!所以,良好的程式設計師都會善用變數的定義! ( 這個部分我們在後續的 shell script 再次提及的!)

    如果說的學理一點,那麼由於在 Linux System 下面,所有的執行續都是需要一個執行碼, 而就如同上面提到的,你『真正以 shell 來跟 Linux 溝通,是在正確的登入 Linux 之後!』這個時候你就有一個 bash 的執行程序,也才可以真正的經由 bash 來跟系統溝通囉!而在進入 shell 之前,也正如同上面提到的,由於系統需要一些變數來提供他資料的存取(或者是一些環境的設定參數值, 例如是否要顯示彩色等等的),所以就有一些所謂的『環境變數』 需要來讀入系統中了!這些環境變數例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的, 為了區別與自訂變數的不同,環境變數通常以大寫字元來表示呢!

    好了,那麼我們就簡單的來對『什麼是變數』作個簡單的定義好了: 『變數就是以一組文字或符號等,來取代一些設定或者是一串保留的資料!』, 例如:我設定了『myname』就是『VBird』,所以當你讀取 myname 這個變數的時候,系統自然就會知道!哈!那就是 VBird 啦!最簡單的例子可以取 PATH 來說明!如果你對於『相對路徑與絕對路徑』還有點印象的話, 那麼應該曉得『要下達正確的指令,應該需要指定路徑與檔名』才行!例如你的 ls 指令應該需要以『/bin/ls』來下達指令才對,那麼為何你在任意的路徑下都可以執行 ls 呢?而不需要指定路徑呢?這是因為系統已經預設了一些『搜尋路徑(PATH)』了, 所以當你需要執行一些指令的時候,系統就會依照該 PATH 的設定來進行指令的搜尋!而這個 PATH 就是所謂的變數了!

    那麼如何『顯示變數』呢?這就需要使用到 echo 這個指令啦!


    小標題的圖示變數的取用與設定:echo, 變數設定規則, unset
    說的口沫橫飛的,也不知道『變數』與『變數代表的內容』有啥關係? 當然啦,那我們就將『變數』的『內容』拿出來給您瞧瞧就好了。利用 echo 這個指令來取用變數, 但是,變數在被取用時,前面必須要加上 $ 才行,舉例來說,要知道 PATH 的內容,該如何是好?
    [root@linux ~]# echo $variable
    [root@linux ~]# echo $PATH
    /bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
    [root@linux ~]# echo ${PATH}
    
    變數的取用就如同上面的範例,利用 ehco 就能夠讀出,只是需要在變數名稱前面加上 $ , 或者是以 ${variable} 的方式來取用都可以!當然啦,那個 echo 的功能可是很多的, 我們這裡單純是拿 echo 來讀出變數的內容而已,更多的 echo 使用,請自行給他 man echo 吧! ^_^

    例題一:請在螢幕上面顯示出您的環境變數 HOME 與 MAIL:
    答:
      echo $HOME
      echo $MAIL

    OK!現在我們知道了變數與變數內的之間的相關性了,好了,那麼我要如何『設定』或者是『修改』 某個變數的內容啊?!很簡單啦!用『等號(=)』連接變數與他的內容就好啦!舉例來說: 我要將 myname 這個變數名稱的內容設定為 VBird ,那麼:
    [root@linux ~]# echo $myname
       <==這裡並沒有任何資料∼因為這個變數尚未被設定!是空的!
    [root@linux ~]# myname=VBird
    [root@linux ~]# echo $myname
    VBird  <==出現了!因為這個變數已經被設定了!
    
    瞧!如此一來,這個變數名稱 myname 的內容就帶有 VBird 這個資料囉∼ 而由上面的例子當中,我們也可以知道: 當一個變數名稱尚未被設定時,預設的內容是『空』的另外,變數在設定時,還是需要符合某些規定的,否則會設定失敗喔! 這些規則如下所示啊!
    1. 變數與變數內容以等號『=』來連結;
    2. 等號兩邊不能直接接空白字元;
    3. 變數名稱只能是英文字母與數字,但是數字不能是開頭字元;
    4. 若有空白字元可以使用雙引號『 " 』或單引號『 ' 』來將變數內容結合起來,但須要特別留意, 雙引號內的特殊字元可以保有變數特性,但是單引號內的特殊字元則僅為一般字元;
    5. 必要時需要以跳脫字元『 \ 』來將特殊符號 ( 如 Enter, $, \, 空白字元, ' 等 ) 變成一般符號;
    6. 在一串指令中,還需要藉由其他的指令提供的資訊,可以使用 quote 『 ` command` 』;(特別特別注意,那個 ` 是鍵盤上方的數字鍵 1 左邊那個按鍵,而不是單引號!)
    7. 若該變數為擴增變數內容時,則需以雙引號及 $變數名稱 如:『 "$PATH":/home』繼續累加內容;
    8. 若該變數需要在其他子程序執行,則需要以 export 來使變數變成環境變數, 如『export PATH』;
    9. 通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷 ( 純粹依照使用者興趣與嗜好 ) ;
    10. 取消變數的方法為:『unset 變數名稱』。
    底下我們舉幾個例子來讓您試看看,就知道怎麼設定好您的變數囉!
    範例一:設定一變數 name ,且內容為 VBird 。
    [root@linux ~]# 12name=VBird
    -bash: 12name=VBird: command not found  <==螢幕會顯示錯誤!因為不能以數字開頭!
    [root@linux ~]# name = VBird  <==還是錯誤!因為有空白!
    [root@linux ~]# name=VBird    <==OK 的啦!
    
    範例二:承上題,若變數內容為 VBird's name 呢?
    [root@linux ~]# name=VBird's name  
    # 因為單引號可以將 Enter 這個特殊字符取消,所以,您可以繼續在下一行輸入內容∼
    # 不過,這與我們要達到的功能不同,所以,算是失敗的啦!
    [root@linux ~]# name="VBird's name"  <==OK 的啦!
    [root@linux ~]# name=VBird\'s\ name
    # 利用反斜線 (\) 跳脫特殊字元,例如單引號與空白鍵,這也是 OK 的啦!
    
    範例三:我要在 PATH 這個變數當中『累加』:/home/dmtsai/bin 這個目錄
    [root@linux ~]# PATH=$PATH:/home/dmtsai/bin
    [root@linux ~]# PATH="$PATH":/home/dmtsai/bin
    # 上面這兩種格式在 PATH 裡頭的設定都是 OK 的!但是底下的例子就不見得囉!
    
    範例四:呈範例三,我要將 name 的內容多出 "yes" 呢?
    [root@linux ~]# name=$nameyes  
    # 知道了吧?如果沒有雙引號,那麼變數成了啥?name 的內容是 $nameyes 這個變數!
    # 呵呵!我們可沒有設定過 nameyes 這個變數吶!所以,應該是底下這樣才對!
    [root@linux ~]# name="$name"yes
    [root@linux ~]# name=${name}yes
    
    範例五:如何讓我剛剛設定的 name=VBird 可以用在下個 shell 的程序?
    [root@linux ~]# name=VBird
    [root@linux ~]# bash        <==進入到所謂的子程序
    [root@linux ~]# echo $name  <==嘿嘿!並沒有剛剛設定的內容喔!
    [root@linux ~]# exit        <==離開剛剛的子程序
    [root@linux ~]# export name
    [root@linux ~]# bash        <==進入到所謂的子程序
    [root@linux ~]# echo $name  <==出現了設定值了!
    [root@linux ~]# exit        <==離開剛剛的子程序
    # 什麼是『子程序』呢?就是說,在我目前這個 shell 的情況下,
    # 去啟用另一個新的 shell ,新的那個 shell 就是子程序啦!在一般的狀態下,
    # 父程序的自訂變數是無法在子程序內使用的。但是透過 export 將變數變成
    # 環境變數後,就能夠在子程序底下應用了!很不賴吧!至於程序的相關概念,
    # 我們會在『程序與資源管理』章節當中提到的喔!
    
    範例六:如何進入到您目前核心的模組目錄?
    [root@linux ~]# cd /lib/modules/`uname -r`/kernel
    # 每個作業系統核心版本都不相同,以 FC4 為例,他的預設核心版本是 
    # 2.6.11-1.1369_FC4 所以,他的模組目錄在 /lib/modules/2.6.11-1.1369_FC4/kernel 。
    # 因為每個 distributions 的這個值都不相同,但是我們卻可以利用 uname -r 這個指令
    # 先取得版本資訊,所以囉,就可以透過上面指令當中的內含指令 `uname -r` 
    # 先取得版本輸出到 cd .. 那個指令當中,就能夠順利的進入目前核心的驅動程式所放置
    # 的目錄囉!很方便吧!
    
    範例七:取消剛剛設定的 name 這個變數內容
    [root@linux ~]# unset name
    
    根據上面的案例你可以試試看!就可以瞭解變數的設定囉!這個是很重要的呦!請勤加練習!! 其中,較為重要的一些特殊符號的使用囉!例如單引號、雙引號、跳脫字元、錢字號、quote 符號等等,底下的例題想一想吧!

    例題二:在變數的設定當中,單引號與雙引號的用途有何不同?
    答:
      單引號與雙引號的最大不同在於雙引號仍然可以保有變數的內容,但單引號內僅能是一般字元 ,而不會有特殊符號。我們以底下的例子做說明:假設您定義了一個變數, name=VBird ,現在想以 name 這個變數的內容定義出 myname 顯示 VBird its me 這個內容,要如何訂定呢?

        [root@linux ~]# name=VBird
        [root@linux ~]# echo $name
        VBird
        [root@linux ~]# myname="$name its me"
        [root@linux ~]# echo $myname
        VBird its me
        [root@linux ~]# myname='$name its me'
        [root@linux ~]# echo $myname
        $name its me

      發現了嗎?沒錯!使用了單引號的時候,那麼 $name 將失去原有的變數內容, 僅為一般字元的顯示型態而已!這裡必需要特別小心在意!

    例題三:在指令下達的過程中, quote ( ` ) 這個符號代表的意義為何?
    答:
      在一串指令中,在 ` 之內的指令將會被先執行,而其執行出來的結果將做為外部的輸入資訊!例如 uname -r 會顯示出目前的核心版本,而我們的核心版本在 /lib/modules 裡面,因此,你可以先執行 uname -r 找出核心版本,然後再以『 cd 目錄』到該目錄下,當然也可以執行如同上面範例六的執行內容囉。

      另外再舉個例子,我們也知道, locate 指令可以列出所有的相關檔案檔名,但是, 如果我想要知道各個檔案的權限呢?舉例來說,我想要知道每個 crontab 相關檔名的權限:

        [root@linux ~]# ls -l `locate crontab`

      如此一來,先以 locate 將檔名資料都列出來,再以 ls 指令來處理的意思啦!瞭了嗎? ^_^


    小標題的圖示變數的用途
    我們知道 PATH 這個變數是我們在執行指令的時候,所需要具備的指令搜尋目錄資料, 沒有他,我們就得要使用絕對路徑來下達指令才行。當然,還有很多變數都有他特別的意義存在。 除此之外,『我為何需要設定變數』呢? 要跟大家介紹這個『變數』,當然是因為他有相當程度的意義存在的啊! 底下就跟大家介紹一下,鳥哥設定變數的時機喔!
      我的案例一:最簡單的例子就是 『簡化路徑名稱』囉!以鳥哥為例,我的工作在 Unix 系統之下進行一些數值模式的模擬工作,偏偏由於資料量太大, 為了怕日後忘記這個目錄的內容與主要的意義,所以我的檔名都取的很長, 偏偏在執行模式的過程中,常常會切換目錄!我哩ㄌㄟ,光是打那幾行路徑名稱就快要瘋掉了! 所以我就設定那幾行目錄名稱成為一個四個字元的變數,如此一來我只要輸入『 cd $VARI 』這個指令,嘿嘿!馬上就移動到該路徑下了!很方便吧!當然變數的意義還不止於此, 不過這是最簡單的實例說明囉!
      我的案例二:另外一個常常需要變數的咚咚是在 scripts 裡面,例如我寫的一個偵測登錄檔的小程式 logfile.sh 這個咚咚, 由於裡頭常常需要用到『儲存路徑』,偏偏可能每個人的存取路徑都不太一樣, 而如果要修改存取路徑的話,嘿嘿!好幾十行要同時修改呢!還可能會改錯! 那麼我只要定義一個變數,然後後續的所有資料都使用這個變數的內容!嘿嘿! 那麼只要大家修改了這個變數的內容(只要一行),後續的動作就不需要修正了!這個動作常在程式或者是 script 當中看到的!
    所以囉,有很多的時候為了方便或者是使用於 scripts 的意義,我們必須要設定變數! 當然囉,如果是跟系統終端機環境有關的設定值,很多也是利用變數來幫助達成的∼ 底下我們就來談一談所謂的『環境變數』吧!


    小標題的圖示環境變數的功能
    環境變數可以幫我們達到很多功能∼包括家目錄的變換啊、提示字元的顯示啊、執行檔搜尋的路徑啊等等的, 還有很多很多啦!那麼,既然環境變數有那麼多的功能,問一下,目前我的 shell 環境中, 有多少變數啊?!呵呵!我們可以利用兩個指令來查閱,分別是 env 與 export 呢!


  • 一些環境變數的說明: env
  • 範例一:列出目前的 shell 環境下的所有環境變數與其內容。
    [root@linux ~]# env
    HOSTNAME=linux.dmtsai.tw   <== 這部主機的主機名稱
    SHELL=/bin/bash            <== 目前這個環境下,使用的 Shell 是哪一個程式?
    TERM=xterm                 <== 這個終端機使用的環境是什麼類型
    HISTSIZE=1000              <== 這個就是『記錄指令的筆數』在 FC4 預設可記錄 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: <== 一些顏色顯示
    ENV=/root/.bashrc          <== 使用的個人環境設定檔
    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.UTF-8           <== 這個與語系有關,底下會再介紹!
    HOME=/root                 <== 這個使用者的家目錄啊!
    _=/bin/env                 <== 上一次使用的指令的最後一個參數(或指令本身)
    
    env 是 environment (環境) 的簡寫啊∼ 上面的例子當中,是列出來所有的環境變數。當然,如果使用 export 也會是一樣的內容∼ 只不過, export 還有其他額外的功能就是了,我們等一下再提這個 export 指令。 那麼上面這些變數有些什麼功用呢?底下我們就一個一個來分析分析!
    • HOME : 代表使用者的家目錄。還記得我們可以使用 cd ~ 去到使用者的家目錄嗎?或者利用 cd 就可以直接回到使用者家目錄了。那就是取用這個功能啦∼ 有很多程式都可能會取用到這個變數的值喔!

    • SHELL : 告知我們,目前這個環境使用的 SHELL 是哪支程式? 如果是 bash 的話,預設是 /bin/bash 的啦!

    • HISTSIZE : 這個與『歷史命令』有關,亦即是, 我們曾經下達過的指令可以被系統記錄下來,而記錄的『筆數』則是由這個值來設定的。

    • ENV : 這個使用者所使用的個人化環境設定檔的讀取檔案。

    • 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@linux ~]# declare -i number=$RANDOM*10/32767 ; echo $number
      8   <== 此時會隨機取出 0~9 之間的數值喔!
      
    大致上是有這些環境變數啦∼裡面有些比較重要的參數,在底下我們都會另外進行一些說明的∼

  • 其他所有的變數說明: set
  • 而除了這些環境變數之外,還有沒有什麼重要的變數呢?當然有啊! 我們在 bash 的環境下,其實還有一些挺重要的變數,這些變數是『在這個 shell 環境下有效』的, 如果是在『子程序』,這些變數值就不會相同了。 那麼如何觀察目前 shell 環境下的所有變數呢?很簡單啊,就用 set 即可!set 這個指令除了會將環境變數列出來之外,其他我們的自訂變數,與所有的變數,都會被列出來喔!資訊多好多。 底下僅列出幾個重要的內容。
    [root@linux ~]# set
    BASH=/bin/bash           <== bash 的主程式放置路徑
    BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release" 
    [5]="i386-redhat-linux-gnu")      <== bash 的版本啊!
    BASH_VERSION='3.00.16(1)-release' <== bash 的版本啊!
    COLORS=/etc/DIR_COLORS.xterm      <== 使用的顏色紀錄檔案
    COLUMNS=115              <== 在目前的終端機環境下,使用的欄位有幾個字元長度
    HISTFILE=/root/.bash_history      <== 歷史命令記錄的放置檔案,隱藏檔
    HISTFILESIZE=1000        <== 存起來(與上個變數有關)的檔案之指令的最大紀錄筆數。
    HISTSIZE=1000            <== 目前環境下,可記錄的歷史命令最大筆數。
    HOSTTYPE=i386            <== 主機安裝的軟體主要類型。我們用的是 i386 相容機器軟體
    IFS=$' \t\n'             <== 預設的分隔符號
    LINES=35                 <== 目前的終端機下的最大行數
    MACHTYPE=i386-redhat-linux-gnu    <== 安裝的機器類型
    MAILCHECK=60             <== 與郵件有關。每 60 秒去掃瞄一次信箱有無新信!
    OLDPWD=/home             <== 上個工作目錄。我們可以用 cd - 來取用這個變數。
    OSTYPE=linux-gnu         <== 作業系統的類型!
    PPID=20046               <== 父程序的 PID (會在後續章節才介紹)
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"'
                             <== 上面這個是命令提示字元!與底下也有關。
    PS1='[\u@\h \W]\$ '      <== PS1 就厲害了。這個是命令提示字元,也就是我們常見的
                                 [root@linux ~]# 或 [dmtsai ~]$ 的設定值啦!可以更動的!
    RANDOM=13586             <== 亂數啊!上面已經提過囉∼
    SUPPORTED=zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8 <== 本系統所支援的語系
    name=VBird               <== 剛剛設定的自訂變數也可以被列出來喔!
    $                        <== 目前這個 shell 所使用的 PID
    ?                        <== 剛剛執行完指令的回傳值。
    
    一般來說,不論是否為環境變數,只要跟我們目前這個 shell 的操作介面有關的變數, 通常都會被設定為大寫字元,也就是說,『基本上,在 Linux 預設的情況中,使用{大寫的字母}來設定的變數一般為系統內定需要的變數』。

    使用 set 除了會將系統的預設值秀出來之外,連帶的所有的你自己設定的變數也會被秀出來! 同時需要注意的是,若當時有相當多人同時在線上的話,那麼 你的變數只能給自己使用 ( 除非改的是系統的預設參數檔,如 /etc/profile ),而不會干擾到別人的!就如同前面所說的, 由於你登入 Linux 之後會取得一個 PID ,而你的設定將只對這個 PID 與子程序有關!此外, 這次登入所進行的變數設定,如果沒有更動到設定檔, 那麼這次設定的變數在下次登入時將被取消掉 ( 因為程序 PID 不見囉! ) !所以囉, 如果你想要你的變數每次都能在你登入的時候自動就設定好了,那麼就必須將你的設定寫入登入時載入的設定檔! ( 更多的程序相關的說明,不要急∼我們會在後面的 程序與資源管理 當中好好的提一提的! )

    OK!OK!那麼上頭那些變數當中,有哪些是比較重要的?大概有這幾個吧!
    • PS1:(提示字元的設定)

      這是 PS1 (數字的 1 不是英文字母!),這個東西就是我們的『命令提示字元』啊! 當我們每次按下 [Enter] 按鍵去執行某個指令後,最後要再次出現提示字元時, 就會主動去讀取這個變數值了。上頭 PS1 內顯示的是一些特殊符號,每個版本 bash 的 PSI 變數內的特殊符號可能有些許的差異, 你應該主動的以 man bash 去查詢一下相關的變數。底下我列出 FC4 的環境下, 預設的 bash 的 PS1 變數內的特殊符號代表意義:

      • \d :代表日期,格式為 Weekday Month Date,例如 "Mon Aug 1"
      • \H :完整的主機名稱。舉例來說,鳥哥的練習機 linux.dmtsai.tw ,那麼這個主機名稱就是 linux.dmtsai.tw
      • \h :僅取主機名稱的第一個名字。以上述來講,就是 linux 而已, .dmtsai.tw 被省略。
      • \t :顯示時間,為 24 小時格式,如: HH:MM:SS
      • \T :顯示時間,12 小時的時間格式!
      • \A :顯示時間,24 小時格式, HH:MM
      • \u :目前使用者的帳號名稱;
      • \v :BASH 的版本資訊;
      • \w :完整的工作目錄名稱。家目錄會以 ~ 取代;
      • \W :利用 basename 取得工作目錄名稱,所以僅會列出最後一個目錄名。
      • \# :下達的第幾個指令。
      • \$ :提示字元,如果是 root 時,提示字元為 # ,否則就是 $ 囉∼

      OK!所以,由預設的 PS1 內容為: '\[\u@\h \W\]\$ ' 就可以瞭解為何我們的提示字元會是: [root@linux ~]# 了吧!好了,那麼假設我想要有類似底下的提示字元:

        [root@linux /home/dmtsai 16:50 #12]#

      ,那個 # 代表第 12 次下達的指令。 那麼應該如何設定 PS1 呢?可以這樣啊:
      [root@linux home]# PS1='[\u@\h \w \A #\#]\$ '
      [root@linux /home 17:02 #85]# 
      # 看到了嗎?提示字元變了!變的很有趣吧!其中,那個 #85 比較有趣,
      # 如果您按下 [Enter] 後,該數字就會增加喔!為啥?上面有說明ㄇㄟ!
      

    • $:(關於本 shell 的 PID)

      其實這個咚咚代表的是『目前這個 Shell 的執行緒代號』,亦即是所謂的 PID (Process ID)。 更多的程序觀念,我們會在第四章的時候提及。想要知道我們的 shell 的 PID ,就可以: echo $$ 即可!

    • ?:(關於上個執行指令的回傳碼)

      蝦密?問號也是一個特殊的變數?沒錯!在 bash 裡面這個變數可重要的很! 這個變數是:『上個執行的指令所回傳的值』, 上面這句話的重點是『上一個指令』與『回傳值』兩個地方。當我們執行某些指令時, 這些指令都會回傳一個執行後的代碼。一般來說,如果成功的執行該指令, 則會回傳一個 0 值,如果執行過程發生錯誤,就會回傳『錯誤代碼』才對!一般就是以非為 0 的數值來取代。 我們以底下的例子來看看:
      [root@linux ~]# echo $SHELL
      /bin/bash
      [root@linux ~]# echo $?
      0
      # 因為上個指令執行過程中,並沒有錯誤,為成功的執行完畢,所以回傳 0 。
      [root@linux ~]# 12name=VBird
      -bash: 12name=VBird: command not found
      [root@linux ~]# echo $?
      127
      # 發生錯誤啦!所以 echo $? 時,就會出現錯誤的代碼!
      # 我們可以利用這個代碼來搜尋錯誤的原因喔!
      [root@linux ~]# echo $?
      0
      # 咦!怎麼又變成正確了?這是因為 "?" 只與『上一個執行指令』有關,
      # 所以,我們上一個指令是執行『 echo $? 』,當然沒有錯誤,所以是 0 沒錯!
      

    • OSTYPE, HOSTTYPE, MACHTYPE:(主機硬體與核心的等級)

      這幾個東西與程式的安裝有關。我們在『Linux 主機規劃』 裡面提到過關於主機的等級方面的問題,當我們在安裝軟體的時候, 需要透過編譯器來將原始碼編譯成為二進位的檔案 (binary file)。但是, 我們可以針對硬體的配備來進行編譯的最佳化,此時,這些參數就可以被用到了! 基本上,目前主要的 distribution 都是針對 i386 亦即最低等級的機器進行最佳化, 這樣才能夠安裝在較高階的機器上,如果以 686 的機型來最佳化, 那麼,可就無法向下相容的喔!(早期的 OpenLinux 是針對 686 機器來釋出軟體, 所以,當時的 OpenLinux 是無法安裝在 P-166 的機器上的。 )

    自訂變數轉成環境變數: export
    好了,上面我們環境變數也提過了,一些自訂變數也提過了,那麼,這兩者有啥不同? 他的不同處,我們在 變數設定規則 當中稍微提過, 主要是由於變數可否被子程序所引用。

    當你取得一個 bash 之後,亦即得到了一個程序了,但是若你再次的執行一次 bash ,那麼你將進入『子程序』,這個程序的概念我們在資源管理章節中再詳談,這裡您先有個概念即可。 那麼由於您已經進入了該子程序,所以在父程序中的自訂變數設定將不再繼續的存在。 會存在子程序中的,僅有『環境變數』

    換個角度來想,也就是說,如果我能將自訂變數變成環境變數的話,那不就可以讓該變數值繼續存在於子程序了? 呵呵!沒錯!此時,那個 export 指令就很有用啦! 如您想要讓該變數內容繼續的在子程序中使用,那麼就請執行:
      export 變數
    這個東西用在『引用他人的檔案或者其他程序』時,相當的重要的! 尤其像鳥哥常常兩三個檔案互相引用來引用去的,如果忘記設定 export 的話,那麼不同的檔案中的相同變數值,將需要一再地重複設定才行!所以,我只要在頭一個檔案使用 export 的話,那麼後續的檔案引用時,將會把該變數內容讀進來!好用的很,如果僅下達 export 而沒有接變數時,那麼此時將會把所有的『環境變數』秀出來喔!例如:
    [root@linux ~]# export
    declare -x ENV="/root/.bashrc"
    declare -x HISTSIZE="1000"
    declare -x HOME="/root"
    declare -x HOSTNAME="linux.dmtsai.tw"
    declare -x INPUTRC="/etc/inputrc"
    declare -x LANG="en_US.UTF-8"
    declare -x MAIL="/var/spool/mail/root"
    declare -x SHELL="/bin/bash"
    # 很多都直接省略了!不然....重複性太高,浪費版面∼ ^_^
    

    小標題的圖示語系檔案的變數 (locale)
    還記得我們在首次進入 Linux 那個章節裡面提到的,關於語系編碼的問題嗎? 就是當我們使用 man command 的方式去查詢某個資料的說明檔時,該說明檔的內容可能會因為我們使用的語系, 而產生一些亂碼。另外,利用 ls 查詢檔案的時間時,也可能會有亂碼出現在時間的部分。 那個問題其實就是語系的問題啦。

    目前大多數的 Linux distributions 已經都是支援萬國碼,此外,也都支援大部分的語言語系了。 這有賴於 i18n 支援的幫助呢! 那麼我們的 Linux 到底支援了多少的語系呢?這可以由 locale 這個指令來查詢到喔!
    [root@linux ~]# locale -a
    aa_DJ
    aa_DJ.iso88591
    en_US
    en_US.iso88591
    en_US.iso885915
    en_US.utf8
    zh_TW
    zh_TW.big5
    zh_TW.euctw
    zh_TW.utf8
    # 其實輸出的內容有很多,鳥哥將一些資訊捨棄了∼
    # 從上面的輸出中,我們也不難看出,系統是有支援 big5, utf8 等中文語系資料的!
    
    中文語系至少支援了兩種以上的編碼,一種是目前還是很常見的 big5 ,另一種則是越來越熱門的 utf-8 編碼。 那麼我們如何修訂這些編碼呢?其實可以透過底下這些變數的說:
    [root@linux ~]# LANG         <==主語言的環境
    [root@linux ~]# LC_CTYPE     <==字元辨識的編碼
    [root@linux ~]# LC_NUMERIC   <==數字系統的顯示訊息
    [root@linux ~]# LC_TIME      <==時間系統的顯示資料
    [root@linux ~]# LC_COLLATE   <==字串的比較與排序等
    [root@linux ~]# LC_MONETARY  <==幣值格式的顯示等
    [root@linux ~]# LC_MESSAGES  <==訊息顯示的內容,如功能表、錯誤訊息等
    [root@linux ~]# LC_ALL       <==語言環境的整體設定。
    
    基本上,你可以逐一設定每個與語系有關的變數資料,但事實上,如果其他的語系變數都未設定, 且您有設定 LANG 或者是 LC_ALL 時,則其他的語系變數就會被這兩個變數所取代! 這也是為什麼我們在 FC4 當中,通常僅設定 LANG 這個變數而已!因為他是最主要的設定變數。 好了,那麼你應該要覺得奇怪的是,為什麼在 Linux 主機的終端機介面 (tty1 ~ tty6) 的環境下,如果 LANG=zh_TW.big5 這個設定值生效後,使用 man 或者其他訊息輸出時, 都會有一堆亂碼,尤其是使用 ls -l 這個參數時?

    因為在 Linux 主機的終端機介面下,那個環境是無法顯示像中文這麼複雜的編碼的文字, 所以,就會產生亂碼了。也就是如此,所以,我們才會必須要在 tty1 ~ tty6 的環境下, 加裝一些中文化介面的軟體,才能夠看到中文啊!不過,如果您是在 Windows 主機以遠端連線伺服器的軟體連線到主機的話,那麼,嘿嘿!其實文字介面確實是可以看到中文的。 所以,此時反而您得要在 LANG 設定中文編碼才好呢!

    無論如何,如果發生一些亂碼的問題,那麼設定系統裡面保有的語系編碼, 例如: en_US 或 en_US.utf8 等等的設定,應該就 OK 的啦!好了,那麼系統預設支援多少種語系呢? 當我們使用 locale 時,系統是列出目前 Linux 主機內保有的語系檔案, 這些語系檔案都放置在: /usr/lib/locale/ 這個目錄中。 但是,目前的這個 shell 環境所支援的語系,則是要看 SUPPORTED 這個變數才對喔!

    那麼,如果我想要修訂系統的語系支援呢?可以修訂 /etc/sysconfig/i18n 這個檔案呢! 這個檔案的內容有點像這樣:
    [root@linux ~]# vi /etc/sysconfig/i18n
    LANG="en_US.UTF-8"
    SYSFONT="latarcyrheb-sun16"
    SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"
    
    你可以在這個檔案當中加入 LC_TIME 或者其他語系相關變數的設定內容, 也可以直接修改 LANG 那個變數即可啊! ^_^ 但,事實上,我們還可以透過個人的環境設定檔來設定 LANG 呢! 如此一來,則不必修訂系統的語系檔案,比較安全啦!
    Tips:
    假設你用 vi 編輯一個純文字檔,這個純文字檔在編輯的時候,是在 Windows 上面編輯的, 那麼這個檔案的預設編碼應該是以 zh_TW.big5 所編輯的才對。但是,如果你的 shell 環境中, 卻是使用 LANG=en_US 時,則當你編輯該檔案時,就可能會看到『亂碼』, 或者輸入的中文可能會變成『亂碼』了。此時,只要你離開 vi ,然後執行 LANG=zh_TW.big5 , 然後再重新以 vi 編輯該檔案,呵呵!應該就能夠看到中文啦!但是請注意, 這個方法當然不適用 tty1 ~ tty6 的環境,原因上面已經提過囉∼ 僅適合以類似 putty 軟體由 Windows 電腦連線到 linux 主機上的做業!

    小標題的圖示變數的有效範圍
    蝦密??變數也有使用的『範圍』?沒錯啊∼我們在上頭的 export 指令說明中,就提到了這個概念了。如果在跑程式的時候,有父程序與子程序的不同程序關係時, 則『變數』可否被引用是 export 有關。被 export 後的變數,我們可以稱他為『環境變數』! 環境變數可以被子程序所引用,但是其他的自訂變數內容就不會存在於子程序中。也就是說: 我們自行設定的變數,只在目前這個 shell 環境當中存在, 在子程序中將不會存在此一變數。除非使用 export 將自訂變數變成環境變數。

    其實除了 shell 的父、子程序外,在腳本( scripts )的編寫當中,由於有的軟體會使用到 2 個以上的 scripts 做為一個完整的套件!也就是說,假如你有兩支程式,一支為 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 會去引用 scripts1.sh 的變數,這個時候,嘿嘿!你在 scripts1.sh 當中設定的變數請『千萬記得以 export 設定』, 否則你的變數將無法在兩個 scripts 之間互相被引用喔!當這個 scripts 執行完畢之後,剛剛在 scripts 當中設定的變數也就『失效了!』。

    其實,要瞭解不同程序之間變數的變換,應該要先瞭解『程序』的概念比較好, 但是我們還沒有講到.....沒關係∼等你念到程序章節後,還可以再回來好好的看一看。 基本上,環境變數可以讓子程序繼續引用的原因,是因為:
    • 當啟動一個 shell ,作業系統分配一記憶區塊給 shell 使用,此區域之變數可以讓子程序存取;
    • 利用 export 功能,可以讓變數的內容寫到上述的記憶區塊當中(環境變數);
    • 當載入另一個 shell 時 (亦即啟動子程序,而離開原本的父程序了),子 shell 可以將父 shell 的環境變數所在的記憶區塊導入自己的環境變數區塊當中。
    透過這樣的關係,我們就可以讓某些變數可以在相關的程序之間存在,以幫助自己更方便的操作環境喔!

    小標題的圖示變數鍵盤讀取、陣列與宣告: read, array, declare
    我們上面提到的變數設定功能,都是直接由指令列直接設定的,那麼,可不可以讓使用者能夠經由鍵盤輸入? 什麼意思呢?是否記得某些程式執行的過程當中,會等待使用者輸入 "yes/no" 之類的訊息啊!? 在 bash 裡面也有相對應的功能喔!此外,我們還可以宣告這個變數的屬性, 例如:陣列或者是數字等等的。底下就來看看吧!


  • read
  • 要讀取來自鍵盤輸入的變數,就是用 read 這個指令了。這個指令最常被用在 shell script 的撰寫當中, 以跟使用者進行對談。關於 script 的寫法,我們會在後面章節介紹,底下先來瞧一瞧 read 的相關語法吧!
    [root@linux ~]# read [-pt] variable
    參數:
    -p  :後面可以接提示字元!
    -t  :後面可以接等待的『秒數!』這個比較有趣∼不會一直等待使用者啦!
    範例:
    
    範例一:讓使用者由鍵盤輸入一內容,將該內容變成 atest 變數
    [root@linux ~]# read atest
    This is a test
    [root@linux ~]# echo $atest
    This is a test
    
    範例二:提示使用者 30 秒內輸入自己的大名,將該輸入字串做成 named 變數
    [root@linux ~]# read -p "Please keyin your name: " -t 30 named
    Please keyin your name: VBird Tsai
    [root@linux ~]# echo $named
    VBird Tsai
    
    read 之後不加任何參數,直接加上變數名稱,那麼底下就會主動出現一個空白行,等待您輸入。 如果加上 -t 後面接秒數之後,例如上面的範例當中,那麼 30 秒之內沒有任何動作時, 該指令就會自動略過了∼如果是加上 -p ,嘿嘿!後面就會有比較多可以用的提示字元給我們參考! 在指令的下達裡面,比較美觀啦! ^_^


  • declare / typeset
  • declare 或 typeset 是一樣的功能,就是在宣告變數的屬性。如果使用 declare 後面並沒有接任何參數, 那麼 bash 就會主動的將所有的變數名稱與內容通通叫出來,就好像使用 set 一樣啦! 那麼 declare 還有什麼語法呢?看看先:
    [root@linux ~]# declare [-aixr] variable
    參數:
    -a  :將後面的 variable 定義成為陣列 (array)
    -i  :將後面接的 variable 定義成為整數數字 (integer)
    -x  :用法與 export 一樣,就是將後面的 variable 變成環境變數;
    -r  :將一個 variable 的變數設定成為 readonly ,該變數不可被更改內容,也不能 unset
    範例:
    範例一:讓變數 sum 進行 100+300+50 的加總結果
    [root@linux ~]# sum=100+300+50
    [root@linux ~]# echo $sum
    100+300+50  <==咦!怎麼沒有幫我計算加總?因為這是文字型態的變數屬性啊!
    [root@linux ~]# declare -i sum=100+300+50
    [root@linux ~]# echo $sum
    450         <==瞭乎??
    
    範例二:將 sum 變成環境變數
    [root@linux ~]# declare -x sum
    
    範例三:讓 sum 變成唯讀屬性,不可更動!
    [root@linux ~]# declare -r sum
    [root@linux ~]# sum=tesgting
    -bash: sum: readonly variable  <==老天爺∼不能改這個變數了!
    
    declare 也是個很有用的功能∼尤其是當我們需要使用到底下的陣列功能時, 他也可以幫我們宣告陣列的屬性喔!不過,老話一句,陣列也是在 shell script 比較常用的啦!


  • 陣列屬性 array 說明
  • 某些時候,我們必須使用陣列來宣告一些變數,這有什麼好處啊?在一般人的使用上, 果然是看不出來有什麼好處的!不過,如果您曾經寫過程式的話,那才會比較瞭解陣列的意義∼ 陣列對寫數值程式的設計師來說,可是不能錯過學習的重點之一哩!好!不囉唆∼ 那麼要如何設定陣列的變數與內容呢?在 bash 裡頭,陣列的設定方式是:
      var[index]=content
    意思是說,我有一個陣列名稱為 var ,而這個陣列的內容為 var[1]=小明, var[2]=大明, var[3]=好明 .... 等等,那個 index 就是一些數字啦,重點是用中刮號 ([ ]) 來設定的。 目前我們 bash 提供的是一維陣列。老實說,如果您不必寫一些複雜的程式, 那麼這個陣列的地方,可以先略過,等到有需要再來學習即可!因為要製作出陣列, 通常與迴圈或者其他判斷式交互使用才有比較高的意義存在!
    範例:設定上面提到的 var[1] ∼ var[3] 的變數。
    [root@linux ~]# var[1]="small min"
    [root@linux ~]# var[2]="big min"
    [root@linux ~]# var[3]="nice min"
    [root@linux ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"
    
    比較有趣的地方在於『讀取』,一般來說,建議直接以 ${陣列} 的方式來讀取, 比較正確無誤的啦!

    小標題的圖示與檔案系統及程序的限制關係: ulimit
    想像一個狀況:我的 Linux 主機裡面同時登入了十個人,這十個人不知怎麼搞的, 同時開啟了 100 個檔案,每個檔案的大小約 10MBytes ,請問一下, 我的 Linux 主機的記憶體要有多大才夠? 10*100*10 = 10000 MBytes ∼∼ 老天爺,這樣,系統不掛點才有鬼哩!為了要預防這個情況的發生,所以, 我們的 bash 是可以『限制使用者的某些系統資源』的,包括可以開啟的檔案數量, 可以使用的 CPU 時間,可以使用的記憶體總量等等。如何設定?用 ulimit 吧!
    [root@linux ~]# ulimit [-SHacdflmnpstuv] [配額]
    參數:
    -H  :hard limit ,嚴格的設定,必定不能超過設定的值;
    -S  :soft limit ,警告的設定,可以超過這個設定值,但是會有警告訊息,
          並且,還是無法超過 hard limit 的喔!也就是說,假設我的 soft limit
          為 80 , hard limit 為 100 ,那麼我的某個資源可以用到 90 ,
          可以超過 80 ,還是無法超過 100 ,而且在 80~90 之間,會有警告訊息的意思。
    -a  :列出所有的限制額度;
    -c  :可建立的最大核心檔案容量 (core files)
    -d  :程序資料可使用的最大容量
    -f  :此 shell 可以建立的最大檔案容量 (一般可能設定為 2GB)單位為 Kbytes
    -l  :可用於鎖定 (lock) 的記憶體量
    -p  :可用以管線處理 (pipe) 的數量
    -t  :可使用的最大 CPU 時間 (單位為秒)
    -u  :單一使用者可以使用的最大程序(process)數量。
    範例:
    範例一:列出所有的限制資料
    [root@linux ~]# ulimit -a
    
    範例二:限制使用者僅能建立 1MBytes 以下的容量的檔案
    [root@linux ~]# ulimit -f 1024
    
    還記得我們在 Linux 磁碟檔案系統 裡面提到過,單一 filesystem 能夠支援的單一檔案大小與 block 的大小有關。例如 block size 為 1024 byte 時,單一檔案可達 16GB 的容量。但是,我們可以用 ulimit 來限制使用者可以建立的檔案大小喔! 利用 ulimit -f 就可以來設定了!例如上面的範例二,要注意單位喔!單位是 Kbytes。 若改天你一直無法建立一個大容量的檔案,記得瞧一瞧 ulimit 的資訊喔!( 不過,要注意的是,一般身份使用者如果以 ulimit 設定了 -f 的檔案大小, 那麼他『只能減小檔案大小,不能增加檔案大小喔!』)

    小標題的圖示額外的變數設定功能
    剛剛我們提到了兩種變數取用的方法,分別是這樣:
    [root@linux ~]# echo $HOME
    [root@linux ~]# echo ${HOME}
    
    那麼,在那個 ${variable} 的使用方法中,其實,我們還可以將變數進行一些修訂的工作喔! 只要加上一些字符標誌,後面再接著使用比對字串,就能夠修改變數的內容了! 我們取底下的例子來說明:在底下的例子中,假設我的變數名稱為 vbird ,且內容為 /home/vbird/testing/testing.x.sh。
    1. 完整呈現 vbird 這個變數的內容;
    [root@linux ~]# vbird="/home/vbird/testing/testing.x.sh"
    [root@linux ~]# echo ${vbird}
    /home/vbird/testing/testing.x.sh
    
    2. 在 vbird 變數中,從最前面開始比對,若開頭為 / ,則刪除兩個 / 
       之間的所有資料,亦即 /*/
    [root@linux ~]# echo ${vbird##/*/}
    testing.x.sh    <==刪除了 /home/vbird/testing/
    [root@linux ~]# echo ${vbird#/*/}
    vbird/testing/testing.x.sh   <==僅刪除 /home/ 而已
    # 這兩個小例子有趣了∼變數名稱後面如果接了兩個 ## ,表示在 ##
    # 後面的字串取『最長的』那一段;如果僅有一個 # ,表示取『最小的那一段』喔!
    
    3. 承上題,如果是從後面開始,刪除 /* 呢?
    [root@linux ~]# echo ${vbird%%/*/}
    /home/vbird/testing/testing.x.sh  <==都沒被刪除
    [root@linux ~]# echo ${vbird%%/*}
        <==被刪除光了!
    [root@linux ~]# echo ${vbird%/*}
    /home/vbird/testing   <==只刪除 /testing.x.sh 部分
    # 這個例子當中需要特別注意,那個 % 比對的是『最後面那個字元』的意思,
    # 所以囉,第一個方式當然不對∼因為 vbird 這個變數的內容最後面是 h 而不是 / 啊!
    # 至於 %%/* 則是刪除『最長的那個 /* 』,當然就是全部喔!而 %/* 則是最短的那個!
    
    4. 將 vbird 變數中的 testing 取代為 TEST
    [root@linux ~]# echo ${vbird/testing/TEST}
    /home/vbird/TEST/testing.x.sh
    [root@linux ~]# echo ${vbird//testing/TEST}
    /home/vbird/TEST/TEST.x.sh
    # 如果變數後面接的是 / 時,那麼表示後面是進行『取代』的工作∼而且僅取代『第一個』
    # 但如果是 // ,則表示全部的字串都取代啊!
    
    這裡您稍微留意一下就好了∼反正就是變數後面可以接 #, ##, %, %%, /, // , 而他們存在的意義並不相同的啦∼

    另外,幾個不同的變數內容還可以進行判斷呢! 舉例來說,目前我需要用到兩個變數,分別是 var 與 str , 那我想要針對 str 這個變數內容是否有設定成一個字串,亦即 "expr" 來決定 var 的內容。 那我可以使用什麼方法來進行判斷呢?如果您會寫 shell script 的話, 直接用 shell script 就好了,如果不會寫,那麼我們就透過簡單的變數判斷吧!
    Tips:
    底下的例子當中,那個 var 與 str 為變數,我們想要針對 str 是否有設定來決定 var 的值喔! 一般來說, str: 代表『str 沒設定或為空的字串時』;至於 str 則僅為『沒有該變數』。
    變數設定方式str 沒有設定 str 為空字串str 已設定非為空字串
    var=${str-expr}var=exprvar=var=$str
    var=${str:-expr}var=exprvar=exprvar=$str
    var=${str+expr}var=var=exprvar=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 輸出至 stderrvar=var=str
    var=${str:?expr}expr 輸出至 stderrexpr 輸出至 stderrvar=str

    根據上面這張表,我們來進行幾個範例的練習吧! ^_^
    範例一:若 str 這個變數內容存在,則 var 設定為 str ,否則 var 設定為 "newvar"
    [root@linux ~]# unset str; var=${str-newvar}
    [root@linux ~]# echo var="$var", str="$str"
    var=newvar, str=        <==因為 str 不存在,所以 var 為 newvar
    [root@linux ~]# str="oldvar"; var=${str-newvar}
    [root@linux ~]# echo var="$var", str="$str"
    var=oldvar, str=oldvar  <==因為 str 存在,所以 var 等於 str 的內容
    
    範例二:若 str 不存在,則 var 與 str 均設定為 newvar,否則 var 與 str 相同
    [root@linux ~]# unset str; var=${str=newvar}
    [root@linux ~]# echo var="$var", str="$str"
    var=newvar, str=newvar  <==因為 str 不存在,所以 var/str 均為 newvar
    [root@linux ~]# str="oldvar"; var=${str=newvar}
    [root@linux ~]# echo var="$var", str="$str"
    var=oldvar, str=oldvar  <==因為 str 存在,所以 var 等於 str 的內容
    
    範例三:若 str 這個變數存在,則 var 等於 str ,否則輸出 "novar"
    [root@linux ~]# unset str; var=${str?novar}
    -bash: str: novar       <==因為 str 不存在,所以輸出錯誤訊息 
    [root@linux ~]# str="oldvar"; var=${str?novar}
    [root@linux ~]# echo var="$var", str="$str"
    var=oldvar, str=oldvar  <==因為 str 存在,所以 var 等於 str 的內容
    
    # 上面這三個案例都沒有提到當 str 有設定,且為空字串的情況喔!
    # 您可以自行測試一下哩!
    
    雖然猛一看,覺得變數沒有什麼奇特的地方,但是,如果仔細瞧一瞧,嘿!一堆環境變數與系統資源方面的變數, 可是會影響到我們在 bash 裡頭是否能夠順利作業的呢!例如 PATH 啊、ulimit 之類的∼ 所以,您還是得要瞭解變數這個玩意才行喔! ^_^


    大標題的圖示命令別名與歷史命令:
    我們知道在早期的 DOS 年代,清除螢幕上的資訊可以使用 cls 來清除,但是在 Linux 裡面, 我們則是使用 clear 來清除畫面的。那麼可否讓 cls 等於 clear 呢?可以啊!用啥方法? link file 還是什麼的?別急!底下我們介紹不用 link file 的命令別名來達成。那麼什麼又是歷史命令? 曾經做過的舉動我們可以將他記錄下來喔!那就是歷史命令囉∼底下分別來談一談這兩個玩意兒。


    小標題的圖示命令別名設定: alias, unalias
    命令別名是一個很有趣的東西,特別是你的慣用指令特別長的時候!還有, 增設預設的屬性在一些慣用的指令上面,可以預防一些不小心誤殺檔案的情況發生的時候! 舉個例子來說,如果你要查詢隱藏檔,並且需要長的列出與一頁一頁翻看,那麼需要下達『 ls -al | more 』這個指令,我是覺得很煩啦! 要輸入好幾個單字!那可不可以使用 lm 來簡化呢?!當然可以,你可以在命令列下面下達:
    [root@linux ~]# alias lm='ls -l | more'
    
    嘿嘿!我立刻多出了一個可以執行的指令喔!這個指令名稱為 lm ,且其實他是執行 ls -al | more 啊!真是方便。不過, 要注意的是:『alias 的定義規則與變數定義規則幾乎相同』, 所以你只要在 alias 後面加上你的 {『別名』='指令 參數' }, 以後你只要輸入 lm 就相當於輸入了 ls -al|more 這一串指令!很方便吧!

    另外,命令別名的設定還可以取代既有的指令喔!舉例來說,我們知道 root 可以移除( rm )任何資料!所以當你以 root 的身份在進行工作時,需要特別小心, 但是總有失手的時候,那麼 rm 提供了一個參數來讓我們確認是否要移除該檔案,那就是 -i 這個參數!所以,你可以這樣做:
    [root@linux ~]# alias rm='rm -i'
    
    嘿嘿!那麼以後使用 rm 的時候,就不用太擔心會有錯誤刪除的情況了!這也是命令別名的優點囉! 那麼如何知道目前有哪些的命令別名呢?就使用 alias 呀!
    [root@linux ~]# alias
    alias l.='ls -d .* --color=tty'
    alias ll='ls -l --color=tty'
    alias lm='ls -al | more'
    alias ls='ls --color=tty'
    alias vi='vim'
    alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
    
    由上面的資料當中,您也會發現一件事情啊,我們在 vi 文書編輯器 裡面提到 vi 與 vim 是不太一樣的, vi 是比較老,而 vim 可以用來取代 vi 喔。我們的 FC4 明明就同時有 vi/vim , 為何我執行 vi 會是進入 vim 呢?呵呵!那就是因為上面的表格當中的『 alias vi='vim' 』這個設定啦! 至於如果要取消命令別名的話,那麼就使用 unalias 吧!例如要將剛剛的 lm 命令別名拿掉,就使用:
    [root@linux ~]# unalias lm
    
    那麼命令別名與變數有什麼不同呢?基本上,他們的意義就不太一樣了! alias 這種命令別名,你可以將他想成是建立一個新的指令名稱, 至於變數則僅是將一個數值或者字串存在某個代表意義當中!舉個例子好了,我們知道以前的 DOS 年代,列出目錄與檔案就是 dir ,而清除螢幕就是 cls ,那麼如果我想要在 linux 裡面也使用相同的指令呢?那就以 alias 來進行指令的別名設定:
      alias cls='clear'
      alias dir='ls -l'
      只要加入這兩行,以後你輸入 cls 及 dir 就可以執行了!很方便吧!


    小標題的圖示歷史命令:history
    前面我們提過 bash 有提供指令歷史的服務!那麼如何查詢我們曾經下達過的指令呢?就使用 history 囉!當然,如果覺得 histsory 要輸入的字元太多太麻煩,可以使用命令別名來設定呢! 不要跟我說還不會設定呦! ^_^
      alias h='history'
    如此則輸入 h 等於輸入 history 囉!好了,我們來談一談 history 的用法吧!
    [root@linux ~]# history [n]
    [root@linux ~]# history [-c]
    [root@linux ~]# history [-raw] histfiles
    參數:
    n   :數字,意思是『要列出最近的 n 筆命令列表』的意思!
    -c  :將目前的 shell 中的所有 history 內容全部消除
    -a  :將目前新增的 history 指令新增入 histfiles 中,若沒有加 histfiles ,
          則預設寫入 ~/.bash_history
    -r  :將 histfiles 的內容讀到目前這個 shell 的 history 記憶中;
    -w  :將目前的 history 記憶內容寫入 histfiles 中!
    範例:
    範例一:列出目前記憶體內的所有 history 記憶
    [root@linux ~]# history
    # 前面省略
     1017  man bash
     1018  ll
     1019  history 
     1020  history
    # 列出的資訊當中,共分兩欄,第一欄為該指令在這個 shell 當中的代碼,
    # 另一個則是指令本身的內容喔!至於會秀出幾筆指令記錄,則與 HISTSIZE 有關!
    
    範例二:列出目前最近的 3 筆資料
    [root@linux ~]# history 3
     1019  history 
     1020  history
     1021  history 3
    
    範例三:立刻將目前的資料寫入 histfile 當中
    [root@linux ~]# history -w
    # 在預設的情況下,會將歷史紀錄寫入 ~/.bash_history 當中!
    [root@linux ~]# echo $HISTSIZE
    1000
    
    在正常的情況下,當我們以 bash 登入 Linux 主機之後,系統會主動的由家目錄的 ~/.bash_history 讀取以前曾經下過的指令,那麼 ~/.bash_history 會記錄幾筆資料呢?這就與你 bash 的 HISTSIZE 這個變數設定值有關了!在預設的 FC4 底下,是會記錄 1000 筆資料的! 那麼假設我這次登入主機後,共下達過 100 次指令,『等我登出時, 系統就會將 101~1100 這總共 1000 筆歷史命令更新到 ~/.bash_history 當中。』 也就是說,歷史命令在我登出時,會將最近的 HISTSIZE 筆記錄到我的紀錄檔當中啦! 當然,也可以用 history -w 強制立刻寫入的!那為何用『更新』兩個字呢? 因為 ~/.bash_history 記錄的筆數永遠都是 HISTSIZE 那麼多,舊的訊息會被主動的拿掉! 僅保留最新的!

    那麼 history 這個歷史命令只可以讓我查詢命令而已嗎?呵呵!當然不止啊! 我們可以利用相關的功能來幫我們執行命令呢!舉例來說囉:
    [root@linux ~]# !number
    [root@linux ~]# !command
    [root@linux ~]# !!
    參數:
    number  :執行第幾筆指令的意思;
    command :由最近的指令向前搜尋『指令串開頭為 command』的那個指令,並執行;
    !!      :就是執行上一個指令(相當於按↑按鍵後,按 Enter)
    範例:
    [root@linux ~]# history
       66  man rm
       67  alias
       68  man history
       69  history 
    [root@linux ~]# !66  <==執行第 66 筆指令
    [root@linux ~]# !!   <==執行上一個指令,本例中亦即 !66 
    [root@linux ~]# !al  <==執行最近以 al 為開頭的指令(上頭列出的第 67 個)
    
    經過上面的介紹,瞭乎?歷史命令用法可多了!如果我想要執行上一個指令, 除了使用上下鍵之外,我可以直接以『 !! 』 來下達上個指令的內容,此外, 我也可以直接選擇下達第 n 個指令,『 !n 』來執行,也可以使用指令標頭,例如 『 !vi 』來執行最近指令開頭是 vi 的指令列!相當的方便而好用!基本上 history 的用途很大的!但是需要小心安全的問題!尤其是 root 的歷史紀錄檔案,這是 Cracker 的最愛!因為不小心的 root 會將很多的重要資料在執行的過程中會被紀錄在 ~/.bash_history 當中,如果這個檔案被解析的話,後果不堪吶!無論如何,使用 history 配合『 ! 』曾經使用過的指令下達是很有效率的一個指令方法!

    大標題的圖示Bash Shell 使用環境:
    是否記得我們登入主機的時候,螢幕上頭會有一些說明文字,告知我們的 Linux 版本啊什麼的, 還有,登入的時候,我們還可以給予使用者一些訊息或者歡迎文字呢。此外, 我們習慣的環境變數、命令別名等等的,是否可以登入就主動的幫我設定好? 這些都是需要來注意的。另外,這些設定值又可以分為系統整體設定值與各人喜好設定值, 僅是一些檔案放置的地點不同啦!這我們後面也會來談一談的!


    小標題的圖示絕對路徑與相對路徑
    這個議題說到快要爛掉了∼從一開始到現在,這個絕對路徑與相對路徑的問題我們就提到不知道多少次了, 因為他實在很重要∼這與 PATH 這個變數關係很大!老實說, 萬一你的 PATH 沒有設定完整的時候,下達指令就必須要以『 一長列的指令連帶根目錄都要列出來 』,呵呵那就是絕對路徑的設定法啦! 基本上,這個『 絕對路徑』與『相對路徑 』的觀念是很重要的!否則你將常常會找不到檔案說! 所謂的『絕對路徑』就是以根目錄開始寫入到檔案的一種命令寫定方法,舉例來說,我目前在 /home/test 這個 test 使用者的家目錄中,我想要看看裡面的 .bashrc 這個檔案的資料,使用的是 more 這個指令,而這個指令在 /bin/more 當中,則正確的下達指令的方法為:
    [root@linux ~]# /bin/more .bashrc
    
    我在的目錄為 /home/test !這是絕對路徑寫法! 而如果你還記得我們在 Linux 檔案與目錄管理 那一篇文章中提到的觀念的話,那麼應該記得使用 ls -al 時會出現兩個一定存在的目錄,分別是『.』與『..』,分別代表是『這個路徑』,與『上一層路徑』!
    [root@linux ~]# ls -al
    drwxrwxr-x  2 root  root   4096  Aug 15 11:05 .
    drwxrwxr-x  2 root  root   4096  Aug 14 23:26 ..
    
    所以說,要執行上一層目錄中的命令,可以下達『../command 』那個 command 指的是存在的可執行檔!那麼我因為在 /home/test 裡面,距離 /bin 有兩層上層目錄,所以我要使用 /bin/more 這個執行檔,並且使用相對路徑的方法,就必須使用:
    [root@linux ~]# ../../bin/more .bashrc
    
    這種相對路徑的方法相當廣泛的被運用於 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 則可以寫成:
    [root@linux ~]# ./squid
    
    請特別留意這方面的問題!『新手特別容易犯這個錯誤呢!


    小標題的圖示登錄訊息顯示資料: /etc/issue, /etc/motd
    還記得我們在終端機介面 (tty1 ~ tty6) 登入的時候,會有幾行提示的字串嗎? 那個字串寫在哪裡啊?呵呵!在 /etc/issue 裡面啊!先來看看:
    [root@linux ~]# cat /etc/issue
    Fedora Core release 4 (Stentz)
    Kernel \r on an \m
    
    
    在 FC4 裡面預設有三行,這個在我們本機登入時就會顯示在 title 的地方呢∼ 咦!那麼那個 \r 及 \m 是啥?您可以使用 man issue 配合 man mingetty 就能夠知道:

    issue 內的各代碼意義
    \d 本地端時間的日期;
    \l 顯示第幾個終端機介面;
    \m 顯示硬體的等級 (i386/i486/i586/i686...);
    \n 顯示主機的網路名稱;
    \o 顯示 domain name;
    \r 作業系統的版本 (相當於 uname -r)
    \t 顯示本地端時間的時間;
    \s 作業系統的名稱;
    \v 作業系統的版本。

    所以,如果您想要顯示終端機的號碼,就可以加上 \l 在 /etc/issue 檔案內囉∼就能夠修改登入字元。 咦!但是還有個 /etc/issue.net 呢!這是啥?沒啥啦!這個是提供給 telnet 這個遠端登入程式用的。 當我們使用 telnet 連接到主機時,主機的登入畫面就會顯示 /etc/issue.net 而不是 /etc/issue 呢!

    至於如果您想要讓使用者登入後取得一些訊息,例如您想要讓大家都知道的訊息, 那麼可以將訊息加入 /etc/motd 裡面去!例如:當登入後,告訴登入者, 系統將會在某個固定時間進行維護工作,可以這樣做:
    [root@linux ~]# vi /etc/motd
    Hello everyone,
    Our server will be maintained at 2005/10/10 0:00 ~ 24:00.
    Please don't login at that time. ^_^
    
    那麼當你的使用者登入主機後,就會顯示這樣的訊息出來:
    Last login: Mon Aug 15 10:17:10 2005 from 127.0.0.1
    Hello everyone,
    Our server will be maintained at 2005/10/10 0:00 ~ 24:00.
    Please don't login at that time. ^_^
    
    是否很方便啊!? ^_^


    小標題的圖示環境設定檔: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source
    關於取得 bash 的環境變數等資料,其實可以有系統規劃與各人喜好, 一般來說,建議使用者直接修改個人設定值即可,不需要更動到系統啦∼ 底下我們分別來談一談幾個有趣的設定檔喔!要注意的是,在指令列輸入的變數也好、命令別名也罷, 都是針對該次登入的設定而已,所以只要您一登出,那麼上次的設定值就會不見去! 因此,我們需要有幾個檔案來幫助我們,每次登入的時候,就已經幫我們搞定了環境的設定囉!


  • 系統設定值
  • 所謂的系統設定值,也就是說每個使用者進入到 bash shell 之後,會先讀取的設定檔案! 預設的設定檔案有下列幾個:

  • /etc/sysconfig/i18n
  • 記得我們在幾個重要變數內談到的語系資料嗎?! 那個語系是由 i18n 所維護的,而 FC4 預設的系統語系設定檔就在 /etc/sysconfig/i18n 當中。 這個檔案有點像這樣:
    [root@linux ~]# cat /etc/sysconfig/i18n
    LANG="zh_TW.UTF-8"
    SYSFONT="latarcyrheb-sun16"
    SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"
    
    我預設使用 zh_TW.UTF-8 來作為我的整體語系,當然,我可以在這裡修改 LANG 以及其他相關的語系變數, 例如 LC_CTYPE 或者是 LC_TIME 等等的。不過,一般來說,使用者自己個人的設定不建議在這裡做更動啦! 他們可以自行設定他們自己的設定檔啊!

  • /etc/profile
  • 這個檔案設定了幾個重要的變數,例如:『PATH、USER、MAIL、 HOSTNAME、HISTSIZE、umask』等等,也同時規劃出 /etc/inputrc 這個針對鍵盤熱建設定的檔案的資料內容。你可以在這裡設定總體的 PATH 等等的資訊! 同時,這個檔案也規劃出 /etc/profile.d 及 /etc/inputrc 這兩個目錄與檔案!

    總之,你可以瞭解到剛剛我們學會的變數設定方式,在這個檔案中也可以設定呢! 但是設定上需要特別小心,因為所有的使用者皆會使用到這個檔案的資訊。通常我都喜歡將 /usr/local/bin 這個路徑加成最前面,這是因為通常自己安裝的套件自己最喜歡, 所以當然是最先搜尋囉! ^_^!此外,請注意一下,可以將 HISTSIZE 的大小改變一下,改成 50 就可以啦!比較安全!( 註:這個檔案不論在那個 Linux distributions 當中均存在 /etc/profile 當中,所以,請特別留意此一檔案即可! )。

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

  • /etc/profile.d/*.sh
  • /etc/profile.d 是一個目錄,裡面針對 bash 及 C-shell 規範了一些資料。 以 FC4 為例,這個目錄裡面就針對了顏色、語系、vim 及 which 等指令進行一些額外的設定, 例如 alias 之類的規範值。我們的 vim 被用 alias 命名為 vi 就是在這個目錄下被設定好的。 當然啦,這個目錄的由來其實是在 /etc/profile 這個檔案內規範的啦! 你可以自行設定一些 *.sh 的檔名的檔案來書寫自己的系統設定值喔!

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

    事實上,這個檔案內最重要的其實是 MANPATH 這個變數設定啦! 我們搜尋 man page 時,會依據 MANPATH 的路徑去分別搜尋啊!另外,要注意的是, 這個檔案在各大不同版本 Linux distributions 中,檔名都不太相同,例如 FC4 用的是 /etc/man.config ,而 SuSE 用的則是 /etc/manpath.config , 可以利用 [tab] 按鍵來進行檔名的補齊啦!

    這就是系統在設定的時候常常會使用的檔案!需要特別留意的是,通常設定完了這幾個檔案之後,都需要先 logout 在 login 之後才會將設定整個啟動起來!


  • 個人設定值
  • 那麼個人的喜好設定在哪裡?嘿嘿嘿嘿!那就是在個人家目錄的幾個隱藏檔當中囉! 分別會使用到底下的幾個檔案啦!( 注意!底下的檔案都是隱藏檔,需要使用 ls -al 方能顯示出來 ) ,另外,注意一下囉!底下那個『 ~ 』代表的是『家目錄』的意思:

  • ~/.bash_profile, ~/.bash_login, ~/.profile
  • 這三個檔案通常只要一個就夠了,一般預設是以 ~/.bash_profile 的檔名存在。 會有這麼多的檔案,其實是因應其他 shell 轉換過來的使用者的習慣而已。 這個檔案可以定義個人化的路徑 (PATH) 與環境變數等等。不過,還是有順位上的差異, bash 啟動時,會先去讀取 ~/.bash_profile,找不到時,就去讀取 ~/.bash_login ,然後才是 ~/.profile

  • ~/.bashrc
  • 鳥哥一般都是將自己的需要輸入在這個檔案裡面的呢! 我的個人化設定值都會寫在這裡說∼例如命令別名、路徑等等。

  • ~/.bash_history
  • 還記得我們在歷史命令提到過這個檔案吧?!呵呵!沒錯∼預設的情況下, 我們的歷史命令就記錄在這裡啊!而這個檔案能夠記錄幾筆資料,則與 HISTSIZE 這個變數有關啊。每次登入 bash 後,bash 會先讀取這個檔案,將所有的歷史指令讀入記憶體, 因此,當我們登入 bash 後就可以查知上次使用過哪些指令囉。至於更多的歷史指令, 請自行回去參考喔!

  • ~/.bash_logout
  • 這個檔案則記錄了『當我登出 bash 後,系統再幫我做完什麼動作後才離開』的意思。 你可以去讀取一下這個檔案的內容,預設的情況下,登出時, bash 只是幫我們清掉螢幕的訊息而已。 不過,你也可以將一些備份或者是其他你認為重要的工作寫在這個檔案中(例如清空暫存檔), 那麼當你離開 Linux 的時候,就可以解決一些煩人的事情囉!

    好了,我們知道在變數的設定規範當中,後輸入的設定值可以取代先輸入的設定值, 那麼在我們登入 bash 的時候,這些設定檔到底是如何讀取的呢?他是這樣讀取的:
    1. 先讀取 /etc/profile ,再根據 /etc/profile 的內容去讀取其他額外的設定檔, 例如 /etc/profile.d 與 /etc/inputrc 等等設定檔;
    2. 根據不同的使用者,到使用者家目錄去讀取 ~/.bash_profile 或 ~/.bash_login 或 ~/.profile 等設定檔;
    3. 根據不同使用者,到他家目錄去讀取 ~/.bashrc 。
    所以囉,當我登入 bash 後,最終讀取的設定檔竟然是 ~/.bashrc 呢! 也就是說,在 ~/.bashrc 裡面的設定會是最終的設定值!所以囉, 通常鳥哥我喜歡將個人的一些常用 alias 或 PATH 等環境變數或自訂變數都寫到這個檔案去, 如此一來,不論原來系統幫我們做了什麼設定值,我都可以使用屬於自己熟悉的環境呢! 鳥哥的 ~/.bashrc 有點像這樣:
    [root@linux ~]# vi ~/.bashrc
    # .bashrc
    
    # Source global definitions
    if [ -f /etc/bashrc ]; then
            . /etc/bashrc
    fi
    
    # User specific aliases and functions
    PATH="/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
    PATH="$PATH":/usr/X11R6/bin:/home/dmtsai/bin
    LANG=zh_TW.big5
    LC_TIME=C
    export PATH LC_TIME LANG
    umask 022
    
    alias   rm='rm -i'
    alias   cp='cp -i'
    alias   mv='mv -i'
    alias   ll='ls -l'
    alias   lm='ls -al|more'
    alias   h='history'
    
    仔細看到上頭這個檔案,會不會覺得奇怪啊!為什麼會有第五行的『 . /etc/bashrc 』呢? 那個小數點 (.) 代表什麼意思啊??其實 if [ ... ]; then .... fi 是 shell script 當中的程式寫法, 這個我們會在下一章當中介紹。不過,那個 . 則需要好好的談一談喔!一般來說,如果修改完了設定檔, 通常就是 logout 後再重新 login 到 bash 內,就能夠將環境設定檔重讀了!不過, 我們可以使用底下的方式來讓該設定檔立即生效:
    [root@linux ~]# source file
    範例:
    [root@linux ~]# source ~/.bashrc
    [root@linux ~]#  .  ~/.bashrc
    
    利用 source 或小數點 (.) 都可以將設定檔的內容讀進來目前的 shell 環境中! 舉例來說,我修改了 ~/.bashrc ,那麼不需要登出,立即以 source ~/.bashrc 就可以將剛剛最新設定的內容讀進來目前的環境中!很不錯吧!此外,什麼時候會使用到不同的設定檔呢? 最常發生在一個人的工作環境分為多重的時候了!舉個例子來說,在我的大型主機中, 我常常需要負責兩到三個不同的案子,每個案子所需要處理的環境變數訂定並不相同, 那麼我就將這兩三個案子分別編寫屬於該案子的環境變數設定檔案,當我需要該環境時,就直接『 source 變數檔 』,如此一來,環境變數的設定就變的更簡便而靈活了!

  • login shell 與 non-login shell
  • 事實上,這些環境設定檔在讀取時,還是有一些差異的,這就得要談到所謂的『login shell』與 『non-login shell』的差異了。基本上,就字面上的意義來解釋的話,所謂的 loign shell 指的就是當使用者登入 Linux 系統時,所取得的那個環境設定檔稱為 login shell。 當登入後,啟動其他的 bash 時所取用的環境設定檔就稱為 non-login shell 。

    舉例來說,我以 dmtsai 這個使用者身份登入 Linux 後,然後為了要執行一些數值模擬的工作,而去執行 csh 這個 C shell , 那麼此時我就取得了 non-login shell 了。

    另外一個例子是,當我以 X Window 的環境登入 Linux 時,我們不是可以使用『終端機』來開啟 shell 嗎?當登入 Linux 的時候所取得的那個 X 的環境也可以讀入 login shell 的。因此,在 X 環境下所啟動的終端機 (shell),那些 shell 所使用的環境設定檔都是 non-login shell 喔!

    login 與 non-login shell 的差異除了取得的時機不同之外,其實他們讀取的環境設定檔也不相同。 我們上頭說過一些個人的環境設定檔案了吧?那麼這兩種類型的 shell 該讀取什麼檔案呢? 當登入 Linux ,亦即是取得 login shell 時,會讀取 ~/.bash_profile, ~/.bash_login, ~/.profile, 這三個檔案的優先順序已經在上面提過,自行參考一下。至於在取得 login shell 後繼續動作的其他 non-login shell ,讀取的就是僅有 ~/.bashrc 囉∼。而大部分的 linux distributions 都會將 ~/.bash_profile 的內容指到 ~/.bashrc 去,這樣比較簡單囉∼

    小標題的圖示終端機的環境設定: stty, set
    什麼叫做『終端機環境』啊?!我們在 首次登入 Linux 時就提過,可以在 tty1 ~ tty6 這六個文字介面的終端機 (terminal) 環境中登入,那麼登入的時候我們可以取得一些字元設定的功能喔! 舉例來說,我們可以利用倒退鍵 (backspace,就是那個←符號的按鍵) 來刪除命令列上的字元, 也可以使用 [ctrl]+c 來強制終止一個指令的運行,當輸入錯誤時,就會有聲音跑出來警告。這是怎麼辦到的呢? 很簡單啊!因為登入終端機的時候,會自動的取得一些終端機的輸入環境的設定啊!

    事實上,目前我們使用的 Linux distributions 都幫我們作了最棒的使用者環境了, 所以大家可以不用擔心操作環境的問題。不過,在某些 Unix like 的機器中,還是可能需要動用一些手腳, 才能夠讓我們的輸入比較快樂∼舉例來說,利用 [backspace] 刪除,要比利用 [Del] 按鍵來的順手吧! 但是某些 Unix 偏偏是以 [del] 來進行字元的刪除啊!所以,這個時候就可以動動手腳囉∼

    那麼如何查閱目前的一些按鍵內容呢?可以利用 stty (setting tty 終端機的意思) 呢! stty 也可以幫助設定終端機的輸入按鍵代表意義喔!
    [root@linux ~]# stty [-a]
    參數:
    -a  :將目前所有的 stty 參數列出來;
    範例:
    範例一:列出所有的按鍵與按鍵內容
    [root@linux ~]# stty -a
    speed 38400 baud; rows 40; columns 80; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; 
    eol2 = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase 
    = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl 
    ixon -ixoff -iuclc -ixany -imaxbel opost -olcuc -ocrnl onlcr -onocr 
    -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten 
    echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
    
    我們可以利用 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@linux ~]# stty erase ^h
    
    那麼從此之後,你的刪除字元就得要使用 [ctrl]+h 囉,按下 [backspace] 則會出現 ^? 字樣呢! 如果想要回復利用 [backspace] ,就下達 stty erase ^? 即可啊! 至於更多的 stty 說明,記得參考一下 man stty 的內容喔!

    除了 stty 之外,其實我們的 bash 還有自己的一些終端機設定值呢!那就是利用 set 來設定的! 我們之前提到一些變數時,可以利用 set 來顯示,除此之外,其實 set 還可以幫我們設定整個指令輸出/輸入的環境。 例如記錄歷史命令、顯示錯誤內容等等。
    [root@linux ~]# set [-uvCHhmBx]
    參數:
    -u  :預設不啟用。若啟用後,當使用未設定變數時,會顯示錯誤訊息;
    -v  :預設不啟用。若啟用後,在訊息被輸出前,會先顯示訊息的原始內容;
    -x  :預設不啟用。若啟用後,在指令被執行前,會顯示指令內容(前面有 ++ 符號)
    -h  :預設啟用。與歷史命令有關(下節介紹);
    -H  :預設啟用。與歷史命令有關(下節介紹);
    -m  :預設啟用。與工作管理有關(未來介紹);
    -B  :預設啟用。與刮號 [] 的作用有關;
    -C  :預設不啟用。若使用 >  等,則若檔案存在時,該檔案不會被覆蓋。
    範例:
    範例一:顯示目前所有的 set 設定值
    [root@linux ~]# echo $-
    himBH
    # 那個 $- 變數內容就是 set 的所有設定啦! bash 預設是 himBH 喔!
    
    範例二:設定 "若使用未定義變數時,則顯示錯誤訊息" 
    [root@linux ~]# set -u
    [root@linux ~]# echo $vbirding
    -bash: vbirding: unbound variable
    # 預設情況下,未設定/未宣告 的變數都會是『空的』,不過,若設定 -u 參數,
    # 那麼當使用未設定的變數時,就會有問題啦!很多的 shell 都預設啟用 -u 參數。
    # 若要取消這個參數,輸入 set +u 即可!
    
    範例三:執行前,顯示該指令內容。
    [root@linux ~]# set -x
    [root@linux ~]# echo $HOME
    + echo /root
    /root
    ++ echo -ne '\033]0;root@linux:~\007'
    # 看見否?要輸出的指令都會先被列印到螢幕上喔!前面會多出 + 的符號!
    
    另外,其實我們還有其他的按鍵設定功能呢!就是在 /etc/inputrc 這個檔案裡面設定。
    [root@linux ~]# 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 裡頭還支援一些萬用字元喔 (wild card) !多了這些萬用字元, 我們利用 bash 處理資料就更方便了!底下我們列出一些常用的萬用字元喔:

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

    在上面的『按鍵組合』當中,有沒有發現跟上個小節很相似的內容啊!? 呵呵∼沒錯啦!那些組合鍵都可以在 stty 當中來進行不同的設定的!好玩吧! 至於上面的萬用字元當中,最常用的就屬 *, ?, [] 及 ` 了!我們提幾個簡單的例子:
    [root@linux ~]# ls test*      <==那個 * 代表後面不論接幾個字元都予以接受
    [root@linux ~]# ls test?      <==那個 ? 代表後面『一定』要接『一個』字元
    [root@linux ~]# ls test???    <==那個 ??? 代表『一定要接三個』字元!
    [root@linux ~]# cp test[1-5] /tmp
    # 將 test1, test2, test3, test4, test5 若存在的話,就拷貝到 /tmp 
    [root@linux ~]# cp test[!1-5] /tmp
    # 只要不是 test1, test2, test3, test4, test5 之外的其他 test? ,
    # 若存在的話,就拷貝到 /tmp 
    [root@linux ~]# cd /lib/modules/`uname -r`/kernel/drivers
    # 被 ` ` 括起來的內容『會先執行』
    
    上面幾個例子相當的有趣!尤其是最後面兩個!需要注意的是, [1-5] 裡面『代表只有一個字元』但是範圍可以由 1-5 ,這樣來說的話,那麼我們如果允許『只要檔名裡面含有至少一個大寫字元』時,就可以將檔案 copy 出來的話,可以這樣做:
      cp *[A-Z]* /tmp
    很有趣吧?!也就是說『 [ ] 謹代表一個字元,而這個字元的定義可以是範圍(-), 可以是指定項目,也可以是兩者並存。 』舉例來說,我想要找出在 /etc/ 底下所有含有數字的檔案, 可以這樣:
      ls -lda /etc/*[0-9]*
    但如果我只想要找出含有 3 及 5 的檔名的檔案呢?就會是這樣:
      ls -lda /etc/*[35]*
    如果是『不想要』某些範圍或者是單字呢?就使用 [!] 即可!例如不想要有小寫字元為開頭的檔案:
      ls -lda /etc/[!a-z]*
    很好玩吧!至於那個 ` 是啥?在一串指令當中, `command` 內的指令會先被執行, 執行完的訊息再回傳到外部指令來處理!也就是說:
    1. 系統先執行 uname -r 找出輸出的結果;
    2. 將結果累加在目錄上面,來執行 cd 的功能!
    很棒吧!!另外,這個 quot (`) 的功能,也可以利用 $() 來取代喔!例如:
      cd /lib/modules/$(uname -r)/kernel
    這些基本的功能需要特別來瞭解一下才行呦!至於更多的使用方式, 我們會在後續的正規表示法當中在詳談的!

    大標題的圖示資料流重導向
    資料流重導向 (redirect) 由字面上的意思來看,好像就是將『資料給他傳導到其他地方去』的樣子? 呵呵!是啊是啊!沒錯∼資料流重導向就是將某個指令執行後應該要出現在螢幕上的資料, 給他傳輸到其他的地方,例如檔案或者是裝置 (例如印表機之類的!)!這玩意兒在 Linux 的文字模式底下可重要的! 尤其是如果我們想要將某些資料儲存下來時,就更有用了!


    小標題的圖示什麼是資料流重導向
    好傢伙!什麼是資料流重導向啊?這得要由指令的執行結果談起! 一般來說,如果你要執行一個指令,通常他會是這樣的:

    指令執行過程的資料傳輸情況
    圖三、指令執行過程的資料傳輸情況

    我們執行一個指令的時候,這個指令可能會由檔案讀入資料,經過處理之後,再將資料輸出到螢幕上。 在圖三當中, standard output 與 standard error 分別代表標準輸出與標準錯誤輸出, 這兩個玩意兒預設都是輸出到螢幕上面來的啊!舉個簡單例子來說, 我們下達『 cat /etc/crontab /etc/vbirdsay 』這個指令時,cat 會由 /etc/crontab 與 /etc/vbirdsay 讀入資料, 然後再將資料輸出到螢幕上,不過,因為系統本來就不存在 /etc/vbirdsay 這個檔案, 所以就會顯示錯誤訊息,這個錯誤訊息也會輸出到螢幕上來喔!

    在這樣的過程當中,我們可以將 standard error (簡稱 stderr) 與 standard output (簡稱 stdout) 給他傳送到其他不同的地方,而不是螢幕上頭!傳送的目標處,通常是檔案或者是裝置! 而傳送的指令則是如下所示:
    1. 標準輸入(stdin) :代碼為 0 ,使用 < 或 << ;
    2. 標準輸出(stdout):代碼為 1 ,使用 > 或 >> ;
    3. 標準錯誤輸出(stderr):代碼為 2 ,使用 2> 或 2>> ;
    舉例來說,如果我想要將我目前根目錄下所有的目錄都記錄下來的話,也就是說,將 ls -l / 這個指令的輸出結果儲存下來,就可以:
    [root@linux ~]# ls -l /  >  ~/rootfile
    # 本來 ls -l / 會將根目錄的資料列出到螢幕上;
    # 現在我使用了 > ~/rootfile 後,則本來應該在螢幕上出現的資料
    # 就會被『重新導向』到 ~/rootfile 檔案內了!就可以將該資料儲存!
    
    此時,原本應該在螢幕上面出現的資料通通不見去∼因為那些資料都被寫入到 ~/rootfile 去了! 當然,那個檔案的檔名隨便你取啦∼如果你下達:『 cat ~/rootfile 』就可以看到原本應該在螢幕上面的資料囉。 那麼如果我再次下達:『 ls -l /home > ~/rootfile 』後,那麼那個 ~/rootfile 檔案的內容變成什麼? 呵呵!變成『僅有 ls -l /home 的資料』而已!咦!原本的 ls -l / 資料就不見了嗎?是的! 因為該檔案的建立方式是:
    1. 該檔案 (本例中是 ~/rootfile) 若不存在,系統會自動的將他建立起來,但是,
    2. 當這個檔案存在的時候,那麼系統就會先將這個檔案內容清空,然後再將資料寫入!
    3. 也就是若以 > 輸出到一個既存檔案中,呵呵,那個檔案就會被覆蓋掉囉!
    那如果我想要將資料累加,不想要將舊的資料刪除,那該如何是好? 呵呵!就利用 >> 就好啦!例如上面的例子中,就變成『ls -l / >> ~/rootfile』 如此一來,當 ~/rootfile 不存在時,系統會主動建立這個檔案,若該檔案已存在, 則資料會在該檔案的最下方累加進去!基本上,指令的下達方式:

    command>
    1>
    2>
    2>>
    <
    裝置或檔案

    當然啦,一串指令的最左邊一定是指令,而在 >,2>,< 右邊的,必須是檔案或裝置才行! 此外,那個 > 會等於 1> ,因為 standard output 代碼是 1 ,可以省略啦! 再者, 1 與 > 之間並沒有空格喔!是緊接在一起的!注意注意!我們底下來玩幾個東西好了:
    範例一:將目前目錄下的檔案資訊全部儲存到 list.txt 檔案中
    [root@linux ~]# ls -al > list.txt
    
    範例二:將根目錄下的資料也儲存到 list.txt 檔案中
    [root@linux ~]# ls -al / >> list.txt
    
    好了,對於『 > , >> 』這兩個東西有一定的概念之後,我們來深入的談一談『資料流重導向』的觀念吧! 如前所述,基本上, Linux 執行的結果中,可以約略的分成『正確輸出』與『錯誤輸出』兩種資料。 例如,當你以一般身份執行 find 這個指令時,例如執行『 find / -name testing 』時,由於你是一般身份,又有些資料夾是不允許一般身份者進入的, 所以囉,當你使用 find 時,就會有錯誤訊息發生了!但同時如果有 testing 這個檔案在你可以進入的資料夾當中,那麼螢幕也會輸出到給你看!因此, 就具有正確的與錯誤的輸出兩種囉!(分別稱為 Stdout 與 Stderror)例如下面為執行結果: 裡面的『 find: /home/root: Permission denied 』就告訴你該資料夾你沒有權限進入, 這就是錯誤的輸出了,那麼『 /home/dmtsai/tseting 』就是正確的輸出了!
    [dmtsai@linux ~]$ find /home -name testing
    find: /home/test1: Permission denied   <== Starndard error
    find: /home/root: Permission denied    <== Starndard error
    find: /home/masda: Permission denied   <== Starndard error
    /home/dmtsai/testing                   <== Starndard output
    
    好了,那麼假如我們想要將資料輸出到 list 這個檔案中呢?執行『 find / -name testing > list 』 會有什麼結果?呵呵,你會發現 list 裡面存了剛剛那個『正確』的輸出資料, 至於螢幕上還是會有錯誤的訊息出現呢!傷腦筋!如果想要將正確的與錯誤的資料分別存入不同的檔案中需要怎麼做?! 呵呵!其實在資料的重導向方面,正確的寫法應該是『 1> 』與『 2> 』才對!但是如果只有 > 則預設是以 1> 來進行資料的!那個 1> 是輸出正確資料, 2> 則是錯誤資料輸出項目。也就是說:
    • 1> :是將正確的資料輸出到指定的地方去
    • 2> :是將錯誤的資料輸出到指定的地方去
    好了,那麼上面的例子中,我們如何將資料輸出到不同的地方去呢?可以這麼寫:
    [dmtsai@linux ~]$ find /home -name testing > list_right 2> list_error
    
    這樣一來,剛剛執行的結果中,有 Permission 的那幾行錯誤資訊都會跑到 list_error 這個檔案中,至於正確的輸出資料則會存到 list_right 這個檔案中囉!這樣可以瞭解了嗎? 如果有點混亂的話,去休息一下再來看看吧!!

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