1. 程式人生 > >鳥哥的Linux私房菜讀書筆記--shell的變數功能

鳥哥的Linux私房菜讀書筆記--shell的變數功能

1、變數的特性

            變數的可變性和方便性、影響bash環境操作的變數、指令碼程式的設計。一般情況下系統內定變數為大寫。

2、變數的取用與設定

<1>變數的取用

             命令:$  echo $變數名

             命令:$  echo $ { 變數名 }

<2>變數的設定(變數命名失敗後需要按下復原鍵:ctrl+v)

  變數的設定規則 (1) 變數與變數內容以一個等號『=』來連結,如下所示:『myname=VBird』 (2)等號兩邊不能直接接空格符,如下所示為錯誤:『myname = VBird』或『myname=VBird Tsai』 (3)變數名稱只能是英文字母與數字,但是開頭字元不能是數字,如下為錯誤:『2myname=VBird』 (4)變數內容若有空格符可使用雙引號『"』(成對)或單引號『'』(成對)將變數內容結合起來,但          o 雙引號內的特殊字元如 $ 等,可以保有原本的特性

,如下所示:           『var="lang is $LANG"』則『echo $var』可得『lang is zh_TW.UTF-8』          o 單引號內的特殊字元則僅為一般字元 (純文字),如下所示:           『var='lang is $LANG'』則『echo $var』可得『lang is $LANG』 (5)可用跳脫字元『 \ 』將特殊符號(如 [Enter], $, \, 空格符, '等)變成一般字元,如:『myname=VBird\ Tsai』 (6)在一串指令的執行中,還需要藉由其他額外的指令所提供的資訊時,可以使用反單引號『`指令`』或 『$(指           令)』。特別注意,那個 ` 是鍵盤上方的數字鍵 1 左邊那個按鍵,而不是單引號! 例如想要取得核心版本的設定:          『version=$(uname -r)』再『echo $version』可得『3.10.0-229.el7.x86_64』 (7)若該變數為擴增變數內容時,則可用 "$變數名稱" 或 ${變數} 累加內容,如下所示:         『PATH="$PATH":/home/bin』或『PATH=${PATH}:/home/bin』 (8) 若該變數需要在其他子程式執行,則需要以 export 來使變數變成環境變數:『export PATH』 (9)通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷 (純粹依照使用者興趣與嗜好) ; (10) 取消變數的方法為使用 unset :『unset 變數名稱』例如取消 myname 的設定:『unset myname』

在當前shell下去啟用新的shell,新啟用的即為其子程式,一般情況下父程式定義的變數在子程式中是無法使用的,可以通過export命令將變數變成環境變數,就能夠在子程式下使用了。

3、環境變數的功能

<1>用env觀察環境變數與常見你環境變數說明

命令:$  env       ##列出當前shell環境下 的所有環境變數與其內容

變數:HOME    使用cd  ~可以切換到自己的家目錄下,其實質是採用變數~來代替家目錄的路徑

變數:SHELL    檢視當前環境使用的shell是哪種

變數:HISTSIZE    檢視歷史指令

變數:MAIL    當使用mail指令收信時,系統會讀取郵箱信件

變數:PATH    執行檔案搜尋路徑,目錄間用:隔開

變數:LANG    檢視語系資料

變數:RANDOM    檢視由隨機數生成器生成的隨機數

<2>用set觀察所有變數(含環境變數與自定義變數)

命令:$ set

變數: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 時,提示字元為 # ,否則就是 $ 囉~

變數:$     關於本機的shell的PID,即執行緒代號(process  ID)

變數:?    關於上一個指令的回傳值。執行某些指令時,這些指令都會回傳一個執行後的程式碼,如果成功執行指令,則回傳                       值為0,如果錯誤就會回傳錯誤程式碼

變數:OSTYPE,HOSTTYPE,MACHTYPE    主機硬體與核心的等級

<3>自定義變數轉化為環境變數

命令:$  export   變數名稱    ##在當前shell下去啟用新的shell,新啟用的即為其子程式,一般情況下父程式定義的變數在子                                                      程式中是無法使用的,可以通過export命令將變數變成環境變數,就能夠在子程式下使用了。

4、影響顯示結果的語系變數

命令:$ locale    ##檢視支援語系

當系統設定LANG或者LC_ALL時,其它的語系變數將被這兩個取代

主機內的語系檔案放置位置:/usr/lib/locale

整體系統預設語系定義位置:/etc/locale.conf

5、變數的有效範圍

環境變數=全域性變數    自定義變數=區域性變數

環境變數之所以可以被子程式引用是因為記憶體配置關係:

    · 當啟動一個 shell,作業系統會分配一記憶區塊給 shell 使用,此記憶體內之變數可讓子程式取用     · 若在父程式利用 export 功能,可以讓自定義變數的內容寫到上述的記憶區塊當中(環境變數);     · 當載入另一個 shell 時 (亦即啟動子程式,而離開原本的父程式了),子 shell 可以將父 shell 的環境變數所        在的記憶區塊匯入自己的環境變數區塊當中。

6、變數鍵盤讀取、陣列與宣告

<1>讀取

      命令:$ read   [-pt]   變數名       選項與引數:               -p :後面可以接提示字元!               -t :後面可以接等待的『秒數!』

<2>宣告變數的型別(declare / typeset)

      命令:$  declare [-aixr] variable       選項與引數:               -a :將後面名為 variable 的變數定義成為陣列 (array) 型別               -i :將後面名為 variable 的變數定義成為整數數字 (integer) 型別               -x :用法與 export 一樣,就是將後面的 variable 變成環境變數;將-變成+,可以使環境變數轉換為自定義變數。               -r :將變數設定成為 readonly 型別,該變數不可被更改內容,也不能 unset       範例一:讓變數 sum 進行 100+300+50 的加總結果               [[email protected] ~]$ sum=100+300+50               [[email protected] ~]$ echo ${sum}               100+300+50 <==咦!怎麼沒有幫我計算加總?因為這是文字型態的變數屬性啊!               [[email protected] ~]$ declare -i sum=100+300+50               [email protected] ~]$ echo ${sum}               450        由於在預設的情況底下, bash 對於變數有幾個基本的定義:               · 變數型別預設為『字串』,所以若不指定變數型別,則 1+2 為一個『字串』而不是『計算式』。 所以                 上述第一個執行的結果才會出現那個情況的;               · bash 環境中的數值運算,預設最多僅能到達整數形態,所以 1/3 結果是 0;

