變數類型:全域變數(環境變數)和局部變數(本地變數)
環境變數可以在定義它們的shell及其派生出來的任意子進程的shell中使用。局部變數只能在定義它們的函數/指令碼中使用。還有一些變數是使用者建立的,其他的則是專用的shell變數。 1、全域變數(環境變數):
環境變數可用於定義shell的運行環境,環境變數可以在設定檔中定義與修改,也可以在命令列中設定,但是命令列中的修改操作在終端重啟時就會丟失,因此最好在設定檔中修改(使用者家目錄的“.bash_profile“檔案或者全域配置“/etc/profile”、“/etc/bashrc”檔案或者“/etc/profile.d”檔案中定義。)將環境變數放在profile檔案中,每次使用者登入時這些變數值將被初始化。比如HOME、USER、SHELL、UID等再使用者登入之前就已經被/bin/login程式設定好了。
常見系統內容變數:
TMOUT:設定自動結束的誤操作等待時間
HOSTTYPE:系統檔案系統類型
HISTSIZE:曆史命令記錄條數
HOME:使用者登入時進入的目錄,家目錄
UID:目前使用者的id
SHELL:當前shell解譯器
PWD:當前所在路徑(每改變一次目錄,該值就會改變)
PATH:可執行檔預設路徑
等等。
可以用echo來顯示查看全域變數(eg:echo $HOME)。env(或printenv)、set也可以用來查看系統的環境變數,但不是單獨查看。而用unset臨時取消環境變數(eg:unset USER),要永久生效還是要寫到設定檔中
自訂環境變數(採用export):
①export 變數名=value
②變數名=value;export 變數名
③declare -x 變數名=value
這裡依舊是臨時生效,在shell終端關閉後就消失了,寫到設定檔中則永久生效(注意:寫到設定檔中後需要運行一遍設定檔的指令碼才可生效,否則等重啟時生效)
命令列的三種方式測試如下:
關於環境變數PATH與export的更詳細的內容,可參考: Linux環境變數與系統編程學習筆記 2、局部變數(本地變數):
本地變數在使用者當前的shell生存期的指令碼中使用。在一個函數中將某個變數聲明為local,則該變數就是一個局部變數,只在本函數中有效。
定義:
變數名=value
變數名=’value’
變數名=”value”
shell中變數名的要求:一般遵循字母、數字、下滑線組成,不能以數字開頭
eg:以下指令碼執行後(互動式非互動式都可以測試)輸出什麼( c與 c與{c}等同)。
a=192.168.1.1b='192.168.1.2'c="192.168.1.3"echo "A=$a"echo "B=$b"echo "C=${c}"a=192.168.1.1-$bb='192.168.1.2-$b'c="192.168.1.3-$b"echo "A=$a"echo "B=$b"echo "C=${c}"
輸出結果如下:
A=192.168.1.1B=192.168.1.2C=192.168.1.3A=192.168.1.1-192.168.1.2B=192.168.1.2-$bC=192.168.1.3-192.168.1.2-$b
總結分析:
單引號與雙引號的區別在於:單引號內若存在變數,存在的變數當做字串不會被解析,原樣輸出;而雙引號中若存在變數,該變數會被解析出其具體的值再加入到字串中。①不加引號可以直接定義內容包含數字、字串、路徑名等,適合定義數字②單引號適合於純定義字串,③而雙引號適合於字串的內容中包含有變數的內容的定義。(習慣:數字以及不帶空格的簡單字串不加引號,其它長的特別是有空格的字串加雙引號;遇到“$變數名”,但不想解析的加單引號,但一般出現$都是為瞭解析變數,所以單引號較少使用)
注意:單引號與雙引號的特點不具有普遍性,如下:
在普通shell中:
ETT=123echo '$ETT'//列印$ETT(單引號不解析)echo "$ETT" //列印123(雙引號解析)
而在awk中調用shell變數:
awk 'BEGIN {print '$ETT'}'//列印123(單引號解析)awk 'BEGIN {print "$ETT"}'//列印$ETT(雙引號不解析)
雖然在awk中不具有普遍性,但是在普通Shell中還是具有普遍性的。 3、關於局部變數的其它一些問題
①用反引號將命令的結果作為變數名是常用的方法,eg:cmd=`date +%F`②用$符號將命令的結果作為變數名也比較常用,eg:cmd=$(date +%F)③變數在大括弧上的使用:在以時間、主機名稱等為包名一部分來打包的時候常用
eg1:用時間作為檔案名稱的一部分打包
cmd=$(date +%F) //由於`date +%F`的反引號不容易辨認,就不太使用`date +%F`tar -zcf code_$(date+ %F)_kang.tar.gz /etc //沒有問題tar -zcf code_`date +%F`_kang.tar.gz /etc //沒有問題tar -zcf code_kang_$cmd.tar.gz /etc //沒有問題tar -zcf code_$cmd_kang.tar.gz /etc//會有歧義,因為系統會不清楚是應該解析$cmd還是cmd_kangtar -zcf code_${cmd}_kang.tar.gz /etc //不會有歧義
對後兩種測試結果如下(不加{}的與理想結果是不符的):
eg2:用主機名稱與時間打包
cmd=$(date +%F)host=$(hostname)tar -zcf code_${cmd}_${host}.tar.gz /etc
測試:
養成將字串括起來使用的習慣防止不易發現的錯誤。 4、Shell的特殊變數:
$0:擷取當前執行的shell指令碼的檔案名稱(執行時給定的是完整路徑則擷取到的也是完整路徑)
兩個命令與$0的組合測試:擷取一個帶路徑的檔案的路徑名與檔案名稱兩部分
dirname(擷取目錄名部分)basename(擷取檔案名稱部分)
測試:
$n:擷取當前執行的shell指令碼的第n個參數,如果n=0則擷取的是指令碼的檔案名稱。如果n>9則需要用大括弧括起來,eg:${21}
測試$n:
$*:擷取當前執行的shell的所有參數,將所有的命令列參數視為單個字串$#:擷取當前shell命令列中參數的總個數$@:這個程式的所有參數"$1" "$2" "$3" "...",這是將參數傳遞給其它程式的最佳方式,因為它會保留所有內嵌在每個參數裡的任何空白$*與$@的區別:$*將命令列的所有參數視為一個字串:"$1$2$3..."$@將命令列的每個參數視為單個的字串:"$1" "$2" "$3" ...
基本測試如下:
擷取狀態變數:$$:擷取當前的shell進程號$?:擷取執行上一個指令的傳回值(0為成功,非零為失敗),可以對上一個命令執行是否成功進行判斷。$_:在此之前執行的命令或指令碼的最後一個參數
$?變數其實擷取的是上一個程式返回給父進程shell的傳回值(該值在0-255之間:0表示運行成功,2表示許可權拒絕,1~125為運行失敗原因是指令碼命令、系統命令錯誤或參數傳遞錯誤,126為找到該命令但是無法執行,127為無該命令/程式,>128表示命令被系統強制結束)
$?的不同傳回值測試:
$?的值範圍測試如下:
$?在指令碼中的應用:
常用來判斷上一步是否成功(壓縮失敗列印ERROR壓縮成功列印OK):