SHELL十三問之十三:for、while 與 until 差在哪?

終於,來到shell 十三問的最後一問了...  長長吐一口氣~~~~
7p)P$R4lBj,r/R@
)^ Cl'z y最後要介紹的是 shell script 設計中常見的"循環"(loop)。BSD愛好者樂園G5jo`(d&GM;Qf*Ka`
所謂的 loop 就是 script 中的一段在一定條件下反覆執行的代碼。
A1KKR$rbbash shell  中常用的 loop 有如下三種:BSD愛好者樂園8{;Ha6p.CU t;@|X
* forBSD愛好者樂園u-b-N3Z+Y(pJ6Pa.S
* whileBSD愛好者樂園c4R f&f$H/Be%X;ge
* until
q~]$FABSD愛好者樂園;Z7nH.];f)|.xN�G|4P
for loop 是從一個清單列表中讀進變量值,並"依次"的循環執行 do 到 done 之間的命令行。
Y)s B&Nz例:

dhz6`Y9U"~L5Gb

for var in one two three four fiveBSD愛好者樂園3dk:_6O X{J3E
do
9?^H/@$NO T    echo -----------
[8LT4E6VU3Y    echo '$var is '$varBSD愛好者樂園n [4f3VG
    echoBSD愛好者樂園0d-C ^,W nE*C
done

s8w L [ d

上例的執行結果將會是:BSD愛好者樂園(Z8F'Z!a(tm
1) for 會定義一個叫 var 的變量,其值依次是 one two three four five 。BSD愛好者樂園'f ^Z} s8h!O2o+d
2) 因爲有 5 個變量值,因此 do 與 done 之間的命令行會被循環執行 5 次。
6C�N%E]D LlL3) 每次循環均用 echo 產生三行句子。
-[2{k-@o(Q     而第二行中不在 hard quote 之內的 $var 會依次被替換爲 one two three four five 。
8f5?'Qe/ M.`l4) 當最後一個變量值處理完畢,循環結束。
N$LR I3~ C6?PMBSD愛好者樂園Nu$wVL(Ks2x3P
我們不難看出,在  for loop 中,變量值的多寡,決定循環的次數。BSD愛好者樂園4HDh:^z0SR
然而,變量在循環中是否使用則不一定,得視設計需求而定。
.mjnqT2]Q倘若 for loop 沒有使用 in 這個 keyword 來指定變量值清單的話,其值將從 $@ (或 $* )中繼承:
BSD愛好者樂園d%L `,y-C c

for var; doBSD愛好者樂園,S/Z+v+Et3a
    ....
_#hp(MK'^P.edone

qad`/9T!iB

(若你忘記了 positional parameter ,請溫習第 9 章...)
"kA$Xv0J ]#N QSy }~BSD愛好者樂園}l#W3zw8J X
for loop 用於處理"清單"(list)項目非常方便,其清單除了可明確指定或從 positional parameter 取得之外,也可從變量替換或命令替換取得... (再一次提醒:別忘了命令行的"重組"特性﹗)
ft1Wm E4E(b#k然而,對於一些"累計變化"的項目(如整數加減),for 亦能處理:
BSD愛好者樂園6V2qwu Yf

for ((i=1;i<=10;i++))BSD愛好者樂園Jfh$X2t mN
doBSD愛好者樂園I,GZgV�qh
   echo "num is $i"BSD愛好者樂園U0L9{k�w.gxO
done
BSD愛好者樂園TGG(n;G:K /Vz

除了for loop ,上面的例子我們也可改用  while loop 來做到:BSD愛好者樂園h w9x;nS){

num=1BSD愛好者樂園+/zY m2T:XY)t
while [ "$num" -le 10 ]; do
;nr_0C g q hU    echo "num is $num"BSD愛好者樂園t0V6/#cVFr
    num=$(($num + 1))BSD愛好者樂園C'T0X xaLD `2NQ8z
done
BSD愛好者樂園}1vK-_ ja4y+d

while loop 的原理與 for loop 稍有不同:
z&Q;_Q}它不是逐次處理清單中的變量值,而是取決於 while 後面的命令行之 return value :BSD愛好者樂園5U1tq;FK} B aY-a
* 若爲 ture ,則執行 do 與 done 之間的命令,然後重新判斷 while 後的 return value 。
x8jQ2V+l.H* 若爲 false ,則不再執行 do 與 done 之間的命令而結束循環。
P| @u _0ks kN~pu7KBSD愛好者樂園$n6]d D t%@
分析上例:
:{(Y5F-fI4GN1) 在 while 之前,定義變量 num=1 。BSD愛好者樂園5Hj^fN
2) 然後測試(test) $num 是否小於或等於 10 。
9gM!G�?EcV{4~ V3) 結果爲 true ,於是執行 echo 並將 num 的值加一。BSD愛好者樂園f'[;MI'Gb7Uq9Q0D
4) 再作第二輪測試,其時 num 的值爲 1+1=2 ,依然小於或等於 10,因此爲  true ,繼續循環。BSD愛好者樂園%Z:z8fC-t6Nv r:sr
5) 直到 num 爲 10+1=11 時,測試纔會失敗... 於是結束循環。
+[ ]4RY6d?W%bBSD愛好者樂園$z:m)waW�bU BJ
我們不難發現:BSD愛好者樂園PY.KWZ8V%J
* 若 while 的測試結果永遠爲 true 的話,那循環將一直永久執行下去:

9h(]V_l BP/+c

while :; do
6TU.nq8JV-Q b b    echo looping...
'e#y/cl$X p?Lidone
BSD愛好者樂園/k/6u#Dru"LY

