1Tcl
控制結(jié)構(gòu)允許程序根據(jù)不同的狀態(tài)、條件和參數(shù)來(lái)選擇不同的處理和執(zhí)行路徑,從而使代碼具有更強(qiáng)的靈活性、健壯性和可讀性。
Tcl?提供了?if、if/else、if/elseif、foreach、?for、while?和?switc等命令來(lái)管理控制結(jié)構(gòu)。這些命令和其他語(yǔ)言如C語(yǔ)言的條件語(yǔ)句的作用相同。需要區(qū)別的是在?Tcl?中所有控制結(jié)構(gòu)都是由相應(yīng)的命令來(lái)實(shí)現(xiàn),而?C?語(yǔ)言中則是一條控制語(yǔ)句??刂平Y(jié)構(gòu)通常要求帶有一個(gè)延遲執(zhí)行命令體或者過(guò)程體,這個(gè)命令體需要用花括號(hào)括起來(lái)以加以界定。
1.1if/else 命令
if?命令根據(jù)表達(dá)式的結(jié)果來(lái)執(zhí)行命令體:如果表達(dá)式結(jié)果為真,則執(zhí)行命令體,否則會(huì)執(zhí)行另外一個(gè)條件命令體(如果存在的話)。后面兩個(gè)命令體(elseif?和?else)是可選的。
[語(yǔ)法]?if { test expr?測(cè)試表達(dá)式?}?{
body 1
}?elseif {test expr?測(cè)試表達(dá)式}? {
body2
} else {
test expr
}
1.語(yǔ)法中用以界定過(guò)程體的花括號(hào)一定要和?if?命令在同一行上!因?yàn)閷?duì)?Tcl?來(lái)講,換行符就是命令結(jié)束符,所以如果在?if?表達(dá)式后直接換行,寫(xiě)成:
if { test expr }
{
...
}
就會(huì)出錯(cuò)。Tcl?遇到換行后就認(rèn)為命令結(jié)束,但找不到執(zhí)行命令體,返回錯(cuò)誤。其他的控制命令,還有以后的過(guò)程定義命令等等都存在這個(gè)問(wèn)題。
但情況并不全部如此。當(dāng)在一個(gè)花括號(hào)體內(nèi)或者一個(gè)雙引號(hào)體內(nèi)換行的時(shí)候,解釋器不認(rèn)為是命令的結(jié)束,所以上面的語(yǔ)法中,我們只將執(zhí)行命令體的第一個(gè)花括號(hào)(左括號(hào))留在了?if?命令行和?else?命令行,然后另起一行書(shū)寫(xiě)執(zhí)行命令體的過(guò)程語(yǔ)句,右括號(hào)也被單獨(dú)放到了一行上。這樣做是為了提高可讀性和便于查錯(cuò)。
2.如果?if?后面還有?else/elseif?命令,則要留意?else/elseif?的位置。else/elseif?要跟在?if?執(zhí)行命令體的后面一個(gè)花括號(hào)后,不能分行,要有空格間隔花括號(hào)和?else /elseif。
3.花括號(hào)括起的表達(dá)式、執(zhí)行命令體或者其他內(nèi)容相當(dāng)于變量存在,所以前后與其他命令元素之前要有空格,否則?Tcl?會(huì)返回語(yǔ)法錯(cuò)誤。
4.可以使用多個(gè)?elseif?來(lái)創(chuàng)建一連串的條件命令控制結(jié)構(gòu)。
5.表達(dá)式支持變量替換和命令替換。
6.表達(dá)式的計(jì)算結(jié)果如果是”true”、”yes”和非零值就判斷為真,如果結(jié)果
是”false”、”no”和零則判斷為假。控制命令根據(jù)表達(dá)式結(jié)果來(lái)判斷是否執(zhí)行相應(yīng)的執(zhí)行命令體。
1.2for命令
for?命令和?C?語(yǔ)言的?for?語(yǔ)句相似。for?命令的語(yǔ)法格式為:
[語(yǔ)法]:for {start} {test expr} {next} {body?
}
for?命令有四個(gè)變?cè)?em>start?是預(yù)置條件或者初始化命令,告訴?for?命令起始執(zhí)行條件。test
expr?是條件布爾表達(dá)式,以決定是否執(zhí)行循環(huán)體?body,如果是真,則執(zhí)行循環(huán)體,如果假則退出命令。如果表達(dá)式真,則在執(zhí)行循環(huán)體后處理?next?命令,即?next?是一個(gè)后置命令執(zhí)行體。前三個(gè)變?cè)梢赃x擇置空,而將相應(yīng)的處理放到循環(huán)體?body?中去。
1.3while命令
while?命令格式為:
[語(yǔ)法]:while {test?} {
body
}
while?命令和?for?命令非常相似。只要?test?為真,while?就執(zhí)行循環(huán)體直到?test?變?yōu)榧?。for命令和?while?命令的主要區(qū)別是,在?while?循環(huán)體內(nèi)你必須更改被檢測(cè)的測(cè)試體?test?的值,否則如果值一直沒(méi)有改變成假時(shí),while?將無(wú)限的執(zhí)行循環(huán)體。而?for?命令你可以將這種處理過(guò)程在?next?變?cè)酗@式給出。
1.4switch 命令
switch?命令通過(guò)將給定字符串與不同的匹配模式進(jìn)行匹配從而選擇執(zhí)行多分支命令體。
switch?可基于模式匹配。命令格式為:
[語(yǔ)法]: switch [option]?string?{
pattern-1?{body1}
pattern-2?{body2}
pattern-n?{bodyn}
}
說(shuō)明:
1.option?主要有:
-exact??用精確匹配(默認(rèn));
-glob ?????? ????? ?用?glob?格式行模式匹配;?-regexp???用?正則表達(dá)式模式匹配;?--????????????標(biāo)記選項(xiàng)結(jié)束或者說(shuō)明不用選項(xiàng)。
1.5eval命令
用于創(chuàng)建和運(yùn)行tcl腳本的通用構(gòu)造塊。它接受任一多個(gè)參數(shù),把它們用分隔符串接起來(lái),然后把串接的結(jié)果作為一個(gè)tcl腳本處理。
set reset {
set a 0
set b 0
set c 0
}
...
eval $reset
又如:
set vars {a b c d}
eval unset $vars
串接?unset $vars?參數(shù)后結(jié)果為
unset {a b c d}
然后把以上語(yǔ)句作為一個(gè)tcl腳本執(zhí)行,結(jié)果清除a b c d四個(gè)變量。
1.6source和return命令
讀取一個(gè)文件,將其內(nèi)容作為tcl腳本運(yùn)行。一個(gè)參數(shù),該參數(shù)指定要讀取的文件名。例如:
source init.tcl改命令運(yùn)行init.tcl文件的內(nèi)容??梢杂媒^對(duì)路徑或相對(duì)路徑。source的返回值就是文件內(nèi)容的返回值,即文件中最后一個(gè)命令的返回值。另外source允許在文件內(nèi)的腳本中使用return命令終止過(guò)程。使用source命令,可以將一個(gè)大的腳本分為小的模塊,又一個(gè)主腳本用source調(diào)用其他的腳本模塊??梢酝ㄟ^(guò)把過(guò)程定義放到一個(gè)文件中,把可重用的過(guò)程建立成庫(kù)。
1.7break和continue命令
break?命令可以用來(lái)無(wú)條件停止并跳出循環(huán);continue 命令可以用來(lái)結(jié)束目前這一輪的循環(huán),直接跳到下一輪循環(huán)。
2Perl
2.1布爾值判斷
如果是數(shù)字,0表示假,其它所有數(shù)字都是真。
如果是字符串,空字符串('')為假,其它所有字符串為真(有例外,見(jiàn)下一條)。
如果是字符串'0',perl是當(dāng)作數(shù)值0來(lái)處理的,所以這是唯一的非空但為假的字符串。
如果既不是數(shù)字,也不是字符串,那么先轉(zhuǎn)換為數(shù)字或字符串再做判斷(也就是"undef"表示假,其它所有引用表示真)。
"!"表示取反。
perl有個(gè)技巧,將兩個(gè)"!"一起用,相當(dāng)于"負(fù)負(fù)得正",所以原來(lái)是真的仍然是真的,原來(lái)是假的仍然是假的。但實(shí)際上,perl會(huì)將它們轉(zhuǎn)換值"1"和"undef"。
2.2條件判斷if和unless
它們都是條件判斷語(yǔ)句,都支持else、elsif子句。
其中CONDITION可以是任意一個(gè)標(biāo)量值。布爾值的判斷很簡(jiǎn)單,方式和bash shell有點(diǎn)類似,但有點(diǎn)相反。unless和if判斷方式相反,if的condition為真則執(zhí)行后面的代碼,否則執(zhí)行else或者退出if結(jié)構(gòu)。unless則是condition為假時(shí)才執(zhí)行后面的代碼,否則執(zhí)行else或退出unless結(jié)構(gòu)。所以,unless相當(dāng)于if的else部分,或者相當(dāng)于if (!condition)。一般來(lái)說(shuō),不會(huì)用到unless的else語(yǔ)句,因?yàn)樗耆梢愿木幊蒳f語(yǔ)句。之所以有時(shí)候會(huì)使用unless而不是if的否定形式,是因?yàn)橛袝r(shí)候的條件語(yǔ)句用if來(lái)寫(xiě)確實(shí)不方便。
2.3三目運(yùn)算符
perl也支持三目運(yùn)算符:如果expression返回真,則整個(gè)表達(dá)式返回if_true,否則返回if_false。
例如,求平均值,如果$n=0,則輸出"------"。
它等價(jià)于:
三目運(yùn)算符可以寫(xiě)出更復(fù)雜的分支:
執(zhí)行結(jié)果:
2.4邏輯運(yùn)算符and(&&)、or(||)、not(!)
&&運(yùn)算符只有兩邊為真時(shí)才返回真,且短路計(jì)算:expr1為假時(shí)直接返回false,不會(huì)評(píng)估expr2。||運(yùn)算符只要一邊為真時(shí)就返回真,且短路計(jì)算:expr1為真時(shí)直接返回true,不會(huì)評(píng)估expr2。and和or基本等價(jià)于對(duì)應(yīng)的&&和||,但文字格式的邏輯運(yùn)算符優(yōu)先級(jí)非常低。not和!求反,同樣文字格式的not的優(yōu)先級(jí)很低。因?yàn)榉?hào)格式的邏輯運(yùn)算符優(yōu)先級(jí)很高,所以往往左邊和右邊都會(huì)加上括號(hào),而文字格式的優(yōu)先級(jí)很低,左右兩邊不需加括號(hào)。
or運(yùn)算符往往用于連接兩個(gè)"成功執(zhí)行,否則就"的子句。例如,打開(kāi)文件,如果打開(kāi)失敗,就結(jié)束該perl程序:
更常見(jiàn)的,還會(huì)分行縮進(jìn):
同樣,and運(yùn)算符也常用于連接兩個(gè)行為:左邊為真,就執(zhí)行右邊的操作(例如賦值)。
以下是3個(gè)語(yǔ)句是等價(jià)語(yǔ)句:
2.5while和until循環(huán)
until和其它某些語(yǔ)言的until循環(huán)有所不同,perl的until循環(huán),內(nèi)部的commands主體可能一次也不會(huì)執(zhí)行,因?yàn)镻erl會(huì)先進(jìn)行條件判斷,當(dāng)條件為假時(shí)就執(zhí)行,如果第一次判斷就為真,則直接退出until。
2.6for循環(huán)
Perl中的for循環(huán)采取C語(yǔ)言的for風(fēng)格,例如:
需要注意的是,上面的$i默認(rèn)是全局變量,循環(huán)結(jié)束后還有效。可以使用my關(guān)鍵字將其聲明為局部變量:
for循環(huán)不僅僅只支持?jǐn)?shù)值遞增、遞減的循環(huán)方式,還支持其它類型的循環(huán),只要能進(jìn)行判斷即可。見(jiàn)下面的例子。
for關(guān)鍵字后面括號(hào)中的3個(gè)表達(dá)式都可以省略,但兩個(gè)分號(hào)不能省略:
如果省略第三個(gè)表達(dá)式,則表示一直判斷,直到退出循環(huán)或者無(wú)限循環(huán)。如果省略第二個(gè)表達(dá)式,則表示不判斷,所以會(huì)無(wú)限循環(huán)。如果省略第一個(gè)表達(dá)式,則表示不做初始賦值。例如,下面分別省略第三個(gè)表達(dá)式和省略所有表達(dá)式:
對(duì)于無(wú)限循環(huán),Perl中更好更優(yōu)化的方式是使用:
Perl中的for也支持成員測(cè)試性的遍歷,就像shell中的for i in ...的操作一樣,它期待一個(gè)列表上下文,表示遍歷整個(gè)列表。如果省略控制變量,表示使用$_。例如:
像for遍歷列表元素的操作,可以使用foreach來(lái)替代,大多數(shù)迭代列表的時(shí)候它們可以互換。
2.7foreach循環(huán)
foreach更適合用于遍歷,所有foreach都能直接修改關(guān)鍵字為for而轉(zhuǎn)換成for循環(huán)。當(dāng)寫(xiě)成for格式的時(shí)候,perl通過(guò)判斷括號(hào)中的分號(hào)來(lái)決定這是foreach循環(huán)還是for的普通循環(huán)。但for能實(shí)現(xiàn)的循環(huán)功能,foreach不一定能實(shí)現(xiàn),因?yàn)閒or中有初始變量,有條件判斷,而foreach則是簡(jiǎn)單版的for循環(huán)。
先解釋下foreach的用法:
例如,迭代從1到10的列表:
其中$i稱為控制變量,每迭代一次都會(huì)從迭代列表中取出一個(gè)元素賦值給控制變量。可以省略控制變量,這時(shí)將采用默認(rèn)的變量$_:
foreach可以改寫(xiě)為for:
關(guān)于for循環(huán)和foreach循環(huán),如果在遍歷過(guò)程中修改了元素的值,它會(huì)直接修改原始值。換句話說(shuō),迭代時(shí)賦值給控制變量的元素的引用,而不是賦值元素再賦值給控制變量。
當(dāng)foreach/for遍歷結(jié)束后,控制變量將復(fù)原為foreach/for遍歷前的值(例如未定義的是undef)。
2.8each
each用來(lái)遍歷hash或數(shù)組,每次迭代的過(guò)程中,都獲取hash的key和value,數(shù)組的index(數(shù)值,從0開(kāi)始)和元素值。each放在列表上下文,會(huì)返回key/value或index/element,放在標(biāo)量上下文則只返回key或index。
遍歷hash:
輸出結(jié)果:
遍歷數(shù)組:
輸出結(jié)果:
each放在標(biāo)量上下文:
輸出結(jié)果:
2.9執(zhí)行一次的語(yǔ)句塊
使用大括號(hào)包圍一段語(yǔ)句,這些語(yǔ)句就屬于這個(gè)語(yǔ)句塊,這個(gè)語(yǔ)句塊其實(shí)是一個(gè)循環(huán)塊結(jié)構(gòu),只不過(guò)它只循環(huán)一次。語(yǔ)句塊也有自己的范圍,例如可以將變量定義為局部變量。
2.10循環(huán)控制last、next、redo、LABEL
last相當(dāng)于其它語(yǔ)言里的break關(guān)鍵字,用于退出當(dāng)前循環(huán)塊(for/foreach/while/until/執(zhí)行一次的語(yǔ)句塊都屬于循環(huán)塊),注意是只退出當(dāng)前層次的循環(huán),不會(huì)退出外層循環(huán)next相當(dāng)于其它語(yǔ)言里的continue關(guān)鍵字,用于跳入下一次迭代。同樣只作用于當(dāng)前層次的循環(huán)redo用于跳轉(zhuǎn)到當(dāng)前循環(huán)層次的頂端,所以本次迭代中曾執(zhí)行過(guò)的語(yǔ)句可能會(huì)再次執(zhí)行標(biāo)簽用于為循環(huán)塊打上標(biāo)記,以便那些循環(huán)塊控制關(guān)鍵字(last/next/redo)可以指定操作的循環(huán)層次。
以下是打標(biāo)簽的示例(標(biāo)簽建議采用大寫(xiě)):
上面的標(biāo)簽循環(huán)中,首先讀取一行輸入,然后進(jìn)入foreach遍歷,因?yàn)閟plit沒(méi)有參數(shù),所以使用默認(rèn)參數(shù)$_,這個(gè)$_所屬范圍是while循環(huán),split以空格作為分隔符分割這一行,同時(shí)foreach也沒(méi)有控制變量,所以使用默認(rèn)的控制變量$_,這個(gè)$_所屬范圍是foreach循環(huán)。當(dāng)foreach的$_能匹配字符串"error"則直接退出while循環(huán),而不僅僅是自己的foreach循環(huán)。這里if語(yǔ)句后采用的匹配目標(biāo)是屬于foreach的默認(rèn)變量$_。
例如,這個(gè)perl程序讀取a.txt文件,其中a.txt文件的內(nèi)容如下:
執(zhí)行這個(gè)perl程序:
可見(jiàn),只輸出了a.txt中第二行Error前的4個(gè)單詞。
2.11附加循環(huán)continue
perl中還有一個(gè)continue關(guān)鍵字,它可以是一個(gè)函數(shù),也可以跟一個(gè)代碼塊。
如果指定了BLOCK,continue可用于while和foreach之后,表示附加在循環(huán)結(jié)構(gòu)上的代碼塊。
每次循環(huán)中都會(huì)執(zhí)行此代碼塊,執(zhí)行完后進(jìn)入下一循環(huán)。
在continue代碼塊內(nèi)部,也可以使用redo、last和next控制關(guān)鍵字。所以,這幾個(gè)流程控制關(guān)鍵字更細(xì)致一點(diǎn)的作用是:redo、last直接控制循環(huán)主體,而next是控制continue代碼塊。所以:
實(shí)際上,while和foreach在沒(méi)有給定continue的時(shí)候,邏輯上等價(jià)于給了一個(gè)空的代碼塊,這時(shí)next可以跳轉(zhuǎn)到空代碼而進(jìn)入下一輪循環(huán)。
例如:
輸出結(jié)果:
3Shell
和 Java、PHP 等語(yǔ)言不一樣,sh 的流程控制不可為空,如(以下為 PHP 流程控制寫(xiě)法):
在 sh/bash 里可不能這么寫(xiě),如果 else 分支沒(méi)有語(yǔ)句執(zhí)行,就不要寫(xiě)這個(gè) else。
3.1if else
if 語(yǔ)句語(yǔ)法格式:
寫(xiě)成一行(適用于終端命令提示符):
末尾的?fi?就是?if?倒過(guò)來(lái)拼寫(xiě)。
3.2if else-if else
if else-if else 語(yǔ)法格式:
if else 的?[...]?判斷語(yǔ)句中大于使用?-gt,小于使用?-lt。
如果使用?((...))?作為判斷語(yǔ)句,大于和小于可以直接使用?>?和?<。
以下實(shí)例判斷兩個(gè)變量是否相等:
輸出結(jié)果:
使用?((...))?作為判斷語(yǔ)句:
輸出結(jié)果:
if else 語(yǔ)句經(jīng)常與 test 命令結(jié)合使用,如下所示:
輸出結(jié)果:
3.3for循環(huán)
與其他編程語(yǔ)言類似,Shell支持for循環(huán)。
for循環(huán)一般格式為:
寫(xiě)成一行:
當(dāng)變量值在列表里,for?循環(huán)即執(zhí)行一次所有命令,使用變量名獲取列表中的當(dāng)前取值。命令可為任何有效的?shell?命令和語(yǔ)句。in?列表可以包含替換、字符串和文件名。in列表是可選的,如果不用它,for循環(huán)使用命令行的位置參數(shù)。例如,順序輸出當(dāng)前列表中的數(shù)字:
輸出結(jié)果:
順序輸出字符串中的字符:
輸出結(jié)果:
3.4while 語(yǔ)句
while?循環(huán)用于不斷執(zhí)行一系列命令,也用于從輸入文件中讀取數(shù)據(jù)。其語(yǔ)法格式為:
以下是一個(gè)基本的?while?循環(huán),測(cè)試條件是:如果?int?小于等于?5,那么條件返回真。int?從?1?開(kāi)始,每次循環(huán)處理時(shí),int?加?1。運(yùn)行上述腳本,返回?cái)?shù)字?1?到?5,然后終止。
運(yùn)行腳本,輸出:
while循環(huán)可用于讀取鍵盤(pán)信息。下面的例子中,輸入信息被設(shè)置為變量FILM,按結(jié)束循環(huán)。
3.5無(wú)限循環(huán)
無(wú)限循環(huán)語(yǔ)法格式:
或者
或者
3.6until 循環(huán)
until?循環(huán)執(zhí)行一系列命令直至條件為?true?時(shí)停止。until?循環(huán)與?while?循環(huán)在處理方式上剛好相反。一般?while?循環(huán)優(yōu)于?until?循環(huán),但在某些時(shí)候—也只是極少數(shù)情況下,until?循環(huán)更加有用。until?語(yǔ)法格式:
condition?一般為條件表達(dá)式,如果返回值為?false,則繼續(xù)執(zhí)行循環(huán)體內(nèi)的語(yǔ)句,否則跳出循環(huán)。
以下實(shí)例我們使用?until?命令來(lái)輸出?0 ~ 9?的數(shù)字:
運(yùn)行結(jié)果:
輸出結(jié)果為:
3.7case ... esac
case ... esac?為多選擇語(yǔ)句,與其他語(yǔ)言中的?switch ... case?語(yǔ)句類似,是一種多分支選擇結(jié)構(gòu),每個(gè)?case?分支用右圓括號(hào)開(kāi)始,用兩個(gè)分號(hào)?;;?表示?break,即執(zhí)行結(jié)束,跳出整個(gè)?case ... esac?語(yǔ)句,esac(就是?case?反過(guò)來(lái))作為結(jié)束標(biāo)記。可以用?case?語(yǔ)句匹配一個(gè)值與一個(gè)模式,如果匹配成功,執(zhí)行相匹配的命令。case ... esac?語(yǔ)法格式如下:
case?工作方式如上所示,取值后面必須為單詞?in,每一模式必須以右括號(hào)結(jié)束。取值可以為變量或常數(shù),匹配發(fā)現(xiàn)取值符合某一模式后,其間所有命令開(kāi)始執(zhí)行直至?;;。取值將檢測(cè)匹配的每一個(gè)模式。一旦模式匹配,則執(zhí)行完匹配模式相應(yīng)命令后不再繼續(xù)其他模式。如果無(wú)一匹配模式,使用星號(hào)?*?捕獲該值,再執(zhí)行后面的命令。下面的腳本提示輸入?1?到?4,與每一種模式進(jìn)行匹配:
輸入不同的內(nèi)容,會(huì)有不同的結(jié)果,例如:
下面的腳本匹配字符串:
輸出結(jié)果為:
3.8跳出循環(huán)
在循環(huán)過(guò)程中,有時(shí)候需要在未達(dá)到循環(huán)結(jié)束條件時(shí)強(qiáng)制跳出循環(huán),Shell?使用兩個(gè)命令來(lái)實(shí)現(xiàn)該功能:break?和?continue。
break?命令允許跳出所有循環(huán)(終止執(zhí)行后面的所有循環(huán))。下面的例子中,腳本進(jìn)入死循環(huán)直至用戶輸入數(shù)字大于5。要跳出這個(gè)循環(huán),返回到shell提示符下,需要使用break命令。
執(zhí)行以上代碼,輸出結(jié)果為:
continue?命令與?break?命令類似,只有一點(diǎn)差別,它不會(huì)跳出所有循環(huán),僅僅跳出當(dāng)前循環(huán)。對(duì)上面的例子進(jìn)行修改:
運(yùn)行代碼發(fā)現(xiàn),當(dāng)輸入大于5的數(shù)字時(shí),該例中的循環(huán)不會(huì)結(jié)束,語(yǔ)句?echo "游戲結(jié)束"?永遠(yuǎn)不會(huì)被執(zhí)行
參考文獻(xiàn)
https://www.runoob.com/linux/linux-shell-process-control.html
https://www.junmajinlong.com/shell/script_course/shell_flow_control/
https://blog.csdn.net/J080624/article/details/107457247
https://www.cnblogs.com/kane1990/archive/2011/12/19/2293978.html
https://blog.csdn.net/sinat_41774721/article/details/122928261
https://www.cnblogs.com/huguodong/p/5882597.html
https://www.cnblogs.com/f-ck-need-u/p/9511878.html
https://www.jc2182.com/perl/perl-workflow.html
https://blog.csdn.net/sunshoupo211/article/details/30747887
https://www.runoob.com/perl/perl-conditions.html
https://www.runoob.com/perl/perl-loops.html