<3>陣列變數型別

命令:陣列名[序號]=內容

讀取陣列變數時,建議直接以:$ echo   { 陣列名[序號] }來讀取。

7、與檔案系統及程式的限制關係:ulimit

限制使用者的某些系統資源

       命令:$ ulimit [-SHacdfltu] [配額]        選項與引數:               -H :hard limit ,嚴格的設定,必定不能超過這個設定的數值;               -S :soft limit ,警告的設定,可以超過這個設定值,但是若超過則有警告訊息。 在設定上,通常 soft 會                                          比 hard 小,舉例來說,soft 可設定為 80 而 hard設定為 100,那麼你可以使用到 90 (因為沒有超過 100),但                          介於 80~100 之間時,系統會有警告訊息通知你!               -a :後面不接任何選項與引數,可列出所有的限制額度;               -c :當某些程式發生錯誤時,系統可能會將該程式在記憶體中的資訊寫成檔案(除錯用), 這種檔案就被稱為核心檔案                         (core file)。此為限制每個核心檔案的最大容量。               -f :此 shell 可以建立的最大檔案容量(一般可能設定為 2GB)單位為 Kbytes,一般使用者只可減少不可增加。               -d :程式可使用的最大斷裂記憶體(segment)容量;               -l :可用於鎖定 (lock) 的記憶體量               -t :可使用的最大 CPU 時間 (單位為秒)               -u :單一使用者可以使用的最大程式(process)數量。

當想要復原ulimit的設定最簡單的辦法是登出重新登入。亦或者可以重新設定ulimit。

8、變數內容的刪除、取代與替換

<1>變數內容的刪除與取代

          #:符合取代蚊子最短的那個。    ##:符合取代文字最長的那個。

