日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

鸟哥的Linux私房菜(基础篇)- 第十一章、认识与学习 BASH

發(fā)布時(shí)間:2025/3/21 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 鸟哥的Linux私房菜(基础篇)- 第十一章、认识与学习 BASH 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
第十一章、認(rèn)識(shí)與學(xué)習(xí) BASH
最近升級(jí)日期:2009/08/25
在 Linux 的環(huán)境下,如果你不懂 bash 是什么,那么其他的東西就不用學(xué)了!因?yàn)榍懊鎺渍挛覀兪褂媒K端機(jī)下達(dá)命令的方式,就是透過 bash 的環(huán)境來(lái)處理的喔!所以說(shuō),他很重要吧!bash 的東西非常的多,包括變量的配置與使用、bash 操作環(huán)境的建置、數(shù)據(jù)流重導(dǎo)向的功能,還有那好用的管線命令!好好清一清腦門,準(zhǔn)備用功去啰~ ^_^這個(gè)章節(jié)幾乎是所有命令列模式 (command line) 與未來(lái)主機(jī)維護(hù)與管理的重要基礎(chǔ),一定要好好仔細(xì)的閱讀喔!

1. 認(rèn)識(shí) BASH 這個(gè) Shell
  1.1 硬件、核心與 Shell
  1.2 為何要學(xué)文字接口的 shell
  1.3 系統(tǒng)的合法 shell 與 /etc/shells 功能
  1.4 Bash shell 的功能
  1.5 Bash shell 的內(nèi)建命令: type
  1.6 命令的下達(dá)
2. Shell 的變量功能
  2.1 什么是變量?
  2.2 變量的取用與配置:echo, 變量配置守則, unset
  2.3 環(huán)境變量的功能:env 與常見環(huán)境變量說(shuō)明, set, export
  2.4 影響顯示結(jié)果的語(yǔ)系變量 (locale)
  2.5 變量的有效范圍:
  2.6 變量鍵盤讀取、數(shù)組與宣告: read, declare, array
  2.7 與文件系統(tǒng)及程序的限制關(guān)系: ulimit
  2.8 變量?jī)?nèi)容的刪除、取代與替換:, 刪除與取代,測(cè)試與替換
3. 命令別名與歷史命令
  3.1 命令別名配置: alias, unalias
  3.2 歷史命令: history, HISTSIZE
4. Bash shell 的操作環(huán)境
  4.1 路徑與命令搜尋順序
  4.2 bash 的進(jìn)站與歡迎信息: /etc/issue, /etc/motd
  4.3 環(huán)境配置文件:login, non-login shell, /etc/profile, ~/.bash_profile, source, ~/.bashrc
  4.4 終端機(jī)的環(huán)境配置: stty, set
  4.5 通配符與特殊符號(hào)
5. 數(shù)據(jù)流重導(dǎo)向 (Redirection)
  5.1 何謂數(shù)據(jù)流重導(dǎo)向?
  5.2 命令運(yùn)行的判斷依據(jù): ; , &&, ||
6. 管線命令 (pipe)
  6.1 擷取命令: cut, grep
  6.2 排序命令: sort, uniq, wc
  6.3 雙向重導(dǎo)向: tee
  6.4 字符轉(zhuǎn)換命令: tr, col, join, paste, expand
  6.5 分割命令: split
  6.6 參數(shù)代換: xargs
  6.7 關(guān)于減號(hào) - 的用途
7. 重點(diǎn)回顧
8. 本章習(xí)題
9. 參考數(shù)據(jù)與延伸閱讀
10. 針對(duì)本文的建議:http://phorum.vbird.org/viewtopic.php?t=23884

認(rèn)識(shí) BASH 這個(gè) Shell

我們?cè)诘谝徽?Linux 是什么當(dāng)中提到了:管理整個(gè)計(jì)算機(jī)硬件的其實(shí)是操作系統(tǒng)的核心 (kernel),這個(gè)核心是需要被保護(hù)的!所以我們一般使用者就只能透過 shell 來(lái)跟核心溝通,以讓核心達(dá)到我們所想要達(dá)到的工作。那么系統(tǒng)有多少 shell 可用呢?為什么我們要使用 bash 啊?底下分別來(lái)談一談喔!


硬件、核心與 Shell

