shell 腳本與函數(shù)還有位置參數(shù)的功能;傳統(tǒng)的說(shuō)法應(yīng)該是”命令行參數(shù)”;
shell 為內(nèi)嵌算數(shù)提供了一種標(biāo)記法,稱(chēng)為算數(shù)展開(kāi).shell 回對(duì)$((...))里的算符表達(dá)式進(jìn)行計(jì)算,再將計(jì)算后的結(jié)構(gòu)放回到命令的文本內(nèi).
有兩個(gè)相似的命令提供變量的管理,一個(gè)是 readonly,它可以使變量稱(chēng)為只讀模式;而賦值給它們是被禁止的.在 shell 程序中,這是創(chuàng)建符號(hào)常量的一個(gè)好方法:
days_per_week=7 賦值
readonly days_per_week 設(shè)為只讀模式
export,readonly
語(yǔ)法:
export name[=word]...
export -p
readonly name[=word]...
readonly =p
用途:
export 用于修改或打印環(huán)境變量,readonly 則使得變量不得修改.
主要選項(xiàng):
-p:打印命令的名稱(chēng)以及所有被到處(只讀)變量的名稱(chēng)與值,這種方式可使得 shell 重新讀取輸出以便重新建立環(huán)境(只讀設(shè)置).
行為模式:
使用-p 選項(xiàng),這兩條命令都會(huì)分別打印他們的名稱(chēng)以及被到處的或只讀的所有變量.
較常見(jiàn)的命令是 export,用法是將變量放進(jìn)環(huán)境變量里.環(huán)境是一個(gè)名稱(chēng)與值的簡(jiǎn)單列表,可供所有執(zhí)行中的程序使用.新的進(jìn)程會(huì)從父進(jìn)程繼承環(huán)境,也可以在建立新的紫禁城之前修改它.export 命令可將新變量添加到環(huán)境中:
PATH=$PATH:/usr/local/bin 更新 PATH
export PATH 導(dǎo)出它
使用 export -p 命令可以顯示當(dāng)前環(huán)境
變量可以添加到程序環(huán)境中,但是對(duì) shell 或接下來(lái)的命令不會(huì)一直有效:將該變量賦值,置于命令名稱(chēng)與參數(shù)前即可:
PATH=/bin:/usr/bin awk ‘...’ file1 file2
這個(gè) PATH 值只對(duì)后面 awk 起作用,其他命令將使用系統(tǒng) PATH.
使用 env 命令顯示所有環(huán)境變量.
unset 命令從執(zhí)行中的 shell 中刪除變量與函數(shù).
案例:
清除環(huán)境變量的值使用 unset 命令.如果未定義指定值,則該變量值將被設(shè)為 NULL.
首先使用命令export TEST=”test”來(lái)增加一個(gè)環(huán)境變量
接著使用命令env | grep TEST,得到結(jié)果 TEST=test
然后使用命令unset $TEST 刪除環(huán)境變量 TEST
最后使用命令env | grep TEST命令,該命令不會(huì)有輸出,說(shuō)明成功的刪除了.
其中 unset 還可以通過(guò)添加-f選項(xiàng)刪除指定的函數(shù).
unset 的行為模式
如果沒(méi)有提供選項(xiàng),則參數(shù)將視為變量名稱(chēng),并告知變量已刪
除,如果使用-f 選項(xiàng),參數(shù)則被視為函數(shù)名稱(chēng),并刪除函數(shù).
注意:myvar=賦值并不會(huì)將 myvar 刪除,只不過(guò)試講其設(shè)為 null 字符串.相對(duì)的:unset myvar 完全刪除它.這一差異在于”是變量設(shè)置”以為”是變量設(shè)置,但非 null”展開(kāi).
參數(shù)展開(kāi)
var =”hello,world”
echo ${var}
hello,world
其實(shí)這里說(shuō)的參數(shù)(parameter)不就是我們通常說(shuō)的變量(variable)么? 嗯。。其實(shí)大部分時(shí)候這倆名詞的意思基本等同。只不過(guò)在 Shell 中 parameter(參數(shù))是 variable(變量)的超集: 變量名不能以數(shù)字開(kāi)頭,而參數(shù)名可以。比如說(shuō)$1 就表示命令行傳入的第一個(gè)參數(shù)。
參數(shù)展開(kāi)是 shell 提供變量值在程序中使用的過(guò)程:例如,作為新變量的值,或是作為命令行的部分或全部參數(shù).最簡(jiǎn)單的形式如下所示:
reminder =”Time to go to the dentist” 將值存儲(chǔ)在 reminder 中
sleep 120 等待兩分鐘
echo $reminder 顯示信息
在 shell 下,有更復(fù)雜的形式可用于更特殊的情況.這些形式都是將變量名稱(chēng)括在花括號(hào)里(${variable}),然后再增加額外的語(yǔ)法以告訴 shell 該做些什么.花括號(hào)本身也是很好用的,當(dāng)你需要在變量名稱(chēng)之后馬上跟著一個(gè)可能會(huì)解釋為名稱(chēng)一部分的字符時(shí),他就派上用場(chǎng)了:
reminder =”Time to go to the dentist” 將值存儲(chǔ)在reminder中 sleep 120 等待兩分鐘 echo ${reminder} 顯示信息
警告:默認(rèn)情況下,未定義的變量會(huì)展開(kāi)為 null(空的)字符串.程序隨便亂寫(xiě),就可能會(huì)導(dǎo)致災(zāi)難發(fā)生:
rm -rf /$MYPROGRAM 如果未設(shè)置 MYPROGRAM,就會(huì)有大災(zāi)難發(fā)生了,所以在寫(xiě) 程序時(shí)一定要小心.
第一組字符串處理運(yùn)算符用來(lái)測(cè)試變量的存在狀態(tài),且為在某種情況下的允許默認(rèn)值的替換.
替換運(yùn)算符
|
運(yùn)算符 |
替換 |
|
${varname:=word} |
如果varname存在且不是null,則返回它的值;否則,設(shè)置它為word,并返回其值 用途:如果變量未定義,則返回默認(rèn)值. 范例:如果?count未定義,則?echo?${count:-0}的值為0 |
|
${varname:word} |
如果varname存在且不是null,則返回它的值;否則,設(shè)置它為word,并返回其值. 用途:如果變量未定義,則設(shè)置變量為默認(rèn)值. 范例:如果count未定義,echo${count:=0}輸出為0 |
|
${varname:?message} |
如果varname存在且非null,則返回它的值;否則,顯示varname:message,并退出當(dāng)前的命令或腳本.省略message會(huì)出現(xiàn)默認(rèn)信息parameter?null?or?not?set.注意,在交互式shell下不需要退出(在不同的shell間會(huì)有不同的行為,用戶(hù)需自行注意). 用途:為了捕捉由于變量未定義所導(dǎo)致的錯(cuò)誤. 范例:${count:?”undefined”}將顯示:count:undefined!,且如果count未定義,則退出 |
|
${varname:+word} |
如果varname存在且非null,則返回word;否則,返回null. 用途:未測(cè)試變量的存在. 如果:如果count已定義,則${count:+1}返回1(也就是真) |
該表中每個(gè)運(yùn)算符內(nèi)的冒號(hào)(:)都是可選的.如果省略冒號(hào),則將每個(gè)定義的”存在且非 null”部分改為”存在”,也就是說(shuō),運(yùn)算符僅用于測(cè)試變量是否存在.
模式匹配運(yùn)算符
|
運(yùn)算符 |
替換 |
|
例:${path#/*/} |
結(jié)果:tolstoy/mem/long.file.name |
|
例:${variable##pattern} |
如果模式匹配于變量值的開(kāi)頭處,則刪除匹配的最長(zhǎng)部分,并返回剩下的部分. |
|
例:${path##/*/} |
結(jié)果:long.file.name |
|
例:${path%.*} |
結(jié)果:/home/tolstoy/mem/long.file |
|
例:${variable%pattern} |
如果模式匹配于變量值的結(jié)尾處,則刪除匹配的最短部分,并返回剩下的部分. |
|
例:${variable%%pattern} |
如果模式匹配于變量值的結(jié)尾處,則刪除匹配的最長(zhǎng)部分,并返回省下的部分 |
|
例:${path%%.*} |
結(jié)果:/home/tolstoy/mem/long |
案例分析:${parameter#word}或{parameter##word}
作用:從 parameter 頭部開(kāi)始匹配 word,并刪除成功匹配的部分.在構(gòu)造 word 時(shí)可以使用””表示任意長(zhǎng)度的字符,”?”表示單位長(zhǎng)度字符,并可用形如”[a-c]”的方式制定匹配”abc”中的任意字符.
另外,”#”和”##”的區(qū)別在于前置是匹配最短,而后者是最長(zhǎng)匹配;實(shí)際上就是正則表達(dá)式中的”懶惰”和”貪婪”的概念.
var=br1br2ead
```echo ${var$$br} 輸出:2ead echo ${var#br} 輸出:1br2ead 案例: ${parameter%word}或${parameter%%word} 作用:與前例相似,唯一不同的是從$parameter 的為不開(kāi)始匹配. var="La.Maison.en.Petits.Cubes.avi" echo ${var%.} 輸出:La.Maison.en.Petits.Cubes echo ${var%%.}```
輸出:La
分析:匹配案例中的”.”時(shí),shel l會(huì)從$var 的尾部開(kāi)始查找”.”,如果是最短匹配(echo ${var%.}),則會(huì)找到第一個(gè)”.”就停止,否則(echo ${var%%.*})會(huì)一直找到最后一個(gè)”.”才停止.可以看到,這種用法可以分方便的去掉文件后綴,從而得到文件名.
使用${#variable}可以獲得 variable 的長(zhǎng)度:
案例:variable=qwertyuiop;
echo ${#variable}
輸出:10
記憶:
這里用到了兩種匹配模式://,匹配任何位于兩個(gè)斜杠之間的元素;.,匹配點(diǎn)號(hào)之后接著的任何元素.
所謂的位置參數(shù),指的是 shell 腳本的命令行參數(shù);同時(shí)也表示 zaishell 函數(shù)內(nèi)的函數(shù)參數(shù),他們的名稱(chēng)是以單個(gè)的整數(shù)來(lái)命名.當(dāng)整數(shù)大于9時(shí),就應(yīng)該以花括號(hào)括起來(lái):
echo frist arg is $1
echo tenth arg is ${10}
也可以將其與模式匹配運(yùn)算符結(jié)合,應(yīng)用到位置參數(shù):
filename=${1:-/dev/tty} 如果給定參數(shù)則使用它,如無(wú)參數(shù)則使用/dev/tty
接下來(lái)的特殊”變量”提供了對(duì)傳遞的參數(shù)的總數(shù)的訪問(wèn),以及一次對(duì)所有參數(shù)的訪問(wèn):
$# : 提供傳遞到 shell 腳本或函數(shù)的參數(shù)總是.當(dāng)你是為了處理選項(xiàng)和參數(shù)而建立循環(huán)時(shí),它會(huì)很有用.舉例:
while [ $# !=0 ] 以 shift 逐漸減少$#,循環(huán)將會(huì)終止
do
case $1 in
... 處理第一個(gè)參數(shù)
esac
shift 已開(kāi)第一個(gè)參數(shù)
done
$*,$@ : 以此表示所有的命令行參數(shù).著兩個(gè)參數(shù)可用來(lái)把命令行參數(shù)傳遞給腳本或函數(shù)所執(zhí)行的程序.
“$” : 將所有命令行參數(shù)視為單個(gè)字符串.等同于”$1 $2 ...” $IFS 的第一個(gè)字符用來(lái)作為分隔符,衣服個(gè)不同的值來(lái)建立字符串.案例: printf “他和 arguments were %s\n” “$”
“$@” : 將所有的命令韓參數(shù)視為單獨(dú)的而個(gè)體,就業(yè)就單獨(dú)字符串.等同于”$1” “$2” ....這是將參數(shù)傳遞給其他程序的最佳凡是,因?yàn)樗麜?huì)保留所有的內(nèi)嵌在每個(gè)參數(shù)里的任何空白.案例:
lpr “$@” 現(xiàn)實(shí)每一個(gè)文件
shift 命令是用來(lái)”截去”來(lái)自列表的位置參數(shù),由左開(kāi)始.一旦執(zhí)行 shift,$1 的初值會(huì)永遠(yuǎn)消失,取而代之的是$2 的舊值.$2 的值變成$3 的舊值,依次類(lèi)推.$#的值會(huì)逐次減一.shift 也可使用一個(gè)可選的參數(shù),也就是要位移的參數(shù)的計(jì)數(shù).單純的 shift 等同于 shift 1.案例:
set -- hello “hi there” greetings 結(jié)束選項(xiàng)部分,自 hello 開(kāi)始新的參數(shù)
echo $# 顯示計(jì)數(shù)值
for i in $* 循環(huán)處理每一個(gè)參數(shù)
> do echo i is $i
> done
輸出:
i is hello
i is hi
i is there
i is greeting
注意,內(nèi)嵌的空白已消失
使用命令:for i in $@ 在沒(méi)有雙引號(hào)的額情況下,$@和$得到的結(jié)果一樣
> do echo i is $i
> done
加了雙引號(hào) for i in “$” $*表示一個(gè)字符串
> do echo i in $i
> done
輸出:
i in hello hi there greeting
加了雙引號(hào) for i in “$@” $@保留真正的參數(shù)值
輸出:
i in hello
i in hi there
i in greeting
使用命令 shift 截去第一個(gè)參數(shù)
echo there are now $# arguments
輸出:there are now 2arguments 證明第一個(gè)參數(shù)已經(jīng)消失
使用命令:
for i in “$@”
輸出為:
i in hi there
i in greeting
POSIX 中的內(nèi)置變量
|
變量 |
意義 |
|
# |
表示變量的個(gè)數(shù),常用于循環(huán) |
|
@ |
當(dāng)前命令行所有參數(shù),置于雙引號(hào)中,表示個(gè)別命令 |
|
* |
當(dāng)前命令行所有參數(shù).置于雙引號(hào)中,表示將命令行所有參數(shù)當(dāng)做一個(gè)單獨(dú)參數(shù) |
|
-(連字號(hào)) |
在引用數(shù)給予shell的選項(xiàng) |
|
? |
表示上一個(gè)命令退出的狀態(tài) |
|
$ |
表示當(dāng)前進(jìn)程編號(hào) |
|
0 |
表示當(dāng)前進(jìn)程名稱(chēng) |
|
! |
表示最近一個(gè)后臺(tái)命令的進(jìn)程編號(hào) |
|
HOME |
表示當(dāng)前用戶(hù)的根目錄 |
|
IFS |
表示內(nèi)部的字符分隔符 |
|
LANG |
當(dāng)前locale默認(rèn)名稱(chēng) |
|
PATH |
環(huán)境變量 |
|
PPID |
父進(jìn)程編號(hào) |
|
PWD |
當(dāng)前工作目錄 |
特殊變量$$可在編寫(xiě)腳本時(shí)用來(lái)建立具有唯一性的文件名(多半是臨時(shí)的),這是根據(jù) shell 的進(jìn)程編號(hào)建立文件名.不過(guò)系統(tǒng)中還有一個(gè) mktemp 也能做同樣的事情.
shell 的算數(shù)運(yùn)算符與C語(yǔ)言里的差不多,優(yōu)先級(jí)與順序也相同.
|
運(yùn)算符 |
意義 |
順序 |
|
++?-- |
增加以減少,可前置也可放在結(jié)尾 |
由左至右 |
|
+?-?!?~ |
一元的正好與符號(hào);邏輯與位的取反 |
由右至左 |
|
*?/?% |
乘?除?取余 |
由左至右 |
|
+?- |
加?減 |
由左至右 |
|
?<<?>> |
向左位移,向右位移 |
由左至右 |
|
<?<=?>?>= |
比較 |
由左至右 |
|
==?!= |
相等不相等 |
由左至右 |
|
& |
位的AND |
由左至右 |
|
^ |
韋德Exclusive?OR |
由左至右 |
|
| |
位的OR |
由左至右 |
|
&& |
邏輯的AND |
由左至右 |
|
|| |
邏輯的OR |
由左至右 |
|
?: |
條件表達(dá)式 |
由右至左 |
|
=?+=?-=?*=?/=&=?^=?<<=?>>=?|= |
賦值運(yùn)算符 |
由右至左 |
該表的運(yùn)算符的優(yōu)先級(jí)由高排列至最低.
可利用圓括號(hào)將子表達(dá)式語(yǔ)句括起來(lái).像 C 一樣:關(guān)系運(yùn)算符(<,<=,>,>=,==與!=)產(chǎn)生數(shù)字結(jié)果中,1 為真,0 為假.
例如:$((3>2))的值為 1;echo $(((3>2)||(4<=1)))也為 1,因?yàn)橹鴥蓚€(gè)子表達(dá)式里有一個(gè)為真.
對(duì)邏輯的 AND 與 OR 運(yùn)算符而言,任何非 0 值函數(shù)都為真:
echo $((3&&4)) 3 與 4 都為”真”
++和--運(yùn)算符不用說(shuō)了.++與--運(yùn)算符是可選的;實(shí)際上,所有支持 ${{...}}的 shell,都可以讓用戶(hù)在提供變量名稱(chēng)時(shí),無(wú)須前置$符號(hào).