範例一:先讓小寫的 path 自定義變數設定的與 PATH 內容相同 [[email protected] ~]$ path=${PATH} [[email protected] ~]$ echo ${path} /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin 範例二:假設我不喜歡 local/bin,所以要將前 1 個目錄刪除掉,如何顯示? [[email protected] ~]$ 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 範例三:我想要刪除前面所有的目錄,僅保留最後一個目錄 [[email protected] ~]$ 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 [[email protected] ~]$ echo ${path##/*:} /home/dmtsai/bin 多加了一個 # 變成 ## 之後,他變成『刪除掉最長的那個資料』!亦即是:# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin 範例四:我想要刪除最後面那個目錄,亦即從 : 到 bin 為止的字串 [[email protected] ~]$ 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 範例五:那如果我只想要保留第一個目錄呢? [[email protected] ~]$ echo ${path%%:*bin} /usr/local/bin # 同樣的, %% 代表的則是最長的符合字串,所以結果其實是來自如下: # /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin

例題: 假設你是 dmtsai ,那你的 MAIL 變數應該是 /var/spool/mail/dmtsai 。假設你只想要保留最後面那個檔名 (dmtsai), 前面的目錄名稱都不要了,如何利用 $MAIL 變數來達成? 答:題意其實是這樣『/var/spool/mail/dmtsai』,亦即刪除掉兩條斜線間的所有資料(最長符合)。 這個時候你就可 以這樣做即可: [[email protected] ~]$ echo ${MAIL##/*/} 相反的,如果你只想要拿掉檔名,保留目錄的名稱,亦即是『/var/spool/mail/dmtsai』 (最短符合)。但假設 你並不知道結尾的字母為何,此時你可以利用萬用字元來處理即可,如下所示: [[email protected] ~]$ echo ${MAIL%/*}

範例六:將 path 的變數內容內的 sbin 取代成大寫 SBIN: [[email protected] ~]$ echo ${path/sbin/SBIN} usr/local/bin:/usr/bin:/usr/local/SBIN:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin # 這個部分就容易理解的多了!關鍵詞在於那兩個斜線,兩斜線中間的是舊字串 # 後面的是新字串,所以結果就會出現如上述的特殊字型部分囉! [[email protected] ~]$ echo ${path//sbin/SBIN} /usr/local/bin:/usr/bin:/usr/local/SBIN:/usr/SBIN:/home/dmtsai/.local/bin:/home/dmtsai/bin # 如果是兩條斜線,那麼就變成所有符合的內容都會被取代喔!

總結

變數設定方式  說明
${變數#關鍵詞} ${變數##關鍵詞} 若變數內容從頭開始的資料符合『關鍵詞』,則將符合的最短資料刪除 若變數內容從頭開始的資料符合『關鍵詞』,則將符合的最長資料刪除
${變數%關鍵詞} ${變數%%關鍵詞} 若變數內容從尾向前的資料符合『關鍵詞』,則將符合的最短資料刪除 若變數內容從尾向前的資料符合『關鍵詞』,則將符合的最長資料刪除
${變數/舊字串/新字串} ${變數//舊字串/新字串} 若變數內容符合『舊字串』則『第一個舊字串會被新字串取代』 若變數內容符合『舊字串』則『全部的舊字串會被新字串取代』

<2>變數的測試與內容替換(var和str為兩個變數)

變數設定方式  str 沒有設定  str 為空字串 str 已設定非為空字串
var=${str-expr}  var=expr var= var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr}  var= var=expr var=expr
var=${str:+expr}  var= var= var=expr
var=${str=expr} str=expr    var=expr str=expr    var= str不變     var=$str
var=${str:=expr}  str=expr    var=expr str=expr    var=expr str 不變    var=$str
var=${str?expr}  expr 輸出至 stderr  var=  var=$str
var=${str:?expr}  expr 輸出至 stderr  expr 輸出至 stderr  var=$str

總結:(1)  -   不會影響舊變數的內容

           (2):被測試的變數未被設定或者是已被設定為空字串時,都能夠用後面的內容替代。

           (3)(str:)表示沒有設定或為空的字串

           (4)=  用來替換新變數的內容