這應(yīng)該是個(gè)蠻有趣的話題:『什么是 Shell』?相信只要摸過計(jì)算機(jī),對(duì)于操作系統(tǒng) (不論是 Linux 、 Unix 或者是 Windows) 有點(diǎn)概念的朋友們大多聽過這個(gè)名詞,因?yàn)橹灰小翰僮飨到y(tǒng)』那么就離不開Shell 這個(gè)東西。不過,在討論 Shell 之前,我們先來(lái)了解一下計(jì)算機(jī)的運(yùn)行狀況吧!舉個(gè)例子來(lái)說(shuō):當(dāng)你要計(jì)算機(jī)傳輸出來(lái)『音樂』的時(shí)候,你的計(jì)算機(jī)需要什么東西呢

  • 硬件:當(dāng)然就是需要你的硬件有『聲卡芯片』這個(gè)配備,否則怎么會(huì)有聲音;
  • 核心管理:操作系統(tǒng)的核心可以支持這個(gè)芯片組,當(dāng)然還需要提供芯片的驅(qū)動(dòng)程序啰;
  • 應(yīng)用程序:需要使用者 (就是你) 輸入發(fā)生聲音的命令啰!
  • 這就是基本的一個(gè)輸出聲音所需要的步驟!也就是說(shuō),你必須要『輸入』一個(gè)命令之后,『硬件』才會(huì)透過你下達(dá)的命令來(lái)工作!那么硬件如何知道你下達(dá)的命令呢?那就是kernel (核心) 的控制工作了!也就是說(shuō),我們必須要透過『Shell 』將我們輸入的命令與 Kernel 溝通,好讓 Kernel 可以控制硬件來(lái)正確無(wú)誤的工作!基本上,我們可以透過底下這張圖來(lái)說(shuō)明一下:


    圖 1.1.1、硬件、核心與用戶的相關(guān)性圖示

    我們?cè)诘诹阏聝?nèi)的操作系統(tǒng)小節(jié)曾經(jīng)提到過,操作系統(tǒng)其實(shí)是一組軟件,由于這組軟件在控制整個(gè)硬件與管理系統(tǒng)的活動(dòng)監(jiān)測(cè),如果這組軟件能被用戶隨意的操作,若使用者應(yīng)用不當(dāng),將會(huì)使得整個(gè)系統(tǒng)崩潰!因?yàn)椴僮飨到y(tǒng)管理的就是整個(gè)硬件功能嘛!所以當(dāng)然不能夠隨便被一些沒有管理能力的終端用戶隨意使用啰!

    但是我們總是需要讓用戶操作系統(tǒng)的,所以就有了在操作系統(tǒng)上面發(fā)展的應(yīng)用程序啦!用戶可以透過應(yīng)用程序來(lái)指揮核心,讓核心達(dá)成我們所需要的硬件任務(wù)!如果考慮如第零章所提供的操作系統(tǒng)圖標(biāo)(圖4.2.1),我們可以發(fā)現(xiàn)應(yīng)用程序其實(shí)是在最外層,就如同雞蛋的外殼一樣,因此這個(gè)咚咚也就被稱呼為殼程序 (shell) 啰!

    其實(shí)殼程序的功能只是提供用戶操作系統(tǒng)的一個(gè)接口,因此這個(gè)殼程序需要可以呼叫其他軟件才好。我們?cè)诘谖逭碌降谑绿岬竭^很多命令,包括 man, chmod, chown, vi, fdisk, mkfs 等等命令,這些命令都是獨(dú)立的應(yīng)用程序,但是我們可以透過殼程序 (就是命令列模式) 來(lái)操作這些應(yīng)用程序,讓這些應(yīng)用程序呼叫核心來(lái)運(yùn)行所需的工作哩!這樣對(duì)于殼程序是否有了一定的概念了?

    Tips:
    也就是說(shuō),只要能夠操作應(yīng)用程序的接口都能夠稱為殼程序。狹義的殼程序指的是命令列方面的軟件,包括本章要介紹的 bash 等。廣義的殼程序則包括圖形接口的軟件!因?yàn)閳D形接口其實(shí)也能夠操作各種應(yīng)用程序來(lái)呼叫核心工作啊!不過在本章中,我們主要還是在使用 bash 啦!

    為何要學(xué)文字接口的 shell?

    文字接口的 shell 是很不好學(xué)的,但是學(xué)了之后好處多多!所以,在這里鳥哥要先對(duì)您進(jìn)行一些心理建設(shè),先來(lái)了解一下為啥學(xué)習(xí) shell 是有好處的,這樣你才會(huì)有信心繼續(xù)玩下去 ^_^


    • 文字接口的 shell:大家都一樣!

    鳥哥常常聽到這個(gè)問題:『我干嘛要學(xué)習(xí) shell 呢?不是已經(jīng)有很多的工具可以提供我配置我的主機(jī)了?我為何要花這么多時(shí)間去學(xué)命令呢?不是以X Window 按一按幾個(gè)按鈕就可以搞定了嗎?』唉~還是得一再地強(qiáng)調(diào),X Window 還有 Web 接口的配置工具例如 Webmin (注1) 是真的好用的家伙,他真的可以幫助我們很簡(jiǎn)易的配置好我們的主機(jī),甚至是一些很進(jìn)階的配置都可以幫我們搞定。

    但是鳥哥在前面的章節(jié)里面也已經(jīng)提到過相當(dāng)多次了, X Window 與 web 接口的工具,他的接口雖然親善,功能雖然強(qiáng)大,但畢竟他是將所有利用到的軟件都整合在一起的一組應(yīng)用程序而已,并非是一個(gè)完整的套件,所以某些時(shí)候當(dāng)你升級(jí)或者是使用其他套件管理模塊 (例如 tarball 而非 rpm 文件等等)時(shí),就會(huì)造成配置的困擾了。甚至不同的 distribution 所設(shè)計(jì)的 X window 接口也都不相同,這樣也造成學(xué)習(xí)方面的困擾。

    文字接口的 shell 就不同了!幾乎各家 distributions 使用的 bash 都是一樣的!如此一來(lái),你就能夠輕輕松松的轉(zhuǎn)換不同的 distributions ,就像武俠小說(shuō)里面提到的『一法通、萬(wàn)法通!』


    • 遠(yuǎn)程管理:文字接口就是比較快!

    此外,Linux 的管理常常需要透過遠(yuǎn)程聯(lián)機(jī),而聯(lián)機(jī)時(shí)文字接口的傳輸速度一定比較快,而且,較不容易出現(xiàn)斷線或者是信息外流的問題,因此,shell 真的是得學(xué)習(xí)的一項(xiàng)工具。而且,他可以讓您更深入 Linux ,更了解他,而不是只會(huì)按一按鼠標(biāo)而已!所謂『天助自助者!』多摸一點(diǎn)文本模式的東西,會(huì)讓你與Linux 更親近呢!


    • Linux 的任督二脈: shell 是也!

    有些朋友也很可愛,常會(huì)說(shuō):『我學(xué)這么多干什么?又不常用,也用不到!』嘿嘿!有沒有聽過『書到用時(shí)方恨少?』當(dāng)你的主機(jī)一切安然無(wú)恙的時(shí)候,您當(dāng)然會(huì)覺得好像學(xué)這么多的東西一點(diǎn)幫助也沒有呀!萬(wàn)一,某一天真的不幸給他中標(biāo)了,您該如何是好?是直接重新安裝?還是先追蹤入侵來(lái)源后進(jìn)行漏洞的修補(bǔ)?或者是干脆就關(guān)站好了?這當(dāng)然涉及很多的考慮,但就以鳥哥的觀點(diǎn)來(lái)看,多學(xué)一點(diǎn)總是好的,尤其我們可以有備而無(wú)患嘛!甚至學(xué)的不精也沒有關(guān)系,了解概念也就OK 啦!畢竟沒有人要您一定要背這么多的內(nèi)容啦!了解概念就很了不起了!

    此外,如果你真的有心想要將您的主機(jī)管理的好,那么良好的shell 程序編寫是一定需要的啦!就鳥哥自己來(lái)說(shuō),鳥哥管理的主機(jī)雖然還不算多,只有區(qū)區(qū)不到十部,但是如果每部主機(jī)都要花上幾十分鐘來(lái)查閱他的登錄文件信息以及相關(guān)的信息,那么鳥哥可能會(huì)瘋掉!基本上,也太沒有效率了!這個(gè)時(shí)候,如果能夠藉由 shell 提供的數(shù)據(jù)流重導(dǎo)向以及管線命令,呵呵!那么鳥哥分析登錄信息只要花費(fèi)不到十分鐘就可以看完所有的主機(jī)之重要信息了!相當(dāng)?shù)暮糜媚?#xff01;

    由于學(xué)習(xí) shell 的好處真的是多多啦!所以,如果你是個(gè)系統(tǒng)管理員,或者有心想要管理系統(tǒng)的話,那么shell 與 shell scripts 這個(gè)東西真的有必要看一看!因?yàn)樗拖瘛捍蛲ㄈ味蕉},任何武功都能隨你應(yīng)用』的說(shuō)!


    系統(tǒng)的合法 shell 與 /etc/shells 功能

    知道什么是 Shell 之后,那么我們來(lái)了解一下 Linux 使用的是哪一個(gè)shell 呢?什么!哪一個(gè)?難道說(shuō) shell 不就是『一個(gè) shell 嗎?』哈哈!那可不!由于早年的Unix 年代,發(fā)展者眾,所以由于 shell 依據(jù)發(fā)展者的不同就有許多的版本,例如常聽到的Bourne SHell (sh) 、在 Sun 里頭默認(rèn)的 C SHell、 商業(yè)上常用的 K SHell、,還有 TCSH 等等,每一種 Shell 都各有其特點(diǎn)。至于 Linux 使用的這一種版本就稱為『Bourne Again SHell (簡(jiǎn)稱 bash) 』,這個(gè) Shell 是 Bourne Shell 的增強(qiáng)版本,也是基準(zhǔn)于 GNU 的架構(gòu)下發(fā)展出來(lái)的呦!

    在介紹 shell 的優(yōu)點(diǎn)之前,先來(lái)說(shuō)一說(shuō) shell 的簡(jiǎn)單歷史吧(注2):第一個(gè)流行的shell 是由 Steven Bourne 發(fā)展出來(lái)的,為了紀(jì)念他所以就稱為 Bourne shell,或直接簡(jiǎn)稱為 sh !而后來(lái)另一個(gè)廣為流傳的 shell 是由柏克萊大學(xué)的 BillJoy 設(shè)計(jì)依附于 BSD 版的 Unix 系統(tǒng)中的 shell ,這個(gè) shell 的語(yǔ)法有點(diǎn)類似C 語(yǔ)言,所以才得名為 C shell ,簡(jiǎn)稱為 csh !由于在學(xué)術(shù)界 Sun 主機(jī)勢(shì)力相當(dāng)?shù)凝嫶?#xff0c;而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一個(gè)很重要而且流傳很廣的 shell 之一 。

    Tips:
    由于 Linux 為 C 程序語(yǔ)言撰寫的,很多程序設(shè)計(jì)師使用 C 來(lái)開發(fā)軟件,因此 C shell 相對(duì)的就很熱門了。另外,還記得我們?cè)诘谝徽隆inux 是什么提到的吧?Sun 公司的創(chuàng)始人就是 Bill Joy,而 BSD 最早就是 Bill Joy 發(fā)展出來(lái)的啊。

    那么目前我們的 Linux (以 CentOS 5.x 為例) 有多少我們可以使用的 shells 呢?你可以檢查一下 /etc/shells 這個(gè)文件,至少就有底下這幾個(gè)可以用的 shells:

    • /bin/sh (已經(jīng)被 /bin/bash 所取代)
    • /bin/bash (就是 Linux 默認(rèn)的 shell)
    • /bin/ksh (Kornshell 由 AT&T Bell lab. 發(fā)展出來(lái)的,兼容于 bash)
    • /bin/tcsh (整合 C Shell ,提供更多的功能)
    • /bin/csh (已經(jīng)被 /bin/tcsh 所取代)
    • /bin/zsh (基于 ksh 發(fā)展出來(lái)的,功能更強(qiáng)大的 shell)

    雖然各家 shell 的功能都差不多,但是在某些語(yǔ)法的下達(dá)方面則有所不同,因此建議你還是得要選擇某一種 shell 來(lái)熟悉一下較佳。Linux 默認(rèn)就是使用 bash ,所以最初你只要學(xué)會(huì) bash 就非常了不起了! ^_^!另外,咦!為什么我們系統(tǒng)上合法的 shell 要寫入 /etc/shells 這個(gè)文件啊?這是因?yàn)橄到y(tǒng)某些服務(wù)在運(yùn)行過程中,會(huì)去檢查使用者能夠使用的 shells ,而這些 shell 的查詢就是藉由 /etc/shells 這個(gè)文件啰!

    舉例來(lái)說(shuō),某些 FTP 網(wǎng)站會(huì)去檢查使用者的可用 shell ,而如果你不想要讓這些使用者使用 FTP 以外的主機(jī)資源時(shí),可能會(huì)給予該使用者一些怪怪的 shell,讓使用者無(wú)法以其他服務(wù)登陸主機(jī)。這個(gè)時(shí)候,你就得將那些怪怪的 shell 寫到 /etc/shells 當(dāng)中了。舉例來(lái)說(shuō),我們的 CentOS 5.x的 /etc/shells 里頭就有個(gè) /sbin/nologin 文件的存在,這個(gè)就是我們說(shuō)的怪怪的 shell 啰~

    那么,再想一想,我這個(gè)使用者什么時(shí)候可以取得 shell 來(lái)工作呢?還有,我這個(gè)使用者默認(rèn)會(huì)取得哪一個(gè) shell 啊?還記得我們?cè)诘谖逭碌脑诮K端界面登陸linux小節(jié)當(dāng)中提到的登陸動(dòng)作吧?當(dāng)我登陸的時(shí)候,系統(tǒng)就會(huì)給我一個(gè) shell 讓我來(lái)工作了。而這個(gè)登陸取得的 shell 就記錄在 /etc/passwd 這個(gè)文件內(nèi)!這個(gè)文件的內(nèi)容是啥?

    [root@www ~]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin .....(底下省略).....

    如上所示,在每一行的最后一個(gè)數(shù)據(jù),就是你登陸后可以取得的默認(rèn)的 shell 啦!那你也會(huì)看到, root 是 /bin/bash ,不過,系統(tǒng)賬號(hào) bin 與 daemon 等等,就使用那個(gè)怪怪的 /sbin/nologin 啰~關(guān)于使用者這部分的內(nèi)容,我們留在第十四章的賬號(hào)管理時(shí)提供更多的說(shuō)明。


    Bash shell 的功能

    既然 /bin/bash 是 Linux 默認(rèn)的 shell ,那么總是得了解一下這個(gè)玩意兒吧!bash 是 GNU 計(jì)劃中重要的工具軟件之一,目前也是Linux distributions 的標(biāo)準(zhǔn) shell 。 bash 主要兼容于 sh ,并且依據(jù)一些使用者需求,而加強(qiáng)的shell 版本。不論你使用的是那個(gè) distribution ,你都難逃需要學(xué)習(xí) bash 的宿命啦!那么這個(gè)shell 有什么好處,干嘛 Linux 要使用他作為默認(rèn)的 shell 呢? bash 主要的優(yōu)點(diǎn)有底下幾個(gè):


    • 命令編修能力 (history):

    bash 的功能里頭,鳥哥個(gè)人認(rèn)為相當(dāng)棒的一個(gè)就是『他能記憶使用過的命令!』這功能真的相當(dāng)?shù)陌?#xff01;因?yàn)槲抑灰诿盍邪础荷舷骆I』就可以找到前/后一個(gè)輸入的命令!而在很多distribution 里頭,默認(rèn)的命令記憶功能可以到達(dá) 1000 個(gè)!也就是說(shuō),你曾經(jīng)下達(dá)過的命令幾乎都被記錄下來(lái)了。

    這么多的命令記錄在哪里呢?在你的家目錄內(nèi)的 .bash_history 啦!不過,需要留意的是,~/.bash_history 記錄的是前一次登陸以前所運(yùn)行過的命令,而至于這一次登陸所運(yùn)行的命令都被緩存在內(nèi)存中,當(dāng)你成功的注銷系統(tǒng)后,該命令記憶才會(huì)記錄到 .bash_history 當(dāng)中

    這有什么功能呢?最大的好處就是可以『查詢?cè)?jīng)做過的舉動(dòng)!』如此可以知道你的運(yùn)行步驟,那么就可以追蹤你曾下達(dá)過的命令,以作為除錯(cuò)的工具!但如此一來(lái)也有個(gè)煩惱,就是如果被黑客入侵了,那么他只要翻你曾經(jīng)運(yùn)行過的命令,剛好你的命令又跟系統(tǒng)有關(guān) (例如直接輸入 MySQL 的密碼在命令列上面),那你的主機(jī)可就傷腦筋了!到底記錄命令的數(shù)目越多還是越少越好?這部份是見仁見智啦,沒有一定的答案的。


    • 命令與文件補(bǔ)全功能: ([tab] 按鍵的好處)

    還記得我們?cè)诘谖逭聝?nèi)的重要的幾個(gè)熱鍵小節(jié)當(dāng)中提到的[tab] 這個(gè)按鍵嗎?這個(gè)按鍵的功能就是在 bash 里頭才有的啦!常常在 bash 環(huán)境中使用 [tab] 是個(gè)很棒的習(xí)慣喔!因?yàn)橹辽倏梢宰屇?span id="ozvdkddzhkzd" class="text_import2">1)少打很多字; 2)確定輸入的數(shù)據(jù)是正確的!使用 [tab] 按鍵的時(shí)機(jī)依據(jù) [tab] 接在命令后或參數(shù)后而有所不同。我們?cè)購(gòu)?fù)習(xí)一次:

    • [Tab] 接在一串命令的第一個(gè)字的后面,則為命令補(bǔ)全;
    • [Tab] 接在一串命令的第二個(gè)字以后時(shí),則為『文件補(bǔ)齊』!

    所以說(shuō),如果我想要知道我的環(huán)境中,所有可以運(yùn)行的命令有幾個(gè)?就直接在 bash 的提示字符后面連續(xù)按兩次 [tab] 按鍵就能夠顯示所有的可運(yùn)行命令了。那如果想要知道系統(tǒng)當(dāng)中所有以 c 為開頭的命令呢?就按下『 c[tab][tab] 』就好啦! ^_^

    是的!真的是很方便的功能,所以,有事沒事,在bash shell 底下,多按幾次 [tab] 是一個(gè)不錯(cuò)的習(xí)慣啦


    • 命令別名配置功能: (alias)

    假如我需要知道這個(gè)目錄底下的所有文件 (包含隱藏檔) 及所有的文件屬性,那么我就必須要下達(dá)『ls -al 』這樣的命令串,唉!真麻煩,有沒有更快的取代方式?呵呵!就使用命令別名呀!例如鳥哥最喜歡直接以lm 這個(gè)自定義的命令來(lái)取代上面的命令,也就是說(shuō),lm 會(huì)等于 ls -al這樣的一個(gè)功能,嘿!那么要如何作呢?就使用 alias 即可!你可以在命令列輸入 alias 就可以知道目前的命令別名有哪些了!也可以直接下達(dá)命令來(lái)配置別名呦:

    alias lm='ls -al'

    • 工作控制、前景背景控制: (job control, foreground, background)

    這部分我們?cè)诘谑哒?Linux 過程控制中再提及!使用前、背景的控制可以讓工作進(jìn)行的更為順利!至于工作控制(jobs)的用途則更廣,可以讓我們隨時(shí)將工作丟到背景中運(yùn)行!而不怕不小心使用了[Ctrl] + c 來(lái)停掉該程序!真是好樣的!此外,也可以在單一登錄的環(huán)境中,達(dá)到多任務(wù)的目的呢!


    • 程序化腳本: (shell scripts)

    在 DOS 年代還記得將一堆命令寫在一起的所謂的『批處理文件』吧?在 Linux 底下的shell scripts 則發(fā)揮更為強(qiáng)大的功能,可以將你平時(shí)管理系統(tǒng)常需要下達(dá)的連續(xù)命令寫成一個(gè)文件,該文件并且可以透過對(duì)談交互式的方式來(lái)進(jìn)行主機(jī)的偵測(cè)工作!也可以藉由shell 提供的環(huán)境變量及相關(guān)命令來(lái)進(jìn)行設(shè)計(jì),哇!整個(gè)設(shè)計(jì)下來(lái)幾乎就是一個(gè)小型的程序語(yǔ)言了!該scripts 的功能真的是超乎我的想象之外!以前在 DOS 底下需要程序語(yǔ)言才能寫的東西,在Linux 底下使用簡(jiǎn)單的 shell scripts 就可以幫你達(dá)成了!真的厲害!這部分我們?cè)诘谑略賮?lái)談!


    • 通配符: (Wildcard)

    除了完整的字符串之外, bash 還支持許多的通配符來(lái)幫助用戶查詢與命令下達(dá)。舉例來(lái)說(shuō),想要知道 /usr/bin 底下有多少以 X 為開頭的文件嗎?使用:『ls -l /usr/bin/X* 』就能夠知道啰~此外,還有其他可供利用的通配符,這些都能夠加快使用者的操作呢!


    Bash shell 的內(nèi)建命令: type

    我們?cè)诘谖逭绿岬疥P(guān)于Linux 的聯(lián)機(jī)幫助文件部分,也就是 man page 的內(nèi)容,那么 bash 有沒有什么說(shuō)明文件啊?開玩笑~這么棒的東西怎么可能沒有說(shuō)明文件!請(qǐng)你在 shell 的環(huán)境下,直接輸入 man bash 瞧一瞧,嘿嘿!不是蓋的吧!讓你看個(gè)幾天幾夜也無(wú)法看完的 bash 說(shuō)明文件,可是很詳盡的數(shù)據(jù)啊! ^_^

    不過,在這個(gè) bash 的 man page 當(dāng)中,不知道你是否有察覺到,咦!怎么這個(gè)說(shuō)明文件里面有其他的文件說(shuō)明啊?舉例來(lái)說(shuō),那個(gè) cd 命令的說(shuō)明就在這個(gè) man page 內(nèi)?然后我直接輸入 man cd 時(shí),怎么出現(xiàn)的畫面中,最上方竟然出現(xiàn)一堆命令的介紹?這是怎么回事?為了方便 shell 的操作,其實(shí) bash 已經(jīng)『內(nèi)建』了很多命令了,例如上面提到的 cd ,還有例如 umask 等等的命令,都是內(nèi)建在 bash 當(dāng)中的呢!

    那我怎么知道這個(gè)命令是來(lái)自于外部命令(指的是其他非 bash 所提供的命令) 或是內(nèi)建在 bash 當(dāng)中的呢?嘿嘿!利用 type 這個(gè)命令來(lái)觀察即可!舉例來(lái)說(shuō):

    [root@www ~]# type [-tpa] name 選項(xiàng)與參數(shù)::不加任何選項(xiàng)與參數(shù)時(shí),type 會(huì)顯示出 name 是外部命令還是 bash 內(nèi)建命令 -t :當(dāng)加入 -t 參數(shù)時(shí),type 會(huì)將 name 以底下這些字眼顯示出他的意義:file :表示為外部命令;alias :表示該命令為命令別名所配置的名稱;builtin :表示該命令為 bash 內(nèi)建的命令功能; -p :如果后面接的 name 為外部命令時(shí),才會(huì)顯示完整文件名; -a :會(huì)由 PATH 變量定義的路徑中,將所有含 name 的命令都列出來(lái),包含 alias范例一:查詢一下 ls 這個(gè)命令是否為 bash 內(nèi)建? [root@www ~]# type ls ls is aliased to `ls --color=tty' <==未加任何參數(shù),列出 ls 的最主要使用情況 [root@www ~]# type -t ls alias <==僅列出 ls 運(yùn)行時(shí)的依據(jù) [root@www ~]# type -a ls ls is aliased to `ls --color=tty' <==最先使用 aliase ls is /bin/ls <==還有找到外部命令在 /bin/ls范例二:那么 cd 呢? [root@www ~]# type cd cd is a shell builtin <==看到了嗎? cd 是 shell 內(nèi)建命令

    透過 type 這個(gè)命令我們可以知道每個(gè)命令是否為 bash 的內(nèi)建命令。此外,由于利用 type 搜尋后面的名稱時(shí),如果后面接的名稱并不能以運(yùn)行檔的狀態(tài)被找到,那么該名稱是不會(huì)被顯示出來(lái)的。也就是說(shuō), type 主要在找出『運(yùn)行檔』而不是一般文件檔名喔!呵呵!所以,這個(gè) type 也可以用來(lái)作為類似which命令的用途啦!找命令用的!


    命令的下達(dá)

    我們?cè)诘谖逭碌拈_始下達(dá)命令小節(jié)已經(jīng)提到過在shell 環(huán)境下的命令下達(dá)方法,如果你忘記了請(qǐng)回到第五章再去回憶一下!這里不重復(fù)說(shuō)明了。鳥哥這里僅就反斜杠 (\) 來(lái)說(shuō)明一下命令下達(dá)的方式啰!

    范例:如果命令串太長(zhǎng)的話,如何使用兩行來(lái)輸出? [vbird@www ~]# cp /var/spool/mail/root /etc/crontab \ > /etc/fstab /root

    上面這個(gè)命令用途是將三個(gè)文件復(fù)制到 /root 這個(gè)目錄下而已。不過,因?yàn)槊钐L(zhǎng),于是鳥哥就利用『 \[Enter] 』來(lái)將 [Enter] 這個(gè)按鍵『跳脫!』開來(lái),讓[Enter] 按鍵不再具有『開始運(yùn)行』的功能!好讓命令可以繼續(xù)在下一行輸入。需要特別留意, [Enter] 按鍵是緊接著反斜杠 (\) 的,兩者中間沒有其他字符。因?yàn)?\ 僅跳脫『緊接著的下一個(gè)字符』而已!所以,萬(wàn)一我寫成:『 \ [Enter] 』,亦即 [Enter] 與反斜杠中間有一個(gè)空格時(shí),則 \ 跳脫的是『空格鍵』而不是 [Enter] 按鍵!這個(gè)地方請(qǐng)?jiān)僮屑?xì)的看一遍!很重要!

    如果順利跳脫 [Enter] 后,下一行最前面就會(huì)主動(dòng)出現(xiàn) > 的符號(hào),你可以繼續(xù)輸入命令啰!也就是說(shuō),那個(gè) > 是系統(tǒng)自動(dòng)出現(xiàn)的,你不需要輸入。

    總之,當(dāng)我們順利的在終端機(jī) (tty) 上面登陸后, Linux 就會(huì)依據(jù) /etc/passwd 文件的配置給我們一個(gè) shell (默認(rèn)是 bash),然后我們就可以依據(jù)上面的命令下達(dá)方式來(lái)操作 shell,之后,我們就可以透過 man 這個(gè)在線查詢來(lái)查詢命令的使用方式與參數(shù)說(shuō)明,很不錯(cuò)吧!那么我們就趕緊更進(jìn)一步來(lái)操作 bash 這個(gè)好玩的東西啰!


    Shell 的變量功能

    變量是 bash 環(huán)境中非常重要的一個(gè)玩意兒,我們知道 Linux 是多人多任務(wù)的環(huán)境,每個(gè)人登陸系統(tǒng)都能取得一個(gè) bash ,每個(gè)人都能夠使用 bash 下達(dá) mail 這個(gè)命令來(lái)收受『自己』的郵件,問題是, bash 是如何得知你的郵件信箱是哪個(gè)文件?這就需要『變量』的幫助啦!所以,你說(shuō)變量重不重要呢?底下我們將介紹重要的環(huán)境變量、變量的取用與配置等數(shù)據(jù),呼呼!動(dòng)動(dòng)腦時(shí)間又來(lái)到啰!^_^


    什么是變量?

    那么,什么是『變量』呢?簡(jiǎn)單的說(shuō),就是讓某一個(gè)特定字符串代表不固定的內(nèi)容就是了。舉個(gè)大家在國(guó)中都會(huì)學(xué)到的數(shù)學(xué)例子,那就是:『 y = ax + b 』這東西,在等號(hào)左邊的(y)就是變量,在等號(hào)右邊的(ax+b)就是變量?jī)?nèi)容。要注意的是,左邊是未知數(shù),右邊是已知數(shù)喔!講的更簡(jiǎn)單一點(diǎn),我們可以『用一個(gè)簡(jiǎn)單的 "字眼" 來(lái)取代另一個(gè)比較復(fù)雜或者是容易變動(dòng)的數(shù)據(jù)』。這有什么好處啊?最大的好處就是『方便!』。


    • 變量的可變性與方便性

    舉例來(lái)說(shuō),我們每個(gè)賬號(hào)的郵件信箱默認(rèn)是以 MAIL 這個(gè)變量來(lái)進(jìn)行存取的,當(dāng) dmtsai 這個(gè)使用者登陸時(shí),他便會(huì)取得 MAIL 這個(gè)變量,而這個(gè)變量的內(nèi)容其實(shí)就是 /var/spool/mail/dmtsai,那如果 vbird 登陸呢?他取得的 MAIL 這個(gè)變量的內(nèi)容其實(shí)就是 /var/spool/mail/vbird 。而我們使用信件讀取命令 mail 來(lái)讀取自己的郵件信箱時(shí),嘿嘿,這支程序可以直接讀取 MAIL 這個(gè)變量的內(nèi)容,就能夠自動(dòng)的分辨出屬于自己的信箱信件啰!這樣一來(lái),設(shè)計(jì)程序的設(shè)計(jì)師就真的很方便的啦!


    圖 2.1.1、程序、變量與不同用戶的關(guān)系

    如上圖所示,由于系統(tǒng)已經(jīng)幫我們規(guī)劃好 MAIL 這個(gè)變量,所以用戶只要知道 mail 這個(gè)命令如何使用即可,mail 會(huì)主動(dòng)的取用 MAIL 這個(gè)變量,就能夠如上圖所示的取得自己的郵件信箱了!(注意大小寫,小寫的 mail 是命令,大寫的 MAIL 則是變量名稱喔!)

    那么使用變量真的比較好嗎?這是當(dāng)然的!想象一個(gè)例子,如果 mail 這個(gè)命令將 root 收信的郵件信箱 (mailbox) 檔名為/var/spool/mail/root 直接寫入程序代碼中。那么當(dāng) dmtsai 要使用 mail 時(shí),將會(huì)取得 /var/spool/mail/root 這個(gè)文件的內(nèi)容!不合理吧!所以你就需要幫 dmtsai 也設(shè)計(jì)一個(gè) mail 的程序,將 /var/spool/mail/dmtsai 寫死到 mail 的程序代碼當(dāng)中!天吶!那系統(tǒng)要有多少個(gè) mail 命令啊?反過來(lái)說(shuō),使用變量就變的很簡(jiǎn)單了!因?yàn)槟悴恍枰鼊?dòng)到程序代碼啊!只要將 MAIL 這個(gè)變量帶入不同的內(nèi)容即可讓所有使用者透過 mail 取得自己的信件!當(dāng)然簡(jiǎn)單多了!


    • 影響 bash 環(huán)境操作的變量

    某些特定變量會(huì)影響到 bash 的環(huán)境喔!舉例來(lái)說(shuō),我們前面已經(jīng)提到過很多次的那個(gè) PATH 變量!你能不能在任何目錄下運(yùn)行某個(gè)命令,與 PATH 這個(gè)變量有很大的關(guān)系。例如你下達(dá) ls 這個(gè)命令時(shí),系統(tǒng)就是透過 PATH 這個(gè)變量里面的內(nèi)容所記錄的路徑順序來(lái)搜尋命令的呢!如果在搜尋完 PATH 變量?jī)?nèi)的路徑還找不到 ls 這個(gè)命令時(shí),就會(huì)在屏幕上顯示『 command not found 』的錯(cuò)誤信息了。

    如果說(shuō)的學(xué)理一點(diǎn),那么由于在 Linux System 下面,所有的線程都是需要一個(gè)運(yùn)行碼,而就如同上面提到的,你『真正以shell 來(lái)跟 Linux 溝通,是在正確的登陸 Linux 之后!』這個(gè)時(shí)候你就有一個(gè)bash 的運(yùn)行程序,也才可以真正的經(jīng)由 bash 來(lái)跟系統(tǒng)溝通啰!而在進(jìn)入 shell之前,也正如同上面提到的,由于系統(tǒng)需要一些變量來(lái)提供他數(shù)據(jù)的存取 (或者是一些環(huán)境的配置參數(shù)值,例如是否要顯示彩色等等的) ,所以就有一些所謂的『環(huán)境變量』需要來(lái)讀入系統(tǒng)中了!這些環(huán)境變量例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的,為了區(qū)別與自定義變量的不同,環(huán)境變量通常以大寫字符來(lái)表示呢!


    • 腳本程序設(shè)計(jì) (shell script) 的好幫手

    這些還都只是系統(tǒng)默認(rèn)的變量的目的,如果是個(gè)人的配置方面的應(yīng)用呢:例如你要寫一個(gè)大型的script 時(shí),有些數(shù)據(jù)因?yàn)榭赡苡捎谟脩袅?xí)慣的不同而有差異,比如說(shuō)路徑好了,由于該路徑在script 被使用在相當(dāng)多的地方,如果下次換了一部主機(jī),都要修改 script 里面的所有路徑,那么我一定會(huì)瘋掉!這個(gè)時(shí)候如果使用變量,而將該變量的定義寫在最前面,后面相關(guān)的路徑名稱都以變量來(lái)取代,嘿嘿!那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程序設(shè)計(jì)師都會(huì)善用變量的定義!


    圖 2.1.2、變量應(yīng)用于 shell script 的示意圖

    最后我們就簡(jiǎn)單的對(duì)『什么是變量』作個(gè)簡(jiǎn)單定義好了:『變量就是以一組文字或符號(hào)等,來(lái)取代一些配置或者是一串保留的數(shù)據(jù)!』,例如:我配置了『myname』就是『VBird』,所以當(dāng)你讀取myname 這個(gè)變量的時(shí)候,系統(tǒng)自然就會(huì)知道!哈!那就是 VBird 啦!那么如何『顯示變量』呢?這就需要使用到 echo 這個(gè)命令啦!


    變量的取用與配置:echo, 變量配置守則, unset

    說(shuō)的口沫橫飛的,也不知道『變量』與『變量代表的內(nèi)容』有啥關(guān)系?那我們就將『變量』的『內(nèi)容』拿出來(lái)給您瞧瞧好了。你可以利用 echo 這個(gè)命令來(lái)取用變量,但是,變量在被取用時(shí),前面必須要加上錢字號(hào)『 $ 』才行,舉例來(lái)說(shuō),要知道 PATH 的內(nèi)容,該如何是好?


    • 變量的取用: echo
    [root@www ~]# echo $variable [root@www ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin [root@www ~]# echo ${PATH}

    變量的取用就如同上面的范例,利用 echo 就能夠讀出,只是需要在變量名稱前面加上 $ ,或者是以 ${變量} 的方式來(lái)取用都可以!當(dāng)然啦,那個(gè) echo 的功能可是很多的,我們這里單純是拿 echo 來(lái)讀出變量的內(nèi)容而已,更多的 echo 使用,請(qǐng)自行給他 man echo 吧! ^_^

    例題: 請(qǐng)?jiān)谄聊簧厦骘@示出您的環(huán)境變量 HOME 與 MAIL: 答: echo $HOME 或者是 echo ${HOME}
    echo $MAIL 或者是 echo ${MAIL}

    現(xiàn)在我們知道了變量與變量?jī)?nèi)容之間的相關(guān)性了,好了,那么我要如何『配置』或者是『修改』某個(gè)變量的內(nèi)容啊?很簡(jiǎn)單啦!用『等號(hào)(=)』連接變量與他的內(nèi)容就好啦!舉例來(lái)說(shuō):我要將 myname 這個(gè)變量名稱的內(nèi)容配置為 VBird ,那么:

    [root@www ~]# echo $myname<==這里并沒有任何數(shù)據(jù)~因?yàn)檫@個(gè)變量尚未被配置!是空的! [root@www ~]# myname=VBird [root@www ~]# echo $myname VBird <==出現(xiàn)了!因?yàn)檫@個(gè)變量已經(jīng)被配置了!

    瞧!如此一來(lái),這個(gè)變量名稱 myname 的內(nèi)容就帶有 VBird 這個(gè)數(shù)據(jù)啰~而由上面的例子當(dāng)中,我們也可以知道:在 bash 當(dāng)中,當(dāng)一個(gè)變量名稱尚未被配置時(shí),默認(rèn)的內(nèi)容是『空』的。另外,變量在配置時(shí),還是需要符合某些規(guī)定的,否則會(huì)配置失敗喔!這些守則如下所示啊!


    • 變量的配置守則
  • 變量與變量?jī)?nèi)容以一個(gè)等號(hào)『=』來(lái)連結(jié),如下所示:
    『myname=VBird』

  • 等號(hào)兩邊不能直接接空格符,如下所示為錯(cuò)誤:
    『myname = VBird』或『myname=VBird Tsai』

  • 變量名稱只能是英文字母與數(shù)字,但是開頭字符不能是數(shù)字,如下為錯(cuò)誤:
    『2myname=VBird』

  • 變量?jī)?nèi)容若有空格符可使用雙引號(hào)『"』或單引號(hào)『'』將變量?jī)?nèi)容結(jié)合起來(lái),但
    • 雙引號(hào)內(nèi)的特殊字符如 $ 等,可以保有原本的特性,如下所示:
      『var="lang is $LANG"』則『echo $var』可得『lang is en_US』
    • 單引號(hào)內(nèi)的特殊字符則僅為一般字符 (純文本),如下所示:
      『var='lang is $LANG'』則『echo $var』可得『lang is $LANG』

  • 可用跳脫字符『 \ 』將特殊符號(hào)(如 [Enter], $, \, 空格符, '等)變成一般字符;

  • 在一串命令中,還需要藉由其他的命令提供的信息,可以使用反單引號(hào)『`命令`』或『$(命令)』。特別注意,那個(gè) ` 是鍵盤上方的數(shù)字鍵 1 左邊那個(gè)按鍵,而不是單引號(hào)!例如想要取得核心版本的配置:
    『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』

  • 若該變量為擴(kuò)增變量?jī)?nèi)容時(shí),則可用 "$變量名稱" 或 ${變量} 累加內(nèi)容,如下所示:
    『PATH="$PATH":/home/bin』

  • 若該變量需要在其他子程序運(yùn)行,則需要以 export 來(lái)使變量變成環(huán)境變量
    『export PATH』

  • 通常大寫字符為系統(tǒng)默認(rèn)變量,自行配置變量可以使用小寫字符,方便判斷 (純粹依照使用者興趣與嗜好) ;

  • 取消變量的方法為使用 unset :『unset 變量名稱』例如取消 myname 的配置:
    『unset myname』
  • 底下讓鳥哥舉幾個(gè)例子來(lái)讓你試看看,就知道怎么配置好你的變量啰!

    范例一:配置一變量 name ,且內(nèi)容為 VBird [root@www ~]# 12name=VBird -bash: 12name=VBird: command not found <==屏幕會(huì)顯示錯(cuò)誤!因?yàn)椴荒芤詳?shù)字開頭! [root@www ~]# name = VBird <==還是錯(cuò)誤!因?yàn)橛锌瞻?#xff01; [root@www ~]# name=VBird <==OK 的啦!范例二:承上題,若變量?jī)?nèi)容為 VBird's name 呢,就是變量?jī)?nèi)容含有特殊符號(hào)時(shí): [root@www ~]# name=VBird's name # 單引號(hào)與雙引號(hào)必須要成對(duì),在上面的配置中僅有一個(gè)單引號(hào),因此當(dāng)你按下 enter 后, # 你還可以繼續(xù)輸入變量?jī)?nèi)容。這與我們所需要的功能不同,失敗啦! # 記得,失敗后要復(fù)原請(qǐng)按下 [ctrl]-c 結(jié)束! [root@www ~]# name="VBird's name" <==OK 的啦! # 命令是由左邊向右找→,先遇到的引號(hào)先有用,因此如上所示,單引號(hào)會(huì)失效! [root@www ~]# name='VBird's name' <==失敗的啦! # 因?yàn)榍皟蓚€(gè)單引號(hào)已成對(duì),后面就多了一個(gè)不成對(duì)的單引號(hào)了!因此也就失敗了! [root@www ~]# name=VBird\'s\ name <==OK 的啦! # 利用反斜杠 (\) 跳脫特殊字符,例如單引號(hào)與空格鍵,這也是 OK 的啦!范例三:我要在 PATH 這個(gè)變量當(dāng)中『累加』:/home/dmtsai/bin 這個(gè)目錄 [root@www ~]# PATH=$PATH:/home/dmtsai/bin [root@www ~]# PATH="$PATH":/home/dmtsai/bin [root@www ~]# PATH=${PATH}:/home/dmtsai/bin # 上面這三種格式在 PATH 里頭的配置都是 OK 的!但是底下的例子就不見得啰!范例四:承范例三,我要將 name 的內(nèi)容多出 "yes" 呢? [root@www ~]# name=$nameyes # 知道了吧?如果沒有雙引號(hào),那么變量成了啥?name 的內(nèi)容是 $nameyes 這個(gè)變量! # 呵呵!我們可沒有配置過 nameyes 這個(gè)變量吶!所以,應(yīng)該是底下這樣才對(duì)! [root@www ~]# name="$name"yes [root@www ~]# name=${name}yes <==以此例較佳!范例五:如何讓我剛剛配置的 name=VBird 可以用在下個(gè) shell 的程序? [root@www ~]# name=VBird [root@www ~]# bash <==進(jìn)入到所謂的子程序 [root@www ~]# echo $name <==子程序:再次的 echo 一下;<==嘿嘿!并沒有剛剛配置的內(nèi)容喔! [root@www ~]# exit <==子程序:離開這個(gè)子程序 [root@www ~]# export name [root@www ~]# bash <==進(jìn)入到所謂的子程序 [root@www ~]# echo $name <==子程序:在此運(yùn)行! VBird <==看吧!出現(xiàn)配置值了! [root@www ~]# exit <==子程序:離開這個(gè)子程序

    什么是『子程序』呢?就是說(shuō),在我目前這個(gè) shell 的情況下,去激活另一個(gè)新的 shell ,新的那個(gè) shell 就是子程序啦!在一般的狀態(tài)下,父程序的自定義變量是無(wú)法在子程序內(nèi)使用的。但是透過 export 將變量變成環(huán)境變量后,就能夠在子程序底下應(yīng)用了!很不賴吧!至于程序的相關(guān)概念,我們會(huì)在第十七章程序管理當(dāng)中提到的喔!

    范例六:如何進(jìn)入到您目前核心的模塊目錄? [root@www ~]# cd /lib/modules/`uname -r`/kernel [root@www ~]# cd /lib/modules/$(uname -r)/kernel

    每個(gè) Linux 都能夠擁有多個(gè)核心版本,且?guī)缀?distribution 的核心版本都不相同。以 CentOS 5.3 (未升級(jí)前) 為例,他的默認(rèn)核心版本是 2.6.18-128.el5 ,所以核心模塊目錄在 /lib/modules/2.6.18-128.el5/kernel/ 內(nèi)。也由于每個(gè) distributions 的這個(gè)值都不相同,但是我們卻可以利用 uname -r 這個(gè)命令先取得版本信息。所以啰,就可以透過上面命令當(dāng)中的內(nèi)含命令 `uname -r` 先取得版本輸出到 cd ... 那個(gè)命令當(dāng)中,就能夠順利的進(jìn)入目前核心的驅(qū)動(dòng)程序所放置的目錄啰!很方便吧!

    其實(shí)上面的命令可以說(shuō)是作了兩次動(dòng)作,亦即是:

  • 先進(jìn)行反單引號(hào)內(nèi)的動(dòng)作『uname -r』并得到核心版本為 2.6.18-128.el5
  • 將上述的結(jié)果帶入原命令,故得命令為:『cd /lib/modules/2.6.18-128.el5/kernel/』
  • 范例七:取消剛剛配置的 name 這個(gè)變量?jī)?nèi)容 [root@www ~]# unset name

    根據(jù)上面的案例你可以試試看!就可以了解變量的配置啰!這個(gè)是很重要的呦!請(qǐng)勤加練習(xí)!其中,較為重要的一些特殊符號(hào)的使用啰!例如單引號(hào)、雙引號(hào)、跳脫字符、錢字號(hào)、反單引號(hào)等等,底下的例題想一想吧!

    例題: 在變量的配置當(dāng)中,單引號(hào)與雙引號(hào)的用途有何不同?
    答: 單引號(hào)與雙引號(hào)的最大不同在于雙引號(hào)仍然可以保有變量的內(nèi)容,但單引號(hào)內(nèi)僅能是一般字符,而不會(huì)有特殊符號(hào)。我們以底下的例子做說(shuō)明:假設(shè)您定義了一個(gè)變量, name=VBird ,現(xiàn)在想以 name 這個(gè)變量的內(nèi)容定義出 myname 顯示 VBird its me 這個(gè)內(nèi)容,要如何訂定呢? [root@www ~]# name=VBird
    [root@www ~]# echo $name
    VBird
    [root@www ~]# myname="$name its me"
    [root@www ~]# echo $myname
    VBird its me
    [root@www ~]# myname='$name its me'
    [root@www ~]# echo $myname
    $name its me 發(fā)現(xiàn)了嗎?沒錯(cuò)!使用了單引號(hào)的時(shí)候,那么 $name 將失去原有的變量?jī)?nèi)容,僅為一般字符的顯示型態(tài)而已!這里必需要特別小心在意!

    例題: 在命令下達(dá)的過程中,反單引號(hào)( ` )這個(gè)符號(hào)代表的意義為何? 答: 在一串命令中,在 ` 之內(nèi)的命令將會(huì)被先運(yùn)行,而其運(yùn)行出來(lái)的結(jié)果將做為外部的輸入信息!例如 uname -r 會(huì)顯示出目前的核心版本,而我們的核心版本在 /lib/modules 里面,因此,你可以先運(yùn)行 uname -r 找出核心版本,然后再以『 cd 目錄』到該目錄下,當(dāng)然也可以運(yùn)行如同上面范例六的運(yùn)行內(nèi)容啰。

    另外再舉個(gè)例子,我們也知道, locate命令可以列出所有的相關(guān)文件檔名,但是,如果我想要知道各個(gè)文件的權(quán)限呢?舉例來(lái)說(shuō),我想要知道每個(gè) crontab 相關(guān)檔名的權(quán)限: [root@www ~]# ls -l `locate crontab` 如此一來(lái),先以 locate 將文件名數(shù)據(jù)都列出來(lái),再以 ls 命令來(lái)處理的意思啦!瞭了嗎? ^_^

    例題: 若你有一個(gè)常去的工作目錄名稱為:『/cluster/server/work/taiwan_2005/003/』,如何進(jìn)行該目錄的簡(jiǎn)化? 答: 在一般的情況下,如果你想要進(jìn)入上述的目錄得要『cd /cluster/server/work/taiwan_2005/003/』,以鳥哥自己的案例來(lái)說(shuō),鳥哥跑數(shù)值模式常常會(huì)配置很長(zhǎng)的目錄名稱(避免忘記),但如此一來(lái)變換目錄就很麻煩。此時(shí),鳥哥習(xí)慣利用底下的方式來(lái)降低命令下達(dá)錯(cuò)誤的問題: [root@www ~]# work="/cluster/server/work/taiwan_2005/003/"
    [root@www ~]# cd $work 未來(lái)我想要使用其他目錄作為我的模式工作目錄時(shí),只要變更 work 這個(gè)變量即可!而這個(gè)變量又可以在 bash的配置文件中直接指定,那我每次登陸只要運(yùn)行『 cd $work 』就能夠去到數(shù)值模式仿真的工作目錄了!是否很方便呢? ^_^

    Tips:
    老實(shí)說(shuō),使用『 version=$(uname -r) 』來(lái)取代『 version=`uname -r` 』比較好,因?yàn)榉磫我?hào)大家老是容易打錯(cuò)或看錯(cuò)!所以現(xiàn)在鳥哥都習(xí)慣使用 $( 命令 ) 來(lái)介紹這個(gè)功能!

    環(huán)境變量的功能

    環(huán)境變量可以幫我們達(dá)到很多功能~包括家目錄的變換啊、提示字符的顯示啊、運(yùn)行文件搜尋的路徑啊等等的,還有很多很多啦!那么,既然環(huán)境變量有那么多的功能,問一下,目前我的 shell 環(huán)境中,有多少默認(rèn)的環(huán)境變量啊?我們可以利用兩個(gè)命令來(lái)查閱,分別是 env 與 export 呢!


    • 用 env 觀察環(huán)境變量與常見環(huán)境變量說(shuō)明
    范例一:列出目前的 shell 環(huán)境下的所有環(huán)境變量與其內(nèi)容。 [root@www ~]# env HOSTNAME=www.vbird.tsai <== 這部主機(jī)的主機(jī)名 TERM=xterm <== 這個(gè)終端機(jī)使用的環(huán)境是什么類型 SHELL=/bin/bash <== 目前這個(gè)環(huán)境下,使用的 Shell 是哪一個(gè)程序? HISTSIZE=1000 <== 『記錄命令的筆數(shù)』在 CentOS 默認(rèn)可記錄 1000 筆 USER=root <== 使用者的名稱啊! LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01: or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0 0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz= 00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3 1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00 ;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些顏色顯示 MAIL=/var/spool/mail/root <== 這個(gè)用戶所取用的 mailbox 位置 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin: /root/bin <== 不再多講啊!是運(yùn)行文件命令搜尋路徑 INPUTRC=/etc/inputrc <== 與鍵盤按鍵功能有關(guān)??梢耘渲锰厥獍存I! PWD=/root <== 目前用戶所在的工作目錄 (利用 pwd 取出!) LANG=en_US <== 這個(gè)與語(yǔ)系有關(guān),底下會(huì)再介紹! HOME=/root <== 這個(gè)用戶的家目錄啊! _=/bin/env <== 上一次使用的命令的最后一個(gè)參數(shù)(或命令本身)

    env 是 environment (環(huán)境) 的簡(jiǎn)寫啊,上面的例子當(dāng)中,是列出來(lái)所有的環(huán)境變量。當(dāng)然,如果使用 export 也會(huì)是一樣的內(nèi)容~只不過, export 還有其他額外的功能就是了,我們等一下再提這個(gè) export 命令。那么上面這些變量有些什么功用呢?底下我們就一個(gè)一個(gè)來(lái)分析分析!

    • HOME
      代表用戶的家目錄。還記得我們可以使用 cd ~ 去到自己的家目錄嗎?或者利用 cd 就可以直接回到用戶家目錄了。那就是取用這個(gè)變量啦~有很多程序都可能會(huì)取用到這個(gè)變量的值!

    • SHELL
      告知我們,目前這個(gè)環(huán)境使用的 SHELL 是哪支程序?Linux 默認(rèn)使用 /bin/bash 的啦!

    • HISTSIZE
      這個(gè)與『歷史命令』有關(guān),亦即是,我們?cè)?jīng)下達(dá)過的命令可以被系統(tǒng)記錄下來(lái),而記錄的『筆數(shù)』則是由這個(gè)值來(lái)配置的。

    • MAIL
      當(dāng)我們使用 mail 這個(gè)命令在收信時(shí),系統(tǒng)會(huì)去讀取的郵件信箱文件 (mailbox)。

    • PATH
      就是運(yùn)行文件搜尋的路徑啦~目錄與目錄中間以冒號(hào)(:)分隔,由于文件的搜尋是依序由 PATH 的變量?jī)?nèi)的目錄來(lái)查詢,所以,目錄的順序也是重要的喔。

    • LANG
      這個(gè)重要!就是語(yǔ)系數(shù)據(jù)啰~很多信息都會(huì)用到他,舉例來(lái)說(shuō),當(dāng)我們?cè)趩?dòng)某些 perl 的程序語(yǔ)言文件時(shí),他會(huì)主動(dòng)的去分析語(yǔ)系數(shù)據(jù)文件,如果發(fā)現(xiàn)有他無(wú)法解析的編碼語(yǔ)系,可能會(huì)產(chǎn)生錯(cuò)誤喔!一般來(lái)說(shuō),我們中文編碼通常是 zh_TW.Big5 或者是 zh_TW.UTF-8,這兩個(gè)編碼偏偏不容易被解譯出來(lái),所以,有的時(shí)候,可能需要修訂一下語(yǔ)系數(shù)據(jù)。這部分我們會(huì)在下個(gè)小節(jié)做介紹的!

    • RANDOM
      這個(gè)玩意兒就是『隨機(jī)隨機(jī)數(shù)』的變量啦!目前大多數(shù)的distributions 都會(huì)有隨機(jī)數(shù)生成器,那就是 /dev/random 這個(gè)文件。我們可以透過這個(gè)隨機(jī)數(shù)文件相關(guān)的變量 ($RANDOM) 來(lái)隨機(jī)取得隨機(jī)數(shù)值喔。在 BASH 的環(huán)境下,這個(gè) RANDOM 變量的內(nèi)容,介于 0~32767 之間,所以,你只要 echo $RANDOM 時(shí),系統(tǒng)就會(huì)主動(dòng)的隨機(jī)取出一個(gè)介于0~32767 的數(shù)值。萬(wàn)一我想要使用 0~9 之間的數(shù)值呢?呵呵~利用 declare 宣告數(shù)值類型,然后這樣做就可以了:
      [root@www ~]# declare -i number=$RANDOM*10/32768 ; echo $number 8 <== 此時(shí)會(huì)隨機(jī)取出 0~9 之間的數(shù)值喔!

    大致上是有這些環(huán)境變量啦~里面有些比較重要的參數(shù),在底下我們都會(huì)另外進(jìn)行一些說(shuō)明的~


    • 用 set 觀察所有變量 (含環(huán)境變量與自定義變量)

    bash 可不只有環(huán)境變量喔,還有一些與 bash 操作接口有關(guān)的變量,以及用戶自己定義的變量存在的。那么這些變量如何觀察呢?這個(gè)時(shí)候就得要使用 set 這個(gè)命令了。 set 除了環(huán)境變量之外,還會(huì)將其他在 bash 內(nèi)的變量通通顯示出來(lái)哩!信息很多,底下鳥哥僅列出幾個(gè)重要的內(nèi)容:

    [root@www ~]# set BASH=/bin/bash <== bash 的主程序放置路徑 BASH_VERSINFO=([0]="3" [1]="2" [2]="25" [3]="1" [4]="release" [5]="i686-redhat-linux-gnu") <== bash 的版本啊! BASH_VERSION='3.2.25(1)-release' <== 也是 bash 的版本啊! COLORS=/etc/DIR_COLORS.xterm <== 使用的顏色紀(jì)錄文件 COLUMNS=115 <== 在目前的終端機(jī)環(huán)境下,使用的字段有幾個(gè)字符長(zhǎng)度 HISTFILE=/root/.bash_history <== 歷史命令記錄的放置文件,隱藏檔 HISTFILESIZE=1000 <== 存起來(lái)(與上個(gè)變量有關(guān))的文件之命令的最大紀(jì)錄筆數(shù)。 HISTSIZE=1000 <== 目前環(huán)境下,可記錄的歷史命令最大筆數(shù)。 HOSTTYPE=i686 <== 主機(jī)安裝的軟件主要類型。我們用的是 i686 兼容機(jī)器軟件 IFS=$' \t\n' <== 默認(rèn)的分隔符 LINES=35 <== 目前的終端機(jī)下的最大行數(shù) MACHTYPE=i686-redhat-linux-gnu <== 安裝的機(jī)器類型 MAILCHECK=60 <== 與郵件有關(guān)。每 60 秒去掃瞄一次信箱有無(wú)新信! OLDPWD=/home <== 上個(gè)工作目錄。我們可以用 cd - 來(lái)取用這個(gè)變量。 OSTYPE=linux-gnu <== 操作系統(tǒng)的類型! PPID=20025 <== 父程序的 PID (會(huì)在后續(xù)章節(jié)才介紹) PS1='[\u@\h \W]\$ ' <== PS1 就厲害了。這個(gè)是命令提示字符,也就是我們常見的[root@www ~]# 或 [dmtsai ~]$ 的配置值啦!可以更動(dòng)的! PS2='> ' <== 如果你使用跳脫符號(hào) (\) 第二行以后的提示字符也 name=VBird <== 剛剛配置的自定義變量也可以被列出來(lái)喔! $ <== 目前這個(gè) shell 所使用的 PID ? <== 剛剛運(yùn)行完命令的回傳值。

    一般來(lái)說(shuō),不論是否為環(huán)境變量,只要跟我們目前這個(gè) shell 的操作接口有關(guān)的變量,通常都會(huì)被配置為大寫字符,也就是說(shuō),『基本上,在 Linux 默認(rèn)的情況中,使用{大寫的字母}來(lái)配置的變量一般為系統(tǒng)內(nèi)定需要的變量』。OK!OK!那么上頭那些變量當(dāng)中,有哪些是比較重要的?大概有這幾個(gè)吧!

    • PS1:(提示字符的配置)

      這是 PS1 (數(shù)字的 1 不是英文字母),這個(gè)東西就是我們的『命令提示字符』喔!當(dāng)我們每次按下 [Enter] 按鍵去運(yùn)行某個(gè)命令后,最后要再次出現(xiàn)提示字符時(shí),就會(huì)主動(dòng)去讀取這個(gè)變量值了。上頭 PS1 內(nèi)顯示的是一些特殊符號(hào),這些特殊符號(hào)可以顯示不同的信息,每個(gè) distributions 的 bash 默認(rèn)的 PS1 變量?jī)?nèi)容可能有些許的差異,不要緊,『習(xí)慣你自己的習(xí)慣』就好了。你可以用 man bash (注3)去查詢一下 PS1 的相關(guān)說(shuō)明,以理解底下的一些符號(hào)意義。

      • \d :可顯示出『星期 月 日』的日期格式,如:"Mon Feb 2"
      • \H :完整的主機(jī)名。舉例來(lái)說(shuō),鳥哥的練習(xí)機(jī)為『www.vbird.tsai』
      • \h :僅取主機(jī)名在第一個(gè)小數(shù)點(diǎn)之前的名字,如鳥哥主機(jī)則為『www』后面省略
      • \t :顯示時(shí)間,為 24 小時(shí)格式的『HH:MM:SS』
      • \T :顯示時(shí)間,為 12 小時(shí)格式的『HH:MM:SS』
      • \A :顯示時(shí)間,為 24 小時(shí)格式的『HH:MM』
      • \@ :顯示時(shí)間,為 12 小時(shí)格式的『am/pm』樣式
      • \u :目前使用者的賬號(hào)名稱,如『root』;
      • \v :BASH 的版本信息,如鳥哥的測(cè)試主板本為 3.2.25(1),僅取『3.2』顯示
      • \w :完整的工作目錄名稱,由根目錄寫起的目錄名稱。但家目錄會(huì)以 ~ 取代;
      • \W :利用 basename 函數(shù)取得工作目錄名稱,所以僅會(huì)列出最后一個(gè)目錄名。
      • \# :下達(dá)的第幾個(gè)命令。
      • \$ :提示字符,如果是 root 時(shí),提示字符為 # ,否則就是 $ 啰~

      好了,讓我們來(lái)看看 CentOS 默認(rèn)的 PS1 內(nèi)容吧:『[\u@\h \W]\$ 』,現(xiàn)在你知道那些反斜杠后的數(shù)據(jù)意義了吧?要注意喔!那個(gè)反斜杠后的數(shù)據(jù)為 PS1 的特殊功能,與 bash 的變量配置沒關(guān)系啦!不要搞混了喔!那你現(xiàn)在知道為何你的命令提示字符是:『 [root@www ~]# 』了吧?好了,那么假設(shè)我想要有類似底下的提示字符: [root@www /home/dmtsai 16:50 #12]# 那個(gè) # 代表第 12 次下達(dá)的命令。那么應(yīng)該如何配置 PS1 呢?可以這樣啊:
      [root@www ~ ]# cd /home [root@www home]# PS1='[\u@\h \w \A #\#]\$ ' [root@www /home 17:02 #85]# # 看到了嗎?提示字符變了!變的很有趣吧!其中,那個(gè) #85 比較有趣, # 如果您再隨便輸入幾次 ls 后,該數(shù)字就會(huì)添加喔!為啥?上面有說(shuō)明滴!

    • $:(關(guān)于本 shell 的 PID)

      錢字號(hào)本身也是個(gè)變量喔!這個(gè)咚咚代表的是『目前這個(gè) Shell 的線程代號(hào)』,亦即是所謂的 PID (Process ID)。更多的程序觀念,我們會(huì)在第四篇的時(shí)候提及。想要知道我們的 shell 的 PID ,就可以用:『echo $$ 』即可!出現(xiàn)的數(shù)字就是你的 PID 號(hào)碼。

    • ?:(關(guān)于上個(gè)運(yùn)行命令的回傳值)

      什么?問號(hào)也是一個(gè)特殊的變量?沒錯(cuò)!在 bash 里面這個(gè)變量可重要的很!這個(gè)變量是:『上一個(gè)運(yùn)行的命令所回傳的值』,上面這句話的重點(diǎn)是『上一個(gè)命令』與『回傳值』兩個(gè)地方。當(dāng)我們運(yùn)行某些命令時(shí),這些命令都會(huì)回傳一個(gè)運(yùn)行后的代碼。一般來(lái)說(shuō),如果成功的運(yùn)行該命令,則會(huì)回傳一個(gè) 0 值,如果運(yùn)行過程發(fā)生錯(cuò)誤,就會(huì)回傳『錯(cuò)誤代碼』才對(duì)!一般就是以非為 0 的數(shù)值來(lái)取代。我們以底下的例子來(lái)看看:
      [root@www ~]# echo $SHELL /bin/bash <==可順利顯示!沒有錯(cuò)誤! [root@www ~]# echo $? 0 <==因?yàn)闆]問題,所以回傳值為 0 [root@www ~]# 12name=VBird -bash: 12name=VBird: command not found <==發(fā)生錯(cuò)誤了!bash回報(bào)有問題 [root@www ~]# echo $? 127 <==因?yàn)橛袉栴},回傳錯(cuò)誤代碼(非為0) # 錯(cuò)誤代碼回傳值依據(jù)軟件而有不同,我們可以利用這個(gè)代碼來(lái)搜尋錯(cuò)誤的原因喔! [root@www ~]# echo $? 0 # 咦!怎么又變成正確了?這是因?yàn)?"?" 只與『上一個(gè)運(yùn)行命令』有關(guān), # 所以,我們上一個(gè)命令是運(yùn)行『 echo $? 』,當(dāng)然沒有錯(cuò)誤,所以是 0 沒錯(cuò)!

    • OSTYPE, HOSTTYPE, MACHTYPE:(主機(jī)硬件與核心的等級(jí))

      我們?cè)诘诹阏?、?jì)算器概論內(nèi)的 CPU 等級(jí)說(shuō)明中談過 CPU ,目前個(gè)人計(jì)算機(jī)的 CPU 主要分為 32/64 位,其中 32 位又可分為 i386, i586, i686,而 64 位則稱為 x86_64。由于不同等級(jí)的 CPU 命令集不太相同,因此你的軟件可能會(huì)針對(duì)某些 CPU 進(jìn)行優(yōu)化,以求取較佳的軟件性能。所以軟件就有 i386, i686 及 x86_64 之分。以目前 (2009) 的主流硬件來(lái)說(shuō),幾乎都是 x86_64 的天下!但是畢竟舊機(jī)器還是非常多,以鳥哥的環(huán)境來(lái)說(shuō),我用 P-III 等級(jí)的計(jì)算機(jī),所以上頭就發(fā)現(xiàn)我的等級(jí)是 i686 啦!

      要留意的是,較高階的硬件通常會(huì)向下兼容舊有的軟件,但較高階的軟件可能無(wú)法在舊機(jī)器上面安裝!我們?cè)诘谌戮驮f(shuō)明過,這里再?gòu)?qiáng)調(diào)一次,你可以在 x86_64 的硬件上安裝 i386 的 Linux 操作系統(tǒng),但是你無(wú)法在 i686 的硬件上安裝x86_64 的 Linux 操作系統(tǒng)!這點(diǎn)得要牢記在心!


    • export: 自定義變量轉(zhuǎn)成環(huán)境變量

    談了 env 與 set 現(xiàn)在知道有所謂的環(huán)境變量與自定義變量,那么這兩者之間有啥差異呢?其實(shí)這兩者的差異在于『該變量是否會(huì)被子程序所繼續(xù)引用』啦!唔!那么啥是父程序?子程序?這就得要了解一下命令的下達(dá)行為了。

    當(dāng)你登陸 Linux 并取得一個(gè) bash 之后,你的 bash 就是一個(gè)獨(dú)立的程序,被稱為 PID 的就是。接下來(lái)你在這個(gè) bash 底下所下達(dá)的任何命令都是由這個(gè) bash 所衍生出來(lái)的,那些被下達(dá)的命令就被稱為子程序了。我們可以用底下的圖示來(lái)簡(jiǎn)單的說(shuō)明一下父程序與子程序的概念:


    圖 2.3.1、程序相關(guān)性示意圖

    如上所示,我們?cè)谠镜?bash 底下運(yùn)行另一個(gè) bash ,結(jié)果操作的環(huán)境接口會(huì)跑到第二個(gè) bash 去(就是子程序),那原本的 bash 就會(huì)在暫停的情況 (睡著了,就是 sleep)。整個(gè)命令運(yùn)行的環(huán)境是實(shí)線的部分!若要回到原本的 bash 去,就只有將第二個(gè) bash 結(jié)束掉 (下達(dá) exit 或 logout) 才行。更多的程序概念我們會(huì)在第四篇談及,這里只要有這個(gè)概念即可。

    這個(gè)程序概念與變量有啥關(guān)系啊?關(guān)系可大了!因?yàn)?span id="ozvdkddzhkzd" class="text_import2">子程序僅會(huì)繼承父程序的環(huán)境變量,子程序不會(huì)繼承父程序的自定義變量啦!所以你在原本 bash 的自定義變量在進(jìn)入了子程序后就會(huì)消失不見,一直到你離開子程序并回到原本的父程序后,這個(gè)變量才會(huì)又出現(xiàn)!

    換個(gè)角度來(lái)想,也就是說(shuō),如果我能將自定義變量變成環(huán)境變量的話,那不就可以讓該變量值繼續(xù)存在于子程序了?呵呵!沒錯(cuò)!此時(shí),那個(gè) export 命令就很有用啦!如你想要讓該變量?jī)?nèi)容繼續(xù)的在子程序中使用,那么就請(qǐng)運(yùn)行:

    [root@www ~]# export 變量名稱

    這東西用在『分享自己的變量配置給后來(lái)呼叫的文件或其他程序』啦!像鳥哥常常在自己的主控文件后面呼叫其他附屬文件(類似函式的功能),但是主控文件與附屬文件內(nèi)都有相同的變量名稱,若一再重復(fù)配置時(shí),要修改也很麻煩,此時(shí)只要在原本的第一個(gè)文件內(nèi)配置好『 export 變量 』,后面所呼叫的文件就能夠使用這個(gè)變量配置了!而不需要重復(fù)配置,這非常實(shí)用于 shell script 當(dāng)中喔!如果僅下達(dá) export 而沒有接變量時(shí),那么此時(shí)將會(huì)把所有的『環(huán)境變量』秀出來(lái)喔!例如:

    [root@www ~]# export declare -x HISTSIZE="1000" declare -x HOME="/root" declare -x HOSTNAME="www.vbird.tsai" declare -x INPUTRC="/etc/inputrc" declare -x LANG="en_US" declare -x LOGNAME="root" # 后面的鳥哥就都直接省略了!不然....浪費(fèi)版面~ ^_^

    那如何將環(huán)境變量轉(zhuǎn)成自定義變量呢?可以使用本章后續(xù)介紹的 declare 呢!


    影響顯示結(jié)果的語(yǔ)系變量 (locale)

    還記得我們?cè)诘谖逭吕锩嫣岬降恼Z(yǔ)系問題嗎?就是當(dāng)我們使用 man command 的方式去查詢某個(gè)數(shù)據(jù)的說(shuō)明文件時(shí),該說(shuō)明檔的內(nèi)容可能會(huì)因?yàn)槲覀兪褂玫恼Z(yǔ)系不同而產(chǎn)生亂碼。另外,利用 ls 查詢文件的時(shí)間時(shí),也可能會(huì)有亂碼出現(xiàn)在時(shí)間的部分。那個(gè)問題其實(shí)就是語(yǔ)系的問題啦。

    目前大多數(shù)的 Linux distributions 已經(jīng)都是支持日漸流行的萬(wàn)國(guó)碼了,也都支持大部分的國(guó)家語(yǔ)系。這有賴于 i18n (注4) 支持的幫助呢!那么我們的 Linux 到底支持了多少的語(yǔ)系呢?這可以由 locale 這個(gè)命令來(lái)查詢到喔!

    [root@www ~]# locale -a ....(前面省略).... zh_TW zh_TW.big5 <==大五碼的中文編碼 zh_TW.euctw zh_TW.utf8 <==萬(wàn)國(guó)碼的中文編碼 zu_ZA zu_ZA.iso88591 zu_ZA.utf8

    正體中文語(yǔ)系至少支持了兩種以上的編碼,一種是目前還是很常見的 big5 ,另一種則是越來(lái)越熱門的 utf-8 編碼。那么我們?nèi)绾涡抻嗊@些編碼呢?其實(shí)可以透過底下這些變量的說(shuō):

    [root@www ~]# locale <==后面不加任何選項(xiàng)與參數(shù)即可! LANG=en_US <==主語(yǔ)言的環(huán)境 LC_CTYPE="en_US" <==字符(文字)辨識(shí)的編碼 LC_NUMERIC="en_US" <==數(shù)字系統(tǒng)的顯示信息 LC_TIME="en_US" <==時(shí)間系統(tǒng)的顯示數(shù)據(jù) LC_COLLATE="en_US" <==字符串的比較與排序等 LC_MONETARY="en_US" <==幣值格式的顯示等 LC_MESSAGES="en_US" <==信息顯示的內(nèi)容,如菜單、錯(cuò)誤信息等 LC_ALL= <==整體語(yǔ)系的環(huán)境 ....(后面省略)....

    基本上,你可以逐一配置每個(gè)與語(yǔ)系有關(guān)的變量數(shù)據(jù),但事實(shí)上,如果其他的語(yǔ)系變量都未配置,且你有配置 LANG 或者是 LC_ALL 時(shí),則其他的語(yǔ)系變量就會(huì)被這兩個(gè)變量所取代!這也是為什么我們?cè)?Linux 當(dāng)中,通常說(shuō)明僅配置 LANG 這個(gè)變量而已,因?yàn)樗亲钪饕呐渲米兞?#xff01;好了,那么你應(yīng)該要覺得奇怪的是,為什么在 Linux 主機(jī)的終端機(jī)接口 (tty1 ~ tty6) 的環(huán)境下,如果配置『 LANG=zh_TW.big5 』這個(gè)配置值生效后,使用 man 或者其他信息輸出時(shí),都會(huì)有一堆亂碼,尤其是使用 ls -l 這個(gè)參數(shù)時(shí)?

    因?yàn)樵?Linux 主機(jī)的終端機(jī)接口環(huán)境下是無(wú)法顯示像中文這么復(fù)雜的編碼文字,所以就會(huì)產(chǎn)生亂碼了。也就是如此,我們才會(huì)必須要在 tty1 ~ tty6 的環(huán)境下,加裝一些中文化接口的軟件,才能夠看到中文啊!不過,如果你是在 MS Windows 主機(jī)以遠(yuǎn)程聯(lián)機(jī)服務(wù)器的軟件聯(lián)機(jī)到主機(jī)的話,那么,嘿嘿!其實(shí)文字接口確實(shí)是可以看到中文的。此時(shí)反而你得要在 LANG 配置中文編碼才好呢!

    Tips:
    無(wú)論如何,如果發(fā)生一些亂碼的問題,那么配置系統(tǒng)里面保有的語(yǔ)系編碼,例如: en_US 或 en_US.utf8 等等的配置,應(yīng)該就 OK 的啦!好了,那么系統(tǒng)默認(rèn)支持多少種語(yǔ)系呢?當(dāng)我們使用 locale 時(shí),系統(tǒng)是列出目前 Linux 主機(jī)內(nèi)保有的語(yǔ)系文件,這些語(yǔ)系文件都放置在:/usr/lib/locale/ 這個(gè)目錄中。

    你當(dāng)然可以讓每個(gè)使用者自己去調(diào)整自己喜好的語(yǔ)系,但是整體系統(tǒng)默認(rèn)的語(yǔ)系定義在哪里呢?其實(shí)就是在 /etc/sysconfig/i18n 啰!這個(gè)文件在 CentOS 5.x 的內(nèi)容有點(diǎn)像這樣:

    [root@www ~]# cat /etc/sysconfig/i18n LANG="zh_TW.UTF-8"

    因?yàn)轼B哥在第四章的安裝時(shí)選擇的是中文語(yǔ)系安裝畫面,所以這個(gè)文件默認(rèn)就會(huì)使用中文編碼啦!你也可以自行將他改成你想要的語(yǔ)系編碼即可。

    Tips:
    假設(shè)你有一個(gè)純文本文件原本是在 Windows 底下創(chuàng)建的,那么這個(gè)文件默認(rèn)應(yīng)該是 big5 的編碼格式。在你將這個(gè)文件上傳到 Linux 主機(jī)后,在 X window 底下打開時(shí),咦!怎么中文字通通變成亂碼了?別擔(dān)心!因?yàn)槿缟纤?#xff0c; i18n 默認(rèn)是萬(wàn)國(guó)碼系統(tǒng)嘛!你只要將開啟該文件的軟件編碼由 utf8 改成 big5 就能夠看到正確的中文了!

    變量的有效范圍

    什么?變量也有使用的『范圍』?沒錯(cuò)啊~我們?cè)谏项^的 export 命令說(shuō)明中,就提到了這個(gè)概念了。如果在跑程序的時(shí)候,有父程序與子程序的不同程序關(guān)系時(shí),則『變量』可否被引用與 export 有關(guān)。被 export 后的變量,我們可以稱他為『環(huán)境變量』!環(huán)境變量可以被子程序所引用,但是其他的自定義變量?jī)?nèi)容就不會(huì)存在于子程序中。

    Tips:
    在某些不同的書籍會(huì)談到『全局變量, global variable』與『局部變量, local variable』。基本上你可以這樣看待:
    環(huán)境變量=全局變量
    自定義變量=局部變量

    在學(xué)理方面,為什么環(huán)境變量的數(shù)據(jù)可以被子程序所引用呢?這是因?yàn)閮?nèi)存配置的關(guān)系!理論上是這樣的:

    • 當(dāng)啟動(dòng)一個(gè) shell,操作系統(tǒng)會(huì)分配一記憶區(qū)塊給 shell 使用,此內(nèi)存內(nèi)之變量可讓子程序取用
    • 若在父程序利用 export 功能,可以讓自定義變量的內(nèi)容寫到上述的記憶區(qū)塊當(dāng)中(環(huán)境變量);
    • 當(dāng)加載另一個(gè) shell 時(shí) (亦即啟動(dòng)子程序,而離開原本的父程序了),子 shell 可以將父 shell 的環(huán)境變量所在的記憶區(qū)塊導(dǎo)入自己的環(huán)境變量區(qū)塊當(dāng)中。

    透過這樣的關(guān)系,我們就可以讓某些變量在相關(guān)的程序之間存在,以幫助自己更方便的操作環(huán)境喔!不過要提醒的是,這個(gè)『環(huán)境變量』與『bash 的操作環(huán)境』意思不太一樣,舉例來(lái)說(shuō), PS1 并不是環(huán)境變量,但是這個(gè) PS1 會(huì)影響到 bash 的接口 (提示字符嘛)!相關(guān)性要厘清喔!^_^


    變量鍵盤讀取、數(shù)組與宣告: read, array, declare

    我們上面提到的變量配置功能,都是由命令列直接配置的,那么,可不可以讓用戶能夠經(jīng)由鍵盤輸入?什么意思呢?是否記得某些程序運(yùn)行的過程當(dāng)中,會(huì)等待使用者輸入 "yes/no" 之類的信息啊?在 bash 里面也有相對(duì)應(yīng)的功能喔!此外,我們還可以宣告這個(gè)變量的屬性,例如:數(shù)組或者是數(shù)字等等的。底下就來(lái)看看吧!


    • read

    要讀取來(lái)自鍵盤輸入的變量,就是用 read 這個(gè)命令了。這個(gè)命令最常被用在 shell script 的撰寫當(dāng)中,想要跟使用者對(duì)談?用這個(gè)命令就對(duì)了。關(guān)于 script 的寫法,我們會(huì)在第十三章介紹,底下先來(lái)瞧一瞧 read 的相關(guān)語(yǔ)法吧!

    [root@www ~]# read [-pt] variable 選項(xiàng)與參數(shù): -p :后面可以接提示字符! -t :后面可以接等待的『秒數(shù)!』這個(gè)比較有趣~不會(huì)一直等待使用者啦!范例一:讓用戶由鍵盤輸入一內(nèi)容,將該內(nèi)容變成名為 atest 的變量 [root@www ~]# read atest This is a test <==此時(shí)光標(biāo)會(huì)等待你輸入!請(qǐng)輸入左側(cè)文字看看 [root@www ~]# echo $atest This is a test <==你剛剛輸入的數(shù)據(jù)已經(jīng)變成一個(gè)變量?jī)?nèi)容!范例二:提示使用者 30 秒內(nèi)輸入自己的大名,將該輸入字符串作為名為 named 的變量?jī)?nèi)容 [root@www ~]# read -p "Please keyin your name: " -t 30 named Please keyin your name: VBird Tsai <==注意看,會(huì)有提示字符喔! [root@www ~]# echo $named VBird Tsai <==輸入的數(shù)據(jù)又變成一個(gè)變量的內(nèi)容了!

    read 之后不加任何參數(shù),直接加上變量名稱,那么底下就會(huì)主動(dòng)出現(xiàn)一個(gè)空白行等待你的輸入(如范例一)。如果加上 -t 后面接秒數(shù),例如上面的范例二,那么 30 秒之內(nèi)沒有任何動(dòng)作時(shí),該命令就會(huì)自動(dòng)略過了~如果是加上 -p ,嘿嘿!在輸入的光標(biāo)前就會(huì)有比較多可以用的提示字符給我們參考!在命令的下達(dá)里面,比較美觀啦! ^_^


    • declare / typeset

    declare 或 typeset 是一樣的功能,就是在『宣告變量的類型』。如果使用 declare 后面并沒有接任何參數(shù),那么 bash 就會(huì)主動(dòng)的將所有的變量名稱與內(nèi)容通通叫出來(lái),就好像使用 set 一樣啦!那么 declare 還有什么語(yǔ)法呢?看看先:

    [root@www ~]# declare [-aixr] variable 選項(xiàng)與參數(shù): -a :將后面名為 variable 的變量定義成為數(shù)組 (array) 類型 -i :將后面名為 variable 的變量定義成為整數(shù)數(shù)字 (integer) 類型 -x :用法與 export 一樣,就是將后面的 variable 變成環(huán)境變量; -r :將變量配置成為 readonly 類型,該變量不可被更改內(nèi)容,也不能 unset范例一:讓變量 sum 進(jìn)行 100+300+50 的加總結(jié)果 [root@www ~]# sum=100+300+50 [root@www ~]# echo $sum 100+300+50 <==咦!怎么沒有幫我計(jì)算加總?因?yàn)檫@是文字型態(tài)的變量屬性啊! [root@www ~]# declare -i sum=100+300+50 [root@www ~]# echo $sum 450 <==瞭乎??

    由于在默認(rèn)的情況底下, bash 對(duì)于變量有幾個(gè)基本的定義:

    • 變量類型默認(rèn)為『字符串』,所以若不指定變量類型,則 1+2 為一個(gè)『字符串』而不是『計(jì)算式』。所以上述第一個(gè)運(yùn)行的結(jié)果才會(huì)出現(xiàn)那個(gè)情況的;
    • bash 環(huán)境中的數(shù)值運(yùn)算,默認(rèn)最多僅能到達(dá)整數(shù)形態(tài),所以 1/3 結(jié)果是 0;

    現(xiàn)在你曉得為啥你需要進(jìn)行變量宣告了吧?如果需要非字符串類型的變量,那就得要進(jìn)行變量的宣告才行啦!底下繼續(xù)來(lái)玩些其他的 declare 功能。

    范例二:將 sum 變成環(huán)境變量 [root@www ~]# declare -x sum [root@www ~]# export | grep sum declare -ix sum="450" <==果然出現(xiàn)了!包括有 i 與 x 的宣告!范例三:讓 sum 變成只讀屬性,不可更動(dòng)! [root@www ~]# declare -r sum [root@www ~]# sum=tesgting -bash: sum: readonly variable <==老天爺~不能改這個(gè)變量了!范例四:讓 sum 變成非環(huán)境變量的自定義變量吧! [root@www ~]# declare +x sum <== 將 - 變成 + 可以進(jìn)行『取消』動(dòng)作 [root@www ~]# declare -p sum <== -p 可以單獨(dú)列出變量的類型 declare -ir sum="450" <== 看吧!只剩下 i, r 的類型,不具有 x 啰!

    declare 也是個(gè)很有用的功能~尤其是當(dāng)我們需要使用到底下的數(shù)組功能時(shí),他也可以幫我們宣告數(shù)組的屬性喔!不過,老話一句,數(shù)組也是在 shell script 比較常用的啦!比較有趣的是,如果你不小心將變量配置為『只讀』,通常得要注銷再登陸才能復(fù)原該變量的類型了! @_@


    • 數(shù)組 (array) 變量類型

    某些時(shí)候,我們必須使用數(shù)組來(lái)宣告一些變量,這有什么好處啊?在一般人的使用上,果然是看不出來(lái)有什么好處的!不過,如果您曾經(jīng)寫過程序的話,那才會(huì)比較了解數(shù)組的意義~數(shù)組對(duì)寫數(shù)值程序的設(shè)計(jì)師來(lái)說(shuō),可是不能錯(cuò)過學(xué)習(xí)的重點(diǎn)之一哩!好!不啰唆~那么要如何配置數(shù)組的變量與內(nèi)容呢?在 bash 里頭,數(shù)組的配置方式是:

    var[index]=content

    意思是說(shuō),我有一個(gè)數(shù)組名為 var ,而這個(gè)數(shù)組的內(nèi)容為 var[1]=小明, var[2]=大明, var[3]=好明 .... 等等,那個(gè) index 就是一些數(shù)字啦,重點(diǎn)是用中刮號(hào) ([ ]) 來(lái)配置的。目前我們 bash 提供的是一維數(shù)組。老實(shí)說(shuō),如果您不必寫一些復(fù)雜的程序,那么這個(gè)數(shù)組的地方,可以先略過,等到有需要再來(lái)學(xué)習(xí)即可!因?yàn)橐谱鞒鰯?shù)組,通常與循環(huán)或者其他判斷式交互使用才有比較高的存在意義!

    范例:配置上面提到的 var[1] ~ var[3] 的變量。 [root@www ~]# var[1]="small min" [root@www ~]# var[2]="big min" [root@www ~]# var[3]="nice min" [root@www ~]# echo "${var[1]}, ${var[2]}, ${var[3]}" small min, big min, nice min

    數(shù)組的變量類型比較有趣的地方在于『讀取』,一般來(lái)說(shuō),建議直接以 ${數(shù)組}的方式來(lái)讀取,比較正確無(wú)誤的啦!


    與文件系統(tǒng)及程序的限制關(guān)系:ulimit

    想象一個(gè)狀況:我的 Linux 主機(jī)里面同時(shí)登陸了十個(gè)人,這十個(gè)人不知怎么搞的,同時(shí)開啟了 100 個(gè)文件,每個(gè)文件的大小約 10MBytes ,請(qǐng)問一下,我的 Linux 主機(jī)的內(nèi)存要有多大才夠? 10*100*10 = 10000 MBytes = 10GBytes ...老天爺,這樣,系統(tǒng)不掛點(diǎn)才有鬼哩!為了要預(yù)防這個(gè)情況的發(fā)生,所以我們的 bash 是可以『限制用戶的某些系統(tǒng)資源』的,包括可以開啟的文件數(shù)量,可以使用的 CPU 時(shí)間,可以使用的內(nèi)存總量等等。如何配置?用 ulimit 吧!

    [root@www ~]# ulimit [-SHacdfltu] [配額] 選項(xiàng)與參數(shù): -H :hard limit ,嚴(yán)格的配置,必定不能超過這個(gè)配置的數(shù)值; -S :soft limit ,警告的配置,可以超過這個(gè)配置值,但是若超過則有警告信息。在配置上,通常 soft 會(huì)比 hard 小,舉例來(lái)說(shuō),soft 可配置為 80 而 hard 配置為 100,那么你可以使用到 90 (因?yàn)闆]有超過 100),但介于 80~100 之間時(shí),系統(tǒng)會(huì)有警告信息通知你! -a :后面不接任何選項(xiàng)與參數(shù),可列出所有的限制額度; -c :當(dāng)某些程序發(fā)生錯(cuò)誤時(shí),系統(tǒng)可能會(huì)將該程序在內(nèi)存中的信息寫成文件(除錯(cuò)用),這種文件就被稱為核心文件(core file)。此為限制每個(gè)核心文件的最大容量。 -f :此 shell 可以創(chuàng)建的最大文件容量(一般可能配置為 2GB)單位為 Kbytes -d :程序可使用的最大斷裂內(nèi)存(segment)容量; -l :可用于鎖定 (lock) 的內(nèi)存量 -t :可使用的最大 CPU 時(shí)間 (單位為秒) -u :單一用戶可以使用的最大程序(process)數(shù)量。范例一:列出你目前身份(假設(shè)為root)的所有限制數(shù)據(jù)數(shù)值 [root@www ~]# ulimit -a core file size (blocks, -c) 0 <==只要是 0 就代表沒限制 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited <==可創(chuàng)建的單一文件的大小 pending signals (-i) 11774 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 <==同時(shí)可開啟的文件數(shù)量 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 11774 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited范例二:限制用戶僅能創(chuàng)建 10MBytes 以下的容量的文件 [root@www ~]# ulimit -f 10240 [root@www ~]# ulimit -a file size (blocks, -f) 10240 <==最大量為10240Kbyes,相當(dāng)10Mbytes [root@www ~]# dd if=/dev/zero of=123 bs=1M count=20 File size limit exceeded <==嘗試創(chuàng)建 20MB 的文件,結(jié)果失敗了!

    還記得我們?cè)诘诎苏?Linux 磁盤文件系統(tǒng)里面提到過,單一 filesystem能夠支持的單一文件大小與 block 的大小有關(guān)。例如 block size 為 1024 byte 時(shí),單一文件可達(dá)16GB 的容量。但是,我們可以用 ulimit 來(lái)限制使用者可以創(chuàng)建的文件大小喔!利用 ulimit -f 就可以來(lái)配置了!例如上面的范例二,要注意單位喔!單位是 Kbytes。若改天你一直無(wú)法創(chuàng)建一個(gè)大容量的文件,記得瞧一瞧 ulimit 的信息喔!

    Tips:
    想要復(fù)原 ulimit 的配置最簡(jiǎn)單的方法就是注銷再登陸,否則就是得要重新以 ulimit 配置才行!不過,要注意的是,一般身份使用者如果以 ulimit 配置了 -f 的文件大小,那么他『只能繼續(xù)減小文件容量,不能添加文件容量喔!』另外,若想要管控使用者的 ulimit 限值,可以參考第十四章的 pam 的介紹。

    變量?jī)?nèi)容的刪除、取代與替換

    變量除了可以直接配置來(lái)修改原本的內(nèi)容之外,有沒有辦法透過簡(jiǎn)單的動(dòng)作來(lái)將變量的內(nèi)容進(jìn)行微調(diào)呢?舉例來(lái)說(shuō),進(jìn)行變量?jī)?nèi)容的刪除、取代與替換等!是可以的!我們可以透過幾個(gè)簡(jiǎn)單的小步驟來(lái)進(jìn)行變量?jī)?nèi)容的微調(diào)喔!底下就來(lái)試試看!


    • 變量?jī)?nèi)容的刪除與取代

    變量的內(nèi)容可以很簡(jiǎn)單的透過幾個(gè)咚咚來(lái)進(jìn)行刪除喔!我們使用 PATH 這個(gè)變量的內(nèi)容來(lái)做測(cè)試好了。請(qǐng)你依序進(jìn)行底下的幾個(gè)例子來(lái)玩玩,比較容易感受的到鳥哥在這里想要表達(dá)的意義:

    范例一:先讓小寫的 path 自定義變量配置的與 PATH 內(nèi)容相同 [root@www ~]# path=${PATH} [root@www ~]# echo $path /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦!范例二:假設(shè)我不喜歡 kerberos,所以要將前兩個(gè)目錄刪除掉,如何顯示? [root@www ~]# echo ${path#/*kerberos/bin:} /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

    上面這個(gè)范例很有趣的!他的重點(diǎn)可以用底下這張表格來(lái)說(shuō)明:

    ${variable#/*kerberos/bin:} 上面的特殊字體部分是關(guān)鍵詞!用在這種刪除模式所必須存在的${variable#/*kerberos/bin:} 這就是原本的變量名稱,以上面范例二來(lái)說(shuō),這里就填寫 path 這個(gè)『變量名稱』啦!${variable#/*kerberos/bin:} 這是重點(diǎn)!代表『從變量?jī)?nèi)容的最前面開始向右刪除』,且僅刪除最短的那個(gè)${variable#/*kerberos/bin:} 代表要被刪除的部分,由于 # 代表由前面開始刪除,所以這里便由開始的 / 寫起。需要注意的是,我們還可以透過通配符 * 來(lái)取代 0 到無(wú)窮多個(gè)任意字符 以上面范例二的結(jié)果來(lái)看, path 這個(gè)變量被刪除的內(nèi)容如下所示: /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦!

    很有趣吧!這樣了解了 # 的功能了嗎?接下來(lái)讓我們來(lái)看看底下的范例三!

    范例三:我想要?jiǎng)h除前面所有的目錄,僅保留最后一個(gè)目錄 [root@www ~]# echo ${path#/*:} /usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin: /root/bin <==這兩行其實(shí)是同一行啦! # 由于一個(gè) # 僅刪除掉最短的那個(gè),因此他刪除的情況可以用底下的刪除線來(lái)看: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦![root@www ~]# echo ${path##/*:} /root/bin # 嘿!多加了一個(gè) # 變成 ## 之后,他變成『刪除掉最長(zhǎng)的那個(gè)數(shù)據(jù)』!亦即是: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦!

    非常有趣!不是嗎?因?yàn)樵?PATH 這個(gè)變量的內(nèi)容中,每個(gè)目錄都是以冒號(hào)『:』隔開的,所以要從頭刪除掉目錄就是介于斜線 (/) 到冒號(hào) (:) 之間的數(shù)據(jù)!但是 PATH 中不止一個(gè)冒號(hào) (:) 啊!所以 # 與 ## 就分別代表:

    • # :符合取代文字的『最短的』那一個(gè);
    • ##:符合取代文字的『最長(zhǎng)的』那一個(gè)

    上面談到的是『從前面開始刪除變量?jī)?nèi)容』,那么如果想要『從后面向前刪除變量?jī)?nèi)容』呢?這個(gè)時(shí)候就得使用百分比 (%) 符號(hào)了!來(lái)看看范例四怎么做吧!

    范例四:我想要?jiǎng)h除最后面那個(gè)目錄,亦即從 : 到 bin 為止的字符串 [root@www ~]# echo ${path%:*bin} /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin <==注意啊!最后面一個(gè)目錄不見去! # 這個(gè) % 符號(hào)代表由最后面開始向前刪除!所以上面得到的結(jié)果其實(shí)是來(lái)自如下: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦!范例五:那如果我只想要保留第一個(gè)目錄呢? [root@www ~]# echo ${path%%:*bin} /usr/kerberos/sbin # 同樣的, %% 代表的則是最長(zhǎng)的符合字符串,所以結(jié)果其實(shí)是來(lái)自如下: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==這兩行其實(shí)是同一行啦!

    由于我是想要由變量?jī)?nèi)容的后面向前面刪除,而我這個(gè)變量?jī)?nèi)容最后面的結(jié)尾是『/root/bin』,所以你可以看到上面我刪除的數(shù)據(jù)最終一定是『bin』,亦即是『:*bin』那個(gè) * 代表通配符!至于 % 與 %% 的意義其實(shí)與 # 及 ## 類似!這樣理解否?

    例題: 假設(shè)你是 root ,那你的 MAIL 變量應(yīng)該是 /var/spool/mail/root 。假設(shè)你只想要保留最后面那個(gè)檔名 (root),前面的目錄名稱都不要了,如何利用 $MAIL 變量來(lái)達(dá)成? 答: 題意其實(shí)是這樣『/var/spool/mail/root』,亦即刪除掉兩條斜線間的所有數(shù)據(jù)(最長(zhǎng)符合)。這個(gè)時(shí)候你就可以這樣做即可:
    [root@www ~]# echo ${MAIL##/*/}
    相反的,如果你只想要拿掉文件名,保留目錄的名稱,亦即是『/var/spool/mail/root』(最短符合)。但假設(shè)你并不知道結(jié)尾的字母為何,此時(shí)你可以利用通配符來(lái)處理即可,如下所示:
    [root@www ~]# echo ${MAIL%/*}

    了解了刪除功能后,接下來(lái)談?wù)勅〈?#xff01;繼續(xù)玩玩范例六啰!

    范例六:將 path 的變量?jī)?nèi)容內(nèi)的 sbin 取代成大寫 SBIN: [root@www ~]# echo ${path/sbin/SBIN} /usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin # 這個(gè)部分就容易理解的多了!關(guān)鍵詞在于那兩個(gè)斜線,兩斜線中間的是舊字符串 # 后面的是新字符串,所以結(jié)果就會(huì)出現(xiàn)如上述的特殊字體部分啰![root@www ~]# echo ${path//sbin/SBIN} /usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/SBIN:/usr/local/bin:/SBIN:/bin: /usr/SBIN:/usr/bin:/root/bin # 如果是兩條斜線,那么就變成所有符合的內(nèi)容都會(huì)被取代喔!

    我們將這部份作個(gè)總結(jié)說(shuō)明一下:

    變量配置方式說(shuō)明
    ${變量#關(guān)鍵詞}
    ${變量##關(guān)鍵詞}
    若變量?jī)?nèi)容從頭開始的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最短數(shù)據(jù)刪除
    若變量?jī)?nèi)容從頭開始的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最長(zhǎng)數(shù)據(jù)刪除
    ${變量%關(guān)鍵詞}
    ${變量%%關(guān)鍵詞}
    若變量?jī)?nèi)容從尾向前的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最短數(shù)據(jù)刪除
    若變量?jī)?nèi)容從尾向前的數(shù)據(jù)符合『關(guān)鍵詞』,則將符合的最長(zhǎng)數(shù)據(jù)刪除
    ${變量/舊字符串/新字符串}
    ${變量//舊字符串/新字符串}
    若變量?jī)?nèi)容符合『舊字符串』則『第一個(gè)舊字符串會(huì)被新字符串取代』
    若變量?jī)?nèi)容符合『舊字符串』則『全部的舊字符串會(huì)被新字符串取代』


    • 變量的測(cè)試與內(nèi)容替換

    在某些時(shí)刻我們常常需要『判斷』某個(gè)變量是否存在,若變量存在則使用既有的配置,若變量不存在則給予一個(gè)常用的配置。我們舉底下的例子來(lái)說(shuō)明好了,看看能不能較容易被你所理解呢!

    范例一:測(cè)試一下是否存在 username 這個(gè)變量,若不存在則給予 username 內(nèi)容為 root [root@www ~]# echo $username<==由于出現(xiàn)空白,所以 username 可能不存在,也可能是空字符串 [root@www ~]# username=${username-root} [root@www ~]# echo $username root <==因?yàn)?username 沒有配置,所以主動(dòng)給予名為 root 的內(nèi)容。 [root@www ~]# username="vbird tsai" <==主動(dòng)配置 username 的內(nèi)容 [root@www ~]# username=${username-root} [root@www ~]# echo $username vbird tsai <==因?yàn)?username 已經(jīng)配置了,所以使用舊有的配置而不以 root 取代

    在上面的范例中,重點(diǎn)在于減號(hào)『 - 』后面接的關(guān)鍵詞!基本上你可以這樣理解:

    new_var=${old_var-content}新的變量,主要用來(lái)取代舊變量。新舊變量名稱其實(shí)常常是一樣的new_var=${old_var-content}這是本范例中的關(guān)鍵詞部分!必須要存在的哩!new_var=${old_var-content}舊的變量,被測(cè)試的項(xiàng)目!new_var=${old_var-content}變量的『內(nèi)容』,在本范例中,這個(gè)部分是在『給予未配置變量的內(nèi)容』

    不過這還是有點(diǎn)問題!因?yàn)?username 可能已經(jīng)被配置為『空字符串』了!果真如此的話,那你還可以使用底下的范例來(lái)給予username 的內(nèi)容成為 root 喔!

    范例二:若 username 未配置或?yàn)榭兆址?#xff0c;則將 username 內(nèi)容配置為 root [root@www ~]# username="" [root@www ~]# username=${username-root} [root@www ~]# echo $username<==因?yàn)?username 被配置為空字符串了!所以當(dāng)然還是保留為空字符串! [root@www ~]# username=${username:-root} [root@www ~]# echo $username root <==加上『 : 』后若變量?jī)?nèi)容為空或者是未配置,都能夠以后面的內(nèi)容替換!

    在大括號(hào)內(nèi)有沒有冒號(hào)『 : 』的差別是很大的!加上冒號(hào)后,被測(cè)試的變量未被配置或者是已被配置為空字符串時(shí),都能夠用后面的內(nèi)容 (本例中是使用 root 為內(nèi)容) 來(lái)替換與配置!這樣可以了解了嗎?除了這樣的測(cè)試之外,還有其他的測(cè)試方法喔!鳥哥將他整理如下:

    Tips:
    底下的例子當(dāng)中,那個(gè) var 與 str 為變量,我們想要針對(duì) str 是否有配置來(lái)決定 var 的值喔!一般來(lái)說(shuō), str: 代表『str 沒配置或?yàn)榭盏淖址畷r(shí)』;至于 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

    根據(jù)上面這張表,我們來(lái)進(jìn)行幾個(gè)范例的練習(xí)吧! ^_^!首先讓我們來(lái)測(cè)試一下,如果舊變量 (str) 不存在時(shí),我們要給予新變量一個(gè)內(nèi)容,若舊變量存在則新變量?jī)?nèi)容以舊變量來(lái)替換,結(jié)果如下:

    測(cè)試:先假設(shè) str 不存在 (用 unset) ,然后測(cè)試一下減號(hào) (-) 的用法: [root@www ~]# unset str; var=${str-newvar} [root@www ~]# echo var="$var", str="$str" var=newvar, str= <==因?yàn)?str 不存在,所以 var 為 newvar測(cè)試:若 str 已存在,測(cè)試一下 var 會(huì)變?cè)鯓?#xff1f;: [root@www ~]# str="oldvar"; var=${str-newvar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因?yàn)?str 存在,所以 var 等于 str 的內(nèi)容

    關(guān)于減號(hào) (-) 其實(shí)上面我們談過了!這里的測(cè)試只是要讓你更加了解,這個(gè)減號(hào)的測(cè)試并不會(huì)影響到舊變量的內(nèi)容。如果你想要將舊變量?jī)?nèi)容也一起替換掉的話,那么就使用等號(hào) (=) 吧!

    測(cè)試:先假設(shè) str 不存在 (用 unset) ,然后測(cè)試一下等號(hào) (=) 的用法: [root@www ~]# unset str; var=${str=newvar} [root@www ~]# echo var="$var", str="$str" var=newvar, str=newvar <==因?yàn)?str 不存在,所以 var/str 均為 newvar測(cè)試:如果 str 已存在了,測(cè)試一下 var 會(huì)變?cè)鯓?#xff1f; [root@www ~]# str="oldvar"; var=${str=newvar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因?yàn)?str 存在,所以 var 等于 str 的內(nèi)容

    那如果我只是想知道,如果舊變量不存在時(shí),整個(gè)測(cè)試就告知我『有錯(cuò)誤』,此時(shí)就能夠使用問號(hào)『 ? 』的幫忙啦!底下這個(gè)測(cè)試練習(xí)一下先!

    測(cè)試:若 str 不存在時(shí),則 var 的測(cè)試結(jié)果直接顯示 "無(wú)此變量" [root@www ~]# unset str; var=${str?無(wú)此變量} -bash: str: 無(wú)此變量 <==因?yàn)?str 不存在,所以輸出錯(cuò)誤信息 測(cè)試:若 str 存在時(shí),則 var 的內(nèi)容會(huì)與 str 相同! [root@www ~]# str="oldvar"; var=${str?novar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因?yàn)?str 存在,所以 var 等于 str 的內(nèi)容

    基本上這種變量的測(cè)試也能夠透過 shell script 內(nèi)的 if...then... 來(lái)處理,不過既然 bash 有提供這么簡(jiǎn)單的方法來(lái)測(cè)試變量,那我們也可以多學(xué)一些嘛!不過這種變量測(cè)試通常是在程序設(shè)計(jì)當(dāng)中比較容易出現(xiàn),如果這里看不懂就先略過,未來(lái)有用到判斷變量值時(shí),再回來(lái)看看吧! ^_^


    命令別名與歷史命令:

    我們知道在早期的 DOS 年代,清除屏幕上的信息可以使用 cls 來(lái)清除,但是在 Linux 里面,我們則是使用 clear 來(lái)清除畫面的。那么可否讓 cls 等于 clear 呢?可以啊!用啥方法?link file 還是什么的?別急!底下我們介紹不用 link file 的命令別名來(lái)達(dá)成。那么什么又是歷史命令?曾經(jīng)做過的舉動(dòng)我們可以將他記錄下來(lái)喔!那就是歷史命令啰~底下分別來(lái)談一談這兩個(gè)玩意兒。


    命令別名配置: alias, unalias

    命令別名是一個(gè)很有趣的東西,特別是你的慣用命令特別長(zhǎng)的時(shí)候!還有,增設(shè)默認(rèn)的選項(xiàng)在一些慣用的命令上面,可以預(yù)防一些不小心誤殺文件的情況發(fā)生的時(shí)候!舉個(gè)例子來(lái)說(shuō),如果你要查詢隱藏檔,并且需要長(zhǎng)的列出與一頁(yè)一頁(yè)翻看,那么需要下達(dá)『ls -al | more』這個(gè)命令,我是覺得很煩啦!要輸入好幾個(gè)單字!那可不可以使用 lm 來(lái)簡(jiǎn)化呢?當(dāng)然可以,你可以在命令行下面下達(dá):

    [root@www ~]# alias lm='ls -al | more'

    立刻多出了一個(gè)可以運(yùn)行的命令喔!這個(gè)命令名稱為 lm ,且其實(shí)他是運(yùn)行 ls -al | more 啊!真是方便。不過,要注意的是:『alias 的定義守則與變量定義守則幾乎相同』,所以你只要在 alias 后面加上你的 {『別名』='命令 選項(xiàng)...' },以后你只要輸入 lm 就相當(dāng)于輸入了 ls -al|more 這一串命令!很方便吧!

    另外,命令別名的配置還可以取代既有的命令喔!舉例來(lái)說(shuō),我們知道 root可以移除 (rm) 任何數(shù)據(jù)!所以當(dāng)你以 root 的身份在進(jìn)行工作時(shí),需要特別小心,但是總有失手的時(shí)候,那么 rm 提供了一個(gè)選項(xiàng)來(lái)讓我們確認(rèn)是否要移除該文件,那就是 -i 這個(gè)選項(xiàng)!所以,你可以這樣做:

    [root@www ~]# alias rm='rm -i'

    那么以后使用 rm 的時(shí)候,就不用太擔(dān)心會(huì)有錯(cuò)誤刪除的情況了!這也是命令別名的優(yōu)點(diǎn)啰!那么如何知道目前有哪些的命令別名呢?就使用 alias 呀!

    [root@www ~]# alias alias cp='cp -i' alias l.='ls -d .* --color=tty' alias ll='ls -l --color=tty' alias lm='ls -l | more' alias ls='ls --color=tty' alias mv='mv -i' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --show-dot --show-tilde'

    由上面的數(shù)據(jù)當(dāng)中,你也會(huì)發(fā)現(xiàn)一件事情啊,我們?cè)诘谑碌?vim 程序編輯器里面提到 vi 與 vim 是不太一樣的,vim 可以多作一些額外的語(yǔ)法檢驗(yàn)與顏色顯示,默認(rèn)的 root 是單純使用 vi 而已。如果你想要使用 vi 就直接以 vim 來(lái)開啟文件的話,使用『 alias vi='vim' 』這個(gè)配置即可。至于如果要取消命令別名的話,那么就使用 unalias 吧!例如要將剛剛的 lm 命令別名拿掉,就使用:

    [root@www ~]# unalias lm

    那么命令別名與變量有什么不同呢?命令別名是『新創(chuàng)一個(gè)新的命令,你可以直接下達(dá)該命令』的,至于變量則需要使用類似『 echo 』命令才能夠呼叫出變量的內(nèi)容!這兩者當(dāng)然不一樣!很多初學(xué)者在這里老是搞不清楚!要注意啊! ^_^

    例題: DOS 年代,列出目錄與文件就是 dir ,而清除屏幕就是 cls ,那么如果我想要在linux 里面也使用相同的命令呢? 答: 很簡(jiǎn)單,透過 clear 與 ls 來(lái)進(jìn)行命令別名的建置: alias cls='clear'
    alias dir='ls -l'


    歷史命令:history

    前面我們提過 bash 有提供命令歷史的服務(wù)!那么如何查詢我們?cè)?jīng)下達(dá)過的命令呢?就使用history 啰!當(dāng)然,如果覺得 histsory 要輸入的字符太多太麻煩,可以使用命令別名來(lái)配置呢!不要跟我說(shuō)還不會(huì)配置呦! ^_^

    [root@www ~]# alias h='history'

    如此則輸入 h 等于輸入 history 啰!好了,我們來(lái)談一談 history 的用法吧!

    [root@www ~]# history [n] [root@www ~]# history [-c] [root@www ~]# history [-raw] histfiles 選項(xiàng)與參數(shù): n :數(shù)字,意思是『要列出最近的 n 筆命令行表』的意思! -c :將目前的 shell 中的所有 history 內(nèi)容全部消除 -a :將目前新增的 history 命令新增入 histfiles 中,若沒有加 histfiles ,則默認(rèn)寫入 ~/.bash_history -r :將 histfiles 的內(nèi)容讀到目前這個(gè) shell 的 history 記憶中; -w :將目前的 history 記憶內(nèi)容寫入 histfiles 中!范例一:列出目前內(nèi)存內(nèi)的所有 history 記憶 [root@www ~]# history # 前面省略1017 man bash1018 ll1019 history 1020 history # 列出的信息當(dāng)中,共分兩欄,第一欄為該命令在這個(gè) shell 當(dāng)中的代碼, # 另一個(gè)則是命令本身的內(nèi)容喔!至于會(huì)秀出幾筆命令記錄,則與 HISTSIZE 有關(guān)!范例二:列出目前最近的 3 筆數(shù)據(jù) [root@www ~]# history 31019 history 1020 history1021 history 3范例三:立刻將目前的數(shù)據(jù)寫入 histfile 當(dāng)中 [root@www ~]# history -w # 在默認(rèn)的情況下,會(huì)將歷史紀(jì)錄寫入 ~/.bash_history 當(dāng)中! [root@www ~]# echo $HISTSIZE 1000

    在正常的情況下,歷史命令的讀取與記錄是這樣的:

    • 當(dāng)我們以 bash 登陸 Linux 主機(jī)之后,系統(tǒng)會(huì)主動(dòng)的由家目錄的 ~/.bash_history讀取以前曾經(jīng)下過的命令,那么 ~/.bash_history 會(huì)記錄幾筆數(shù)據(jù)呢?這就與你 bash 的HISTFILESIZE 這個(gè)變量配置值有關(guān)了!

    • 假設(shè)我這次登陸主機(jī)后,共下達(dá)過 100 次命令,『等我注銷時(shí),系統(tǒng)就會(huì)將 101~1100 這總共 1000 筆歷史命令升級(jí)到 ~/.bash_history 當(dāng)中。』也就是說(shuō),歷史命令在我注銷時(shí),會(huì)將最近的 HISTFILESIZE 筆記錄到我的紀(jì)錄文件當(dāng)中啦!

    • 當(dāng)然,也可以用 history -w 強(qiáng)制立刻寫入的!那為何用『升級(jí)』兩個(gè)字呢?因?yàn)?~/.bash_history 記錄的筆數(shù)永遠(yuǎn)都是 HISTFILESIZE 那么多,舊的信息會(huì)被主動(dòng)的拿掉!僅保留最新的!

    那么 history 這個(gè)歷史命令只可以讓我查詢命令而已嗎?呵呵!當(dāng)然不止啊!我們可以利用相關(guān)的功能來(lái)幫我們運(yùn)行命令呢!舉例來(lái)說(shuō)啰:

    [root@www ~]# !number [root@www ~]# !command [root@www ~]# !! 選項(xiàng)與參數(shù): number :運(yùn)行第幾筆命令的意思; command :由最近的命令向前搜尋『命令串開頭為 command』的那個(gè)命令,并運(yùn)行; !! :就是運(yùn)行上一個(gè)命令(相當(dāng)于按↑按鍵后,按 Enter)[root@www ~]# history66 man rm67 alias68 man history69 history [root@www ~]# !66 <==運(yùn)行第 66 筆命令 [root@www ~]# !! <==運(yùn)行上一個(gè)命令,本例中亦即 !66 [root@www ~]# !al <==運(yùn)行最近以 al 為開頭的命令(上頭列出的第 67 個(gè))

    經(jīng)過上面的介紹,瞭乎?歷史命令用法可多了!如果我想要運(yùn)行上一個(gè)命令,除了使用上下鍵之外,我可以直接以『 !! 』 來(lái)下達(dá)上個(gè)命令的內(nèi)容,此外,我也可以直接選擇下達(dá)第 n 個(gè)命令,『 !n 』來(lái)運(yùn)行,也可以使用命令標(biāo)頭,例如『 !vi 』來(lái)運(yùn)行最近命令開頭是 vi 的命令列!相當(dāng)?shù)姆奖愣糜?#xff01;

    基本上 history 的用途很大的!但是需要小心安全的問題!尤其是 root 的歷史紀(jì)錄文件,這是Cracker 的最愛!因?yàn)椴恍⌒牡?root 會(huì)將很多的重要數(shù)據(jù)在運(yùn)行的過程中會(huì)被紀(jì)錄在~/.bash_history 當(dāng)中,如果這個(gè)文件被解析的話,后果不堪吶!無(wú)論如何,使用 history 配合『! 』曾經(jīng)使用過的命令下達(dá)是很有效率的一個(gè)命令下達(dá)方法!


    • 同一賬號(hào)同時(shí)多次登陸的 history 寫入問題

    有些朋友在練習(xí) linux 的時(shí)候喜歡同時(shí)開好幾個(gè) bash 接口,這些 bash 的身份都是 root 。這樣會(huì)有 ~/.bash_history 的寫入問題嗎?想一想,因?yàn)檫@些 bash 在同時(shí)以 root 的身份登陸,因此所有的 bash 都有自己的 1000 筆記錄在內(nèi)存中。因?yàn)榈鹊阶N時(shí)才會(huì)升級(jí)記錄文件,所以啰,最后注銷的那個(gè) bash 才會(huì)是最后寫入的數(shù)據(jù)。唔!如此一來(lái)其他 bash 的命令操作就不會(huì)被記錄下來(lái)了(其實(shí)有被記錄,只是被后來(lái)的最后一個(gè) bash 所覆蓋升級(jí)了) 。

    由于多重登陸有這樣的問題,所以很多朋友都習(xí)慣單一 bash 登陸,再用工作控制 (job control, 第四篇會(huì)介紹) 來(lái)切換不同工作!這樣才能夠?qū)⑺性?jīng)下達(dá)過的命令記錄下來(lái),也才方便未來(lái)系統(tǒng)管理員進(jìn)行命令的 debug 啊!


    • 無(wú)法記錄時(shí)間

    歷史命令還有一個(gè)問題,那就是無(wú)法記錄命令下達(dá)的時(shí)間。由于這 1000 筆歷史命令是依序記錄的,但是并沒有記錄時(shí)間,所以在查詢方面會(huì)有一些不方便。如果讀者們有興趣,其實(shí)可以透過 ~/.bash_logout 來(lái)進(jìn)行 history 的記錄,并加上 date 來(lái)添加時(shí)間參數(shù),也是一個(gè)可以應(yīng)用的方向喔!有興趣的朋友可以先看看情境模擬題一吧!


    Bash Shell 的操作環(huán)境:

    是否記得我們登陸主機(jī)的時(shí)候,屏幕上頭會(huì)有一些說(shuō)明文字,告知我們的 Linux 版本啊什么的,還有,登陸的時(shí)候我們還可以給予用戶一些信息或者歡迎文字呢。此外,我們習(xí)慣的環(huán)境變量、命令別名等等的,是否可以登陸就主動(dòng)的幫我配置好?這些都是需要注意的。另外,這些配置值又可以分為系統(tǒng)整體配置值與各人喜好配置值,僅是一些文件放置的地點(diǎn)不同啦!這我們后面也會(huì)來(lái)談一談的!


    路徑與命令搜尋順序

    我們?cè)诘诹屡c第七章都曾談過『相對(duì)路徑與絕對(duì)路徑』的關(guān)系,在本章的前幾小節(jié)也談到了 alias 與 bash 的內(nèi)建命令?,F(xiàn)在我們知道系統(tǒng)里面其實(shí)有不少的 ls 命令,或者是包括內(nèi)建的 echo 命令,那么來(lái)想一想,如果一個(gè)命令 (例如 ls) 被下達(dá)時(shí),到底是哪一個(gè) ls 被拿來(lái)運(yùn)行?很有趣吧!基本上,命令運(yùn)行的順序可以這樣看:

  • 以相對(duì)/絕對(duì)路徑運(yùn)行命令,例如『 /bin/ls 』或『 ./ls 』;
  • 由 alias 找到該命令來(lái)運(yùn)行;
  • 由 bash 內(nèi)建的 (builtin) 命令來(lái)運(yùn)行;
  • 透過 $PATH 這個(gè)變量的順序搜尋到的第一個(gè)命令來(lái)運(yùn)行。
  • 舉例來(lái)說(shuō),你可以下達(dá) /bin/ls 及單純的 ls 看看,會(huì)發(fā)現(xiàn)使用 ls 有顏色但是 /bin/ls 則沒有顏色。因?yàn)?/bin/ls 是直接取用該命令來(lái)下達(dá),而 ls 會(huì)因?yàn)椤?alias ls='ls --color=tty' 』這個(gè)命令別名而先使用!如果想要了解命令搜尋的順序,其實(shí)透過 type -a ls 也可以查詢的到啦!上述的順序最好先了解喔!

    例題: 配置 echo 的命令別名成為 echo -n ,然后再觀察 echo 運(yùn)行的順序 答:
    [root@www ~]# alias echo='echo -n' [root@www ~]# type -a echo echo is aliased to `echo -n' echo is a shell builtin echo is /bin/echo
    瞧!很清楚吧!先 alias 再 builtin 再由 $PATH 找到 /bin/echo 啰!


    bash 的進(jìn)站與歡迎信息:/etc/issue, /etc/motd

    什么! bash 也有進(jìn)站畫面與歡迎信息喔?真假?真的啊!還記得在終端機(jī)接口 (tty1 ~ tty6) 登陸的時(shí)候,會(huì)有幾行提示的字符串嗎?那就是進(jìn)站畫面啊!那個(gè)字符串寫在哪里啊?呵呵!在 /etc/issue 里面啊!先來(lái)看看:

    [root@www ~]# cat /etc/issue CentOS release 5.3 (Final) Kernel \r on an \m

    鳥哥是以完全未升級(jí)過的 CentOS 5.3 作為范例,里面默認(rèn)有三行,較有趣的地方在于 \r 與 \m。就如同 $PS1 這變量一樣,issue 這個(gè)文件的內(nèi)容也是可以使用反斜杠作為變量取用喔!你可以 man issue 配合 man mingetty 得到底下的結(jié)果:

    issue 內(nèi)的各代碼意義
    \d 本地端時(shí)間的日期;
    \l 顯示第幾個(gè)終端機(jī)接口;
    \m 顯示硬件的等級(jí) (i386/i486/i586/i686...);
    \n 顯示主機(jī)的網(wǎng)絡(luò)名稱;
    \o 顯示 domain name;
    \r 操作系統(tǒng)的版本 (相當(dāng)于 uname -r)
    \t 顯示本地端時(shí)間的時(shí)間;
    \s 操作系統(tǒng)的名稱;
    \v 操作系統(tǒng)的版本。

    做一下底下這個(gè)練習(xí),看看能不能取得你要的進(jìn)站畫面?

    例題: 如果你在 tty3 的進(jìn)站畫面看到如下顯示,該如何配置才能得到如下畫面? CentOS release 5.3 (Final) (terminal: tty3)
    Date: 2009-02-05 17:29:19
    Kernel 2.6.18-128.el5 on an i686
    Welcome!

    注意,tty3 在不同的 tty 有不同顯示,日期則是再按下 [enter] 后就會(huì)所有不同。 答: 很簡(jiǎn)單,參考上述的反斜杠功能去修改 /etc/issue 成為如下模樣即可(共五行):
    CentOS release 5.3 (Final) (terminal: \l) Date: \d \t Kernel \r on an \m Welcome!
    曾有鳥哥的學(xué)生在這個(gè) /etc/issue 內(nèi)修改數(shù)據(jù),光是利用簡(jiǎn)單的英文字母作出屬于他自己的進(jìn)站畫面,畫面里面有他的中文名字呢!非常厲害!也有學(xué)生做成類似很大一個(gè)『囧』在進(jìn)站畫面,都非常有趣!

    你要注意的是,除了 /etc/issue 之外還有個(gè) /etc/issue.net 呢!這是啥?這個(gè)是提供給 telnet 這個(gè)遠(yuǎn)程登錄程序用的。當(dāng)我們使用 telnet 連接到主機(jī)時(shí),主機(jī)的登陸畫面就會(huì)顯示 /etc/issue.net 而不是 /etc/issue 呢!

    至于如果您想要讓使用者登陸后取得一些信息,例如您想要讓大家都知道的信息,那么可以將信息加入 /etc/motd 里面去!例如:當(dāng)?shù)顷懞?#xff0c;告訴登陸者,系統(tǒng)將會(huì)在某個(gè)固定時(shí)間進(jìn)行維護(hù)工作,可以這樣做:

    [root@www ~]# vi /etc/motd Hello everyone, Our server will be maintained at 2009/02/28 0:00 ~ 24:00. Please don't login server at that time. ^_^

    那么當(dāng)你的使用者(包括所有的一般賬號(hào)與 root)登陸主機(jī)后,就會(huì)顯示這樣的信息出來(lái):

    Last login: Thu Feb 5 22:35:47 2009 from 127.0.0.1 Hello everyone, Our server will be maintained at 2009/02/28 0:00 ~ 24:00. Please don't login server at that time. ^_^

    bash 的環(huán)境配置文件

    你是否會(huì)覺得奇怪,怎么我們什么動(dòng)作都沒有進(jìn)行,但是一進(jìn)入 bash 就取得一堆有用的變量了?這是因?yàn)橄到y(tǒng)有一些環(huán)境配置文件案的存在,讓 bash 在啟動(dòng)時(shí)直接讀取這些配置文件,以規(guī)劃好 bash 的操作環(huán)境啦!而這些配置文件又可以分為全體系統(tǒng)的配置文件以及用戶個(gè)人偏好配置文件。要注意的是,我們前幾個(gè)小節(jié)談到的命令別名啦、自定義的變量啦,在你注銷 bash 后就會(huì)失效,所以你想要保留你的配置,就得要將這些配置寫入配置文件才行。底下就讓我們來(lái)聊聊吧!


    • login 與 non-login shell

    在開始介紹 bash 的配置文件前,我們一定要先知道的就是 login shell 與 non-login shell!重點(diǎn)在于有沒有登陸 (login) 啦!

    • login shell:取得 bash 時(shí)需要完整的登陸流程的,就稱為 login shell。舉例來(lái)說(shuō),你要由 tty1 ~ tty6 登陸,需要輸入用戶的賬號(hào)與密碼,此時(shí)取得的 bash 就稱為『 login shell 』啰;

    • non-login shell:取得 bash 接口的方法不需要重復(fù)登陸的舉動(dòng),舉例來(lái)說(shuō),(1)你以 X window 登陸 Linux 后,再以 X 的圖形化接口啟動(dòng)終端機(jī),此時(shí)那個(gè)終端接口并沒有需要再次的輸入賬號(hào)與密碼,那個(gè) bash 的環(huán)境就稱為non-login shell了。(2)你在原本的 bash 環(huán)境下再次下達(dá) bash 這個(gè)命令,同樣的也沒有輸入賬號(hào)密碼,那第二個(gè) bash (子程序) 也是 non-login shell 。

    為什么要介紹 login, non-login shell 呢?這是因?yàn)檫@兩個(gè)取得 bash 的情況中,讀取的配置文件數(shù)據(jù)并不一樣所致。由于我們需要登陸系統(tǒng),所以先談?wù)?login shell 會(huì)讀取哪些配置文件?一般來(lái)說(shuō),login shell 其實(shí)只會(huì)讀取這兩個(gè)配置文件:

  • /etc/profile:這是系統(tǒng)整體的配置,你最好不要修改這個(gè)文件;
  • ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:屬于使用者個(gè)人配置,你要改自己的數(shù)據(jù),就寫入這里!
  • 那么,就讓我們來(lái)聊一聊這兩個(gè)文件吧!這兩個(gè)文件的內(nèi)容可是非常繁復(fù)的喔!


    • /etc/profile (login shell 才會(huì)讀)

    你可以使用 vim 去閱讀一下這個(gè)文件的內(nèi)容。這個(gè)配置文件可以利用使用者的標(biāo)識(shí)符 (UID) 來(lái)決定很多重要的變量數(shù)據(jù),這也是每個(gè)使用者登陸取得 bash 時(shí)一定會(huì)讀取的配置文件!所以如果你想要幫所有使用者配置整體環(huán)境,那就是改這里啰!不過,沒事還是不要隨便改這個(gè)文件喔這個(gè)文件配置的變量主要有:

    • PATH:會(huì)依據(jù) UID 決定 PATH 變量要不要含有 sbin 的系統(tǒng)命令目錄;
    • MAIL:依據(jù)賬號(hào)配置好使用者的 mailbox 到 /var/spool/mail/賬號(hào)名;
    • USER:根據(jù)用戶的賬號(hào)配置此一變量?jī)?nèi)容;
    • HOSTNAME:依據(jù)主機(jī)的 hostname 命令決定此一變量?jī)?nèi)容;
    • HISTSIZE:歷史命令記錄筆數(shù)。CentOS 5.x 配置為 1000 ;

    /etc/profile 可不止會(huì)做這些事而已,他還會(huì)去呼叫外部的配置數(shù)據(jù)喔!在 CentOS 5.x 默認(rèn)的情況下,底下這些數(shù)據(jù)會(huì)依序的被呼叫進(jìn)來(lái):

    • /etc/inputrc

      其實(shí)這個(gè)文件并沒有被運(yùn)行啦!/etc/profile 會(huì)主動(dòng)的判斷使用者有沒有自定義輸入的按鍵功能,如果沒有的話, /etc/profile就會(huì)決定配置『INPUTRC=/etc/inputrc』這個(gè)變量!此一文件內(nèi)容為 bash 的熱鍵啦、[tab]要不要有聲音啦等等的數(shù)據(jù)!因?yàn)轼B哥覺得 bash 默認(rèn)的環(huán)境已經(jīng)很棒了,所以不建議修改這個(gè)文件!

    • /etc/profile.d/*.sh

      其實(shí)這是個(gè)目錄內(nèi)的眾多文件!只要在 /etc/profile.d/ 這個(gè)目錄內(nèi)且擴(kuò)展名為 .sh ,另外,使用者能夠具有 r 的權(quán)限,那么該文件就會(huì)被 /etc/profile 呼叫進(jìn)來(lái)。在 CentOS 5.x 中,這個(gè)目錄底下的文件規(guī)范了 bash 操作接口的顏色、語(yǔ)系、ll 與 ls 命令的命令別名、vi 的命令別名、which 的命令別名等等。如果你需要幫所有使用者配置一些共享的命令別名時(shí),可以在這個(gè)目錄底下自行創(chuàng)建擴(kuò)展名為 .sh 的文件,并將所需要的數(shù)據(jù)寫入即可喔!

    • /etc/sysconfig/i18n

      這個(gè)文件是由 /etc/profile.d/lang.sh 呼叫進(jìn)來(lái)的!這也是我們決定 bash 默認(rèn)使用何種語(yǔ)系的重要配置文件!文件里最重要的就是 LANG 這個(gè)變量的配置啦!我們?cè)谇懊娴膌ocale 討論過這個(gè)文件啰!自行回去瞧瞧先!

    反正你只要記得,bash 的 login shell 情況下所讀取的整體環(huán)境配置文件其實(shí)只有 /etc/profile,但是 /etc/profile 還會(huì)呼叫出其他的配置文件,所以讓我們的 bash 操作接口變的非常的友善啦!接下來(lái),讓我們來(lái)瞧瞧,那么個(gè)人偏好的配置文件又是怎么回事?


    • ~/.bash_profile (login shell 才會(huì)讀)

    bash 在讀完了整體環(huán)境配置的 /etc/profile 并藉此呼叫其他配置文件后,接下來(lái)則是會(huì)讀取使用者的個(gè)人配置文件。在 login shell 的 bash 環(huán)境中,所讀取的個(gè)人偏好配置文件其實(shí)主要有三個(gè),依序分別是:

  • ~/.bash_profile
  • ~/.bash_login
  • ~/.profile
  • 其實(shí) bash 的 login shell 配置只會(huì)讀取上面三個(gè)文件的其中一個(gè),而讀取的順序則是依照上面的順序。也就是說(shuō),如果 ~/.bash_profile 存在,那么其他兩個(gè)文件不論有無(wú)存在,都不會(huì)被讀取。如果 ~/.bash_profile 不存在才會(huì)去讀取 ~/.bash_login,而前兩者都不存在才會(huì)讀取 ~/.profile 的意思。會(huì)有這么多的文件,其實(shí)是因應(yīng)其他 shell 轉(zhuǎn)換過來(lái)的使用者的習(xí)慣而已。先讓我們來(lái)看一下 root 的 /root/.bash_profile 的內(nèi)容是怎樣呢?

    [root@www ~]# cat ~/.bash_profile # .bash_profile# Get the aliases and functions if [ -f ~/.bashrc ]; then <==底下這三行在判斷并讀取 ~/.bashrc. ~/.bashrc fi# User specific environment and startup programs PATH=$PATH:$HOME/bin <==底下這幾行在處理個(gè)人化配置 export PATH unset USERNAME

    這個(gè)文件內(nèi)有配置 PATH 這個(gè)變量喔!而且還使用了 export 將 PATH 變成環(huán)境變量呢!由于 PATH 在 /etc/profile 當(dāng)中已經(jīng)配置過,所以在這里就以累加的方式添加用戶家目錄下的 ~/bin/ 為額外的運(yùn)行文件放置目錄。這也就是說(shuō),你可以將自己創(chuàng)建的運(yùn)行檔放置到你自己家目錄下的 ~/bin/ 目錄啦!那就可以直接運(yùn)行該運(yùn)行檔而不需要使用絕對(duì)/相對(duì)路徑來(lái)運(yùn)行該文件。

    這個(gè)文件的內(nèi)容比較有趣的地方在于 if ... then ... 那一段!那一段程序代碼我們會(huì)在第十三章 shell script 談到,假設(shè)你現(xiàn)在是看不懂的。該段的內(nèi)容指的是『判斷家目錄下的 ~/.bashrc 存在否,若存在則讀入 ~/.bashrc 的配置』。bash 配置文件的讀入方式比較有趣,主要是透過一個(gè)命令『 source 』來(lái)讀取的!也就是說(shuō) ~/.bash_profile 其實(shí)會(huì)再呼叫 ~/.bashrc 的配置內(nèi)容喔!最后,我們來(lái)看看整個(gè) login shell的讀取流程:


    圖 4.3.1、login shell 的配置文件讀取流程

    實(shí)線的的方向是主線流程,虛線的方向則是被呼叫的配置文件!從上面我們也可以清楚的知道,在 CentOS 的 login shell 環(huán)境下,最終被讀取的配置文件是『 ~/.bashrc 』這個(gè)文件喔!所以,你當(dāng)然可以將自己的偏好配置寫入該文件即可。底下我們還要討論一下 source 與 ~/.bashrc 喔!


    • source :讀入環(huán)境配置文件的命令

    由于 /etc/profile 與 ~/.bash_profile 都是在取得 login shell 的時(shí)候才會(huì)讀取的配置文件,所以,如果你將自己的偏好配置寫入上述的文件后,通常都是得注銷再登陸后,該配置才會(huì)生效。那么,能不能直接讀取配置文件而不注銷登陸呢?可以的!那就得要利用 source 這個(gè)命令了!

    [root@www ~]# source 配置文件檔名范例:將家目錄的 ~/.bashrc 的配置讀入目前的 bash 環(huán)境中 [root@www ~]# source ~/.bashrc <==底下這兩個(gè)命令是一樣的! [root@www ~]# . ~/.bashrc

    利用 source 或小數(shù)點(diǎn) (.) 都可以將配置文件的內(nèi)容讀進(jìn)來(lái)目前的 shell 環(huán)境中!舉例來(lái)說(shuō),我修改了 ~/.bashrc ,那么不需要注銷,立即以 source ~/.bashrc 就可以將剛剛最新配置的內(nèi)容讀進(jìn)來(lái)目前的環(huán)境中!很不錯(cuò)吧!還有,包括 ~/bash_profile 以及 /etc/profile 的配置中,很多時(shí)候也都是利用到這個(gè) source (或小數(shù)點(diǎn)) 的功能喔!

    有沒有可能會(huì)使用到不同環(huán)境配置文件的時(shí)候?有啊!最常發(fā)生在一個(gè)人的工作環(huán)境分為多種情況的時(shí)候了!舉個(gè)例子來(lái)說(shuō),在鳥哥的大型主機(jī)中,常常需要負(fù)責(zé)兩到三個(gè)不同的案子,每個(gè)案子所需要處理的環(huán)境變量訂定并不相同,那么鳥哥就將這兩三個(gè)案子分別編寫屬于該案子的環(huán)境變量配置文件案,當(dāng)需要該環(huán)境時(shí),就直接『source 變量文件 』,如此一來(lái),環(huán)境變量的配置就變的更簡(jiǎn)便而靈活了!


    • ~/.bashrc (non-login shell 會(huì)讀)

    談完了 login shell 后,那么 non-login shell 這種非登陸情況取得 bash 操作接口的環(huán)境配置文件又是什么?當(dāng)你取得 non-login shell 時(shí),該 bash 配置文件僅會(huì)讀取 ~/.bashrc 而已啦!那么默認(rèn)的 ~/.bashrc 內(nèi)容是如何?

    [root@www ~]# cat ~/.bashrc # .bashrc# User specific aliases and functions alias rm='rm -i' <==使用者的個(gè)人配置 alias cp='cp -i' alias mv='mv -i'# Source global definitions if [ -f /etc/bashrc ]; then <==整體的環(huán)境配置. /etc/bashrc fi

    特別注意一下,由于 root 的身份與一般使用者不同,鳥哥是以 root 的身份取得上述的數(shù)據(jù),如果是一般使用者的 ~/.bashrc 會(huì)有些許不同。看一下,你會(huì)發(fā)現(xiàn)在 root 的 ~/.bashrc 中其實(shí)已經(jīng)規(guī)范了較為保險(xiǎn)的命令別名了。此外,咱們的 CentOS 5.x 還會(huì)主動(dòng)的呼叫 /etc/bashrc 這個(gè)文件喔!為什么需要呼叫 /etc/bashrc 呢?因?yàn)?span id="ozvdkddzhkzd" class="text_import2">/etc/bashrc 幫我們的 bash 定義出底下的數(shù)據(jù):

    • 依據(jù)不同的 UID 規(guī)范出 umask 的值;
    • 依據(jù)不同的 UID 規(guī)范出提示字符 (就是 PS1 變量);
    • 呼叫 /etc/profile.d/*.sh 的配置

    你要注意的是,這個(gè) /etc/bashrc 是 CentOS 特有的 (其實(shí)是 Red Hat 系統(tǒng)特有的),其他不同的 distributions 可能會(huì)放置在不同的檔名就是了。由于這個(gè) ~/.bashrc 會(huì)呼叫 /etc/bashrc 及 /etc/profile.d/*.sh ,所以,萬(wàn)一你沒有 ~/.bashrc (可能自己不小心將他刪除了),那么你會(huì)發(fā)現(xiàn)你的 bash 提示字符可能會(huì)變成這個(gè)樣子:

    -bash-3.2$

    不要太擔(dān)心啦!這是正常的,因?yàn)槟悴]有呼叫 /etc/bashrc 來(lái)規(guī)范 PS1 變量啦!而且這樣的情況也不會(huì)影響你的 bash 使用。如果你想要將命令提示字符捉回來(lái),那么可以復(fù)制 /etc/skel/.bashrc 到你的家目錄,再修訂一下你所想要的內(nèi)容,并使用 source 去呼叫 ~/.bashrc ,那你的命令提示字符就會(huì)回來(lái)啦!


    • 其他相關(guān)配置文件

    事實(shí)上還有一些配置文件可能會(huì)影響到你的 bash 操作的,底下就來(lái)談一談:

    • /etc/man.config

      這個(gè)文件乍看之下好像跟 bash 沒相關(guān)性,但是對(duì)于系統(tǒng)管理員來(lái)說(shuō),卻也是很重要的一個(gè)文件!這的文件的內(nèi)容『規(guī)范了使用man 的時(shí)候, man page 的路徑到哪里去尋找!』所以說(shuō)的簡(jiǎn)單一點(diǎn),這個(gè)文件規(guī)定了下達(dá)man 的時(shí)候,該去哪里查看數(shù)據(jù)的路徑配置!

      那么什么時(shí)候要來(lái)修改這個(gè)文件呢?如果你是以tarball 的方式來(lái)安裝你的數(shù)據(jù),那么你的 man page 可能會(huì)放置在/usr/local/softpackage/man 里頭,那個(gè) softpackage 是你的套件名稱,這個(gè)時(shí)候你就得以手動(dòng)的方式將該路徑加到 /etc/man.config 里頭,否則使用 man 的時(shí)候就會(huì)找不到相關(guān)的說(shuō)明檔啰。

      事實(shí)上,這個(gè)文件內(nèi)最重要的其實(shí)是 MANPATH 這個(gè)變量配置啦!我們搜尋 man page 時(shí),會(huì)依據(jù) MANPATH 的路徑去分別搜尋啊!另外,要注意的是,這個(gè)文件在各大不同版本 Linux distributions 中,檔名都不太相同,例如 CentOS 用的是/etc/man.config ,而 SuSE 用的則是 /etc/manpath.config ,可以利用 [tab] 按鍵來(lái)進(jìn)行文件名的補(bǔ)齊啦!

    • ~/.bash_history

      還記得我們?cè)跉v史命令提到過這個(gè)文件吧?默認(rèn)的情況下,我們的歷史命令就記錄在這里啊!而這個(gè)文件能夠記錄幾筆數(shù)據(jù),則與 HISTFILESIZE這個(gè)變量有關(guān)啊。每次登陸 bash 后,bash 會(huì)先讀取這個(gè)文件,將所有的歷史命令讀入內(nèi)存,因此,當(dāng)我們登陸 bash 后就可以查知上次使用過哪些命令啰。至于更多的歷史命令,請(qǐng)自行回去參考喔!

    • ~/.bash_logout

      這個(gè)文件則記錄了『當(dāng)我注銷 bash 后,系統(tǒng)再幫我做完什么動(dòng)作后才離開』的意思。你可以去讀取一下這個(gè)文件的內(nèi)容,默認(rèn)的情況下,注銷時(shí), bash 只是幫我們清掉屏幕的信息而已。不過,你也可以將一些備份或者是其他你認(rèn)為重要的工作寫在這個(gè)文件中 (例如清空緩存盤),那么當(dāng)你離開 Linux 的時(shí)候,就可以解決一些煩人的事情啰!

    終端機(jī)的環(huán)境配置: stty, set

    我們?cè)诘谖逭率状蔚顷?Linux 時(shí)就提過,可以在 tty1 ~ tty6 這六個(gè)文字接口的終端機(jī) (terminal) 環(huán)境中登陸,登陸的時(shí)候我們可以取得一些字符配置的功能喔!舉例來(lái)說(shuō),我們可以利用退格鍵 (backspace,就是那個(gè)←符號(hào)的按鍵) 來(lái)刪除命令行上的字符,也可以使用 [ctrl]+c 來(lái)強(qiáng)制終止一個(gè)命令的運(yùn)行,當(dāng)輸入錯(cuò)誤時(shí),就會(huì)有聲音跑出來(lái)警告。這是怎么辦到的呢?很簡(jiǎn)單啊!因?yàn)榈顷懡K端機(jī)的時(shí)候,會(huì)自動(dòng)的取得一些終端機(jī)的輸入環(huán)境的配置啊!

    事實(shí)上,目前我們使用的 Linux distributions 都幫我們作了最棒的使用者環(huán)境了,所以大家可以不用擔(dān)心操作環(huán)境的問題。不過,在某些 Unix like 的機(jī)器中,還是可能需要?jiǎng)佑靡恍┦帜_,才能夠讓我們的輸入比較快樂~舉例來(lái)說(shuō),利用 [backspace] 刪除,要比利用 [Del] 按鍵來(lái)的順手吧!但是某些 Unix 偏偏是以 [del] 來(lái)進(jìn)行字符的刪除啊!所以,這個(gè)時(shí)候就可以動(dòng)動(dòng)手腳啰~

    那么如何查閱目前的一些按鍵內(nèi)容呢?可以利用 stty (setting tty 終端機(jī)的意思) 呢!stty 也可以幫助配置終端機(jī)的輸入按鍵代表意義喔!

    [root@www ~]# stty [-a] 選項(xiàng)與參數(shù): -a :將目前所有的 stty 參數(shù)列出來(lái);范例一:列出所有的按鍵與按鍵內(nèi)容 [root@www ~]# stty -a speed 38400 baud; rows 24; columns 80; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; ....(以下省略)....

    我們可以利用 stty -a 來(lái)列出目前環(huán)境中所有的按鍵列表,在上頭的列表當(dāng)中,需要注意的是特殊字體那幾個(gè),此外,如果出現(xiàn) ^ 表示 [Ctrl] 那個(gè)按鍵的意思。舉例來(lái)說(shuō), intr = ^C 表示利用 [ctrl] + c 來(lái)達(dá)成的。幾個(gè)重要的代表意義是:

    • eof ??: End of file 的意思,代表『結(jié)束輸入』。
    • erase : 向后刪除字符,
    • intr ?: 送出一個(gè) interrupt (中斷) 的訊號(hào)給目前正在 run 的程序;
    • kill ?: 刪除在目前命令列上的所有文字;
    • quit? : 送出一個(gè) quit 的訊號(hào)給目前正在 run 的程序;
    • start : 在某個(gè)程序停止后,重新啟動(dòng)他的 output
    • stop ?: 停止目前屏幕的輸出;
    • susp ?: 送出一個(gè) terminal stop 的訊號(hào)給正在 run 的程序。

    記不記得我們?cè)诘谖逭轮v過幾個(gè) Linux 熱鍵啊?沒錯(cuò)!就是這個(gè) stty 配置值內(nèi)的 intr / eof 啰~至于刪除字符,就是 erase 那個(gè)配置值啦!如果你想要用 [ctrl]+h 來(lái)進(jìn)行字符的刪除,那么可以下達(dá):

    [root@www ~]# stty erase ^h

    那么從此之后,你的刪除字符就得要使用 [ctrl]+h 啰,按下 [backspace] 則會(huì)出現(xiàn) ^? 字樣呢!如果想要回復(fù)利用 [backspace] ,就下達(dá)stty erase ^? 即可啊!至于更多的 stty 說(shuō)明,記得參考一下 man stty 的內(nèi)容喔!

    除了 stty 之外,其實(shí)我們的 bash 還有自己的一些終端機(jī)配置值呢!那就是利用 set 來(lái)配置的!我們之前提到一些變量時(shí),可以利用 set 來(lái)顯示,除此之外,其實(shí) set 還可以幫我們配置整個(gè)命令輸出/輸入的環(huán)境。例如記錄歷史命令、顯示錯(cuò)誤內(nèi)容等等。

    [root@www ~]# set [-uvCHhmBx] 選項(xiàng)與參數(shù): -u :默認(rèn)不激活。若激活后,當(dāng)使用未配置變量時(shí),會(huì)顯示錯(cuò)誤信息; -v :默認(rèn)不激活。若激活后,在信息被輸出前,會(huì)先顯示信息的原始內(nèi)容; -x :默認(rèn)不激活。若激活后,在命令被運(yùn)行前,會(huì)顯示命令內(nèi)容(前面有 ++ 符號(hào)) -h :默認(rèn)激活。與歷史命令有關(guān); -H :默認(rèn)激活。與歷史命令有關(guān); -m :默認(rèn)激活。與工作管理有關(guān); -B :默認(rèn)激活。與刮號(hào) [] 的作用有關(guān); -C :默認(rèn)不激活。若使用 > 等,則若文件存在時(shí),該文件不會(huì)被覆蓋。范例一:顯示目前所有的 set 配置值 [root@www ~]# echo $- himBH # 那個(gè) $- 變量?jī)?nèi)容就是 set 的所有配置啦! bash 默認(rèn)是 himBH 喔!范例二:配置 "若使用未定義變量時(shí),則顯示錯(cuò)誤信息" [root@www ~]# set -u [root@www ~]# echo $vbirding -bash: vbirding: unbound variable # 默認(rèn)情況下,未配置/未宣告 的變量都會(huì)是『空的』,不過,若配置 -u 參數(shù), # 那么當(dāng)使用未配置的變量時(shí),就會(huì)有問題啦!很多的 shell 都默認(rèn)激活 -u 參數(shù)。 # 若要取消這個(gè)參數(shù),輸入 set +u 即可!范例三:運(yùn)行前,顯示該命令內(nèi)容。 [root@www ~]# set -x [root@www ~]# echo $HOME + echo /root /root ++ echo -ne '\033]0;root@www:~' # 看見否?要輸出的命令都會(huì)先被打印到屏幕上喔!前面會(huì)多出 + 的符號(hào)!

    另外,其實(shí)我們還有其他的按鍵配置功能呢!就是在前一小節(jié)提到的 /etc/inputrc 這個(gè)文件里面配置。

    [root@www ~]# cat /etc/inputrc # do not bell on tab-completion #set bell-style noneset meta-flag on set input-meta on set convert-meta off set output-meta on .....以下省略.....

    還有例如 /etc/DIR_COLORS* 與 /etc/termcap 等,也都是與終端機(jī)有關(guān)的環(huán)境配置文件案呢!不過,事實(shí)上,鳥哥并不建議您修改 tty 的環(huán)境呢,這是因?yàn)?bash 的環(huán)境已經(jīng)配置的很親和了,我們不需要額外的配置或者修改,否則反而會(huì)產(chǎn)生一些困擾。不過,寫在這里的數(shù)據(jù),只是希望大家能夠清楚的知道我們的終端機(jī)是如何進(jìn)行配置的喔! ^_^!最后,我們將 bash 默認(rèn)的組合鍵給他匯整如下:

    組合按鍵運(yùn)行結(jié)果
    Ctrl + C終止目前的命令
    Ctrl + D輸入結(jié)束 (EOF),例如郵件結(jié)束的時(shí)候;
    Ctrl + M就是 Enter 啦!
    Ctrl + S暫停屏幕的輸出
    Ctrl + Q恢復(fù)屏幕的輸出
    Ctrl + U在提示字符下,將整列命令刪除
    Ctrl + Z『暫?!荒壳暗拿?/td>


    通配符與特殊符號(hào)

    在 bash 的操作環(huán)境中還有一個(gè)非常有用的功能,那就是通配符 (wildcard) !我們利用 bash 處理數(shù)據(jù)就更方便了!底下我們列出一些常用的通配符喔:

    符號(hào)意義
    *代表『 0 個(gè)到無(wú)窮多個(gè)』任意字符
    ?代表『一定有一個(gè)』任意字符
    [ ]同樣代表『一定有一個(gè)在括號(hào)內(nèi)』的字符(非任意字符)。例如 [abcd] 代表『一定有一個(gè)字符,可能是 a, b, c, d 這四個(gè)任何一個(gè)』
    [ - ]若有減號(hào)在中括號(hào)內(nèi)時(shí),代表『在編碼順序內(nèi)的所有字符』。例如 [0-9] 代表0 到 9 之間的所有數(shù)字,因?yàn)閿?shù)字的語(yǔ)系編碼是連續(xù)的!
    [^ ]若中括號(hào)內(nèi)的第一個(gè)字符為指數(shù)符號(hào) (^) ,那表示『反向選擇』,例如 [^abc] 代表一定有一個(gè)字符,只要是非 a, b, c 的其他字符就接受的意思。

    接下來(lái)讓我們利用通配符來(lái)玩些東西吧!首先,利用通配符配合 ls 找檔名看看:

    [root@www ~]# LANG=C <==由于與編碼有關(guān),先配置語(yǔ)系一下范例一:找出 /etc/ 底下以 cron 為開頭的檔名 [root@www ~]# ll -d /etc/cron* <==加上 -d 是為了僅顯示目錄而已范例二:找出 /etc/ 底下文件名『剛好是五個(gè)字母』的文件名 [root@www ~]# ll -d /etc/????? <==由于 ? 一定有一個(gè),所以五個(gè) ? 就對(duì)了范例三:找出 /etc/ 底下文件名含有數(shù)字的文件名 [root@www ~]# ll -d /etc/*[0-9]* <==記得中括號(hào)左右兩邊均需 *范例四:找出 /etc/ 底下,檔名開頭非為小寫字母的文件名: [root@www ~]# ll -d /etc/[^a-z]* <==注意中括號(hào)左邊沒有 *范例五:將范例四找到的文件復(fù)制到 /tmp 中 [root@www ~]# cp -a /etc/[^a-z]* /tmp

    除了通配符之外,bash 環(huán)境中的特殊符號(hào)有哪些呢?底下我們先匯整一下:

    符號(hào)內(nèi)容
    #批注符號(hào):這個(gè)最常被使用在 script 當(dāng)中,視為說(shuō)明!在后的數(shù)據(jù)均不運(yùn)行
    \跳脫符號(hào):將『特殊字符或通配符』還原成一般字符
    |管線 (pipe):分隔兩個(gè)管線命令的界定(后兩節(jié)介紹);
    ;連續(xù)命令下達(dá)分隔符:連續(xù)性命令的界定 (注意!與管線命令并不相同)
    ~用戶的家目錄
    $取用變量前導(dǎo)符:亦即是變量之前需要加的變量取代值
    &工作控制 (job control):將命令變成背景下工作
    !邏輯運(yùn)算意義上的『非』 not 的意思!
    /目錄符號(hào):路徑分隔的符號(hào)
    >, >>數(shù)據(jù)流重導(dǎo)向:輸出導(dǎo)向,分別是『取代』與『累加』
    <, <<數(shù)據(jù)流重導(dǎo)向:輸入導(dǎo)向 (這兩個(gè)留待下節(jié)介紹)
    ' '單引號(hào),不具有變量置換的功能
    " "具有變量置換的功能!
    ` `兩個(gè)『 ` 』中間為可以先運(yùn)行的命令,亦可使用 $( )
    ( )在中間為子 shell 的起始與結(jié)束
    { }在中間為命令區(qū)塊的組合!

    以上為 bash 環(huán)境中常見的特殊符號(hào)匯整!理論上,你的『檔名』盡量不要使用到上述的字符啦!


    數(shù)據(jù)流重導(dǎo)向

    數(shù)據(jù)流重導(dǎo)向 (redirect) 由字面上的意思來(lái)看,好像就是將『數(shù)據(jù)給他傳導(dǎo)到其他地方去』的樣子?沒錯(cuò)~數(shù)據(jù)流重導(dǎo)向就是將某個(gè)命令運(yùn)行后應(yīng)該要出現(xiàn)在屏幕上的數(shù)據(jù),給他傳輸?shù)狡渌牡胤?#xff0c;例如文件或者是裝置 (例如打印機(jī)之類的)!這玩意兒在 Linux 的文本模式底下可重要的!尤其是如果我們想要將某些數(shù)據(jù)儲(chǔ)存下來(lái)時(shí),就更有用了!


    什么是數(shù)據(jù)流重導(dǎo)向

    什么是數(shù)據(jù)流重導(dǎo)向啊?這得要由命令的運(yùn)行結(jié)果談起!一般來(lái)說(shuō),如果你要運(yùn)行一個(gè)命令,通常他會(huì)是這樣的:


    圖 5.1.1、命令運(yùn)行過程的數(shù)據(jù)傳輸情況

    我們運(yùn)行一個(gè)命令的時(shí)候,這個(gè)命令可能會(huì)由文件讀入數(shù)據(jù),經(jīng)過處理之后,再將數(shù)據(jù)輸出到屏幕上。在上圖當(dāng)中, standard output 與 standard error output 分別代表『標(biāo)準(zhǔn)輸出』與『標(biāo)準(zhǔn)錯(cuò)誤輸出』,這兩個(gè)玩意兒默認(rèn)都是輸出到屏幕上面來(lái)的啊!那么什么是標(biāo)準(zhǔn)輸出與標(biāo)準(zhǔn)錯(cuò)誤輸出呢?


    • standard output 與 standard error output

    簡(jiǎn)單的說(shuō),標(biāo)準(zhǔn)輸出指的是『命令運(yùn)行所回傳的正確的信息』,而標(biāo)準(zhǔn)錯(cuò)誤輸出可理解為『命令運(yùn)行失敗后,所回傳的錯(cuò)誤信息』。舉個(gè)簡(jiǎn)單例子來(lái)說(shuō),我們的系統(tǒng)默認(rèn)有 /etc/crontab 但卻無(wú) /etc/vbirdsay,此時(shí)若下達(dá)『 cat /etc/crontab /etc/vbirdsay 』這個(gè)命令時(shí),cat 會(huì)進(jìn)行:

    • 標(biāo)準(zhǔn)輸出:讀取 /etc/crontab 后,將該文件內(nèi)容顯示到屏幕上;
    • 標(biāo)準(zhǔn)錯(cuò)誤輸出:因?yàn)闊o(wú)法找到 /etc/vbirdsay,因此在屏幕上顯示錯(cuò)誤信息

    不管正確或錯(cuò)誤的數(shù)據(jù)都是默認(rèn)輸出到屏幕上,所以屏幕當(dāng)然是亂亂的!那能不能透過某些機(jī)制將這兩股數(shù)據(jù)分開呢?當(dāng)然可以啊!那就是數(shù)據(jù)流重導(dǎo)向的功能啊!數(shù)據(jù)流重導(dǎo)向可以將 standard output (簡(jiǎn)稱 stdout) 與 standard erroroutput (簡(jiǎn)稱 stderr) 分別傳送到其他的文件或裝置去,而分別傳送所用的特殊字符則如下所示:

  • 標(biāo)準(zhǔn)輸入  (stdin) :代碼為 0 ,使用 < 或 << ;
  • 標(biāo)準(zhǔn)輸出  (stdout):代碼為 1 ,使用 > 或 >> ;
  • 標(biāo)準(zhǔn)錯(cuò)誤輸出(stderr):代碼為 2 ,使用 2> 或 2>> ;
  • 為了理解 stdout 與 stderr ,我們先來(lái)進(jìn)行一個(gè)范例的練習(xí):

    范例一:觀察你的系統(tǒng)根目錄 (/) 下各目錄的文件名、權(quán)限與屬性,并記錄下來(lái) [root@www ~]# ll / <==此時(shí)屏幕會(huì)顯示出文件名信息[root@www ~]# ll / > ~/rootfile <==屏幕并無(wú)任何信息 [root@www ~]# ll ~/rootfile <==有個(gè)新檔被創(chuàng)建了! -rw-r--r-- 1 root root 1089 Feb 6 17:00 /root/rootfile

    怪了!屏幕怎么會(huì)完全沒有數(shù)據(jù)呢?這是因?yàn)樵尽?ll / 』所顯示的數(shù)據(jù)已經(jīng)被重新導(dǎo)向到 ~/rootfile 文件中了!那個(gè) ~/rootfile 的檔名可以隨便你取。如果你下達(dá)『 cat ~/rootfile 』那就可以看到原本應(yīng)該在屏幕上面的數(shù)據(jù)啰。如果我再次下達(dá):『 ll /home > ~/rootfile 』后,那個(gè) ~/rootfile 文件的內(nèi)容變成什么?他將變成『僅有 ll /home 的數(shù)據(jù)』而已!咦!原本的『 ll / 』數(shù)據(jù)就不見了嗎?是的!因?yàn)樵撐募膭?chuàng)建方式是:

  • 該文件 (本例中是 ~/rootfile) 若不存在,系統(tǒng)會(huì)自動(dòng)的將他創(chuàng)建起來(lái),但是
  • 當(dāng)這個(gè)文件存在的時(shí)候,那么系統(tǒng)就會(huì)先將這個(gè)文件內(nèi)容清空,然后再將數(shù)據(jù)寫入!
  • 也就是若以 > 輸出到一個(gè)已存在的文件中,那個(gè)文件就會(huì)被覆蓋掉啰!
  • 那如果我想要將數(shù)據(jù)累加而不想要將舊的數(shù)據(jù)刪除,那該如何是好?利用兩個(gè)大于的符號(hào) (>>)就好啦!以上面的范例來(lái)說(shuō),你應(yīng)該要改成『 ll / >> ~/rootfile 』即可。如此一來(lái),當(dāng) (1) ~/rootfile 不存在時(shí)系統(tǒng)會(huì)主動(dòng)創(chuàng)建這個(gè)文件;(2)若該文件已存在,則數(shù)據(jù)會(huì)在該文件的最下方累加進(jìn)去!

    上面談到的是 standard output 的正確數(shù)據(jù),那如果是 standard error output 的錯(cuò)誤數(shù)據(jù)呢?那就透過 2> 及2>> 啰!同樣是覆蓋 (2>) 與累加 (2>>) 的特性!我們?cè)趧倓偛耪劦?stdout 代碼是 1 而 stderr 代碼是 2 ,所以這個(gè) 2> 是很容易理解的,而如果僅存在 > 時(shí),則代表默認(rèn)的代碼 1 啰!也就是說(shuō):

    • 1> :以覆蓋的方法將『正確的數(shù)據(jù)』輸出到指定的文件或裝置上;
    • 1>>:以累加的方法將『正確的數(shù)據(jù)』輸出到指定的文件或裝置上;
    • 2> :以覆蓋的方法將『錯(cuò)誤的數(shù)據(jù)』輸出到指定的文件或裝置上;
    • 2>>:以累加的方法將『錯(cuò)誤的數(shù)據(jù)』輸出到指定的文件或裝置上;

    要注意喔,『 1>> 』以及『 2>> 』中間是沒有空格的!OK!有些概念之后讓我們繼續(xù)聊一聊這家伙怎么應(yīng)用吧!當(dāng)你以一般身份運(yùn)行 find這個(gè)命令的時(shí)候,由于權(quán)限的問題可能會(huì)產(chǎn)生一些錯(cuò)誤信息。例如運(yùn)行『 find / -name testing 』時(shí),可能會(huì)產(chǎn)生類似『 find: /root: Permission denied 』之類的信息。例如底下這個(gè)范例:

    范例二:利用一般身份賬號(hào)搜尋 /home 底下是否有名為 .bashrc 的文件存在 [root@www ~]# su - dmtsai <==假設(shè)我的系統(tǒng)有名為 dmtsai 的賬號(hào) [dmtsai@www ~]$ find /home -name .bashrc <==身份是 dmtsai 喔! find: /home/lost+found: Permission denied <== Standard error find: /home/alex: Permission denied <== Standard error find: /home/arod: Permission denied <== Standard error /home/dmtsai/.bashrc <== Standard output

    由于 /home 底下還有我們之前創(chuàng)建的賬號(hào)存在,那些賬號(hào)的家目錄你當(dāng)然不能進(jìn)入啊!所以就會(huì)有錯(cuò)誤及正確數(shù)據(jù)了。好了,那么假如我想要將數(shù)據(jù)輸出到 list 這個(gè)文件中呢?運(yùn)行『 find /home -name .bashrc > list 』會(huì)有什么結(jié)果?呵呵,你會(huì)發(fā)現(xiàn)list 里面存了剛剛那個(gè)『正確』的輸出數(shù)據(jù),至于屏幕上還是會(huì)有錯(cuò)誤的信息出現(xiàn)呢!傷腦筋!如果想要將正確的與錯(cuò)誤的數(shù)據(jù)分別存入不同的文件中需要怎么做?

    范例三:承范例二,將 stdout 與 stderr 分存到不同的文件去 [dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error

    注意喔,此時(shí)『屏幕上不會(huì)出現(xiàn)任何信息』!因?yàn)閯倓傔\(yùn)行的結(jié)果中,有 Permission 的那幾行錯(cuò)誤信息都會(huì)跑到 list_error 這個(gè)文件中,至于正確的輸出數(shù)據(jù)則會(huì)存到 list_right 這個(gè)文件中啰!這樣可以了解了嗎?如果有點(diǎn)混亂的話,去休息一下再來(lái)看看吧!


    • /dev/null 垃圾桶黑洞裝置與特殊寫法

    想象一下,如果我知道錯(cuò)誤信息會(huì)發(fā)生,所以要將錯(cuò)誤信息忽略掉而不顯示或儲(chǔ)存呢?這個(gè)時(shí)候黑洞裝置 /dev/null 就很重要了!這個(gè) /dev/null 可以吃掉任何導(dǎo)向這個(gè)裝置的信息喔!將上述的范例修訂一下:

    范例四:承范例三,將錯(cuò)誤的數(shù)據(jù)丟棄,屏幕上顯示正確的數(shù)據(jù) [dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null /home/dmtsai/.bashrc <==只有 stdout 會(huì)顯示到屏幕上, stderr 被丟棄了

    再想象一下,如果我要將正確與錯(cuò)誤數(shù)據(jù)通通寫入同一個(gè)文件去呢?這個(gè)時(shí)候就得要使用特殊的寫法了!我們同樣用底下的案例來(lái)說(shuō)明:

    范例五:將命令的數(shù)據(jù)全部寫入名為 list 的文件中 [dmtsai@www ~]$ find /home -name .bashrc > list 2> list <==錯(cuò)誤 [dmtsai@www ~]$ find /home -name .bashrc > list 2>&1 <==正確 [dmtsai@www ~]$ find /home -name .bashrc &> list <==正確

    上述表格第一行錯(cuò)誤的原因是,由于兩股數(shù)據(jù)同時(shí)寫入一個(gè)文件,又沒有使用特殊的語(yǔ)法,此時(shí)兩股數(shù)據(jù)可能會(huì)交叉寫入該文件內(nèi),造成次序的錯(cuò)亂。所以雖然最終 list 文件還是會(huì)產(chǎn)生,但是里面的數(shù)據(jù)排列就會(huì)怪怪的,而不是原本屏幕上的輸出排序。至于寫入同一個(gè)文件的特殊語(yǔ)法如上表所示,你可以使用 2>&1 也可以使用 &> !一般來(lái)說(shuō),鳥哥比較習(xí)慣使用 2>&1 的語(yǔ)法啦!


    • standard input : < 與 <<

    了解了 stderr 與 stdout 后,那么那個(gè) < 又是什么呀?呵呵!以最簡(jiǎn)單的說(shuō)法來(lái)說(shuō),那就是『將原本需要由鍵盤輸入的數(shù)據(jù),改由文件內(nèi)容來(lái)取代』的意思。我們先由底下的 cat 命令操作來(lái)了解一下什么叫做『鍵盤輸入』吧!

    范例六:利用 cat 命令來(lái)創(chuàng)建一個(gè)文件的簡(jiǎn)單流程 [root@www ~]# cat > catfile testing cat file test <==這里按下 [ctrl]+d 來(lái)離開[root@www ~]# cat catfile testing cat file test

    由于加入 > 在 cat 后,所以那個(gè) catfile 會(huì)被主動(dòng)的創(chuàng)建,而內(nèi)容就是剛剛鍵盤上面輸入的那兩行數(shù)據(jù)了。唔!那我能不能用純文本文件取代鍵盤的輸入,也就是說(shuō),用某個(gè)文件的內(nèi)容來(lái)取代鍵盤的敲擊呢?可以的!如下所示:

    范例七:用 stdin 取代鍵盤的輸入以創(chuàng)建新文件的簡(jiǎn)單流程 [root@www ~]# cat > catfile < ~/.bashrc [root@www ~]# ll catfile ~/.bashrc -rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc -rw-r--r-- 1 root root 194 Feb 6 18:29 catfile # 注意看,這兩個(gè)文件的大小會(huì)一模一樣!幾乎像是使用 cp 來(lái)復(fù)制一般!

    這東西非常的有幫助!尤其是用在類似 mail 這種命令的使用上。理解 < 之后,再來(lái)則是怪可怕一把的 << 這個(gè)連續(xù)兩個(gè)小于的符號(hào)了。他代表的是『結(jié)束的輸入字符』的意思!舉例來(lái)講:『我要用 cat 直接將輸入的信息輸出到 catfile 中,且當(dāng)由鍵盤輸入 eof 時(shí),該次輸入就結(jié)束』,那我可以這樣做:

    [root@www ~]# cat > catfile << "eof" > This is a test. > OK now stop > eof <==輸入這關(guān)鍵詞,立刻就結(jié)束而不需要輸入 [ctrl]+d[root@www ~]# cat catfile This is a test. OK now stop <==只有這兩行,不會(huì)存在關(guān)鍵詞那一行!

    看到了嗎?利用 << 右側(cè)的控制字符,我們可以終止一次輸入,而不必輸入 [crtl]+d 來(lái)結(jié)束哩!這對(duì)程序?qū)懽骱苡袔椭?#xff01;好了,那么為何要使用命令輸出重導(dǎo)向呢?我們來(lái)說(shuō)一說(shuō)吧!

    • 屏幕輸出的信息很重要,而且我們需要將他存下來(lái)的時(shí)候;
    • 背景運(yùn)行中的程序,不希望他干擾屏幕正常的輸出結(jié)果時(shí);
    • 一些系統(tǒng)的例行命令 (例如寫在 /etc/crontab 中的文件) 的運(yùn)行結(jié)果,希望他可以存下來(lái)時(shí);
    • 一些運(yùn)行命令的可能已知錯(cuò)誤信息時(shí),想以『 2> /dev/null 』將他丟掉時(shí);
    • 錯(cuò)誤信息與正確信息需要分別輸出時(shí)。

    當(dāng)然還有很多的功能的,最簡(jiǎn)單的就是網(wǎng)友們常常問到的:『為何我的 root 都會(huì)收到系統(tǒng) crontab 寄來(lái)的錯(cuò)誤信息呢』這個(gè)咚咚是常見的錯(cuò)誤,而如果我們已經(jīng)知道這個(gè)錯(cuò)誤信息是可以忽略的時(shí)候,嗯!『 2> errorfile 』這個(gè)功能就很重要了吧!了解了嗎?


    命令運(yùn)行的判斷依據(jù): ; , &&, ||

    在某些情況下,很多命令我想要一次輸入去運(yùn)行,而不想要分次運(yùn)行時(shí),該如何是好?基本上你有兩個(gè)選擇,一個(gè)是透過第十三章要介紹的 shell script 撰寫腳本去運(yùn)行,一種則是透過底下的介紹來(lái)一次輸入多重命令喔!


    • cmd ; cmd (不考慮命令相關(guān)性的連續(xù)命令下達(dá))

    在某些時(shí)候,我們希望可以一次運(yùn)行多個(gè)命令,例如在關(guān)機(jī)的時(shí)候我希望可以先運(yùn)行兩次 sync 同步化寫入磁盤后才 shutdown 計(jì)算機(jī),那么可以怎么作呢?這樣做呀:

    [root@www ~]# sync; sync; shutdown -h now

    在命令與命令中間利用分號(hào) (;) 來(lái)隔開,這樣一來(lái),分號(hào)前的命令運(yùn)行完后就會(huì)立刻接著運(yùn)行后面的命令了。這真是方便啊~再來(lái),換個(gè)角度來(lái)想,萬(wàn)一我想要在某個(gè)目錄底下創(chuàng)建一個(gè)文件,也就是說(shuō),如果該目錄存在的話,那我才創(chuàng)建這個(gè)文件,如果不存在,那就算了。也就是說(shuō)這兩個(gè)命令彼此之間是有相關(guān)性的,前一個(gè)命令是否成功的運(yùn)行與后一個(gè)命令是否要運(yùn)行有關(guān)!那就得動(dòng)用到 && 或 || 啰!


    • $? (命令回傳值) 與 && 或 ||

    如同上面談到的,兩個(gè)命令之間有相依性,而這個(gè)相依性主要判斷的地方就在于前一個(gè)命令運(yùn)行的結(jié)果是否正確。還記得本章之前我們?cè)榻B過命令回傳值吧!嘿嘿!沒錯(cuò),您真聰明!就是透過這個(gè)回傳值啦!再?gòu)?fù)習(xí)一次『若前一個(gè)命令運(yùn)行的結(jié)果為正確,在 Linux 底下會(huì)回傳一個(gè) $? = 0 的值』。那么我們?cè)趺赐高^這個(gè)回傳值來(lái)判斷后續(xù)的命令是否要運(yùn)行呢?這就得要藉由『 && 』及『 || 』的幫忙了!注意喔,兩個(gè) & 之間是沒有空格的!那個(gè) | 則是 [Shift]+[\] 的按鍵結(jié)果

    命令下達(dá)情況說(shuō)明
    cmd1 && cmd21. 若 cmd1 運(yùn)行完畢且正確運(yùn)行($?=0),則開始運(yùn)行 cmd2。
    2. 若 cmd1 運(yùn)行完畢且為錯(cuò)誤 ($?≠0),則 cmd2 不運(yùn)行。
    cmd1 || cmd21. 若 cmd1 運(yùn)行完畢且正確運(yùn)行($?=0),則 cmd2 不運(yùn)行。
    2. 若 cmd1 運(yùn)行完畢且為錯(cuò)誤 ($?≠0),則開始運(yùn)行 cmd2。

    上述的 cmd1 及 cmd2 都是命令。好了,回到我們剛剛假想的情況,就是想要:(1)先判斷一個(gè)目錄是否存在; (2)若存在才在該目錄底下創(chuàng)建一個(gè)文件。由于我們尚未介紹如何判斷式 (test) 的使用,在這里我們使用 ls 以及回傳值來(lái)判斷目錄是否存在啦!讓我們進(jìn)行底下這個(gè)練習(xí)看看:

    范例一:使用 ls 查閱目錄 /tmp/abc 是否存在,若存在則用 touch 創(chuàng)建 /tmp/abc/hehe [root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe ls: /tmp/abc: No such file or directory # ls 很干脆的說(shuō)明找不到該目錄,但并沒有 touch 的錯(cuò)誤,表示 touch 并沒有運(yùn)行[root@www ~]# mkdir /tmp/abc [root@www ~]# ls /tmp/abc && touch /tmp/abc/hehe [root@www ~]# ll /tmp/abc -rw-r--r-- 1 root root 0 Feb 7 12:43 hehe

    看到了吧?如果 /tmp/abc 不存在時(shí),touch 就不會(huì)被運(yùn)行,若 /tmp/abc 存在的話,那么 touch 就會(huì)開始運(yùn)行啰!很不錯(cuò)用吧!不過,我們還得手動(dòng)自行創(chuàng)建目錄,傷腦筋~能不能自動(dòng)判斷,如果沒有該目錄就給予創(chuàng)建呢?參考一下底下的例子先:

    范例二:測(cè)試 /tmp/abc 是否存在,若不存在則予以創(chuàng)建,若存在就不作任何事情 [root@www ~]# rm -r /tmp/abc <==先刪除此目錄以方便測(cè)試 [root@www ~]# ls /tmp/abc || mkdir /tmp/abc ls: /tmp/abc: No such file or directory <==真的不存在喔! [root@www ~]# ll /tmp/abc total 0 <==結(jié)果出現(xiàn)了!有進(jìn)行 mkdir

    如果你一再重復(fù)『 ls /tmp/abc || mkdir /tmp/abc 』畫面也不會(huì)出現(xiàn)重復(fù) mkdir 的錯(cuò)誤!這是因?yàn)?/tmp/abc 已經(jīng)存在,所以后續(xù)的 mkdir 就不會(huì)進(jìn)行!這樣理解否?好了,讓我們?cè)俅蔚挠懻撘幌?#xff0c;如果我想要?jiǎng)?chuàng)建 /tmp/abc/hehe 這個(gè)文件,但我并不知道 /tmp/abc 是否存在,那該如何是好?試看看:

    范例三:我不清楚 /tmp/abc 是否存在,但就是要?jiǎng)?chuàng)建 /tmp/abc/hehe 文件 [root@www ~]# ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe

    上面這個(gè)范例三總是會(huì)創(chuàng)建 /tmp/abc/hehe 的喔!不論 /tmp/abc 是否存在。那么范例三應(yīng)該如何解釋呢?由于Linux 底下的命令都是由左往右運(yùn)行的,所以范例三有幾種結(jié)果我們來(lái)分析一下:

    • (1)若 /tmp/abc 不存在故回傳 $?≠0,則 (2)因?yàn)?|| 遇到非為 0 的 $? 故開始 mkdir /tmp/abc,由于 mkdir /tmp/abc會(huì)成功進(jìn)行,所以回傳 $?=0 (3)因?yàn)?&& 遇到 $?=0 故會(huì)運(yùn)行 touch /tmp/abc/hehe,最終 hehe 就被創(chuàng)建了;

    • (1)若 /tmp/abc 存在故回傳 $?=0,則 (2)因?yàn)?|| 遇到 0 的 $? 不會(huì)進(jìn)行,此時(shí) $?=0 繼續(xù)向后傳,故 (3)因?yàn)?&& 遇到 $?=0 就開始創(chuàng)建 /tmp/abc/hehe 了!最終 /tmp/abc/hehe 被創(chuàng)建起來(lái)。

    整個(gè)流程圖示如下:


    圖 5.2.1、 命令依序運(yùn)行的關(guān)系示意圖

    上面這張圖顯示的兩股數(shù)據(jù)中,上方的線段為不存在 /tmp/abc 時(shí)所進(jìn)行的命令行為,下方的線段則是存在 /tmp/abc 所在的命令行為。如上所述,下方線段由于存在 /tmp/abc 所以導(dǎo)致 $?=0 ,讓中間的 mkdir 就不運(yùn)行了!并將 $?=0 繼續(xù)往后傳給后續(xù)的 touch 去利用啦!瞭乎?在任何時(shí)刻你都可以拿上面這張圖作為示意!讓我們來(lái)想想底下這個(gè)例題吧!

    例題: 以 ls 測(cè)試 /tmp/vbirding 是否存在,若存在則顯示 "exist" ,若不存在,則顯示 "not exist"! 答: 這又牽涉到邏輯判斷的問題,如果存在就顯示某個(gè)數(shù)據(jù),若不存在就顯示其他數(shù)據(jù),那我可以這樣做: ls /tmp/vbirding && echo "exist" || echo "not exist" 意思是說(shuō),當(dāng) ls /tmp/vbirding 運(yùn)行后,若正確,就運(yùn)行 echo "exist" ,若有問題,就運(yùn)行 echo "not exist" !那如果寫成如下的狀況會(huì)出現(xiàn)什么? ls /tmp/vbirding || echo "not exist" && echo "exist" 這其實(shí)是有問題的,為什么呢?由圖 5.2.1 的流程介紹我們知道命令是一個(gè)一個(gè)往后運(yùn)行,因此在上面的例子當(dāng)中,如果 /tmp/vbirding 不存在時(shí),他會(huì)進(jìn)行如下動(dòng)作:
  • 若 ls /tmp/vbirding 不存在,因此回傳一個(gè)非為 0 的數(shù)值;
  • 接下來(lái)經(jīng)過 || 的判斷,發(fā)現(xiàn)前一個(gè)命令回傳非為 0 的數(shù)值,因此,程序開始運(yùn)行 echo "not exist" ,而 echo "not exist" 程序肯定可以運(yùn)行成功,因此會(huì)回傳一個(gè) 0 值給后面的命令;
  • 經(jīng)過 && 的判斷,咦!是 0 啊!所以就開始運(yùn)行 echo "exist" 。
  • 所以啊,嘿嘿!第二個(gè)例子里面竟然會(huì)同時(shí)出現(xiàn) not exist 與 exist 呢!真神奇~

    經(jīng)過這個(gè)例題的練習(xí),你應(yīng)該會(huì)了解,由于命令是一個(gè)接著一個(gè)去運(yùn)行的,因此,如果真要使用判斷,那么這個(gè) && 與 || 的順序就不能搞錯(cuò)。一般來(lái)說(shuō),假設(shè)判斷式有三個(gè),也就是:

    command1 && command2 || command3

    而且順序通常不會(huì)變,因?yàn)橐话銇?lái)說(shuō), command2 與 command3 會(huì)放置肯定可以運(yùn)行成功的命令,因此,依據(jù)上面例題的邏輯分析,您就會(huì)曉得為何要如此放置啰~這很有用的啦!而且.....考試也很常考~


    管線命令 (pipe)

    就如同前面所說(shuō)的, bash 命令運(yùn)行的時(shí)候有輸出的數(shù)據(jù)會(huì)出現(xiàn)!那么如果這群數(shù)據(jù)必需要經(jīng)過幾道手續(xù)之后才能得到我們所想要的格式,應(yīng)該如何來(lái)配置?這就牽涉到管線命令的問題了 (pipe) ,管線命令使用的是『 | 』這個(gè)界定符號(hào)!另外,管線命令與『連續(xù)下達(dá)命令』是不一樣的呦!這點(diǎn)底下我們會(huì)再說(shuō)明。底下我們先舉一個(gè)例子來(lái)說(shuō)明一下簡(jiǎn)單的管線命令。

    假設(shè)我們想要知道 /etc/ 底下有多少文件,那么可以利用 ls /etc 來(lái)查閱,不過,因?yàn)?/etc 底下的文件太多,導(dǎo)致一口氣就將屏幕塞滿了~不知道前面輸出的內(nèi)容是啥?此時(shí),我們可以透過 less 命令的協(xié)助,利用:

    [root@www ~]# ls -al /etc | less

    如此一來(lái),使用 ls 命令輸出后的內(nèi)容,就能夠被 less 讀取,并且利用 less 的功能,我們就能夠前后翻動(dòng)相關(guān)的信息了!很方便是吧?我們就來(lái)了解一下這個(gè)管線命令『 | 』的用途吧!其實(shí)這個(gè)管線命令『 | 』僅能處理經(jīng)由前面一個(gè)命令傳來(lái)的正確信息,也就是 standard output 的信息,對(duì)于 stdandard error 并沒有直接處理的能力。那么整體的管線命令可以使用下圖表示:


    圖 6.1.1、 管線命令的處理示意圖

    在每個(gè)管線后面接的第一個(gè)數(shù)據(jù)必定是『命令』喔!而且這個(gè)命令必須要能夠接受 standard input的數(shù)據(jù)才行,這樣的命令才可以是為『管線命令』,例如 less, more, head, tail 等都是可以接受 standard input的管線命令啦。至于例如 ls, cp, mv 等就不是管線命令了!因?yàn)?ls, cp, mv 并不會(huì)接受來(lái)自 stdin 的數(shù)據(jù)。也就是說(shuō),管線命令主要有兩個(gè)比較需要注意的地方:

    • 管線命令僅會(huì)處理 standard output,對(duì)于 standard error output 會(huì)予以忽略
    • 管線命令必須要能夠接受來(lái)自前一個(gè)命令的數(shù)據(jù)成為 standard input 繼續(xù)處理才行。

    多說(shuō)無(wú)益,讓我們來(lái)玩一些管線命令吧!底下的咚咚對(duì)系統(tǒng)管理非常有幫助喔!


    擷取命令: cut, grep

    什么是擷取命令啊?說(shuō)穿了,就是將一段數(shù)據(jù)經(jīng)過分析后,取出我們所想要的?;蛘呤墙?jīng)由分析關(guān)鍵詞,取得我們所想要的那一行!不過,要注意的是,一般來(lái)說(shuō),擷取信息通常是針對(duì)『一行一行』來(lái)分析的,并不是整篇信息分析的喔~底下我們介紹兩個(gè)很常用的信息擷取命令:


    • cut

    cut 不就是『切』嗎?沒錯(cuò)啦!這個(gè)命令可以將一段信息的某一段給他『切』出來(lái)~處理的信息是以『行』為單位喔!底下我們就來(lái)談一談:

    [root@www ~]# cut -d'分隔字符' -f fields <==用于有特定分隔字符 [root@www ~]# cut -c 字符區(qū)間 <==用于排列整齊的信息 選項(xiàng)與參數(shù): -d :后面接分隔字符。與 -f 一起使用; -f :依據(jù) -d 的分隔字符將一段信息分割成為數(shù)段,用 -f 取出第幾段的意思; -c :以字符 (characters) 的單位取出固定字符區(qū)間;范例一:將 PATH 變量取出,我要找出第五個(gè)路徑。 [root@www ~]# echo $PATH /bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games: # 1 | 2 | 3 | 4 | 5 | 6 | 7[root@www ~]# echo $PATH | cut -d ':' -f 5 # 如同上面的數(shù)字顯示,我們是以『 : 』作為分隔,因此會(huì)出現(xiàn) /usr/local/bin # 那么如果想要列出第 3 與第 5 呢?,就是這樣: [root@www ~]# echo $PATH | cut -d ':' -f 3,5范例二:將 export 輸出的信息,取得第 12 字符以后的所有字符串 [root@www ~]# export declare -x HISTSIZE="1000" declare -x INPUTRC="/etc/inputrc" declare -x KDEDIR="/usr" declare -x LANG="zh_TW.big5" .....(其他省略)..... # 注意看,每個(gè)數(shù)據(jù)都是排列整齊的輸出!如果我們不想要『 declare -x 』時(shí), # 就得這么做:[root@www ~]# export | cut -c 12- HISTSIZE="1000" INPUTRC="/etc/inputrc" KDEDIR="/usr" LANG="zh_TW.big5" .....(其他省略)..... # 知道怎么回事了吧?用 -c 可以處理比較具有格式的輸出數(shù)據(jù)! # 我們還可以指定某個(gè)范圍的值,例如第 12-20 的字符,就是 cut -c 12-20 等等! 范例三:用 last 將顯示的登陸者的信息中,僅留下用戶大名 [root@www ~]# last root pts/1 192.168.201.101 Sat Feb 7 12:35 still logged in root pts/1 192.168.201.101 Fri Feb 6 12:13 - 18:46 (06:33) root pts/1 192.168.201.254 Thu Feb 5 22:37 - 23:53 (01:16) # last 可以輸出『賬號(hào)/終端機(jī)/來(lái)源/日期時(shí)間』的數(shù)據(jù),并且是排列整齊的[root@www ~]# last | cut -d ' ' -f 1 # 由輸出的結(jié)果我們可以發(fā)現(xiàn)第一個(gè)空白分隔的字段代表賬號(hào),所以使用如上命令: # 但是因?yàn)?root pts/1 之間空格有好幾個(gè),并非僅有一個(gè),所以,如果要找出 # pts/1 其實(shí)不能以 cut -d ' ' -f 1,2 喔!輸出的結(jié)果會(huì)不是我們想要的。

    cut 主要的用途在于將『同一行里面的數(shù)據(jù)進(jìn)行分解!』最常使用在分析一些數(shù)據(jù)或文字?jǐn)?shù)據(jù)的時(shí)候!這是因?yàn)橛袝r(shí)候我們會(huì)以某些字符當(dāng)作分割的參數(shù),然后來(lái)將數(shù)據(jù)加以切割,以取得我們所需要的數(shù)據(jù)。鳥哥也很常使用這個(gè)功能呢!尤其是在分析 log 文件的時(shí)候!不過,cut 在處理多空格相連的數(shù)據(jù)時(shí),可能會(huì)比較吃力一點(diǎn)。


    • grep

    剛剛的 cut 是將一行信息當(dāng)中,取出某部分我們想要的,而 grep 則是分析一行信息,若當(dāng)中有我們所需要的信息,就將該行拿出來(lái)~簡(jiǎn)單的語(yǔ)法是這樣的:

    [root@www ~]# grep [-acinv] [--color=auto] '搜尋字符串' filename 選項(xiàng)與參數(shù): -a :將 binary 文件以 text 文件的方式搜尋數(shù)據(jù) -c :計(jì)算找到 '搜尋字符串' 的次數(shù) -i :忽略大小寫的不同,所以大小寫視為相同 -n :順便輸出行號(hào) -v :反向選擇,亦即顯示出沒有 '搜尋字符串' 內(nèi)容的那一行! --color=auto :可以將找到的關(guān)鍵詞部分加上顏色的顯示喔!范例一:將 last 當(dāng)中,有出現(xiàn) root 的那一行就取出來(lái); [root@www ~]# last | grep 'root'范例二:與范例一相反,只要沒有 root 的就取出! [root@www ~]# last | grep -v 'root'范例三:在 last 的輸出信息中,只要有 root 就取出,并且僅取第一欄 [root@www ~]# last | grep 'root' |cut -d ' ' -f1 # 在取出 root 之后,利用上個(gè)命令 cut 的處理,就能夠僅取得第一欄啰!范例四:取出 /etc/man.config 內(nèi)含 MANPATH 的那幾行 [root@www ~]# grep --color=auto 'MANPATH' /etc/man.config ....(前面省略).... MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man MANPATH_MAP /usr/bin/X11 /usr/X11R6/man MANPATH_MAP /usr/bin/mh /usr/share/man # 神奇的是,如果加上 --color=auto 的選項(xiàng),找到的關(guān)鍵詞部分會(huì)用特殊顏色顯示喔!

    grep 是個(gè)很棒的命令喔!他支持的語(yǔ)法實(shí)在是太多了~用在正規(guī)表示法里頭,能夠處理的數(shù)據(jù)實(shí)在是多的很~不過,我們這里先不談?wù)?guī)表示法~下一章再來(lái)說(shuō)明~您先了解一下, grep 可以解析一行文字,取得關(guān)鍵詞,若該行有存在關(guān)鍵詞,就會(huì)整行列出來(lái)!


    排序命令: sort, wc, uniq

    很多時(shí)候,我們都會(huì)去計(jì)算一次數(shù)據(jù)里頭的相同型態(tài)的數(shù)據(jù)總數(shù),舉例來(lái)說(shuō),使用 last 可以查得這個(gè)月份有登陸主機(jī)者的身份。那么我可以針對(duì)每個(gè)使用者查出他們的總登陸次數(shù)嗎?此時(shí)就得要排序與計(jì)算之類的命令來(lái)輔助了!底下我們介紹幾個(gè)好用的排序與統(tǒng)計(jì)命令喔!


    • sort

    sort 是很有趣的命令,他可以幫我們進(jìn)行排序,而且可以依據(jù)不同的數(shù)據(jù)型態(tài)來(lái)排序喔!例如數(shù)字與文字的排序就不一樣。此外,排序的字符與語(yǔ)系的編碼有關(guān),因此,如果您需要排序時(shí),建議使用 LANG=C 來(lái)讓語(yǔ)系統(tǒng)一,數(shù)據(jù)排序比較好一些。

    [root@www ~]# sort [-fbMnrtuk] [file or stdin] 選項(xiàng)與參數(shù): -f :忽略大小寫的差異,例如 A 與 a 視為編碼相同; -b :忽略最前面的空格符部分; -M :以月份的名字來(lái)排序,例如 JAN, DEC 等等的排序方法; -n :使用『純數(shù)字』進(jìn)行排序(默認(rèn)是以文字型態(tài)來(lái)排序的); -r :反向排序; -u :就是 uniq ,相同的數(shù)據(jù)中,僅出現(xiàn)一行代表; -t :分隔符,默認(rèn)是用 [tab] 鍵來(lái)分隔; -k :以那個(gè)區(qū)間 (field) 來(lái)進(jìn)行排序的意思范例一:個(gè)人賬號(hào)都記錄在 /etc/passwd 下,請(qǐng)將賬號(hào)進(jìn)行排序。 [root@www ~]# cat /etc/passwd | sort adm:x:3:4:adm:/var/adm:/sbin/nologin apache:x:48:48:Apache:/var/www:/sbin/nologin bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin # 鳥哥省略很多的輸出~由上面的數(shù)據(jù)看起來(lái), sort 是默認(rèn)『以第一個(gè)』數(shù)據(jù)來(lái)排序, # 而且默認(rèn)是以『文字』型態(tài)來(lái)排序的喔!所以由 a 開始排到最后啰!范例二:/etc/passwd 內(nèi)容是以 : 來(lái)分隔的,我想以第三欄來(lái)排序,該如何? [root@www ~]# cat /etc/passwd | sort -t ':' -k 3 root:x:0:0:root:/root:/bin/bash uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin bin:x:1:1:bin:/bin:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin # 看到特殊字體的輸出部分了吧?怎么會(huì)這樣排列啊?呵呵!沒錯(cuò)啦~ # 如果是以文字型態(tài)來(lái)排序的話,原本就會(huì)是這樣,想要使用數(shù)字排序: # cat /etc/passwd | sort -t ':' -k 3 -n # 這樣才行啊!用那個(gè) -n 來(lái)告知 sort 以數(shù)字來(lái)排序啊!范例三:利用 last ,將輸出的數(shù)據(jù)僅取賬號(hào),并加以排序 [root@www ~]# last | cut -d ' ' -f1 | sort

    sort 同樣是很常用的命令呢!因?yàn)槲覀兂3P枰容^一些信息啦!舉個(gè)上面的第二個(gè)例子來(lái)說(shuō)好了!今天假設(shè)你有很多的賬號(hào),而且你想要知道最大的使用者 ID 目前到哪一號(hào)了!呵呵!使用 sort 一下子就可以知道答案咯!當(dāng)然其使用還不止此啦!有空的話不妨玩一玩!


    • uniq

    如果我排序完成了,想要將重復(fù)的數(shù)據(jù)僅列出一個(gè)顯示,可以怎么做呢?

    [root@www ~]# uniq [-ic] 選項(xiàng)與參數(shù): -i :忽略大小寫字符的不同; -c :進(jìn)行計(jì)數(shù)范例一:使用 last 將賬號(hào)列出,僅取出賬號(hào)欄,進(jìn)行排序后僅取出一位; [root@www ~]# last | cut -d ' ' -f1 | sort | uniq范例二:承上題,如果我還想要知道每個(gè)人的登陸總次數(shù)呢? [root@www ~]# last | cut -d ' ' -f1 | sort | uniq -c112 reboot41 root1 wtmp # 從上面的結(jié)果可以發(fā)現(xiàn) reboot 有 12 次, root 登陸則有 41 次! # wtmp 與第一行的空白都是 last 的默認(rèn)字符,那兩個(gè)可以忽略的!

    這個(gè)命令用來(lái)將『重復(fù)的行刪除掉只顯示一個(gè)』,舉個(gè)例子來(lái)說(shuō),你要知道這個(gè)月份登陸你主機(jī)的用戶有誰(shuí),而不在乎他的登陸次數(shù),那么就使用上面的范例,(1)先將所有的數(shù)據(jù)列出;(2)再將人名獨(dú)立出來(lái);(3)經(jīng)過排序;(4)只顯示一個(gè)!由于這個(gè)命令是在將重復(fù)的東西減少,所以當(dāng)然需要『配合排序過的文件』來(lái)處理啰!


    • wc

    如果我想要知道 /etc/man.config 這個(gè)文件里面有多少字?多少行?多少字符的話,可以怎么做呢?其實(shí)可以利用 wc 這個(gè)命令來(lái)達(dá)成喔!他可以幫我們計(jì)算輸出的信息的整體數(shù)據(jù)!

    [root@www ~]# wc [-lwm] 選項(xiàng)與參數(shù): -l :僅列出行; -w :僅列出多少字(英文單字); -m :多少字符;范例一:那個(gè) /etc/man.config 里面到底有多少相關(guān)字、行、字符數(shù)? [root@www ~]# cat /etc/man.config | wc 141 722 4617 # 輸出的三個(gè)數(shù)字中,分別代表: 『行、字?jǐn)?shù)、字符數(shù)』范例二:我知道使用 last 可以輸出登陸者,但是 last 最后兩行并非賬號(hào)內(nèi)容,那么請(qǐng)問,我該如何以一行命令串取得這個(gè)月份登陸系統(tǒng)的總?cè)舜?#xff1f; [root@www ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l # 由于 last 會(huì)輸出空白行與 wtmp 字樣在最底下兩行,因此,我利用 # grep 取出非空白行,以及去除 wtmp 那一行,在計(jì)算行數(shù),就能夠了解啰!

    wc 也可以當(dāng)作命令?這可不是上洗手間的 WC 呢!這是相當(dāng)有用的計(jì)算文件內(nèi)容的一個(gè)工具組喔!舉個(gè)例子來(lái)說(shuō),當(dāng)你要知道目前你的賬號(hào)文件中有多少個(gè)賬號(hào)時(shí),就使用這個(gè)方法:『cat /etc/passwd | wc -l 』啦!因?yàn)?/etc/passwd 里頭一行代表一個(gè)使用者呀!所以知道行數(shù)就曉得有多少的賬號(hào)在里頭了!而如果要計(jì)算一個(gè)文件里頭有多少個(gè)字符時(shí),就使用wc -m 這個(gè)選項(xiàng)吧!


    雙向重導(dǎo)向: tee

    想個(gè)簡(jiǎn)單的東西,我們由前一節(jié)知道 > 會(huì)將數(shù)據(jù)流整個(gè)傳送給文件或裝置,因此我們除非去讀取該文件或裝置,否則就無(wú)法繼續(xù)利用這個(gè)數(shù)據(jù)流。萬(wàn)一我想要將這個(gè)數(shù)據(jù)流的處理過程中將某段信息存下來(lái),應(yīng)該怎么做?利用 tee 就可以啰~我們可以這樣簡(jiǎn)單的看一下:


    圖 6.3.1、tee 的工作流程示意圖

    tee 會(huì)同時(shí)將數(shù)據(jù)流分送到文件去與屏幕 (screen);而輸出到屏幕的,其實(shí)就是 stdout ,可以讓下個(gè)命令繼續(xù)處理喔!

    [root@www ~]# tee [-a] file 選項(xiàng)與參數(shù): -a :以累加 (append) 的方式,將數(shù)據(jù)加入 file 當(dāng)中![root@www ~]# last | tee last.list | cut -d " " -f1 # 這個(gè)范例可以讓我們將 last 的輸出存一份到 last.list 文件中;[root@www ~]# ls -l /home | tee ~/homefile | more # 這個(gè)范例則是將 ls 的數(shù)據(jù)存一份到 ~/homefile ,同時(shí)屏幕也有輸出信息![root@www ~]# ls -l / | tee -a ~/homefile | more # 要注意! tee 后接的文件會(huì)被覆蓋,若加上 -a 這個(gè)選項(xiàng)則能將信息累加。

    tee 可以讓 standard output 轉(zhuǎn)存一份到文件內(nèi)并將同樣的數(shù)據(jù)繼續(xù)送到屏幕去處理!這樣除了可以讓我們同時(shí)分析一份數(shù)據(jù)并記錄下來(lái)之外,還可以作為處理一份數(shù)據(jù)的中間緩存盤記錄之用!tee 這家伙在很多選擇/填充的認(rèn)證考試中很容易考呢!


    字符轉(zhuǎn)換命令: tr, col, join, paste, expand

    我們?cè)? vim 程序編輯器當(dāng)中,提到過 DOS 斷行字符與 Unix 斷行字符的不同,并且可以使用 dos2unix 與 unix2dos 來(lái)完成轉(zhuǎn)換。好了,那么思考一下,是否還有其他常用的字符替代?舉例來(lái)說(shuō),要將大寫改成小寫,或者是將數(shù)據(jù)中的 [tab] 按鍵轉(zhuǎn)成空格鍵?還有,如何將兩篇信息整合成一篇?底下我們就來(lái)介紹一下這些字符轉(zhuǎn)換命令在管線當(dāng)中的使用方法:


    • tr

    tr 可以用來(lái)刪除一段信息當(dāng)中的文字,或者是進(jìn)行文字信息的替換!

    [root@www ~]# tr [-ds] SET1 ... 選項(xiàng)與參數(shù): -d :刪除信息當(dāng)中的 SET1 這個(gè)字符串; -s :取代掉重復(fù)的字符!范例一:將 last 輸出的信息中,所有的小寫變成大寫字符: [root@www ~]# last | tr '[a-z]' '[A-Z]' # 事實(shí)上,沒有加上單引號(hào)也是可以運(yùn)行的,如:『 last | tr [a-z] [A-Z] 』范例二:將 /etc/passwd 輸出的信息中,將冒號(hào) (:) 刪除 [root@www ~]# cat /etc/passwd | tr -d ':'范例三:將 /etc/passwd 轉(zhuǎn)存成 dos 斷行到 /root/passwd 中,再將 ^M 符號(hào)刪除 [root@www ~]# cp /etc/passwd /root/passwd && unix2dos /root/passwd [root@www ~]# file /etc/passwd /root/passwd /etc/passwd: ASCII text /root/passwd: ASCII text, with CRLF line terminators <==就是 DOS 斷行 [root@www ~]# cat /root/passwd | tr -d '\r' > /root/passwd.linux # 那個(gè) \r 指的是 DOS 的斷行字符,關(guān)于更多的字符,請(qǐng)參考 man tr [root@www ~]# ll /etc/passwd /root/passwd* -rw-r--r-- 1 root root 1986 Feb 6 17:55 /etc/passwd -rw-r--r-- 1 root root 2030 Feb 7 15:55 /root/passwd -rw-r--r-- 1 root root 1986 Feb 7 15:57 /root/passwd.linux # 處理過后,發(fā)現(xiàn)文件大小與原本的 /etc/passwd 就一致了!

    其實(shí)這個(gè)命令也可以寫在『正規(guī)表示法』里頭!因?yàn)樗彩怯烧?guī)表示法的方式來(lái)取代數(shù)據(jù)的!以上面的例子來(lái)說(shuō),使用 [] 可以配置一串字呢!也常常用來(lái)取代文件中的怪異符號(hào)!例如上面第三個(gè)例子當(dāng)中,可以去除 DOS 文件留下來(lái)的 ^M 這個(gè)斷行的符號(hào)!這東西相當(dāng)?shù)挠杏?#xff01;相信處理 Linux &Windows 系統(tǒng)中的人們最麻煩的一件事就是這個(gè)事情啦!亦即是 DOS 底下會(huì)自動(dòng)的在每行行尾加入^M 這個(gè)斷行符號(hào)!這個(gè)時(shí)候我們可以使用這個(gè) tr 來(lái)將 ^M 去除! ^M 可以使用\r 來(lái)代替之!


    • col
    [root@www ~]# col [-xb] 選項(xiàng)與參數(shù): -x :將 tab 鍵轉(zhuǎn)換成對(duì)等的空格鍵 -b :在文字內(nèi)有反斜杠 (/) 時(shí),僅保留反斜杠最后接的那個(gè)字符范例一:利用 cat -A 顯示出所有特殊按鍵,最后以 col 將 [tab] 轉(zhuǎn)成空白 [root@www ~]# cat -A /etc/man.config <==此時(shí)會(huì)看到很多 ^I 的符號(hào),那就是 tab [root@www ~]# cat /etc/man.config | col -x | cat -A | more # 嘿嘿!如此一來(lái), [tab] 按鍵會(huì)被取代成為空格鍵,輸出就美觀多了!范例二:將 col 的 man page 轉(zhuǎn)存成為 /root/col.man 的純文本檔 [root@www ~]# man col > /root/col.man [root@www ~]# vi /root/col.man COL(1) BSD General Commands Manual COL(1)N^HNA^HAM^HME^HEc^Hco^Hol^Hl - filter reverse line feeds from inputS^HSY^HYN^HNO^HOP^HPS^HSI^HIS^HSc^Hco^Hol^Hl [-^H-b^Hbf^Hfp^Hpx^Hx] [-^H-l^Hl _^Hn_^Hu_^Hm] # 你沒看錯(cuò)!由于 man page 內(nèi)有些特殊按鈕會(huì)用來(lái)作為類似特殊按鍵與顏色顯示, # 所以這個(gè)文件內(nèi)就會(huì)出現(xiàn)如上所示的一堆怪異字符(有 ^ 的)[root@www ~]# man col | col -b > /root/col.man

    雖然 col 有他特殊的用途,不過,很多時(shí)候,他可以用來(lái)簡(jiǎn)單的處理將 [tab] 按鍵取代成為空格鍵!例如上面的例子當(dāng)中,如果使用 cat -A 則 [tab] 會(huì)以 ^I 來(lái)表示。但經(jīng)過 col -x 的處理,則會(huì)將 [tab] 取代成為對(duì)等的空格鍵!此外,col 經(jīng)常被利用于將 man page轉(zhuǎn)存為純文本文件以方便查閱的功能!如上述的范例二!


    • join

    join 看字面上的意義 (加入/參加) 就可以知道,他是在處理兩個(gè)文件之間的數(shù)據(jù),而且,主要是在處理『兩個(gè)文件當(dāng)中,有"相同數(shù)據(jù)" 的那一行,才將他加在一起』的意思。我們利用底下的簡(jiǎn)單例子來(lái)說(shuō)明:

    [root@www ~]# join [-ti12] file1 file2 選項(xiàng)與參數(shù): -t :join 默認(rèn)以空格符分隔數(shù)據(jù),并且比對(duì)『第一個(gè)字段』的數(shù)據(jù),如果兩個(gè)文件相同,則將兩筆數(shù)據(jù)聯(lián)成一行,且第一個(gè)字段放在第一個(gè)! -i :忽略大小寫的差異; -1 :這個(gè)是數(shù)字的 1 ,代表『第一個(gè)文件要用那個(gè)字段來(lái)分析』的意思; -2 :代表『第二個(gè)文件要用那個(gè)字段來(lái)分析』的意思。范例一:用 root 的身份,將 /etc/passwd 與 /etc/shadow 相關(guān)數(shù)據(jù)整合成一欄 [root@www ~]# head -n 3 /etc/passwd /etc/shadow ==> /etc/passwd <== root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin==> /etc/shadow <== root:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7::: bin:*:14126:0:99999:7::: daemon:*:14126:0:99999:7::: # 由輸出的數(shù)據(jù)可以發(fā)現(xiàn)這兩個(gè)文件的最左邊字段都是賬號(hào)!且以 : 分隔[root@www ~]# join -t ':' /etc/passwd /etc/shadow root:x:0:0:root:/root:/bin/bash:$1$/3AQpE5e$y9A/D0bh6rElAs:14120:0:99999:7::: bin:x:1:1:bin:/bin:/sbin/nologin:*:14126:0:99999:7::: daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:14126:0:99999:7::: # 透過上面這個(gè)動(dòng)作,我們可以將兩個(gè)文件第一字段相同者整合成一行! # 第二個(gè)文件的相同字段并不會(huì)顯示(因?yàn)橐呀?jīng)在第一行了嘛!)范例二:我們知道 /etc/passwd 第四個(gè)字段是 GID ,那個(gè) GID 記錄在 /etc/group 當(dāng)中的第三個(gè)字段,請(qǐng)問如何將兩個(gè)文件整合? [root@www ~]# head -n 3 /etc/passwd /etc/group ==> /etc/passwd <== root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin==> /etc/group <== root:x:0:root bin:x:1:root,bin,daemon daemon:x:2:root,bin,daemon # 從上面可以看到,確實(shí)有相同的部分喔!趕緊來(lái)整合一下![root@www ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group 0:root:x:0:root:/root:/bin/bash:root:x:root 1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:root,bin,daemon 2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:root,bin,daemon # 同樣的,相同的字段部分被移動(dòng)到最前面了!所以第二個(gè)文件的內(nèi)容就沒再顯示。 # 請(qǐng)讀者們配合上述顯示兩個(gè)文件的實(shí)際內(nèi)容來(lái)比對(duì)!

    這個(gè) join 在處理兩個(gè)相關(guān)的數(shù)據(jù)文件時(shí),就真的是很有幫助的啦!例如上面的案例當(dāng)中,我的 /etc/passwd, /etc/shadow, /etc/group 都是有相關(guān)性的,其中 /etc/passwd, /etc/shadow 以賬號(hào)為相關(guān)性,至于 /etc/passwd, /etc/group 則以所謂的 GID (賬號(hào)的數(shù)字定義) 來(lái)作為他的相關(guān)性。根據(jù)這個(gè)相關(guān)性,我們可以將有關(guān)系的數(shù)據(jù)放置在一起!這在處理數(shù)據(jù)可是相當(dāng)有幫助的!但是上面的例子有點(diǎn)難,希望您可以靜下心好好的看一看原因喔!

    此外,需要特別注意的是,在使用 join 之前,你所需要處理的文件應(yīng)該要事先經(jīng)過排序 (sort) 處理!否則有些比對(duì)的項(xiàng)目會(huì)被略過呢!特別注意了!


    • paste

    這個(gè) paste 就要比 join 簡(jiǎn)單多了!相對(duì)于 join 必須要比對(duì)兩個(gè)文件的數(shù)據(jù)相關(guān)性,paste 就直接『將兩行貼在一起,且中間以 [tab] 鍵隔開』而已!簡(jiǎn)單的使用方法:

    [root@www ~]# paste [-d] file1 file2 選項(xiàng)與參數(shù): -d :后面可以接分隔字符。默認(rèn)是以 [tab] 來(lái)分隔的! - :如果 file 部分寫成 - ,表示來(lái)自 standard input 的數(shù)據(jù)的意思。范例一:將 /etc/passwd 與 /etc/shadow 同一行貼在一起 [root@www ~]# paste /etc/passwd /etc/shadow bin:x:1:1:bin:/bin:/sbin/nologin bin:*:14126:0:99999:7::: daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:14126:0:99999:7::: adm:x:3:4:adm:/var/adm:/sbin/nologin adm:*:14126:0:99999:7::: # 注意喔!同一行中間是以 [tab] 按鍵隔開的!范例二:先將 /etc/group 讀出(用 cat),然后與范例一貼上一起!且僅取出前三行 [root@www ~]# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3 # 這個(gè)例子的重點(diǎn)在那個(gè) - 的使用!那玩意兒常常代表 stdin 喔!


    • expand

    這玩意兒就是在將 [tab] 按鍵轉(zhuǎn)成空格鍵啦~可以這樣玩:

    [root@www ~]# expand [-t] file 選項(xiàng)與參數(shù): -t :后面可以接數(shù)字。一般來(lái)說(shuō),一個(gè) tab 按鍵可以用 8 個(gè)空格鍵取代。我們也可以自行定義一個(gè) [tab] 按鍵代表多少個(gè)字符呢!范例一:將 /etc/man.config 內(nèi)行首為 MANPATH 的字樣就取出;僅取前三行; [root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 MANPATH /usr/man MANPATH /usr/share/man MANPATH /usr/local/man # 行首的代表標(biāo)志為 ^ ,這個(gè)我們留待下節(jié)介紹!先有概念即可!范例二:承上,如果我想要將所有的符號(hào)都列出來(lái)?(用 cat) [root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 |cat -A MANPATH^I/usr/man$ MANPATH^I/usr/share/man$ MANPATH^I/usr/local/man$ # 發(fā)現(xiàn)差別了嗎?沒錯(cuò)~ [tab] 按鍵可以被 cat -A 顯示成為 ^I 范例三:承上,我將 [tab] 按鍵配置成 6 個(gè)字符的話? [root@www ~]# grep '^MANPATH' /etc/man.config | head -n 3 | \ > expand -t 6 - | cat -A MANPATH /usr/man$ MANPATH /usr/share/man$ MANPATH /usr/local/man$ 123456123456123456..... # 仔細(xì)看一下上面的數(shù)字說(shuō)明,因?yàn)槲沂且?6 個(gè)字符來(lái)代表一個(gè) [tab] 的長(zhǎng)度,所以, # MAN... 到 /usr 之間會(huì)隔 12 (兩個(gè) [tab]) 個(gè)字符喔!如果 tab 改成 9 的話, # 情況就又不同了!這里也不好理解~您可以多配置幾個(gè)數(shù)字來(lái)查閱就曉得!

    expand 也是挺好玩的~他會(huì)自動(dòng)將 [tab] 轉(zhuǎn)成空格鍵~所以,以上面的例子來(lái)說(shuō),使用 cat -A 就會(huì)查不到 ^I 的字符啰~此外,因?yàn)?[tab] 最大的功能就是格式排列整齊!我們轉(zhuǎn)成空格鍵后,這個(gè)空格鍵也會(huì)依據(jù)我們自己的定義來(lái)添加大小~所以,并不是一個(gè) ^I 就會(huì)換成 8 個(gè)空白喔!這個(gè)地方要特別注意的哩!此外,您也可以參考一下 unexpand 這個(gè)將空白轉(zhuǎn)成 [tab] 的命令功能啊! ^_^


    分割命令: split

    如果你有文件太大,導(dǎo)致一些攜帶式裝置無(wú)法復(fù)制的問題,嘿嘿!找 split 就對(duì)了!他可以幫你將一個(gè)大文件,依據(jù)文件大小或行數(shù)來(lái)分割,就可以將大文件分割成為小文件了!快速又有效啊!真不錯(cuò)~

    [root@www ~]# split [-bl] file PREFIX 選項(xiàng)與參數(shù): -b :后面可接欲分割成的文件大小,可加單位,例如 b, k, m 等; -l :以行數(shù)來(lái)進(jìn)行分割。 PREFIX :代表前導(dǎo)符的意思,可作為分割文件的前導(dǎo)文字。范例一:我的 /etc/termcap 有七百多K,若想要分成 300K 一個(gè)文件時(shí)? [root@www ~]# cd /tmp; split -b 300k /etc/termcap termcap [root@www tmp]# ll -k termcap* -rw-r--r-- 1 root root 300 Feb 7 16:39 termcapaa -rw-r--r-- 1 root root 300 Feb 7 16:39 termcapab -rw-r--r-- 1 root root 189 Feb 7 16:39 termcapac # 那個(gè)檔名可以隨意取的啦!我們只要寫上前導(dǎo)文字,小文件就會(huì)以 # xxxaa, xxxab, xxxac 等方式來(lái)創(chuàng)建小文件的!范例二:如何將上面的三個(gè)小文件合成一個(gè)文件,檔名為 termcapback [root@www tmp]# cat termcap* >> termcapback # 很簡(jiǎn)單吧?就用數(shù)據(jù)流重導(dǎo)向就好啦!簡(jiǎn)單!范例三:使用 ls -al / 輸出的信息中,每十行記錄成一個(gè)文件 [root@www tmp]# ls -al / | split -l 10 - lsroot [root@www tmp]# wc -l lsroot*10 lsrootaa10 lsrootab6 lsrootac26 total # 重點(diǎn)在那個(gè) - 啦!一般來(lái)說(shuō),如果需要 stdout/stdin 時(shí),但偏偏又沒有文件, # 有的只是 - 時(shí),那么那個(gè) - 就會(huì)被當(dāng)成 stdin 或 stdout ~

    在 Windows 操作系統(tǒng)下,你要將文件分割需要如何作?傷腦筋吧!在 Linux 底下就簡(jiǎn)單的多了!你要將文件分割的話,那么就使用 -b size 來(lái)將一個(gè)分割的文件限制其大小,如果是行數(shù)的話,那么就使用-l line 來(lái)分割!好用的很!如此一來(lái),你就可以輕易的將你的文件分割成軟盤 (floppy)的大小,方便你 copy 啰!


    參數(shù)代換: xargs

    xargs 是在做什么的呢?就以字面上的意義來(lái)看, x 是加減乘除的乘號(hào),args 則是 arguments (參數(shù))的意思,所以說(shuō),這個(gè)玩意兒就是在產(chǎn)生某個(gè)命令的參數(shù)的意思!xargs 可以讀入 stdin 的數(shù)據(jù),并且以空格符或斷行字符作為分辨,將 stdin 的數(shù)據(jù)分隔成為 arguments 。因?yàn)槭且钥崭穹鳛榉指?#xff0c;所以,如果有一些檔名或者是其他意義的名詞內(nèi)含有空格符的時(shí)候,xargs 可能就會(huì)誤判了~他的用法其實(shí)也還滿簡(jiǎn)單的!就來(lái)看一看先!

    [root@www ~]# xargs [-0epn] command 選項(xiàng)與參數(shù): -0 :如果輸入的 stdin 含有特殊字符,例如 `, \, 空格鍵等等字符時(shí),這個(gè) -0 參數(shù)可以將他還原成一般字符。這個(gè)參數(shù)可以用于特殊狀態(tài)喔! -e :這個(gè)是 EOF (end of file) 的意思。后面可以接一個(gè)字符串,當(dāng) xargs 分析到這個(gè)字符串時(shí),就會(huì)停止繼續(xù)工作! -p :在運(yùn)行每個(gè)命令的 argument 時(shí),都會(huì)詢問使用者的意思; -n :后面接次數(shù),每次 command 命令運(yùn)行時(shí),要使用幾個(gè)參數(shù)的意思??捶独?。 當(dāng) xargs 后面沒有接任何的命令時(shí),默認(rèn)是以 echo 來(lái)進(jìn)行輸出喔!范例一:將 /etc/passwd 內(nèi)的第一欄取出,僅取三行,使用 finger 這個(gè)命令將每個(gè)賬號(hào)內(nèi)容秀出來(lái) [root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs finger Login: root Name: root Directory: /root Shell: /bin/bash Never logged in. No mail. No Plan. ......底下省略..... # 由 finger account 可以取得該賬號(hào)的相關(guān)說(shuō)明內(nèi)容,例如上面的輸出就是 finger root # 后的結(jié)果。在這個(gè)例子當(dāng)中,我們利用 cut 取出賬號(hào)名稱,用 head 取出三個(gè)賬號(hào), # 最后則是由 xargs 將三個(gè)賬號(hào)的名稱變成 finger 后面需要的參數(shù)!范例二:同上,但是每次運(yùn)行 finger 時(shí),都要詢問使用者是否動(dòng)作? [root@www ~]# cut -d':' -f1 /etc/passwd |head -n 3| xargs -p finger finger root bin daemon ?...y .....(底下省略).... # 呵呵!這個(gè) -p 的選項(xiàng)可以讓用戶的使用過程中,被詢問到每個(gè)命令是否運(yùn)行!范例三:將所有的 /etc/passwd 內(nèi)的賬號(hào)都以 finger 查閱,但一次僅查閱五個(gè)賬號(hào) [root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -n 5 finger finger root bin daemon adm lp ?...y .....(中間省略).... finger uucp operator games gopher ftp ?...y .....(底下省略).... # 在這里鳥哥使用了 -p 這個(gè)參數(shù)來(lái)讓您對(duì)于 -n 更有概念。一般來(lái)說(shuō),某些命令后面 # 可以接的 arguments 是有限制的,不能無(wú)限制的累加,此時(shí),我們可以利用 -n # 來(lái)幫助我們將參數(shù)分成數(shù)個(gè)部分,每個(gè)部分分別再以命令來(lái)運(yùn)行!這樣就 OK 啦!^_^范例四:同上,但是當(dāng)分析到 lp 就結(jié)束這串命令? [root@www ~]# cut -d':' -f1 /etc/passwd | xargs -p -e'lp' finger finger root bin daemon adm ?... # 仔細(xì)與上面的案例做比較。也同時(shí)注意,那個(gè) -e'lp' 是連在一起的,中間沒有空格鍵。 # 上個(gè)例子當(dāng)中,第五個(gè)參數(shù)是 lp 啊,那么我們下達(dá) -e'lp' 后,則分析到 lp # 這個(gè)字符串時(shí),后面的其他 stdin 的內(nèi)容就會(huì)被 xargs 舍棄掉了!

    其實(shí),在 man xargs 里面就有三四個(gè)小范例,您可以自行參考一下內(nèi)容。此外, xargs 真的是很好用的一個(gè)玩意兒!您真的需要好好的參詳參詳!會(huì)使用 xargs 的原因是,很多命令其實(shí)并不支持管線命令,因此我們可以透過 xargs 來(lái)提供該命令引用 standard input 之用!舉例來(lái)說(shuō),我們使用如下的范例來(lái)說(shuō)明:

    范例五:找出 /sbin 底下具有特殊權(quán)限的檔名,并使用 ls -l 列出詳細(xì)屬性 [root@www ~]# find /sbin -perm +7000 | ls -l # 結(jié)果竟然僅有列出 root 所在目錄下的文件!這不是我們要的! # 因?yàn)?ll (ls) 并不是管線命令的原因啊![root@www ~]# find /sbin -perm +7000 | xargs ls -l -rwsr-xr-x 1 root root 70420 May 25 2008 /sbin/mount.nfs -rwsr-xr-x 1 root root 70424 May 25 2008 /sbin/mount.nfs4 -rwxr-sr-x 1 root root 5920 Jun 15 2008 /sbin/netreport ....(底下省略)....

    關(guān)于減號(hào) - 的用途

    管線命令在 bash 的連續(xù)的處理程序中是相當(dāng)重要的!另外,在 log file 的分析當(dāng)中也是相當(dāng)重要的一環(huán),所以請(qǐng)?zhí)貏e留意!另外,在管線命令當(dāng)中,常常會(huì)使用到前一個(gè)命令的 stdout 作為這次的 stdin ,某些命令需要用到文件名 (例如 tar) 來(lái)進(jìn)行處理時(shí),該 stdin 與 stdout 可以利用減號(hào) "-" 來(lái)替代,舉例來(lái)說(shuō):

    [root@www ~]# tar -cvf - /home | tar -xvf -

    上面這個(gè)例子是說(shuō):『我將 /home 里面的文件給他打包,但打包的數(shù)據(jù)不是紀(jì)錄到文件,而是傳送到 stdout;經(jīng)過管線后,將 tar -cvf - /home 傳送給后面的 tar -xvf - 』。后面的這個(gè) - 則是取用前一個(gè)命令的 stdout,因此,我們就不需要使用 file 了!這是很常見的例子喔!注意注意!


    重點(diǎn)回顧
    • 由于核心在內(nèi)存中是受保護(hù)的區(qū)塊,因此我們必須要透過『 Shell 』將我們輸入的命令與 Kernel 溝通,好讓 Kernel 可以控制硬件來(lái)正確無(wú)誤的工作
    • 學(xué)習(xí) shell 的原因主要有:文字接口的 shell 在各大 distribution 都一樣;遠(yuǎn)程管理時(shí)文字接口速度較快;shell 是管理 Linux 系統(tǒng)非常重要的一環(huán),因?yàn)?Linux 內(nèi)很多控制都是以 shell 撰寫的。
    • 系統(tǒng)合法的 shell 均寫在 /etc/shells 文件中;
    • 用戶默認(rèn)登陸取得的 shell 記錄于 /etc/passwd 的最后一個(gè)字段;
    • bash 的功能主要有:命令編修能力;命令與文件補(bǔ)全功能;命令別名配置功能;工作控制、前景背景控制;程序化腳本;通配符
    • type 可以用來(lái)找到運(yùn)行命令為何種類型,亦可用于與 which 相同的功能;
    • 變量就是以一組文字或符號(hào)等,來(lái)取代一些配置或者是一串保留的數(shù)據(jù)
    • 變量主要有環(huán)境變量與自定義變量,或稱為全局變量與局部變量
    • 使用 env 與 export 可觀察環(huán)境變量,其中 export 可以將自定義變量轉(zhuǎn)成環(huán)境變量;
    • set 可以觀察目前 bash 環(huán)境下的所有變量;
    • $? 亦為變量,是前一個(gè)命令運(yùn)行完畢后的回傳值。在 Linux 回傳值為 0 代表運(yùn)行成功;
    • locale 可用于觀察語(yǔ)系數(shù)據(jù);
    • 可用 read 讓用戶由鍵盤輸入變量的值
    • ulimit 可用以限制用戶使用系統(tǒng)的資源情況
    • bash 的配置文件主要分為 login shell 與 non-login shell。login shell 主要讀取 /etc/profile 與 ~/.bash_profile,non-login shell 則僅讀取 ~/.bashrc
    • 通配符主要有: *, ?, [] 等等
    • 數(shù)據(jù)流重導(dǎo)向透過 >, 2>, < 之類的符號(hào)將輸出的信息轉(zhuǎn)到其他文件或裝置去;
    • 連續(xù)命令的下達(dá)可透過 ; && || 等符號(hào)來(lái)處理
    • 管線命令的重點(diǎn)是:『管線命令僅會(huì)處理 standard output,對(duì)于 standard error output 會(huì)予以忽略』『管線命令必須要能夠接受來(lái)自前一個(gè)命令的數(shù)據(jù)成為 standard input 繼續(xù)處理才行?!?/li>
    • 本章介紹的管線命令主要有:cut, grep, sort, wc, uniq, tee, tr, col, join, paste, expand, split, xargs 等。

    本章習(xí)題
    ( 要看答案請(qǐng)將鼠標(biāo)移動(dòng)到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )
    • 情境模擬題一:由于 ~/.bash_history 僅能記錄命令,我想要在每次注銷時(shí)都記錄時(shí)間,并將后續(xù)的命令 50 筆記錄下來(lái),可以如何處理?

      • 目標(biāo):了解 history ,并透過數(shù)據(jù)流重導(dǎo)向的方式記錄歷史命令;
      • 前提:需要了解本章的數(shù)據(jù)流重導(dǎo)向,以及了解 bash 的各個(gè)環(huán)境配置文件信息。

      其實(shí)處理的方式非常簡(jiǎn)單,我們可以了解 date 可以輸出時(shí)間,而利用 ~/.myhistory 來(lái)記錄所有歷史記錄,而目前最新的 50 筆歷史記錄可以使用 history 50 來(lái)顯示,故可以修改 ~/.bash_logout 成為底下的模樣:
      [root@www ~]# vim ~/.bash_logout date >> ~/.myhistory history 50 > > ~/.myhistory clear


    簡(jiǎn)答題部分:
    • 在 Linux 上可以找到哪些 shell(舉出三個(gè)) ?那個(gè)文件記錄可用的 shell ?而 Linux 默認(rèn)的 shell 是? 1) /bin/bash, /bin/tcsh, /bin/csh
      2) /etc/shells
      3) bash ,亦即是 /bin/bash。
    • 在 shell 環(huán)境下,有個(gè)提示字符 (prompt),他可以修改嗎?要改什么?默認(rèn)的提示字符內(nèi)容是? 可以修改的,改 PS1 這個(gè)變量,這個(gè) PS1 變量的默認(rèn)內(nèi)容為:『[\u@\h \W]\$』
    • 如何顯示 HOME 這個(gè)環(huán)境變量? echo $HOME
    • 如何得知目前的所有變量與環(huán)境變量的配置值? 環(huán)境變量用 env 或 export 而所有變量用 set 即可顯示
    • 我是否可以配置一個(gè)變量名稱為 3myhome ? 不行!變量不能以數(shù)字做為開頭,參考變量配置守則的內(nèi)容
    • 在這樣的練習(xí)中『A=B』且『B=C』,若我下達(dá)『unset $A』,則取消的變量是 A 還是 B? 被取消的是 B 喔,因?yàn)?unset $A 相當(dāng)于 unset B 所以取消的是 B ,A 會(huì)繼續(xù)存在!
    • 如何取消變量與命令別名的內(nèi)容? 使用 unset 及 unalias 即可
    • 如何配置一個(gè)變量名稱為 name 內(nèi)容為 It's my name ? name=It\'s\ my\ name 或 name="It's my name"
    • bash 環(huán)境配置文件主要分為哪兩種類型的讀取?分別讀取哪些重要文件? (1)login shell:主要讀取 /etc/profile 及 ~/.bash_profile
      (2)non-logni shell:主要讀取 ~/.bashrc 而已。
    • CentOS 5.x 的 man page 的路徑配置文件案? /etc/man.config
    • 試說(shuō)明 ', ", 與 ` 這些符號(hào)在變量定義中的用途? 參考變量守則那一章節(jié),其中, " 可以具有變量的上下文屬性,' 則僅有一般字符,至于 ` 之內(nèi)則是可先被運(yùn)行的命令。
    • 跳脫符號(hào) \ 有什么用途? 可以用來(lái)跳脫特殊字符,例如 Enter, $ 等等,使成為一般字符!
    • 連續(xù)命令中, ;, &&, || 有何不同? 分號(hào)可以讓兩個(gè) command 連續(xù)運(yùn)行,不考慮 command1的輸出狀態(tài), && 則前一個(gè)命令必需要沒有錯(cuò)誤信息,亦即回傳值需為0 則 command2 才會(huì)被運(yùn)行, || 則與 && 相反!
    • 如何將 last 的結(jié)果中,獨(dú)立出賬號(hào),并且印出曾經(jīng)登陸過的賬號(hào)? last | cut -d ' ' -f1 | sort | uniq
    • 請(qǐng)問 foo1 && foo2 | foo3 > foo4 ,這個(gè)命令串當(dāng)中, foo1/foo2/foo3/foo4 是命令還是文件?整串命令的意義為? foo1, foo2 與 foo3 都是命令, foo4 是裝置或文件。整串命令意義為:
      (1)當(dāng) foo1 運(yùn)行結(jié)果有錯(cuò)誤時(shí),則該命令串結(jié)束;
      (2)若 foo1 運(yùn)行結(jié)果沒有錯(cuò)誤時(shí),則運(yùn)行 foo2 | foo3 > foo4 ;其中:
      (2-1)foo2 將 stdout 輸出的結(jié)果傳給 foo3 處理;
      (2-2)foo3 將來(lái)自 foo2 的 stdout 當(dāng)成 stdin ,處理完后將數(shù)據(jù)流重新導(dǎo)向 foo4 這個(gè)裝置/文件
    • 如何秀出在 /bin 底下任何以 a 為開頭的文件文件名的詳細(xì)數(shù)據(jù)? ls -l /bin/a*
    • 如何秀出 /bin 底下,文件名為四個(gè)字符的文件? ls -l /bin/????
    • 如何秀出 /bin 底下,檔名開頭不是 a-d 的文件? ls -l /bin/[^a-d]*
    • 我想要讓終端機(jī)接口的登陸提示字符修改成我自己喜好的模樣,應(yīng)該要改哪里?(filename) /etc/issue
    • 承上題,如果我是想要讓使用者登陸后,才顯示歡迎信息,又應(yīng)該要改哪里? /etc/motd

    參考數(shù)據(jù)與延伸閱讀
    • 注1:Webmin 的官方網(wǎng)站:http://www.webmin.com/
    • 注2:關(guān)于 shell 的相關(guān)歷史可以參考網(wǎng)絡(luò)農(nóng)夫兄所整理的優(yōu)秀文章。不過由于網(wǎng)絡(luò)農(nóng)夫兄所建置的網(wǎng)站暫時(shí)關(guān)閉,因此底下的鏈接為鳥哥到網(wǎng)絡(luò)上找到的片段文章連結(jié)。若有任何侵權(quán)事宜,請(qǐng)來(lái)信告知,謝謝:
      http://linux.vbird.org/linux_basic/0320bash/csh/
    • 注3:使用 man bash,再以 PS1 為關(guān)鍵詞去查詢,按下數(shù)次 n 往后查詢后,可以得到 PS1 的變量說(shuō)明。
    • 注4:i18n 是由一些 Linux distribution 貢獻(xiàn)者共同發(fā)起的大型計(jì)劃,目的在于讓眾多的 Linuxdistributions 能夠有良好的萬(wàn)國(guó)碼 (Unicode) 語(yǔ)系的支持。詳細(xì)的數(shù)據(jù)可以參考:
      i18n 的官方網(wǎng)站:http://www.openi18n.org/
      康橋大學(xué) Dr Markus Kuhn 的文獻(xiàn):http://www.cl.cam.ac.uk/~mgk25/unicode.html
      Debian 社群所寫的文件:http://www.debian.org/doc/manuals/intro-i18n/
    • 臥龍小三的教學(xué)文件:http://linux.tnc.edu.tw/techdoc/shell/book1.html
    • GNU 計(jì)劃的 BASH 說(shuō)明:http://www.gnu.org/manual/bash-2.05a/html_mono/bashref.html
      鳥哥的備份:http://linux.vbird.org/linux_basic/0320bash/0320bash_reference.php
    • man bash

    2002/06/27:第一次完成
    2003/02/10:重新編排與加入 FAQ
    2005/08/17:將舊的數(shù)據(jù)放置到 這里
    2005/08/17:終于稍微搞定了~花了半個(gè)多月不眠不休~呼~補(bǔ)充了較多的管線命令與數(shù)據(jù)流重導(dǎo)向!
    2005/08/18:加入額外的變量配置部分!
    2005/08/30:加入了 login 與 non-login shell 的簡(jiǎn)單說(shuō)明!
    2006/03/19:原先在 col 的說(shuō)明當(dāng)中,原本命令『cat -A /etc/man.config | col -x | cat -A | more』不該有 -A!
    2006/10/05:感謝小州兄的告知,修正了原本 ~/.bashrc 說(shuō)明當(dāng)中的錯(cuò)誤。
    2007/04/05:原本的 cut 范例說(shuō)明有誤,原本是『我要找出第三個(gè)』應(yīng)該改為『我要找出第五個(gè)』才對(duì)!
    2007/04/11:原本的 join 說(shuō)明沒有加上排序,應(yīng)該需要排序后再處理才對(duì)!
    2007/07/15:原本的額外的變量菜單格有誤,在 var=${str+expr} 與var=${str:+expr} 需要修改,請(qǐng)參考 此處
    2009/01/13:將原本基于 FC4 寫作的舊文章移動(dòng)到此處
    2009/02/03:拿掉了原本的『變量的用途』部分,改以案例說(shuō)明
    2009/02/05:多加了變量刪除、取代與替代部分的范例,看起來(lái)應(yīng)該不會(huì)像前一版那樣不容易理解!
    2009/08/25:加入了情境模擬,并且進(jìn)行一些說(shuō)明的細(xì)部修改而已。

    2010/04/16:感謝wenyenyang兄的告知, wc -c 錯(cuò)誤,是wc -m 才是!

    出處:http://vbird.dic.ksu.edu.tw/linux_basic/0320bash.php

    總結(jié)

    以上是生活随笔為你收集整理的鸟哥的Linux私房菜(基础篇)- 第十一章、认识与学习 BASH的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。