上例的" : "是 bash 的 null command ,不做任何動作,除了送回 true 的 return value 。
(p(Z$/ g}!J因此這個循環不會結束,稱作死循環。
a�[)lEe}o?死循環的產生有可能是故意設計的(如跑 daemon),也可能是設計錯誤。BSD愛好者樂園lei$uj6l k
若要結束死尋環,可透過 signal 來終止(如按下 ctrl-c )。BSD愛好者樂園(M_#o5S3p
(關於 process 與 signal ,等日後有機會再補充,十三問暫時略過。)
c3J,gO:G,S3pmg sBSD愛好者樂園0b6a9pV(|
一旦你能夠理解 while loop 的話,那,就能理解 until loop :BSD愛好者樂園6I(~ D6B,i |
* 與 while 相反,until 是在 return value 爲 false 時進入循環,否則結束。
Nd([!|"y因此,前面的例子我們也可以輕鬆的用  until 來寫:
BSD愛好者樂園%p|1|`(wE6?q

num=1
,FN"}jpuntil [ ! "$num" -le 10 ]; doBSD愛好者樂園#}$i"m&t.J~5QLe)LY y5n6v
    echo "num is $num"
!jG2VmE    num=$(($num + 1))
#j/sd(E/n�gdone

z&s~dPY2^ `^

或是:

+{e*I5r+d4T0TN%|8T

num=1BSD愛好者樂園,iB�dV}D5w
until [ "$num" -gt 10 ]; doBSD愛好者樂園b+c1E h^C `
    echo "num is $num"BSD愛好者樂園t2IPK)~2q [.]^
    num=$(($num + 1))BSD愛好者樂園9_B?!t"rP
done

9Kl#O8`S?2W

okay ,關於 bash 的三個常用的 loop 暫時介紹到這裏。
&^ HN2O&e AaYj在結束本章之前,再跟大家補充兩個與 loop 有關的命令:
6f8N2L }&f&u2f*  breakBSD愛好者樂園'u c(Q }.E[ X0rV
* continue
*yf;LR�xz這兩個命令常用在複合式循環裏,也就是在 do ... done 之間又有更進一層的 loop ,BSD愛好者樂園3k"}vjx tWN,j�I
當然,用在單一循環中也未嘗不可啦...  ^_^BSD愛好者樂園 EV�t+uG {"`
BSD愛好者樂園EB8Zq-H C
break 是用來打斷循環,也就是"強迫結束" 循環。
*rO$TN8tk若 break 後面指定一個數值 n 的話,則"從裏向外"打斷第 n 個循環,默認值爲 break 1 ,也就是打斷當前的循環。BSD愛好者樂園6?)/$jz'Lr)noZ.]
在使用 break 時需要注意的是, 它與 return 及 exit 是不同的:
9~k"roD_!o4B!_ w!]+B;a* break 是結束 loop
ZR-lt"rl!q`* return 是結束 functionBSD愛好者樂園]"T�P,r1H7@a
* exit 是結束 script/shellBSD愛好者樂園2k:EG&p6si&_0gf;X
BSD愛好者樂園 F4[;u*DR%}6Z'q!l3Y
而 continue 則與 break 相反:強迫進入下一次循環動作。
p#c7[ TqZ XH若你理解不來的話,那你可簡單的看成:在 continue 到 done 之間的句子略過而返回循環頂端...BSD愛好者樂園�hK t/E9K.h F
與 break 相同的是:continue 後面也可指定一個數值 n ,以決定繼續哪一層(從裏向外計算)的循環,BSD愛好者樂園*/VA2P%g*U$?-?4itj
默認值爲 continue 1 ,也就是繼續當前的循環。
[P~ Edl.a
'FF q e6a!o1_/ C%D在 shell script 設計中,若能善用 loop ,將能大幅度提高 script 在複雜條件下的處理能力。
!e$b[T /)G�^請多加練習吧....
O;O[$Je$NBSD愛好者樂園,AMH%G{,b
-----------
,FA�a/ ~d9YaBSD愛好者樂園 {nx-Z*V BK
好了,該是到了結束的時候了。
.{M"Vxt eB a婆婆媽媽的跟大家囉唆了一堆關於 shell 的基礎概念,目的不是要告訴大家"答案",而是要帶給大家"啓發"...BSD愛好者樂園1n{V N:Y z2|
在日後關於 shell 的討論中,我或許會經常用"鏈接"方式指引回來十三問中的內容,以便我們在進行技術探討時彼此能有一些討論基礎,而不至於各說各話、徒費時力。但,更希望十三問能帶給你更多的思考與樂趣,至爲重要的是透過實作來加深理解。BSD愛好者樂園(ON&kUz9Y6H+W

K3H Wm0`1b是的,我很重視"實作"與"獨立思考"這兩項學習要素,若你能夠掌握其中真義,那請容我說聲:
[ W:Ke)v!c1F~?!|;/0G2@z--- 恭喜﹗十三問你沒白看了﹗  ^_^BSD愛好者樂園)du%HuaZ3g x B H
BSD愛好者樂園4b1E#{lh|
p.s.BSD愛好者樂園q-cD2E.Gt9yp,/a
至於補充問題部份,我暫時不寫了。而是希望:
*d8]#~)mM"TVIy1) 大家擴充題目。BSD愛好者樂園p0@(CF t^T:i
2) 一起來寫心得。
$O8_J4a F,t9dBSD愛好者樂園'ch,{4K�e*w4B
Good luck and happy studying!

發佈了42 篇原創文章 · 獲贊 5 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章