编程心得
时间:2007-06-15 来源:2005181021
shell编程之循环语句
目标:
完成这一章,你将能够作以下事情:
使用while语句在条件为真的时候重复地执行一段代码。
使用until语句重复执行一段代码直到条件为真。
使用交互性的for语句进行循环控制。
1.循环语句的格式
目标: ????重复的执行一段命令列表。
控制; ????基于一个关键命令的返回值。
三种格式: ??while ... do ... done
??????? until ... do ... done
??????? for ... do ... done
循环语句让你可以重复执行一个命令列表,而决定是继续循环还是跳出循环是基于一个命令的返回值。test命令常常被用来控制一个循环是否继续。
与分支语句不同的是,在分支语句中开始一个分支语句的关键字和结束一个分支语句的关键字是相反的(if/fi 和case/esac),循环语句由一个关键字和一些条件开始,循环体整个用do/done来包围起来。
2.let的使用
语法:
let expression or (( expression ))
例子:
$ x=10??????????$ x=12
$ y=2?????????? $ let "x <10"???
$ let x=x+2 ???????$ echo $?
$ echo $x???????? 1
12????????????$ (( x > 10 ))
$ let "x = x / (y+1)" ??$ echo $?
$ echo $x ????????$ 0
4???????????? $ if ((x > 10 ))
$ (( x = x + 1 ))???? > ?then echo x greater
$ echo $x???????? > ?else echo x not greater
5???????????? fi
?????????????x greater
循环语句通常使用一个增长的数字变量来进行控制。使用let命令,可以在shell脚本中使用算术表达式。这个命令允许使用长的整数运算。在上例中,expression代表一个shell变量的算术表达式和能够被shell识别的操作符,而((? ))可以替let命令。shell能够识别的表达式如下所示:
操作符?????描述
-????? ??减去
!????? ??逻辑相反
* / %????? 乘,除,余数
+ - ??????加,减
<= ?>= ?<?>?关系比较
== !=????? 等于不等于
=??????? 赋值
括号能够被用作改变表达式中计算的顺序,就像在
let "x=x/(y+1)"
中一样
注意双引号被用来忽略括号的特殊含义。同样如果你希望使用空格来分隔操作符和操作符的时候,就必须使用双引号,或者(( ))语句:
let " x = x + (y / 2)" 或者(( x= x+ (y / 2) ))
当使用逻辑和关系操作符,(!,<=,>=,<,>,++,~=),的时候,shell会返回一个代码变量,?会反映结果是真还是假,再一次说明,必须使用双引号来防止shell将大于和小于运算符当作I/O重定向。
3.while
重复执行循环体,直到条件为真
语法:
while??????????????
?? list A
do
?? list B
done
例子:
$ cat test_while
X=1
while (( X <= 10 ))
do
??echo hello X is $X
??let X=X+1
done
$ test_while
hello X is 1
hello X is 2
.
.
.
hello X is 10
while语句是shell提供的一种循环机制,当条件为真的时候它允许循环体中的命令(list B)继续执行。条件判断是通过list A中最后一个命令的返回值来进行。通常一个test或者let命令被用作控制循环的执行,但是任何命令都能被用来产生一个返回值。上面的例子中使用的是test命令可以用let命令来代替,如下:
$ X=1
$ while [ $x -le 10 ]
> do
> ??echo hello X is $X
>?? let X=X+1
> done
命令执行的过程如下:
1.list A中的命令被执行。
2.如果list A中的最后一个命令的返回值为0(真),执行list B。
3.回到第一步。
4.如果list A中的最后一个命令的返回值不为0(假),跳到下面done关键字后的第一个命令。
提醒:注意while循环会无穷执行下去,因为有一些循环的控制命令的返回值永远为真。
$ cat while_infinite
while
?? true
do
?? echo hello
done
$ while_infinite
hello
hello
.
.
ctrl + c
4. while结构举例
例A:???????????????例B
如果ans为yes就重复执行 ???????????当有命令行参数时重复执行
ans=yes???????????????while (($# != 0 ))
while ??????????????? do
[ "$ans" = yes ] ???????????if test -d $1
do ??????????????????then
??echo Enter a name??????????echo contents of $1;
??read name??????????????ls -F $1
??echo $name >> file.names????? fi
??echo "Continue?"????????? shift
??echo Enter yes or no??????? echo There are $# items
??read ans????????????? echo left on the cmd line
done ????????????????done?
上例是两个while语句的例子,例A提示用户输入,然后对用户的输入进行判断,来决定是否继续执行循环,例子B中,循环会对命令行中每一个参数进行判断,如果参数是一个目录,这个目录中的内容会被显示出来。如果这个参数不是一个目录,程序会跳过。注意shift命令的用法,它允许一个一个存取每一个参数。和while命令一起使用可以使这个循环非常灵活。它不关心参数的个数是1个还是100个,循环会继续执行直到所有的参数都被存取。
注意,如果你希望循环至少执行一次,就必须进行某些设置。例A中会执行循环体至少一次因为ans已经被设为yes。在例B中,如果程序的执行不带任何参数($#等于0),这个循环就一次都不会执行。
5.until语句
重复循环直到条件为真为止。
语法:??????例子:
until???????$ cat test_until
?list A????? X=1
do???????? until (( x > 10 ))
?list B????? do
done?????????echo hello X is $X
???????????let X=X+1
????????? done
????????? $ test_until
????????? hello X is 1
????????? hello X is 2
????????? hello X is 3
???????????.
???????????.
???????????.
????????? hello X is 10
until语句是shell提供的另一种循环机制,它会持续执行命令(list B)直到一个条件为真为止。同while循环类似,条件判断由list A中的最后一条命令的返回值来决定的。
命令的执行过程如下:
1.list A中的命令被执行。
2.如果list A中最后一条命令的返回值为非0(假),执行list B。
3.返回到第一步。
4.如果list A中的最后一条命令的返回值为0(真),跳到done关键字后的第一条命令。
注意:until循环的无穷执行下去,因为有些循环语句中的控制语句的返回值始终为假。
$ x=1
$ until
> [ $ x -eq 0 ]
> do
> echo hello
> done
hello
hello
hello
.
.
.
ctrl + c
6.until的例子
例A???????????????例B
重复执行循环体直到ans为no为止 ???????重复执行循环直到没有命令行参数为止
ans=yes?????????????? until (( $# == 0 ))
until ? ????????????? do
? [ "$ans" = no ] ????????? if test -d $1
do ????????????????? then
echo Enter a name??????????? echo context of $1;
?read name ??????????????ls -F $1
?echo $name >> file.names??????fi
?echo "Continue?"??????????shift
?echo Enter yes or no????????echo There are $# items
?read ans ????????????? echo left on the cmd line.
done????????????????done
上例的结构与while语句中的例子类似,但是使用until语句来。注意在两种语句的test条件的逻辑关系是相反的。
同时请注意用户输入的敏感性由一些轻微的变化。使用while语句,只有用户的输入的字符串为“yes”时循环才会执行,继续执行循环的条件十分严格,使用until语句,循环会在用户使用与no不同的任何字符时都会执行。它对于继续进行循环的条件不太严格,你也许希望在决定那一种结构最符合你的要求的时候考虑这一特征。
预定义ans变量的值不再是必须的,因为它的值会被初始化为NULL,由于NULL不等于no,test会返回假,而循环会被执行。你仅仅需要将$ans用括号引起来,以免在test语句执行时发生语法错误。
7.for语句
对列表的每一条目都进行一次循环过程
,每完成一次循环过程就将var赋予列表中下一个条目,直到完成最后一个条目的循环为止
语法: ???????????例子:
for var in list????????$ cat test_for
do?????????????? for X in 1 2 3 4 5
???list A????????? do
done????????????? echo "2 * $X is \c"
??????????????? let X=X*2
??????????????? echo $X
??????????????? done
??????????????? $ test_for
??????????????? 2 * 1 is 2
??????????????? 2 * 2 is 4
??????????????? 2 * 3 is 6
??????????????? 2 * 4 is 8
??????????????? 2 * 5 is 10
在上例中,关键字为for,in,do和done,var代表一个shell变量的名字,这个变量的赋值会贯穿for循环的执行过程中,list是一串由空格或者tab分割开的字符串,在每一次循环执行都要将一个串赋值给var。
for循环的执行过程如下:
1.shell变量var被设置等于list中的第一个字符。
2.list A中的命令会被执行。
3.shell变量var被设置等于list中下一个字符。
4.list A中的命令被执行。
5.循环会持续执行,直到每一个list中的条目都执行过循环为止。
8.for循环的例子
例A:
$ cat example_A
for NAME in $(grep home /etc/passwd | cut -f1 -d:)
do
??mail $NAME < mtg.minutes
??echo mailed mtg.minutes to $NAME
done
例B
$ cat example_B
for FILE in *
do
?if
??test -d $FILE
?then
??ls -F $FILE
?fi
done
for结构是一种非常灵活的循环结构,它能够让循环贯穿任何能产生的列表。使用命令替代可以很容易产生生成列表,就像第一个例子使用管道和过滤器可以产生一个列表。如果你要求多次存取相同的列表,你也许想要将它存储到个文件中。你可以使用cat命令来为你的for循环产生列表,正如下例所示:
??$ cat students
??user1
??user2
user3
??user4
??$ cat for_student_file_copy
??for NAME in $(cat students)
??do
??cp test.file /home/$NAME
??chown $NAME /home/$NAME/test.file
??chmod g-w,o-w /home/$NAME/test.file
??echo done $NAME
??done
??$
存取命令行参数
你可以从命令行参数来产生list:
for i in $*?????????或者?????for i
do???????????????????? do?
??cp $i $HOME/backups????????????cp $i $HOME/backups
done ???????????????????done
9.break,continue,和exit命令
break [n] ?????中止循环过程的执行,并且跳到下一个命令。
continue [n]????停止循环过程的当前一个反复并且跳到循环中的下一个反复过程的开始部分
exit [n] ????? 停止shell程序的执行,并且将返回值设置为n。
在许多情况下,你可能需要在循环的正常中止条件满足之前放弃一个循环的执行。break和continue命令提供了一种无条件的流程控制,通常用在遇到一个错误的情况下来中止当前的循环。而exit命令用在不能从某种情况下恢复出来而必须中止整个程序的运行的时候。
break命令会中止循环并且将控制权传递到done关键字后面的第一个命令。结果是完全跳出这个循环体而继续执行下面的命令。
continue命令有一点不同。当在程序执行过程中遇到这个命令,就会忽略本次循环中剩余的命令,而将控制权交给循环的顶部。这样,continue命令能让你仅仅中止所有循环中的一个循环过程而继续从当前循环的顶部开始执行。
在while和until循环中,这种处理(continue)会导致在初始列表的开始部分继续执行,在for循环中,会将变量设置为列表中的下一个条目,然后继续执行循环。
exit命令停止执行当前的shell程序,并且根据提供的参数为这个shell程序设置一个返回值,如果没有提供返回值参数,当前的shell程序的返回值会被设置为在exit命令之前执行的命令的返回值。
注意:循环的流程控制在正常的情况下应当是通过设置循环开始部分的条件(while,until),或者是列表中的条目都循环完的(for),的情况来结束循环。而对循环过程进行中断操作仅仅应当在循环执行期间遇到没有规律的或者是错误的条件的时候才应当使用。
10.break和continue的例子
while
??true
do
??echo "Enter file to remove: \c"
??read FILE
??if test ! -f $FILE
??then
????echo $FILE is not a regular file
????continue
??fi
??echo removing $FILE
??rm $FILE
?break
done