1. 程式人生 > >Shell全域性變數、區域性變數與特殊變數筆記總結

Shell全域性變數、區域性變數與特殊變數筆記總結

變數型別:全域性變數(環境變數)和區域性變數(本地變數)
環境變數可以在定義它們的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}等同)?

a=192.168.1.1
b='192.168.1.2'
c="192.168.1.3"
echo "A=$a"
echo "B=$b"
echo "C=${c}"
a=192.168.1.1-$b
b='192.168.1.2-$b'
c="192.168.1.3-$b"
echo "A=$a"
echo "B=$b"
echo "C=${c}"

輸出結果如下:

A=192.168.1.1
B=192.168.1.2
C=192.168.1.3
A=192.168.1.1-192.168.1.2
B=192.168.1.2-$b
C=192.168.1.3-192.168.1.2-$b

總結分析:
單引號與雙引號的區別在於:單引號內若存在變數,存在的變數當做字串不會被解析,原樣輸出;而雙引號中若存在變數,該變數會被解析出其具體的值再加入到字串中。①不加引號可以直接定義內容包含數字、字串、路徑名等,適合定義數字②單引號適合於純定義字串,③而雙引號適合於字串的內容中包含有變數的內容的定義。(習慣:數字以及不帶空格的簡單字串不加引號,其它長的特別是有空格的字串加雙引號;遇到“$變數名”,但不想解析的加單引號,但一般出現$都是為了解析變數,所以單引號較少使用)

注意:單引號與雙引號的特點不具有普遍性,如下:
在普通shell中:

ETT=123
echo '$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_kang
tar -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命令列中引數的總個數
[email protected]:這個程式的所有引數"$1" "$2" "$3" "...",這是將引數傳遞給其它程式的最佳方式,因為它會保留所有內嵌在每個引數裡的任何空白

$*與[email protected]的區別:
$*將命令列的所有引數視為一個字串:"$1$2$3..."
[email protected]將命令列的每個引數視為單個的字串:"$1" "$2" "$3" ...

基本測試如下:
這裡寫圖片描述

獲取狀態變數:
$$:獲取當前的shell程序號
$?:獲取執行上一個指令的返回值(0為成功,非零為失敗),可以對上一個命令執行是否成功進行判斷。
$_:在此之前執行的命令或指令碼的最後一個引數

$?變數其實獲取的是上一個程式返回給父程序shell的返回值(該值在0-255之間:0表示執行成功,2表示許可權拒絕,1~125為執行失敗原因是指令碼命令、系統命令錯誤或引數傳遞錯誤,126為找到該命令但是無法執行,127為無該命令/程式,>128表示命令被系統強制結束)

$?的不同返回值測試:
這裡寫圖片描述
$?的值範圍測試如下:

這裡寫圖片描述

$?在指令碼中的應用:
常用來判斷上一步是否成功(壓縮失敗列印ERROR壓縮成功列印OK):
這裡寫圖片描述