消防a0图纸尺寸设计中H,V,D,F都代表哪种线

设计图纸上各种符号的意义_百度文库
赠送免券下载特权
10W篇文档免费专享
部分付费文档8折起
每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
设计图纸上各种符号的意义
&&钢筋、水电图纸上相关符号的意义
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩4页未读,
定制HR最喜欢的简历
你可能喜欢戴A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z罩杯的女性胸部到底有多大?(附明星图片)
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。鳥哥的 Linux 私房菜
底下尚未更新
第十章、認識與學習BASH
最近更新日期:
在 Linux 的環境下,如果你不懂 bash 是什麼,那麼其他的東西就不用學了!因為前面幾章我們使用終端機下達指令的方式,
就是透過 bash 的環境來處理的喔!所以說,他很重要吧!bash 的東西非常的多,包括變數的設定與使用、
bash 操作環境的建置、資料流重導向的功能,還有那好用的管線命令!好好清一清腦門,準備用功去囉~ ^_^
這個章節幾乎是所有指令列模式 (command line) 與未來主機維護與管理的重要基礎,一定要好好仔細的閱讀喔!
10.1 認識 BASH 這個 Shell
我們在當中提到了:
管理整個電腦硬體的其實是作業系統的核心 (kernel),這個核心是需要被保護的!
所以我們一般使用者就只能透過 shell 來跟核心溝通,以讓核心達到我們所想要達到的工作。
那麼系統有多少 shell 可用呢?為什麼我們要使用 bash 啊?底下分別來談一談喔!
10.1.1 硬體、核心與 Shell
這應該是個蠻有趣的話題:『什麼是 Shell 』?相信只要摸過電腦,對於作業系統 (不論是 Linux 、 Unix 或者是 Windows)
有點概念的朋友們大多聽過這個名詞,因為只要有『作業系統』那麼就離不開
Shell 這個東西。不過,在討論 Shell 之前,我們先來瞭解一下電腦的運作狀況吧!
舉個例子來說:當你要電腦傳輸出來『音樂』的時候,你的電腦需要什麼東西呢?
硬體:當然就是需要你的硬體有『音效卡晶片』這個配備,否則怎麼會有聲音;
核心管理:作業系統的核心可以支援這個晶片組,當然還需要提供晶片的驅動程式囉;
應用程式:需要使用者 (就是你) 輸入發生聲音的指令囉!
這就是基本的一個輸出聲音所需要的步驟!也就是說,你必須要『輸入』一個指令之後,
『硬體』才會透過你下達的指令來工作!那麼硬體如何知道你下達的指令呢?那就是
kernel (核心) 的控制工作了!也就是說,我們必須要透過『
Shell 』將我們輸入的指令與 Kernel 溝通,好讓 Kernel 可以控制硬體來正確無誤的工作!
基本上,我們可以透過底下這張圖來說明一下:
圖10.1.1、硬體、核心與使用者的相關性圖示
我們在曾經提到過,
作業系統其實是一組軟體,由於這組軟體在控制整個硬體與管理系統的活動監測,
如果這組軟體能被使用者隨意的操作,若使用者應用不當,將會使得整個系統崩潰!因為作業系統管理的就是整個硬體功能嘛!
所以當然不能夠隨便被一些沒有管理能力的終端用戶隨意使用囉!
但是我們總是需要讓使用者操作系統的,所以就有了在作業系統上面發展的應用程式啦!使用者可以透過應用程式來指揮核心,
讓核心達成我們所需要的硬體任務!如果考慮如,
我們可以發現應用程式其實是在最外層,就如同雞蛋的外殼一樣,因此這個咚咚也就被稱呼為殼程式 (shell) 囉!
其實殼程式的功能只是提供使用者操作系統的一個介面,因此這個殼程式需要可以呼叫其他軟體才好。
我們在第四章到第九章提到過很多指令,包括 man, chmod, chown, vi, fdisk, mkfs 等等指令,這些指令都是獨立的應用程式,
但是我們可以透過殼程式 (就是指令列模式) 來操作這些應用程式,讓這些應用程式呼叫核心來運作所需的工作哩!
這樣對於殼程式是否有了一定的概念了?
也就是說,只要能夠操作應用程式的介面都能夠稱為殼程式。狹義的殼程式指的是指令列方面的軟體,包括本章要介紹的 bash 等。
廣義的殼程式則包括圖形介面的軟體!因為圖形介面其實也能夠操作各種應用程式來呼叫核心工作啊!
不過在本章中,我們主要還是在使用 bash 啦!
10.1.2 為何要學文字介面的 shell?
文字介面的 shell 是很不好學的,但是學了之後好處多多!所以,
在這裡鳥哥要先對您進行一些心理建設,先來瞭解一下為啥學習 shell 是有好處的,這樣你才會有信心繼續玩下去 ^_^
文字介面的 shell:大家都一樣!
鳥哥常常聽到這個問題:『我幹嘛要學習 shell 呢?
不是已經有很多的工具可以提供我設定我的主機了?我為何要花這麼多時間去學指令呢?不是以
X Window 按一按幾個按鈕就可以搞定了嗎?』唉~還是得一再地強調,
X Window 還有 Web 介面的設定工具例如 Webmin () 是真的好用的傢伙,
他真的可以幫助我們很簡易的設定好我們的主機,甚至是一些很進階的設定都可以幫我們搞定。
但是鳥哥在前面的章節裡面也已經提到過相當多次了, X Window 與 web 介面的工具,他的介面雖然親善,功能雖然強大,
但畢竟他是將所有利用到的軟體都整合在一起的一組應用程式而已,
並非是一個完整的套件,所以某些時候當你升級或者是使用其他套件管理模組 (例如 tarball 而非 rpm 檔案等等)
時,就會造成設定的困擾了。甚至不同的 distribution 所設計的 X window 介面也都不相同,這樣也造成學習方面的困擾。
文字介面的 shell 就不同了!幾乎各家 distributions 使用的 bash 都是一樣的!如此一來,
你就能夠輕輕鬆鬆的轉換不同的 distributions ,就像武俠小說裡面提到的『一法通、萬法通!』
遠端管理:文字介面就是比較快!
此外,Linux 的管理常常需要透過遠端連線,而連線時文字介面的傳輸速度一定比較快,
而且,較不容易出現斷線或者是資訊外流的問題,因此,shell 真的是得學習的一項工具。而且,他可以讓您更深入
Linux ,更瞭解他,而不是只會按一按滑鼠而已!所謂『天助自助者!』多摸一點文字模式的東西,會讓你與
Linux 更親近呢!
Linux 的任督二脈: shell 是也!
有些朋友也很可愛,常會說:『我學這麼多幹什麼?
又不常用,也用不到!』嘿嘿!有沒有聽過『書到用時方恨少?』
當你的主機一切安然無恙的時候,您當然會覺得好像學這麼多的東西一點幫助也沒有呀!
萬一,某一天真的不幸給他中標了,您該如何是好?是直接重新安裝?
還是先追蹤入侵來源後進行漏洞的修補?或者是乾脆就關站好了?這當然涉及很多的考量,
但就以鳥哥的觀點來看,多學一點總是好的,尤其我們可以有備而無患嘛!甚至學的不精也沒有關係,瞭解概念也就
OK 啦!畢竟沒有人要您一定要背這麼多的內容啦!瞭解概念就很了不起了!
此外,如果你真的有心想要將您的主機管理的好,那麼良好的
shell 程式編寫是一定需要的啦!就鳥哥自己來說,鳥哥管理的主機雖然還不算多,
只有區區不到十部,但是如果每部主機都要花上幾十分鐘來查閱他的登錄檔資訊以及相關的訊息,
那麼鳥哥可能會瘋掉!基本上,也太沒有效率了!這個時候,如果能夠藉由 shell 提供的資料流重導向以及管線命令,呵呵!
那麼鳥哥分析登錄資訊只要花費不到十分鐘就可以看完所有的主機之重要資訊了!相當的好用呢!
由於學習 shell 的好處真的是多多啦!所以,如果你是個系統管理員,或者有心想要管理系統的話,那麼
shell 與 shell scripts 這個東西真的有必要看一看!因為他就像『打通任督二脈,任何武功都能隨你應用』的說!
10.1.3 系統的合法 shell 與 /etc/shells 功能
知道什麼是 Shell 之後,那麼我們來瞭解一下 Linux 使用的是哪一個 shell 呢?什麼!哪一個?難道說 shell 不就是『一個 shell 嗎?』哈哈!那可不!由於早年的
Unix 年代,發展者眾,所以由於 shell 依據發展者的不同就有許多的版本,例如常聽到的
Bourne SHell (sh) 、在 Sun 裡頭預設的 C SHell、 商業上常用的 K SHell、,
還有 TCSH 等等,每一種 Shell 都各有其特點。至於 Linux 使用的這一種版本就稱為『
Bourne Again SHell (簡稱 bash)
』,這個 Shell 是
Bourne Shell 的增強版本,也是基準於 GNU 的架構下發展出來的呦!
在介紹 shell 的優點之前,先來說一說 shell 的簡單歷史吧():第一個流行的
shell 是由 Steven Bourne 發展出來的,為了紀念他所以就稱為 Bourne shell
,或直接簡稱為 sh !而後來另一個廣為流傳的 shell 是由柏克萊大學的 Bill
Joy 設計依附於 BSD 版的 Unix 系統中的 shell ,這個 shell 的語法有點類似
C 語言,所以才得名為 C shell ,簡稱為 csh !由於在學術界 Sun
主機勢力相當的龐大,而 Sun 主要是 BSD 的分支之一,所以 C shell
也是另一個很重要而且流傳很廣的 shell 之一 。
由於 Linux 為 C 程式語言撰寫的,很多程式設計師使用 C 來開發軟體,因此 C shell 相對的就很熱門了。
另外,還記得我們在提到的吧?
Sun 公司的創始人就是 Bill Joy,而 BSD 最早就是 Bill Joy 發展出來的啊。
那麼目前我們的 Linux (以 CentOS 7.x 為例) 有多少我們可以使用的 shells 呢?
你可以檢查一下 /etc/shells 這個檔案,至少就有底下這幾個可以用的 shells (鳥哥省略了重複的 shell 了!包括 /bin/sh 等於 /usr/bin/sh 囉!):
/bin/sh (已經被 /bin/bash 所取代)
/bin/bash (就是 Linux 預設的 shell)
/bin/tcsh (整合 C Shell ,提供更多的功能)
/bin/csh (已經被 /bin/tcsh 所取代)
雖然各家 shell 的功能都差不多,但是在某些語法的下達方面則有所不同,因此建議你還是得要選擇某一種 shell 來熟悉一下較佳。
Linux 預設就是使用 bash ,所以最初你只要學會 bash 就非常了不起了! ^_^!
另外,咦!為什麼我們系統上合法的 shell 要寫入 /etc/shells 這個檔案啊?
這是因為系統某些服務在運作過程中,會去檢查使用者能夠使用的 shells ,而這些 shell
的查詢就是藉由 /etc/shells 這個檔案囉!
舉例來說,某些 FTP 網站會去檢查使用者的可用 shell ,而如果你不想要讓這些使用者使用 FTP
以外的主機資源時,可能會給予該使用者一些怪怪的 shell,讓使用者無法以其他服務登入主機。
這個時候,你就得將那些怪怪的 shell 寫到 /etc/shells 當中了。舉例來說,我們的 CentOS 7.x
的 /etc/shells 裡頭就有個 /sbin/nologin 檔案的存在,這個就是我們說的怪怪的 shell 囉~
那麼,再想一想,我這個使用者什麼時候可以取得 shell 來工作呢?還有,
我這個使用者預設會取得哪一個 shell 啊?還記得我們在當中提到的登入動作吧?
當我登入的時候,系統就會給我一個 shell 讓我來工作了。
而這個登入取得的 shell 就記錄在 /etc/passwd 這個檔案內!這個檔案的內容是啥?
[dmtsai@study ~]$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(底下省略).....
如上所示,在每一行的最後一個資料,就是你登入後可以取得的預設的 shell 啦!那你也會看到, root 是
/bin/bash ,不過,系統帳號 bin 與 daemon 等等,就使用那個怪怪的 /sbin/nologin
囉~關於使用者這部分的內容,我們留在時提供更多的說明。
10.1.4 Bash shell 的功能
既然 /bin/bash 是 Linux 預設的 shell ,那麼總是得瞭解一下這個玩意兒吧!bash 是 GNU 計畫中重要的工具軟體之一,目前也是
Linux distributions 的標準 shell 。 bash 主要相容於 sh ,並且依據一些使用者需求而加強的
shell 版本。不論你使用的是那個 distribution ,你都難逃需要學習 bash 的宿命啦!那麼這個
shell 有什麼好處,幹嘛 Linux 要使用他作為預設的 shell 呢? bash 主要的優點有底下幾個:
命令編修能力 (history):
bash 的功能裡頭,鳥哥個人認為相當棒的一個就是『他能記憶使用過的指令!』
這功能真的相當的棒!因為我只要在指令列按『上下鍵』就可以找到前/後一個輸入的指令!而在很多
distribution 裡頭,預設的指令記憶功能可以到達 1000 個!也就是說,你曾經下達過的指令幾乎都被記錄下來了。
這麼多的指令記錄在哪裡呢?在你的家目錄內的 .bash_history 啦!
不過,需要留意的是,~/.bash_history 記錄的是前一次登入以前所執行過的指令,
而至於這一次登入所執行的指令都被暫存在記憶體中,當你成功的登出系統後,該指令記憶才會記錄到 .bash_history 當中!
這有什麼優點呢?最大的好處就是可以『查詢曾經做過的舉動!』
如此可以知道你的執行步驟,那麼就可以追蹤你曾下達過的指令,以作為除錯的重要流程!
但如此一來也有個煩惱,就是如果被駭客入侵了,那麼他只要翻你曾經執行過的指令,
剛好你的指令又跟系統有關 (例如直接輸入 MySQL 的密碼在指令列上面),那你的伺服器可就傷腦筋了!
到底記錄指令的數目越多還是越少越好?這部份是見仁見智啦,沒有一定的答案的。
命令與檔案補全功能: ([tab] 按鍵的好處)
還記得我們在當中提到的
[tab] 這個按鍵嗎?這個按鍵的功能就是在 bash 裡頭才有的啦!常常在 bash 環境中使用 [tab]
是個很棒的習慣喔!因為至少可以讓你 1)少打很多字; 2)確定輸入的資料是正確的!
使用 [tab] 按鍵的時機依據 [tab] 接在指令後或參數後而有所不同。我們再複習一次:
[Tab] 接在一串指令的第一個字的後面,則為命令補全;
[Tab] 接在一串指令的第二個字以後時,則為『檔案補齊』!
若安裝 bash-completion 軟體,則在某些指令後面使用 [tab] 按鍵時,可以進行『選項/參數的補齊』功能!
所以說,如果我想要知道我的環境當中所有以 c 為開頭的指令呢?就按下『 c[tab][tab] 』就好啦! ^_^!
是的!真的是很方便的功能,所以,有事沒事,在
bash shell 底下,多按幾次 [tab] 是一個不錯的習慣啦!
命令別名設定功能: (alias)
假如我需要知道這個目錄底下的所有檔案 (包含隱藏檔) 及所有的檔案屬性,那麼我就必須要下達『
ls -al 』這樣的指令串,唉!真麻煩,有沒有更快的取代方式?呵呵!就使用命令別名呀!例如鳥哥最喜歡直接以
lm 這個自訂的命令來取代上面的命令,也就是說, lm 會等於 ls -al
這樣的一個功能,嘿!那麼要如何作呢?就使用 alias 即可!你可以在指令列輸入 alias
就可以知道目前的命令別名有哪些了!也可以直接下達命令來設定別名呦:
alias lm='ls -al'
工作控制、前景背景控制: (job control, foreground, background)
這部分我們在中再提及!
使用前、背景的控制可以讓工作進行的更為順利!至於工作控制(jobs)的用途則更廣,
可以讓我們隨時將工作丟到背景中執行!而不怕不小心使用了
[Ctrl] + c 來停掉該程序!真是好樣的!此外,也可以在單一登入的環境中,達到多工的目的呢!
程式化腳本: (shell scripts)
在 DOS 年代還記得將一堆指令寫在一起的所謂的『批次檔』吧?在 Linux 底下的
shell scripts 則發揮更為強大的功能,可以將你平時管理系統常需要下達的連續指令寫成一個檔案,
該檔案並且可以透過對談互動式的方式來進行主機的偵測工作!也可以藉由
shell 提供的環境變數及相關指令來進行設計,哇!整個設計下來幾乎就是一個小型的程式語言了!該
scripts 的功能真的是超乎鳥哥的想像之外!以前在 DOS 底下需要程式語言才能寫的東西,在
Linux 底下使用簡單的 shell scripts 就可以幫你達成了!真的厲害!這部分我們在再來談!
萬用字元: (Wildcard)
除了完整的字串之外, bash 還支援許多的萬用字元來幫助使用者查詢與指令下達。
舉例來說,想要知道 /usr/bin 底下有多少以 X 為開頭的檔案嗎?使用:『
ls -l /usr/bin/X* 』就能夠知道囉~此外,還有其他可供利用的萬用字元,
這些都能夠加快使用者的操作呢!
總之,bash 這麼好!不學嗎?怎麼可能!來學吧! ^_^
10.1.5 查詢指令是否為 Bash shell 的內建命令: type
我們在提到關於
部分,也就是
man page 的內容,那麼 bash 有沒有什麼說明文件啊?開玩笑~
這麼棒的東西怎麼可能沒有說明文件!請你在 shell 的環境下,直接輸入 man bash 瞧一瞧,
嘿嘿!不是蓋的吧!讓你看個幾天幾夜也無法看完的 bash 說明文件,可是很詳盡的資料啊! ^_^
不過,在這個 bash 的 man page 當中,不知道你是否有察覺到,咦!
怎麼這個說明文件裡面有其他的檔案說明啊?舉例來說,那個 cd 指令的說明就在這個 man page 內?
然後我直接輸入 man cd 時,怎麼出現的畫面中,最上方竟然出現一堆指令的介紹?這是怎麼回事?
為了方便 shell 的操作,其實 bash 已經『內建』了很多指令了,例如上面提到的 cd ,
還有例如 umask 等等的指令,都是內建在 bash 當中的呢!
那我怎麼知道這個指令是來自於外部指令(指的是其他非 bash 所提供的指令) 或是內建在 bash 當中的呢?
嘿嘿!利用 type 這個指令來觀察即可!舉例來說:
[dmtsai@study ~]$ type [-tpa] name
選項與參數:
:不加任何選項與參數時,type 會顯示出 name 是外部指令還是 bash 內建指令
:當加入 -t 參數時,type 會將 name 以底下這些字眼顯示出他的意義:
:表示為外部指令;
:表示該指令為命令別名所設定的名稱;
builtin :表示該指令為 bash 內建的指令功能;
:如果後面接的 name 為外部指令時,才會顯示完整檔名;
:會由 PATH 變數定義的路徑中,將所有含 name 的指令都列出來,包含 alias
範例一:查詢一下 ls 這個指令是否為 bash 內建?
[dmtsai@study ~]$ type ls
ls is aliased to `ls --color=auto' &==未加任何參數,列出 ls 的最主要使用情況
[dmtsai@study ~]$ type -t ls
&==僅列出 ls 執行時的依據
[dmtsai@study ~]$ type -a ls
ls is aliased to `ls --color=auto' &==最先使用 aliase
ls is /usr/bin/ls
&==還有找到外部指令在 /bin/ls
範例二:那麼 cd 呢?
[dmtsai@study ~]$ type cd
cd is a shell builtin
&==看到了嗎? cd 是 shell 內建指令
透過 type 這個指令我們可以知道每個指令是否為 bash 的內建指令。
此外,由於利用 type 搜尋後面的名稱時,如果後面接的名稱並不能以執行檔的狀態被找到,
那麼該名稱是不會被顯示出來的。也就是說, type 主要在找出『執行檔』而不是一般檔案檔名喔!
呵呵!所以,這個 type 也可以用來作為類似 which
指令的用途啦!找指令用的!
10.1.6 指令的下達與快速編輯按鈕
我們在已經提到過在
shell 環境下的指令下達方法,如果你忘記了請回到第四章再去回憶一下!這裡不重複說明了。
鳥哥這裡僅就反斜線 (\) 來說明一下指令下達的方式囉!
範例:如果指令串太長的話,如何使用兩行來輸出?
[dmtsai@study ~]$ cp /var/spool/mail/root /etc/crontab \
& /etc/fstab /root
上面這個指令用途是將三個檔案複製到 /root 這個目錄下而已。不過,因為指令太長,
於是鳥哥就利用『 \[Enter] 』來將 [Enter] 這個按鍵『跳脫!』開來,讓
[Enter] 按鍵不再具有『開始執行』的功能!好讓指令可以繼續在下一行輸入。
需要特別留意, [Enter] 按鍵是緊接著反斜線 (\) 的,兩者中間沒有其他字元。
因為 \ 僅跳脫『緊接著的下一個字符』而已!所以,萬一我寫成:
『 \ [Enter] 』,亦即
[Enter] 與反斜線中間有一個空格時,則 \ 跳脫的是『空白鍵』而不是 [Enter] 按鍵!這個地方請再仔細的看一遍!很重要!
如果順利跳脫 [Enter] 後,下一行最前面就會主動出現 & 的符號,
你可以繼續輸入指令囉!也就是說,那個 & 是系統自動出現的,你不需要輸入。
另外,當你所需要下達的指令特別長,或者是你輸入了一串錯誤的指令時,你想要快速的將這串指令整個刪除掉,一般來說,我們都是按下刪除鍵的。
有沒有其他的快速組合鍵可以協助呢?是有的!常見的有底下這些:
[ctrl]+u/[ctrl]+k分別是從游標處向前刪除指令串 ([ctrl]+u) 及向後刪除指令串 ([ctrl]+k)。
[ctrl]+a/[ctrl]+e分別是讓游標移動到整個指令串的最前面 ([ctrl]+a) 或最後面 ([ctrl]+e)。
總之,當我們順利的在終端機 (tty) 上面登入後, Linux 就會依據 /etc/passwd
檔案的設定給我們一個 shell (預設是 bash),然後我們就可以依據上面的指令下達方式來操作 shell,
之後,我們就可以透過 man 這個線上查詢來查詢指令的使用方式與參數說明,
很不錯吧!那麼我們就趕緊更進一步來操作 bash 這個好玩的東西囉!
10.2 Shell 的變數功能
變數是 bash 環境中非常重要的一個玩意兒,我們知道 Linux 是多人多工的環境,每個人登入系統都能取得一個 bash shell,
每個人都能夠使用 bash 下達 mail 這個指令來收受『自己』的郵件等等。問題是, bash 是如何得知你的郵件信箱是哪個檔案?
這就需要『變數』的幫助啦!所以,你說變數重不重要呢?底下我們將介紹重要的環境變數、變數的取用與設定等資料,
呼呼!動動腦時間又來到囉!^_^
10.2.1 什麼是變數?
那麼,什麼是『變數』呢?簡單的說,就是讓某一個特定字串代表不固定的內容就是了。舉個大家在國中都會學到的數學例子,
那就是:『 y = ax + b 』這東西,在等號左邊的(y)就是變數,在等號右邊的(ax+b)就是變數內容。
要注意的是,左邊是未知數,右邊是已知數喔!
講的更簡單一點,我們可以『用一個簡單的 "字眼"
來取代另一個比較複雜或者是容易變動的資料』。這有什麼好處啊?最大的好處就是『方便!』。
變數的可變性與方便性
舉例來說,我們每個帳號的郵件信箱預設是以 MAIL 這個變數來進行存取的,
當 dmtsai 這個使用者登入時,他便會取得 MAIL 這個變數,而這個變數的內容其實就是 /var/spool/mail/dmtsai,
那如果 vbird 登入呢?他取得的 MAIL 這個變數的內容其實就是 /var/spool/mail/vbird 。
而我們使用信件讀取指令 mail 來讀取自己的郵件信箱時,嘿嘿,這支程式可以直接讀取 MAIL 這個變數的內容,
就能夠自動的分辨出屬於自己的信箱信件囉!這樣一來,設計程式的設計師就真的很方便的啦!
圖10.2.1、程式、變數與不同使用者的關係
如上圖所示,由於系統已經幫我們規劃好 MAIL 這個變數,所以使用者只要知道 mail 這個指令如何使用即可,
mail 會主動的取用 MAIL 這個變數,就能夠如上圖所示的取得自己的郵件信箱了!(注意大小寫,小寫的 mail 是指令,
大寫的 MAIL 則是變數名稱喔!)
那麼使用變數真的比較好嗎?這是當然的!想像一個例子,如果 mail 這個指令將 root 收信的郵件信箱 (mailbox) 檔名為
/var/spool/mail/root 直接寫入程式碼中。那麼當 dmtsai 要使用 mail 時,將會取得 /var/spool/mail/root 這個檔案的內容!
不合理吧!所以你就需要幫 dmtsai 也設計一個 mail 的程式,將 /var/spool/mail/dmtsai 寫死到 mail 的程式碼當中!
天吶!那系統要有多少個 mail 指令啊?反過來說,使用變數就變的很簡單了!因為你不需要更動到程式碼啊!
只要將 MAIL 這個變數帶入不同的內容即可讓所有使用者透過 mail 取得自己的信件!當然簡單多了!
影響 bash 環境操作的變數
某些特定變數會影響到 bash 的環境喔!舉例來說,我們前面已經提到過很多次的那個 PATH 變數!
你能不能在任何目錄下執行某個指令,與 PATH 這個變數有很大的關係。例如你下達 ls 這個指令時,系統就是透過 PATH
這個變數裡面的內容所記錄的路徑順序來搜尋指令的呢!如果在搜尋完 PATH 變數內的路徑還找不到 ls 這個指令時,
就會在螢幕上顯示『 command not found 』的錯誤訊息了。
如果說的學理一點,那麼由於在 Linux System 下面,所有的執行緒都是需要一個執行碼,
而就如同上面提到的,你『真正以
shell 來跟 Linux 溝通,是在正確的登入 Linux 之後!』這個時候你就有一個
bash 的執行程序,也才可以真正的經由 bash 來跟系統溝通囉!而在進入 shell
之前,也正如同上面提到的,由於系統需要一些變數來提供他資料的存取 (或者是一些環境的設定參數值,
例如是否要顯示彩色等等的) ,所以就有一些所謂的『環境變數』
需要來讀入系統中了!這些環境變數例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的,
為了區別與自訂變數的不同,環境變數通常以大寫字元來表示呢!
腳本程式設計 (shell script) 的好幫手
這些還都只是系統預設的變數的目的,如果是個人的設定方面的應用呢:例如你要寫一個大型的
script 時,有些資料因為可能由於使用者習慣的不同而有差異,比如說路徑好了,由於該路徑在
script 被使用在相當多的地方,如果下次換了一部主機,都要修改 script 裡面的所有路徑,那麼我一定會瘋掉!
這個時候如果使用變數,而將該變數的定義寫在最前面,後面相關的路徑名稱都以變數來取代,
嘿嘿!那麼你只要修改一行就等於修改整篇 script 了!方便的很!所以,良好的程式設計師都會善用變數的定義!
圖10.2.2、變數應用於 shell script 的示意圖
最後我們就簡單的對『什麼是變數』作個簡單定義好了:
『變數就是以一組文字或符號等,來取代一些設定或者是一串保留的資料!』,
例如:我設定了『myname』就是『VBird』,所以當你讀取
myname 這個變數的時候,系統自然就會知道!哈!那就是 VBird 啦!
那麼如何『顯示變數』呢?這就需要使用到 echo 這個指令啦!
10.2.2 變數的取用與設定:echo, 變數設定規則, unset
說的口沫橫飛的,也不知道『變數』與『變數代表的內容』有啥關係?
那我們就將『變數』的『內容』拿出來給您瞧瞧好了。你可以利用 echo 這個指令來取用變數,
但是,變數在被取用時,前面必須要加上錢字號『 $ 』才行,舉例來說,要知道 PATH 的內容,該如何是好?
變數的取用: echo
[dmtsai@study ~]$ echo $variable
[dmtsai@study ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
[dmtsai@study ~]$ echo ${PATH}
# 近年來,鳥哥比較偏向使用這種格式喔!
變數的取用就如同上面的範例,利用 echo 就能夠讀出,只是需要在變數名稱前面加上 $ ,
或者是以 ${變數} 的方式來取用都可以!當然啦,那個 echo 的功能可是很多的,
我們這裡單純是拿 echo 來讀出變數的內容而已,更多的 echo 使用,請自行給他 man echo 吧! ^_^
請在螢幕上面顯示出您的環境變數 HOME 與 MAIL:
echo $HOME 或者是 echo ${HOME}echo $MAIL 或者是 echo ${MAIL}
現在我們知道了變數與變數內容之間的相關性了,好了,那麼我要如何『設定』或者是『修改』
某個變數的內容啊?很簡單啦!用『等號(=)』連接變數與他的內容就好啦!舉例來說:
我要將 myname 這個變數名稱的內容設定為 VBird ,那麼:
[dmtsai@study ~]$ echo ${myname}
&==這裡並沒有任何資料~因為這個變數尚未被設定!是空的!
[dmtsai@study ~]$ myname=VBird
[dmtsai@study ~]$ echo ${myname}
&==出現了!因為這個變數已經被設定了!
瞧!如此一來,這個變數名稱 myname 的內容就帶有 VBird 這個資料囉~
而由上面的例子當中,我們也可以知道:
在 bash 當中,當一個變數名稱尚未被設定時,預設的內容是『空』的。
另外,變數在設定時,還是需要符合某些規定的,否則會設定失敗喔!這些規則如下所示啊!
要請各位讀者注意喔,每一種 shell 的語法都不相同~在變數的使用上,bash 在你沒有設定的變數中強迫去 echo 時,它會顯示出空的值。
在其他某些 shell 中,隨便去 echo 一個不存在的變數,它是會出現錯誤訊息的喔!要注意!要注意!
變數的設定規則
變數與變數內容以一個等號『=』來連結,如下所示:
『myname=VBird』
等號兩邊不能直接接空白字元,如下所示為錯誤:
『myname = VBird』或『myname=VBird Tsai』
變數名稱只能是英文字母與數字,但是開頭字元不能是數字,如下為錯誤:
『2myname=VBird』
變數內容若有空白字元可使用雙引號『"』或單引號『'』將變數內容結合起來,但
雙引號內的特殊字元如 $ 等,可以保有原本的特性,如下所示:
『var="lang is $LANG"』則『echo $var』可得『lang is zh_TW.UTF-8』
單引號內的特殊字元則僅為一般字元 (純文字),如下所示:
『var='lang is $LANG'』則『echo $var』可得『lang is $LANG』
可用跳脫字元『 \ 』將特殊符號(如 [Enter], $, \, 空白字元,
'等)變成一般字元,如:
『myname=VBird\ Tsai』
在一串指令的執行中,還需要藉由其他額外的指令所提供的資訊時,可以使用反單引號『`指令`』或
『$(指令)』。特別注意,那個 ` 是鍵盤上方的數字鍵 1 左邊那個按鍵,而不是單引號!
例如想要取得核心版本的設定:『version=$(uname -r)』再『echo
$version』可得『3.10.0-229.el7.x86_64』
若該變數為擴增變數內容時,則可用 "$變數名稱" 或 ${變數} 累加內容,如下所示:
『PATH="$PATH":/home/bin』或『PATH=${PATH}:/home/bin』
若該變數需要在其他子程序執行,則需要以 export 來使變數變成環境變數:
『export PATH』
通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷 (純粹依照使用者興趣與嗜好) ;
取消變數的方法為使用 unset :『unset
變數名稱』例如取消 myname 的設定:
『unset myname』
底下讓鳥哥舉幾個例子來讓你試看看,就知道怎麼設定好你的變數囉!
範例一:設定一變數 name ,且內容為 VBird
[dmtsai@study ~]$ 12name=VBird
bash: 12name=VBird: command not found...
&==螢幕會顯示錯誤!因為不能以數字開頭!
[dmtsai@study ~]$ name = VBird
&==還是錯誤!因為有空白!
[dmtsai@study ~]$ name=VBird
&==OK 的啦!
範例二:承上題,若變數內容為 VBird's name 呢,就是變數內容含有特殊符號時:
[dmtsai@study ~]$ name=VBird's name
# 單引號與雙引號必須要成對,在上面的設定中僅有一個單引號,因此當你按下 enter 後,
# 你還可以繼續輸入變數內容。這與我們所需要的功能不同,失敗啦!
# 記得,失敗後要復原請按下 [ctrl]-c 結束!
[dmtsai@study ~]$ name="VBird's name"
&==OK 的啦!
# 指令是由左邊向右找→,先遇到的引號先有用,因此如上所示, 單引號變成一般字元!
[dmtsai@study ~]$ name='VBird's name'
&==失敗的啦!
# 因為前兩個單引號已成對,後面就多了一個不成對的單引號了!因此也就失敗了!
[dmtsai@study ~]$ name=VBird\'s\ name
&==OK 的啦!
# 利用反斜線 (\) 跳脫特殊字元,例如單引號與空白鍵,這也是 OK 的啦!
範例三:我要在 PATH 這個變數當中『累加』:/home/dmtsai/bin 這個目錄
[dmtsai@study ~]$ PATH=$PATH:/home/dmtsai/bin
[dmtsai@study ~]$ PATH="$PATH":/home/dmtsai/bin
[dmtsai@study ~]$ PATH=${PATH}:/home/dmtsai/bin
# 上面這三種格式在 PATH 裡頭的設定都是 OK 的!但是底下的例子就不見得囉!
範例四:承範例三,我要將 name 的內容多出 "yes" 呢?
[dmtsai@study ~]$ name=$nameyes
# 知道了吧?如果沒有雙引號,那麼變數成了啥?name 的內容是 $nameyes 這個變數!
# 呵呵!我們可沒有設定過 nameyes 這個變數吶!所以,應該是底下這樣才對!
[dmtsai@study ~]$ name="$name"yes
[dmtsai@study ~]$ name=${name}yes
&==以此例較佳!
範例五:如何讓我剛剛設定的 name=VBird 可以用在下個 shell 的程序?
[dmtsai@study ~]$ name=VBird
[dmtsai@study ~]$ bash
&==進入到所謂的子程序
[dmtsai@study ~]$ echo $name
&==子程序:再次的 echo 一下;
&==嘿嘿!並沒有剛剛設定的內容喔!
[dmtsai@study ~]$ exit
&==子程序:離開這個子程序
[dmtsai@study ~]$ export name
[dmtsai@study ~]$ bash
&==進入到所謂的子程序
[dmtsai@study ~]$ echo $name
&==子程序:在此執行!
&==看吧!出現設定值了!
[dmtsai@study ~]$ exit
&==子程序:離開這個子程序
什麼是『子程序』呢?就是說,在我目前這個 shell 的情況下,去啟用另一個新的 shell ,新的那個 shell
就是子程序啦!在一般的狀態下,父程序的自訂變數是無法在子程序內使用的。但是透過 export
將變數變成環境變數後,就能夠在子程序底下應用了!很不賴吧!至於程序的相關概念,
我們會在當中提到的喔!
範例六:如何進入到您目前核心的模組目錄?
[dmtsai@study ~]$ cd /lib/modules/`uname -r`/kernel
[dmtsai@study ~]$ cd /lib/modules/$(uname -r)/kernel
# 以此例較佳!
每個 Linux 都能夠擁有多個核心版本,且幾乎 distribution 的核心版本都不相同。以 CentOS 7.1 (未更新前)
為例,他的預設核心版本是 3.10.0-229.el7.x86_64 ,所以核心模組目錄在 /lib/modules/3.10.0-229.el7.x86_64/kernel/ 內。
也由於每個 distributions 的這個值都不相同,但是我們卻可以利用 uname -r
這個指令先取得版本資訊。所以囉,就可以透過上面指令當中的內含指令 $(uname -r)
先取得版本輸出到 cd ... 那個指令當中,就能夠順利的進入目前核心的驅動程式所放置的目錄囉!很方便吧!
其實上面的指令可以說是作了兩次動作,亦即是:
先進行反單引號內的動作『uname -r』並得到核心版本為 3.10.0-229.el7.x86_64
將上述的結果帶入原指令,故得指令為:『cd /lib/modules/3.10.0-229.el7.x86_64/kernel/』
為什麼鳥哥比較建議記憶 $( command ) 呢?還記得小時候學數學的加減乘除,我們都知道得要先乘除後加減。那如果硬要先加減再乘除呢?
當然就是加上括號 () 來處理即可啊!所以囉,這個指令的處理方式也差不多,只是括號左邊得要加個錢字號就是了!
範例七:取消剛剛設定的 name 這個變數內容
[dmtsai@study ~]$ unset name
根據上面的案例你可以試試看!就可以瞭解變數的設定囉!這個是很重要的呦!請勤加練習!
其中,較為重要的一些特殊符號的使用囉!例如單引號、雙引號、跳脫字元、錢字號、反單引號等等,底下的例題想一想吧!
在變數的設定當中,單引號與雙引號的用途有何不同?
單引號與雙引號的最大不同在於雙引號仍然可以保有變數的內容,但單引號內僅能是一般字元
,而不會有特殊符號。我們以底下的例子做說明:假設您定義了一個變數, name=VBird ,現在想以
name 這個變數的內容定義出 myname 顯示 VBird its me 這個內容,要如何訂定呢?
[dmtsai@study ~]$ name=VBird
[dmtsai@study ~]$ echo $name
[dmtsai@study ~]$ myname="$name its me"
[dmtsai@study ~]$ echo $myname
VBird its me
[dmtsai@study ~]$ myname='$name its me'
[dmtsai@study ~]$ echo $myname
$name its me
發現了嗎?沒錯!使用了單引號的時候,那麼 $name 將失去原有的變數內容,僅為一般字元的顯示型態而已!這裡必需要特別小心在意!
在指令下達的過程中,反單引號( ` )這個符號代表的意義為何?
在一串指令中,在 ` 之內的指令將會被先執行,而其執行出來的結果將做為外部的輸入資訊!例如
uname -r 會顯示出目前的核心版本,而我們的核心版本在 /lib/modules 裡面,因此,你可以先執行
uname -r 找出核心版本,然後再以『 cd 目錄』到該目錄下,當然也可以執行如同上面範例六的執行內容囉。
另外再舉個例子,我們也知道,
指令可以列出所有的相關檔案檔名,但是,如果我想要知道各個檔案的權限呢?舉例來說,我想要知道每個 crontab 相關檔名的權限:
[dmtsai@study ~]$ ls -ld `locate crontab`
[dmtsai@study ~]$ ls -ld $(locate crontab)
如此一來,先以 locate 將檔名資料都列出來,再以 ls 指令來處理的意思啦!瞭了嗎? ^_^
若你有一個常去的工作目錄名稱為:『/cluster/server/work/taiwan_/』,如何進行該目錄的簡化?
在一般的情況下,如果你想要進入上述的目錄得要『cd /cluster/server/work/taiwan_/』,
以鳥哥自己的案例來說,鳥哥跑數值模式常常會設定很長的目錄名稱(避免忘記),但如此一來變換目錄就很麻煩。
此時,鳥哥習慣利用底下的方式來降低指令下達錯誤的問題:
[dmtsai@study ~]$ work="/cluster/server/work/taiwan_/"
[dmtsai@study ~]$ cd $work
未來我想要使用其他目錄作為我的模式工作目錄時,只要變更 work 這個變數即可!而這個變數又可以在 (~/.bashrc)中直接指定,那我每次登入只要執行『 cd $work 』就能夠去到數值模式模擬的工作目錄了!是否很方便呢? ^_^
10.2.3 環境變數的功能
環境變數可以幫我們達到很多功能~包括家目錄的變換啊、提示字元的顯示啊、執行檔搜尋的路徑啊等等的,
還有很多很多啦!那麼,既然環境變數有那麼多的功能,問一下,目前我的 shell 環境中,
有多少預設的環境變數啊?我們可以利用兩個指令來查閱,分別是 env 與 export 呢!
用 env 觀察環境變數與常見環境變數說明
範例一:列出目前的 shell 環境下的所有環境變數與其內容。
[dmtsai@study ~]$ env
HOSTNAME=study.centos.vbird
&== 這部主機的主機名稱
TERM=xterm
&== 這個終端機使用的環境是什麼類型
SHELL=/bin/bash
&== 目前這個環境下,使用的 Shell 是哪一個程式?
HISTSIZE=1000
&== 『記錄指令的筆數』在 CentOS 預設可記錄 1000 筆
OLDPWD=/home/dmtsai
&== 上一個工作目錄的所在
LC_ALL=en_US.utf8
&== 由於語系的關係,鳥哥偷偷丟上來的一個設定
USER=dmtsai
&== 使用者的名稱啊!
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:
or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:
*.tar=01...
&== 一些顏色顯示
MAIL=/var/spool/mail/dmtsai
&== 這個使用者所取用的 mailbox 位置
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
PWD=/home/dmtsai
&== 目前使用者所在的工作目錄 (利用 pwd 取出!)
LANG=zh_TW.UTF-8
&== 這個與語系有關,底下會再介紹!
HOME=/home/dmtsai
&== 這個使用者的家目錄啊!
LOGNAME=dmtsai
&== 登入者用來登入的帳號名稱
_=/usr/bin/env
&== 上一次使用的指令的最後一個參數(或指令本身)
env 是 environment (環境) 的簡寫啊,上面的例子當中,是列出來所有的環境變數。當然,如果使用 export 也會是一樣的內容~
只不過, export 還有其他額外的功能就是了,我們等一下再提這個 export 指令。
那麼上面這些變數有些什麼功用呢?底下我們就一個一個來分析分析!
HOME代表使用者的家目錄。還記得我們可以使用 cd ~
去到自己的家目錄嗎?或者利用 cd 就可以直接回到使用者家目錄了。那就是取用這個變數啦~
有很多程式都可能會取用到這個變數的值!
SHELL告知我們,目前這個環境使用的 SHELL 是哪支程式?
Linux 預設使用 /bin/bash 的啦!
HISTSIZE這個與『歷史命令』有關,亦即是,
我們曾經下達過的指令可以被系統記錄下來,而記錄的『筆數』則是由這個值來設定的。
MAIL當我們使用 mail 這個指令在收信時,系統會去讀取的郵件信箱檔案
(mailbox)。
PATH就是執行檔搜尋的路徑啦~目錄與目錄中間以冒號(:)分隔,
由於檔案的搜尋是依序由 PATH 的變數內的目錄來查詢,所以,目錄的順序也是重要的喔。
LANG這個重要!就是語系資料囉~很多訊息都會用到他,
舉例來說,當我們在啟動某些 perl 的程式語言檔案時,他會主動的去分析語系資料檔案,
如果發現有他無法解析的編碼語系,可能會產生錯誤喔!一般來說,我們中文編碼通常是 zh_TW.Big5 或者是
zh_TW.UTF-8,這兩個編碼偏偏不容易被解譯出來,所以,有的時候,可能需要修訂一下語系資料。
這部分我們會在下個小節做介紹的!
RANDOM這個玩意兒就是『隨機亂數』的變數啦!目前大多數的
distributions 都會有亂數產生器,那就是 /dev/random 這個檔案。
我們可以透過這個亂數檔案相關的變數 ($RANDOM) 來隨機取得亂數值喔。在 BASH 的環境下,這個 RANDOM
變數的內容,介於 0~32767 之間,所以,你只要 echo $RANDOM 時,系統就會主動的隨機取出一個介於
0~32767 的數值。萬一我想要使用 0~9 之間的數值呢?呵呵~利用 declare 宣告數值類型,
然後這樣做就可以了:
[dmtsai@study ~]$ declare -i number=$RANDOM*10/32768 ; echo $number
&== 此時會隨機取出 0~9 之間的數值喔!
大致上是有這些環境變數啦~裡面有些比較重要的參數,在底下我們都會另外進行一些說明的~
用 set 觀察所有變數 (含環境變數與自訂變數)
bash 可不只有環境變數喔,還有一些與 bash 操作介面有關的變數,以及使用者自己定義的變數存在的。
那麼這些變數如何觀察呢?這個時候就得要使用 set 這個指令了。
set 除了環境變數之外,
還會將其他在 bash 內的變數通通顯示出來哩!資訊很多,底下鳥哥僅列出幾個重要的內容:
[dmtsai@study ~]$ set
BASH=/bin/bash
&== bash 的主程式放置路徑
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(1)-release'
&== 這兩行是 bash 的版本啊!
COLUMNS=90
&== 在目前的終端機環境下,使用的欄位有幾個字元長度
HISTFILE=/home/dmtsai/.bash_history
&== 歷史命令記錄的放置檔案,隱藏檔
HISTFILESIZE=1000
&== 存起來(與上個變數有關)的檔案之指令的最大紀錄筆數。
HISTSIZE=1000
&== 目前環境下,記憶體中記錄的歷史命令最大筆數。
IFS=$' \t\n'
&== 預設的分隔符號
&== 目前的終端機下的最大行數
MACHTYPE=x86_64-redhat-linux-gnu
&== 安裝的機器類型
OSTYPE=linux-gnu
&== 作業系統的類型!
PS1='[\u@\h \W]\$ '
&== PS1 就厲害了。這個是命令提示字元,也就是我們常見的
[root@www ~]# 或 [dmtsai ~]$ 的設定值啦!可以更動的!
&== 如果你使用跳脫符號 (\) 第二行以後的提示字元也
&== 目前這個 shell 所使用的 PID
&== 剛剛執行完指令的回傳值。
# 有許多可以使用的函式庫功能被鳥哥取消囉!請自行查閱!
一般來說,不論是否為環境變數,只要跟我們目前這個 shell 的操作介面有關的變數,
通常都會被設定為大寫字元,也就是說,『基本上,在 Linux
預設的情況中,使用{大寫的字母}來設定的變數一般為系統內定需要的變數』。
OK!OK!那麼上頭那些變數當中,有哪些是比較重要的?大概有這幾個吧!
PS1:(提示字元的設定)
這是 PS1 (數字的 1 不是英文字母),這個東西就是我們的『命令提示字元』喔!
當我們每次按下 [Enter] 按鍵去執行某個指令後,最後要再次出現提示字元時,
就會主動去讀取這個變數值了。上頭 PS1 內顯示的是一些特殊符號,這些特殊符號可以顯示不同的資訊,
每個 distributions 的 bash 預設的 PS1 變數內容可能有些許的差異,不要緊,『習慣你自己的習慣』就好了。
你可以用 man bash ()去查詢一下 PS1 的相關說明,以理解底下的一些符號意義。
\d :可顯示出『星期 月 日』的日期格式,如:"Mon Feb 2"
\H :完整的主機名稱。舉例來說,鳥哥的練習機為『study.centos.vbird』
\h :僅取主機名稱在第一個小數點之前的名字,如鳥哥主機則為『study』後面省略
\t :顯示時間,為 24 小時格式的『HH:MM:SS』
\T :顯示時間,為 12 小時格式的『HH:MM:SS』
\A :顯示時間,為 24 小時格式的『HH:MM』
\@ :顯示時間,為 12 小時格式的『am/pm』樣式
\u :目前使用者的帳號名稱,如『dmtsai』;
\v :BASH 的版本資訊,如鳥哥的測試主機版本為 4.2.46(1)-release,僅取『4.2』顯示
\w :完整的工作目錄名稱,由根目錄寫起的目錄名稱。但家目錄會以 ~ 取代;
\W :利用 basename 函數取得工作目錄名稱,所以僅會列出最後一個目錄名。
\# :下達的第幾個指令。
\$ :提示字元,如果是 root 時,提示字元為 # ,否則就是 $ 囉~
好了,讓我們來看看 CentOS 預設的 PS1 內容吧:『[\u@\h \W]\$ 』,現在你知道那些反斜線後的資料意義了吧?
要注意喔!那個反斜線後的資料為 PS1 的特殊功能,與 bash 的變數設定沒關係啦!不要搞混了喔!
那你現在知道為何你的命令提示字元是:『 [dmtsai@study ~]$ 』了吧?好了,那麼假設我想要有類似底下的提示字元:
[dmtsai@study /home/dmtsai 16:50 #12]$
那個 # 代表第 12 次下達的指令。那麼應該如何設定 PS1 呢?可以這樣啊:
[dmtsai@study ~]$ cd /home
[dmtsai@study home]$ PS1='[\u@\h \w \A #\#]\$ '
[dmtsai@study /home 17:02 #85]$
# 看到了嗎?提示字元變了!變的很有趣吧!其中,那個 #85 比較有趣,
# 如果您再隨便輸入幾次 ls 後,該數字就會增加喔!為啥?上面有說明滴!
$:(關於本 shell 的 PID)
錢字號本身也是個變數喔!這個咚咚代表的是『目前這個 Shell 的執行緒代號』,亦即是所謂的 PID (Process ID)。
更多的程序觀念,我們會在第四篇的時候提及。想要知道我們的 shell 的 PID ,就可以用:『
echo $$ 』即可!出現的數字就是你的 PID 號碼。
?:(關於上個執行指令的回傳值)
蝦密?問號也是一個特殊的變數?沒錯!在 bash 裡面這個變數可重要的很!
這個變數是:『上一個執行的指令所回傳的值』,
上面這句話的重點是『上一個指令』與『回傳值』兩個地方。當我們執行某些指令時,
這些指令都會回傳一個執行後的代碼。一般來說,如果成功的執行該指令,
則會回傳一個 0 值,如果執行過程發生錯誤,就會回傳『錯誤代碼』才對!一般就是以非為 0 的數值來取代。
我們以底下的例子來看看:
[dmtsai@study ~]$ echo $SHELL
&==可順利顯示!沒有錯誤!
[dmtsai@study ~]$ echo $?
&==因為沒問題,所以回傳值為 0
[dmtsai@study ~]$ 12name=VBird
bash: 12name=VBird: command not found...
&==發生錯誤了!bash回報有問題
[dmtsai@study ~]$ echo $?
&==因為有問題,回傳錯誤代碼(非為0)
# 錯誤代碼回傳值依據軟體而有不同,我們可以利用這個代碼來搜尋錯誤的原因喔!
[dmtsai@study ~]$ echo $?
# 咦!怎麼又變成正確了?這是因為 "?" 只與『上一個執行指令』有關,
# 所以,我們上一個指令是執行『 echo $? 』,當然沒有錯誤,所以是 0 沒錯!
OSTYPE, HOSTTYPE, MACHTYPE:(主機硬體與核心的等級)
我們在說明中談過 CPU ,
目前個人電腦的 CPU 主要分為 32/64 位元,其中 32 位元又可分為 i386, i586, i686,而 64 位元則稱為 x86_64。
由於不同等級的 CPU 指令集不太相同,因此你的軟體可能會針對某些 CPU 進行最佳化,以求取較佳的軟體性能。
所以軟體就有 i386, i686 及 x86_64 之分。以目前 (2015) 的主流硬體來說,幾乎都是 x86_64 的天下!
因此 CentOS 7 開始,已經不支援 i386 相容模式的安裝光碟了~哇嗚!進步的太快了!
要留意的是,較高階的硬體通常會向下相容舊有的軟體,但較高階的軟體可能無法在舊機器上面安裝!
我們在就曾說明過,
這裡再強調一次,你可以在 x86_64 的硬體上安裝 i386 的 Linux 作業系統,但是你無法在 i686 的硬體上安裝
x86_64 的 Linux 作業系統!這點得要牢記在心!
export: 自訂變數轉成環境變數
談了 env 與 set 現在知道有所謂的環境變數與自訂變數,那麼這兩者之間有啥差異呢?其實這兩者的差異在於『
該變數是否會被子程序所繼續引用』啦!唔!那麼啥是父程序?子程序?
這就得要瞭解一下指令的下達行為了。
當你登入 Linux 並取得一個 bash 之後,你的 bash 就是一個獨立的程序,這個程序的識別使用的是一個稱為程序識別碼,被稱為 PID 的就是。
接下來你在這個 bash 底下所下達的任何指令都是由這個 bash 所衍生出來的,那些被下達的指令就被稱為子程序了。
我們可以用底下的圖示來簡單的說明一下父程序與子程序的概念:
圖10.2.3、程序相關性示意圖
如上所示,我們在原本的 bash 底下執行另一個 bash ,結果操作的環境介面會跑到第二個 bash 去(就是子程序),
那原本的 bash 就會在暫停的情況 (睡著了,就是 sleep)。整個指令運作的環境是實線的部分!若要回到原本的 bash 去,
就只有將第二個 bash 結束掉 (下達 exit 或 logout) 才行。更多的程序概念我們會在第四篇談及,這裡只要有這個概念即可。
這個程序概念與變數有啥關係啊?關係可大了!因為子程序僅會繼承父程序的環境變數,
子程序不會繼承父程序的自訂變數啦!所以你在原本 bash 的自訂變數在進入了子程序後就會消失不見,
一直到你離開子程序並回到原本的父程序後,這個變數才會又出現!
換個角度來想,也就是說,如果我能將自訂變數變成環境變數的話,那不就可以讓該變數值繼續存在於子程序了?
呵呵!沒錯!此時,那個 export 指令就很有用啦!如你想要讓該變數內容繼續的在子程序中使用,那麼就請執行:
[dmtsai@study ~]$ export 變數名稱
這東西用在『分享自己的變數設定給後來呼叫的檔案或其他程序』啦!
像鳥哥常常在自己的主檔案後面呼叫其他附屬檔案(類似函式的功能),但是主檔案與附屬檔案內都有相同的變數名稱,
若一再重複設定時,要修改也很麻煩,此時只要在原本的第一個檔案內設定好『 export 變數 』,
後面所呼叫的檔案就能夠使用這個變數設定了!而不需要重複設定,這非常實用於 shell script 當中喔!
如果僅下達 export 而沒有接變數時,那麼此時將會把所有的『環境變數』秀出來喔!例如:
[dmtsai@study ~]$ export
declare -x HISTSIZE="1000"
declare -x HOME="/home/dmtsai"
declare -x HOSTNAME="study.centos.vbird"
declare -x LANG="zh_TW.UTF-8"
declare -x LC_ALL="en_US.utf8"
# 後面的鳥哥就都直接省略了!不然....浪費版面~ ^_^
那如何將環境變數轉成自訂變數呢?可以使用本章後續介紹的
10.2.4 影響顯示結果的語系變數 (locale)
還記得我們在嗎?
就是當我們使用 man command 的方式去查詢某個資料的說明檔時,該說明檔的內容可能會因為我們使用的語系不同而產生亂碼。
另外,利用 ls 查詢檔案的時間時,也可能會有亂碼出現在時間的部分。那個問題其實就是語系的問題啦。
目前大多數的 Linux distributions 已經都是支援日漸流行的萬國碼了,也都支援大部分的國家語系。
那麼我們的 Linux 到底支援了多少的語系呢?這可以由 locale 這個指令來查詢到喔!
[dmtsai@study ~]$ locale -a
....(前面省略)....
zh_TW.big5
&==大五碼的中文編碼
zh_TW.euctw
zh_TW.utf8
&==萬國碼的中文編碼
zu_ZA.iso88591
zu_ZA.utf8
正體中文語系至少支援了兩種以上的編碼,一種是目前還是很常見的 big5 ,另一種則是越來越熱門的 utf-8 編碼。
那麼我們如何修訂這些編碼呢?其實可以透過底下這些變數的說:
[dmtsai@study ~]$ locale
&==後面不加任何選項與參數即可!
LANG=en_US
&==主語言的環境
LC_CTYPE="en_US"
&==字元(文字)辨識的編碼
LC_NUMERIC="en_US"
&==數字系統的顯示訊息
LC_TIME="en_US"
&==時間系統的顯示資料
LC_COLLATE="en_US"
&==字串的比較與排序等
LC_MONETARY="en_US"
&==幣值格式的顯示等
LC_MESSAGES="en_US"
&==訊息顯示的內容,如功能表、錯誤訊息等
&==整體語系的環境
....(後面省略)....
基本上,你可以逐一設定每個與語系有關的變數資料,但事實上,如果其他的語系變數都未設定,
且你有設定 LANG 或者是 LC_ALL 時,則其他的語系變數就會被這兩個變數所取代!
這也是為什麼我們在 Linux 當中,通常說明僅設定 LANG 或 LC_ALL 這兩個變數而已,因為他是最主要的設定變數!
好了,那麼你應該要覺得奇怪的是,為什麼在 Linux 主機的終端機介面 (tty1 ~ tty6)
的環境下,如果設定『 LANG=zh_TW.utf8 』這個設定值生效後,使用 man 或者其他訊息輸出時,
都會有一堆亂碼,尤其是使用 ls -l 這個參數時?
因為在 Linux 主機的終端機介面環境下是無法顯示像中文這麼複雜的編碼文字,
所以就會產生亂碼了。也就是如此,我們才會必須要在 tty1 ~ tty6 的環境下,
加裝一些中文化介面的軟體,才能夠看到中文啊!不過,如果你是在 MS Windows
主機以遠端連線伺服器的軟體連線到主機的話,那麼,嘿嘿!其實文字介面確實是可以看到中文的。
此時反而你得要在 LC_ALL 設定中文編碼才好呢!
無論如何,如果發生一些亂碼的問題,那麼設定系統裡面保有的語系編碼,
例如: en_US 或 en_US.utf8 等等的設定,應該就 OK 的啦!好了,那麼系統預設支援多少種語系呢?
當我們使用 locale 時,系統是列出目前 Linux 主機內保有的語系檔案,
這些語系檔案都放置在: /usr/lib/locale/ 這個目錄中。
你當然可以讓每個使用者自己去調整自己喜好的語系,但是整體系統預設的語系定義在哪裡呢?
其實就是在 /etc/locale.conf 囉!這個檔案在 CentOS 7.x 的內容有點像這樣:
[dmtsai@study ~]$ cat /etc/locale.conf
LANG=zh_TW.utf8
LC_NUMERIC=zh_TW.UTF-8
LC_TIME=zh_TW.UTF-8
LC_MONETARY=zh_TW.UTF-8
LC_PAPER=zh_TW.UTF-8
LC_MEASUREMENT=zh_TW.UTF-8
因為鳥哥在選擇的是中文語系安裝畫面,
所以這個檔案預設就會使用中文編碼啦!你也可以自行將他改成你想要的語系編碼即可。
假設你有一個純文字檔案原本是在 Windows 底下建立的,那麼這個檔案預設可能是 big5 的編碼格式。
在你將這個檔案上傳到 Linux 主機後,在 X window 底下打開時,咦!怎麼中文字通通變成亂碼了?
別擔心!因為如上所示, Linux 目前大多預設是萬國碼顯示嘛!你只要將開啟該檔案的軟體編碼由 utf8
改成 big5 就能夠看到正確的中文了!
鳥哥原本是中文語系,所有顯示的資料通通是中文。但為了網頁顯示的關係,需要將輸出轉成英文 (en_US.utf8) 的語系來展示才行。
但鳥哥又不想要寫入設定檔!畢竟是暫時顯示用的~那該如何處理?
其實不很難,重點是 LANG 及 LC_ALL 而已!但在 CentOS 7 當中,你要讓 LC_ALL 生效時,得要使用 export 轉成環境變數才行耶!
所以就是這樣搞:
[dmtsai@study ~]$ locale
LANG=zh_TW.UTF-8
LC_CTYPE="zh_TW.UTF-8"
LC_NUMERIC="zh_TW.UTF-8"
LC_TIME="zh_TW.UTF-8"
[dmtsai@study ~]$ LANG=en_US.utf8; locale
[dmtsai@study ~]$ export LC_ALL=en_US.utf8; locale
# 你就會看到與上頭有不同的語系囉!
10.2.5 變數的有效範圍
蝦密?變數也有使用的『範圍』?沒錯啊~我們在上頭的
指令說明中,就提到了這個概念了。如果在跑程式的時候,有父程序與子程序的不同程序關係時,
則『變數』可否被引用與 export 有關。被 export 後的變數,我們可以稱他為『環境變數』!
環境變數可以被子程序所引用,但是其他的自訂變數內容就不會存在於子程序中。
在某些不同的書籍會談到『全域變數, global variable』與『區域變數, local variable』。
在鳥哥的這個章節中,基本上你可以這樣看待:環境變數=全域變數自訂變數=區域變數
在學理方面,為什麼環境變數的資料可以被子程序所引用呢?這是因為記憶體配置的關係!理論上是這樣的:
當啟動一個 shell,作業系統會分配一記憶區塊給 shell 使用,此記憶體內之變數可讓子程序取用
若在父程序利用 export 功能,可以讓自訂變數的內容寫到上述的記憶區塊當中(環境變數);
當載入另一個 shell 時 (亦即啟動子程序,而離開原本的父程序了),子 shell 可以將父 shell
的環境變數所在的記憶區塊導入自己的環境變數區塊當中。
透過這樣的關係,我們就可以讓某些變數在相關的程序之間存在,以幫助自己更方便的操作環境喔!
不過要提醒的是,這個『環境變數』與『bash 的操作環境』意思不太一樣,舉例來說, PS1 並不是環境變數,
但是這個 PS1 會影響到 bash 的介面 (提示字元嘛)!相關性要釐清喔!^_^
10.2.6 變數鍵盤讀取、陣列與宣告: read, array, declare
我們上面提到的變數設定功能,都是由指令列直接設定的,那麼,可不可以讓使用者能夠經由鍵盤輸入?
什麼意思呢?是否記得某些程式執行的過程當中,會等待使用者輸入 "yes/no" 之類的訊息啊?
在 bash 裡面也有相對應的功能喔!此外,我們還可以宣告這個變數的屬性,例如:陣列或者是數字等等的。底下就來看看吧!
要讀取來自鍵盤輸入的變數,就是用 read 這個指令了。這個指令最常被用在 shell script 的撰寫當中,
想要跟使用者對談?用這個指令就對了。關於 script 的寫法,我們會在第十三章介紹,底下先來瞧一瞧 read 的相關語法吧!
[dmtsai@study ~]$ read [-pt] variable
選項與參數:
:後面可以接提示字元!
:後面可以接等待的『秒數!』這個比較有趣~不會一直等待使用者啦!
範例一:讓使用者由鍵盤輸入一內容,將該內容變成名為 atest 的變數
[dmtsai@study ~]$ read atest
This is a test
&==此時游標會等待你輸入!請輸入左側文字看看
[dmtsai@study ~]$ echo ${atest}
This is a test
&==你剛剛輸入的資料已經變成一個變數內容!
範例二:提示使用者 30 秒內輸入自己的大名,將該輸入字串作為名為 named 的變數內容
[dmtsai@study ~]$ read -p "Please keyin your name: " -t 30 named
Please keyin your name: VBird Tsai
&==注意看,會有提示字元喔!
[dmtsai@study ~]$ echo ${named}
VBird Tsai
&==輸入的資料又變成一個變數的內容了!
read 之後不加任何參數,直接加上變數名稱,那麼底下就會主動出現一個空白行等待你的輸入(如範例一)。
如果加上 -t 後面接秒數,例如上面的範例二,那麼 30 秒之內沒有任何動作時,
該指令就會自動略過了~如果是加上 -p ,嘿嘿!在輸入的游標前就會有比較多可以用的提示字元給我們參考!
在指令的下達裡面,比較美觀啦! ^_^
declare / typeset
declare 或 typeset 是一樣的功能,就是在『宣告變數的類型』。如果使用
declare 後面並沒有接任何參數,那麼 bash 就會主動的將所有的變數名稱與內容通通叫出來,就好像使用 set 一樣啦!
那麼 declare 還有什麼語法呢?看看先:
[dmtsai@study ~]$ declare [-aixr] variable
選項與參數:
:將後面名為 variable 的變數定義成為陣列 (array) 類型
:將後面名為 variable 的變數定義成為整數數字 (integer) 類型
:用法與 export 一樣,就是將後面的 variable 變成環境變數;
:將變數設定成為 readonly 類型,該變數不可被更改內容,也不能 unset
範例一:讓變數 sum 進行 100+300+50 的加總結果
[dmtsai@study ~]$ sum=100+300+50
[dmtsai@study ~]$ echo ${sum}
100+300+50
&==咦!怎麼沒有幫我計算加總?因為這是文字型態的變數屬性啊!
[dmtsai@study ~]$ declare -i sum=100+300+50
[dmtsai@study ~]$ echo ${sum}
&==瞭乎??
由於在預設的情況底下, bash 對於變數有幾個基本的定義:
變數類型預設為『字串』,所以若不指定變數類型,則 1+2 為一個『字串』而不是『計算式』。
所以上述第一個執行的結果才會出現那個情況的;
bash 環境中的數值運算,預設最多僅能到達整數形態,所以 1/3 結果是 0;
現在你曉得為啥你需要進行變數宣告了吧?如果需要非字串類型的變數,那就得要進行變數的宣告才行啦!
底下繼續來玩些其他的 declare 功能。
範例二:將 sum 變成環境變數
[dmtsai@study ~]$ declare -x sum
[dmtsai@study ~]$ export | grep sum
declare -ix sum="450"
&==果然出現了!包括有 i 與 x 的宣告!
範例三:讓 sum 變成唯讀屬性,不可更動!
[dmtsai@study ~]$ declare -r sum
[dmtsai@study ~]$ sum=testing
-bash: sum: readonly variable
&==老天爺~不能改這個變數了!
範例四:讓 sum 變成非環境變數的自訂變數吧!
[dmtsai@study ~]$ declare +x sum
&== 將 - 變成 + 可以進行『取消』動作
[dmtsai@study ~]$ declare -p sum
&== -p 可以單獨列出變數的類型
declare -ir sum="450" &== 看吧!只剩下 i, r 的類型,不具有 x 囉!
declare 也是個很有用的功能~尤其是當我們需要使用到底下的陣列功能時,
他也可以幫我們宣告陣列的屬性喔!不過,老話一句,陣列也是在 shell script 比較常用的啦!
比較有趣的是,如果你不小心將變數設定為『唯讀』,通常得要登出再登入才能復原該變數的類型了! @_@
陣列 (array) 變數類型
某些時候,我們必須使用陣列來宣告一些變數,這有什麼好處啊?在一般人的使用上,
果然是看不出來有什麼好處的!不過,如果您曾經寫過程式的話,那才會比較瞭解陣列的意義~
陣列對寫數值程式的設計師來說,可是不能錯過學習的重點之一哩!好!不囉唆~
那麼要如何設定陣列的變數與內容呢?在 bash 裡頭,陣列的設定方式是:
var[index]=content
意思是說,我有一個陣列名稱為 var ,而這個陣列的內容為 var[1]=小明, var[2]=大明,
var[3]=好明 .... 等等,那個 index 就是一些數字啦,重點是用中刮號 ([ ]) 來設定的。
目前我們 bash 提供的是一維陣列。老實說,如果您不必寫一些複雜的程式,
那麼這個陣列的地方,可以先略過,等到有需要再來學習即可!因為要製作出陣列,
通常與迴圈或者其他判斷式交互使用才有比較高的存在意義!
範例:設定上面提到的 var[1] ~ var[3] 的變數。
[dmtsai@study ~]$ var[1]="small min"
[dmtsai@study ~]$ var[2]="big min"
[dmtsai@study ~]$ var[3]="nice min"
[dmtsai@study ~]$ echo "${var[1]}, ${var[2]}, ${var[3]}"
small min, big min, nice min
陣列的變數類型比較有趣的地方在於『讀取』,一般來說,建議直接以 ${陣列}
的方式來讀取,比較正確無誤的啦!這也是為啥鳥哥一開始就建議你使用 ${變數} 來記憶的原因!
10.2.7 與檔案系統及程序的限制關係: ulimit
想像一個狀況:我的 Linux 主機裡面同時登入了十個人,這十個人不知怎麼搞的,
同時開啟了 100 個檔案,每個檔案的大小約 10MBytes ,請問一下,
我的 Linux 主機的記憶體要有多大才夠? 10*100*10 = 10000 MBytes = 10GBytes ...
老天爺,這樣,系統不掛點才有鬼哩!為了要預防這個情況的發生,所以我們的 bash
是可以『限制使用者的某些系統資源』的,包括可以開啟的檔案數量,
可以使用的 CPU 時間,可以使用的記憶體總量等等。如何設定?用 ulimit 吧!
[dmtsai@study ~]$ ulimit [-SHacdfltu] [配額]
選項與參數:
:hard limit ,嚴格的設定,必定不能超過這個設定的數值;
:soft limit ,警告的設定,可以超過這個設定值,但是若超過則有警告訊息。
在設定上,通常 soft 會比 hard 小,舉例來說,soft 可設定為 80 而 hard
設定為 100,那麼你可以使用到 90 (因為沒有超過 100),但介於 80~100 之間時,
系統會有警告訊息通知你!
:後面不接任何選項與參數,可列出所有的限制額度;
:當某些程式發生錯誤時,系統可能會將該程式在記憶體中的資訊寫成檔案(除錯用),
這種檔案就被稱為核心檔案(core file)。此為限制每個核心檔案的最大容量。
:此 shell 可以建立的最大檔案容量(一般可能設定為 2GB)單位為 Kbytes
:程序可使用的最大斷裂記憶體(segment)容量;
:可用於鎖定 (lock) 的記憶體量
:可使用的最大 CPU 時間 (單位為秒)
:單一使用者可以使用的最大程序(process)數量。
範例一:列出你目前身份(假設為一般帳號)的所有限制資料數值
[dmtsai@study ~]$ ulimit -a
core file size
(blocks, -c) 0
&==只要是 0 就代表沒限制
data seg size
(kbytes, -d) unlimited
scheduling priority
(blocks, -f) unlimited
&==可建立的單一檔案的大小
pending signals
max locked memory
(kbytes, -l) 64
max memory size
(kbytes, -m) unlimited
open files
&==同時可開啟的檔案數量
(512 bytes, -p) 8
POSIX message queues
(bytes, -q) 819200
real-time priority
stack size
(kbytes, -s) 8192
(seconds, -t) unlimited
max user processes
virtual memory
(kbytes, -v) unlimited
file locks
(-x) unlimited
範例二:限制使用者僅能建立 10MBytes 以下的容量的檔案
[dmtsai@study ~]$ ulimit -f 10240
[dmtsai@study ~]$ ulimit -a | grep 'file size'
core file size
(blocks, -c) 0
(blocks, -f) 10240 &==最大量為10240Kbyes,相當10Mbytes
[dmtsai@study ~]$ dd if=/dev/zero of=123 bs=1M count=20
File size limit exceeded (core dumped) &==嘗試建立 20MB 的檔案,結果失敗了!
[dmtsai@study ~]$ rm 123
&==趕快將這個檔案刪除囉!同時你得要登出再次的登入才能解開 10M 的限制
還記得我們在裡面提到過,單一 filesystem
能夠支援的單一檔案大小與 block 的大小有關。但是檔案系統的限制容量都允許的太大了!如果想要讓使用者建立的檔案不要太大時,
我們是可以考慮用 ulimit 來限制使用者可以建立的檔案大小喔!利用 ulimit -f 就可以來設定了!例如上面的範例二,要注意單位喔!單位是 Kbytes。
若改天你一直無法建立一個大容量的檔案,記得瞧一瞧 ulimit 的資訊喔!
想要復原 ulimit 的設定最簡單的方法就是登出再登入,否則就是得要重新以 ulimit 設定才行!
不過,要注意的是,一般身份使用者如果以 ulimit 設定了 -f 的檔案大小,
那麼他『只能繼續減小檔案容量,不能增加檔案容量喔!』另外,若想要管控使用者的 ulimit 限值,
可以參考 的介紹。
10.2.8 變數內容的刪除、取代與替換 (Optional)
變數除了可以直接設定來修改原本的內容之外,有沒有辦法透過簡單的動作來將變數的內容進行微調呢?
舉例來說,進行變數內容的刪除、取代與替換等!是可以的!我們可以透過幾個簡單的小步驟來進行變數內容的微調喔!
底下就來試試看!
變數內容的刪除與取代
變數的內容可以很簡單的透過幾個咚咚來進行刪除喔!我們使用 PATH 這個變數的內容來做測試好了。
請你依序進行底下的幾個例子來玩玩,比較容易感受的到鳥哥在這裡想要表達的意義:
範例一:先讓小寫的 path 自訂變數設定的與 PATH 內容相同
[dmtsai@study ~]$ path=${PATH}
[dmtsai@study ~]$ echo ${path}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
範例二:假設我不喜歡 local/bin,所以要將前 1 個目錄刪除掉,如何顯示?
[dmtsai@study ~]$ echo ${path#/*local/bin:}
/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
上面這個範例很有趣的!他的重點可以用底下這張表格來說明:
${variable#/*local/bin:}
上面的特殊字體部分是關鍵字!用在這種刪除模式所必須存在的
${variable#/*local/bin:}
這就是原本的變數名稱,以上面範例二來說,這裡就填寫 path 這個『變數名稱』啦!
${variable#/*local/bin:}
這是重點!代表『從變數內容的最前面開始向右刪除』,且僅刪除最短的那個
${variable#/*local/bin:}
代表要被刪除的部分,由於 # 代表由前面開始刪除,所以這裡便由開始的 / 寫起。
需要注意的是,我們還可以透過萬用字元 * 來取代 0 到無窮多個任意字元
以上面範例二的結果來看, path 這個變數被刪除的內容如下所示:
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
很有趣吧!這樣瞭解了 # 的功能了嗎?接下來讓我們來看看底下的範例三!
範例三:我想要刪除前面所有的目錄,僅保留最後一個目錄
[dmtsai@study ~]$ echo ${path#/*:}
/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
# 由於一個 # 僅刪除掉最短的那個,因此他刪除的情況可以用底下的刪除線來看:
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
[dmtsai@study ~]$ echo ${path##/*:}
/home/dmtsai/bin
# 嘿!多加了一個 # 變成 ## 之後,他變成『刪除掉最長的那個資料』!亦即是:
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
非常有趣!不是嗎?因為在 PATH 這個變數的內容中,每個目錄都是以冒號『:』隔開的,
所以要從頭刪除掉目錄就是介於斜線 (/) 到冒號 (:) 之間的資料!但是 PATH 中不止一個冒號 (:) 啊!
所以 # 與 ## 就分別代表:
# :符合取代文字的『最短的』那一個;
##:符合取代文字的『最長的』那一個
上面談到的是『從前面開始刪除變數內容』,那麼如果想要『從後面向前刪除變數內容』呢?
這個時候就得使用百分比 (%) 符號了!來看看範例四怎麼做吧!
範例四:我想要刪除最後面那個目錄,亦即從 : 到 bin 為止的字串
[dmtsai@study ~]$ echo ${path%:*bin}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin
# 注意啊!最後面一個目錄不見去!
# 這個 % 符號代表由最後面開始向前刪除!所以上面得到的結果其實是來自如下:
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
範例五:那如果我只想要保留第一個目錄呢?
[dmtsai@study ~]$ echo ${path%%:*bin}
/usr/local/bin
# 同樣的, %% 代表的則是最長的符合字串,所以結果其實是來自如下:
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
由於我是想要由變數內容的後面向前面刪除,而我這個變數內容最後面的結尾是『/home/dmtsai/bin』,
所以你可以看到上面我刪除的資料最終一定是『bin』,亦即是『:*bin』那個 * 代表萬用字元!
至於 % 與 %% 的意義其實與 # 及 ## 類似!這樣理解否?
假設你是 dmtsai ,那你的 MAIL 變數應該是 /var/spool/mail/dmtsai 。假設你只想要保留最後面那個檔名 (dmtsai),
前面的目錄名稱都不要了,如何利用 $MAIL 變數來達成?
題意其實是這樣『/var/spool/mail/dmtsai』,亦即刪除掉兩條斜線間的所有資料(最長符合)。
這個時候你就可以這樣做即可:
[dmtsai@study ~]$ echo ${MAIL##/*/}
相反的,如果你只想要拿掉檔名,保留目錄的名稱,亦即是『/var/spool/mail/dmtsai』
(最短符合)。但假設你並不知道結尾的字母為何,此時你可以利用萬用字元來處理即可,如下所示:
[dmtsai@study ~]$ echo ${MAIL%/*}
瞭解了刪除功能後,接下來談談取代吧!繼續玩玩範例六囉!
範例六:將 path 的變數內容內的 sbin 取代成大寫 SBIN:
[dmtsai@study ~]$ echo ${path/sbin/SBIN}
/usr/local/bin:/usr/bin:/usr/local/SBIN:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
# 這個部分就容易理解的多了!關鍵字在於那兩個斜線,兩斜線中間的是舊字串
# 後面的是新字串,所以結果就會出現如上述的特殊字體部分囉!
[dmtsai@study ~]$ echo ${path//sbin/SBIN}
/usr/local/bin:/usr/bin:/usr/local/SBIN:/usr/SBIN:/home/dmtsai/.local/bin:/home/dmtsai/bin
# 如果是兩條斜線,那麼就變成所有符合的內容都會被取代喔!
我們將這部份作個總結說明一下:
${變數#關鍵字}${變數##關鍵字}
若變數內容從頭開始的資料符合『關鍵字』,則將符合的最短資料刪除
若變數內容從頭開始的資料符合『關鍵字』,則將符合的最長資料刪除
${變數%關鍵字}${變數%%關鍵字}
若變數內容從尾向前的資料符合『關鍵字』,則將符合的最短資料刪除
若變數內容從尾向前的資料符合『關鍵字』,則將符合的最長資料刪除
${變數/舊字串/新字串}${變數//舊字串/新字串}
若變數內容符合『舊字串』則『第一個舊字串會被新字串取代』
若變數內容符合『舊字串』則『全部的舊字串會被新字串取代』
變數的測試與內容替換
在某些時刻我們常常需要『判斷』某個變數是否存在,若變數存在則使用既有的設定,若變數不存在則給予一個常用的設定。
我們舉底下的例子來說明好了,看看能不能較容易被你所理解呢!
範例一:測試一下是否存在 username 這個變數,若不存在則給予 username 內容為 root
[dmtsai@study ~]$ echo ${username}
&==由於出現空白,所以 username 可能不存在,也可能是空字串
[dmtsai@study ~]$ username=${username-root}
[dmtsai@study ~]$ echo ${username}
&==因為 username 沒有設定,所以主動給予名為 root 的內容。
[dmtsai@study ~]$ username="vbird tsai" &==主動設定 username 的內容
[dmtsai@study ~]$ username=${username-root}
[dmtsai@study ~]$ echo ${username}
vbird tsai &==因為 username 已經設定了,所以使用舊有的設定而不以 root 取代
在上面的範例中,重點在於減號『 - 』後面接的關鍵字!基本上你可以這樣理解:
new_var=${old_var-content}
新的變數,主要用來取代舊變數。新舊變數名稱其實常常是一樣的
new_var=${old_var-content}
這是本範例中的關鍵字部分!必須要存在的哩!
new_var=${old_var-content}
舊的變數,被測試的項目!
new_var=${old_var-content}
變數的『內容』,在本範例中,這個部分是在『給予未設定變數的內容』
不過這還是有點問題!因為 username 可能已經被設定為『空字串』了!果真如此的話,那你還可以使用底下的範例來給予
username 的內容成為 root 喔!
範例二:若 username 未設定或為空字串,則將 username 內容設定為 root
[dmtsai@study ~]$ username=""
[dmtsai@study ~]$ username=${username-root}
[dmtsai@study ~]$ echo ${username}
&==因為 username 被設定為空字串了!所以當然還是保留為空字串!
[dmtsai@study ~]$ username=${username:-root}
[dmtsai@study ~]$ echo ${username}
&==加上『 : 』後若變數內容為空或者是未設定,都能夠以後面的內容替換!
在大括號內有沒有冒號『 : 』的差別是很大的!加上冒號後,被測試的變數未被設定或者是已被設定為空字串時,
都能夠用後面的內容 (本例中是使用 root 為內容) 來替換與設定!這樣可以瞭解了嗎?除了這樣的測試之外,
還有其他的測試方法喔!鳥哥將他整理如下:
底下的例子當中,那個 var 與 str 為變數,我們想要針對 str 是否有設定來決定 var 的值喔!
一般來說, 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=exprvar=expr
str 不變var=str 不變var=$str
var=${str:=expr}str=exprvar=expr
str=exprvar=exprstr 不變var=$str
var=${str?expr}expr 輸出至 stderrvar=var=$str
var=${str:?expr}expr 輸出至 stderrexpr 輸出至 stderrvar=$str
根據上面這張表,我們來進行幾個範例的練習吧! ^_^!首先讓我們來測試一下,如果舊變數 (str) 不存在時,
我們要給予新變數一個內容,若舊變數存在則新變數內容以舊變數來替換,結果如下:
測試:先假設 str 不存在 (用 unset) ,然後測試一下減號 (-) 的用法:
[dmtsai@study ~]$
var=${str-newvar}
[dmtsai@study ~]$ echo "var=${var}, str=${str}"
var=newvar, str=
&==因為 str 不存在,所以 var 為 newvar
測試:若 str 已存在,測試一下 var 會變怎樣?:
[dmtsai@study ~]$ str="oldvar"; var=${str-newvar}
[dmtsai@study ~]$ echo "var=${var}, str=${str}"
var=oldvar, str=oldvar
&==因為 str 存在,所以 var 等於 str 的內容
關於減號 (-) 其實上面我們談過了!這裡的測試只是要讓你更加瞭解,這個減號的測試並不會影響到舊變數的內容。
如果你想要將舊變數內容也一起替換掉的話,那麼就使用等號 (=) 吧!
測試:先假設 str 不存在 (用 unset) ,然後測試一下等號 (=) 的用法:
[dmtsai@study ~]$
var=${str=newvar}
[dmtsai@study ~]$ echo "var=${var}, str=${str}"
var=newvar, str=newvar
&==因為 str 不存在,所以 var/str 均為 newvar
測試:如果 str 已存在了,測試一下 var 會變怎樣?
[dmtsai@study ~]$ str="oldvar"; var=${str=newvar}
[dmtsai@study ~]$ echo "var=${var}, str=${str}"
var=oldvar, str=oldvar
&==因為 str 存在,所以 var 等於 str 的內容
那如果我只是想知道,如果舊變數不存在時,整個測試就告知我『有錯誤』,此時就能夠使用問號『 ? 』的幫忙啦!
底下這個測試練習一下先!
測試:若 str 不存在時,則 var 的測試結果直接顯示 "無此變數"
[dmtsai@study ~]$
var=${str?無此變數}
-bash: str: 無此變數
&==因為 str 不存在,所以輸出錯誤訊息
測試:若 str 存在時,則 var 的內容會與 str 相同!
[dmtsai@study ~]$ str="oldvar"; var=${str?novar}
[dmtsai@study ~]$ echo "var=${var}, str=${str}"
var=oldvar, str=oldvar
&==因為 str 存在,所以 var 等於 str 的內容
基本上這種變數的測試也能夠透過 shell script 內的 if...then... 來處理,
不過既然 bash 有提供這麼簡單的方法來測試變數,那我們也可以多學一些嘛!
不過這種變數測試通常是在程式設計當中比較容易出現,如果這裡看不懂就先略過,未來有用到判斷變數值時,再回來看看吧! ^_^
10.3 命令別名與歷史命令
我們知道在早期的 DOS 年代,清除螢幕上的資訊可以使用 cls 來清除,但是在 Linux 裡面,
我們則是使用 clear 來清除畫面的。那麼可否讓 cls 等於 clear 呢?可以啊!用啥方法?
link file 還是什麼的?別急!底下我們介紹不用 link file 的命令別名來達成。那麼什麼又是歷史命令?
曾經做過的舉動我們可以將他記錄下來喔!那就是歷史命令囉~底下分別來談一談這兩個玩意兒。
10.3.1 命令別名設定: alias, unalias
命令別名是一個很有趣的東西,特別是你的慣用指令特別長的時候!還有,
增設預設的選項在一些慣用的指令上面,可以預防一些不小心誤殺檔案的情況發生的時候!
舉個例子來說,如果你要查詢隱藏檔,並且需要長的列出與一頁一頁翻看,那麼需要下達『
ls -al | more 』這個指令,鳥哥是覺得很煩啦!
要輸入好幾個單字!那可不可以使用 lm 來簡化呢?當然可以,你可以在命令列下面下達:
[dmtsai@study ~]$ alias lm='ls -al | more'
立刻多出了一個可以執行的指令喔!這個指令名稱為 lm ,且其實他是執行 ls -al | more 啊!真是方便。不過,
要注意的是:『alias 的定義規則與幾乎相同』,
所以你只要在 alias 後面加上你的 {『別名』='指令 選項...' },
以後你只要輸入 lm 就相當於輸入了 ls -al|more 這一串指令!很方便吧!
另外,命令別名的設定還可以取代既有的指令喔!舉例來說,我們知道 root
可以移除 (rm) 任何資料!所以當你以 root 的身份在進行工作時,需要特別小心,
但是總有失手的時候,那麼 rm 提供了一個選項來讓我們確認是否要移除該檔案,那就是 -i
這個選項!所以,你可以這樣做:
[dmtsai@study ~]$ alias rm='rm -i'
那麼以後使用 rm 的時候,就不用太擔心會有錯誤刪除的情況了!這也是命令別名的優點囉!
那麼如何知道目前有哪些的命令別名呢?就使用 alias 呀!
[dmtsai@study ~]$ alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias lm='ls -al | more'
alias ls='ls --color=auto'
alias rm='rm -i'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
由上面的資料當中,你也會發現一件事情啊,我們在裡面提到
vi 與 vim 是不太一樣的,vim 可以多作一些額外的語法檢驗與顏色顯示。一般用戶會有 vi=vim 的命令別名,但是 root 則是單純使用 vi 而已。
如果你想要使用 vi 就直接以 vim 來開啟檔案的話,使用『 alias vi='vim' 』這個設定即可。
至於如果要取消命令別名的話,那麼就使用 unalias 吧!例如要將剛剛的 lm 命令別名拿掉,就使用:
[dmtsai@study ~]$ unalias lm
那麼命令別名與變數有什麼不同呢?命令別名是『新創一個新的指令,
你可以直接下達該指令』的,至於變數則需要使用類似『 echo 』指令才能夠呼叫出變數的內容!
這兩者當然不一樣!很多初學者在這裡老是搞不清楚!要注意啊! ^_^
DOS 年代,列出目錄與檔案就是 dir ,而清除螢幕就是 cls ,那麼如果我想要在
linux 裡面也使用相同的指令呢?
很簡單,透過 clear 與 ls 來進行命令別名的建置:
alias cls='clear'alias dir='ls -l'
10.3.2 歷史命令:history
前面我們提過 bash 有提供指令歷史的服務!那麼如何查詢我們曾經下達過的指令呢?就使用
history 囉!當然,如果覺得 histsory 要輸入的字元太多太麻煩,可以使用命令別名來設定呢!
不要跟我說還不會設定呦! ^_^
[dmtsai@study ~]$ alias h='history'
如此則輸入 h 等於輸入 history 囉!好了,我們來談一談 history 的用法吧!
[dmtsai@study ~]$ history [n]
[dmtsai@study ~]$ history [-c]
[dmtsai@study ~]$ history [-raw] histfiles
選項與參數:
:數字,意思是『要列出最近的 n 筆命令列表』的意思!
:將目前的 shell 中的所有 history 內容全部消除
:將目前新增的 history 指令新增入 histfiles 中,若沒有加 histfiles ,
則預設寫入 ~/.bash_history
:將 histfiles 的內容讀到目前這個 shell 的 history 記憶中;
:將目前的 history 記憶內容寫入 histfiles 中!
範例一:列出目前記憶體內的所有 history 記憶
[dmtsai@study ~]$ history
# 前面省略
# 列出的資訊當中,共分兩欄,第一欄為該指令在這個 shell 當中的代碼,
# 另一個則是指令本身的內容喔!至於會秀出幾筆指令記錄,則與 HISTSIZE 有關!
範例二:列出目前最近的 3 筆資料
[dmtsai@study ~]$ history 3
範例三:立刻將目前的資料寫入 histfile 當中
[dmtsai@study ~]$ history -w
# 在預設的情況下,會將歷史紀錄寫入 ~/.bash_history 當中!
[dmtsai@study ~]$ echo ${HISTSIZE}
在正常的情況下,歷史命令的讀取與記錄是這樣的:
當我們以 bash 登入 Linux 主機之後,系統會主動的由家目錄的 ~/.bash_history
讀取以前曾經下過的指令,那麼 ~/.bash_history 會記錄幾筆資料呢?這就與你 bash 的
HISTFILESIZE 這個變數設定值有關了!
假設我這次登入主機後,共下達過 100 次指令,『等我登出時,
系統就會將 101~1100 這總共 1000 筆歷史命令更新到 ~/.bash_history 當中。』
也就是說,歷史命令在我登出時,會將最近的 HISTFILESIZE 筆記錄到我的紀錄檔當中啦!
當然,也可以用 history -w 強制立刻寫入的!那為何用『更新』兩個字呢?
因為 ~/.bash_history 記錄的筆數永遠都是 HISTFILESIZE 那麼多,舊的訊息會被主動的拿掉!
僅保留最新的!
那麼 history 這個歷史命令只可以讓我查詢命令而已嗎?呵呵!當然不止啊!
我們可以利用相關的功能來幫我們執行命令呢!舉例來說囉:
[dmtsai@study ~]$ !number
[dmtsai@study ~]$ !command
[dmtsai@study ~]$ !!
選項與參數:
:執行第幾筆指令的意思;
command :由最近的指令向前搜尋『指令串開頭為 command』的那個指令,並執行;
:就是執行上一個指令(相當於按↑按鍵後,按 Enter)
[dmtsai@study ~]$ history
man history
[dmtsai@study ~]$ !66
&==

我要回帖

更多关于 2018三层别墅设计图纸 的文章

 

随机推荐