SHELL十三问之十三:for、while 与 until 差在哪?

本文深入讲解了Shell脚本中常见的循环结构,包括for循环、while循环和until循环的使用方法及注意事项,通过实例演示了如何利用这些循环结构来处理列表项目和实现累积变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

终于,来到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!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值