五、流程控制之循环
5.1 for循环
-
带列表的for循环
执行时Shell会将in关键字后面列表的第1个元素的值赋给变量var,然后执行循环体,当循环体中的语句执行完毕之后,将第2个元素的值赋给变量以此类推,当列表中的所有的元素都被访问后,for循环结构终止,程序将继续执行done语句后面的其他语句。
bash#格式1:{}中可以是一系列的数字或者字符串;例如:{1,2,3},{1..10},{1..10..2}表示10以内的奇数,{a..z},{a..z..2}等 for var in {1..10} do command done #格式2:命令执行后的输出作为for循环列表中的循环值 for var in `command` do command done示例1:
bash[root@server ~]# mkdir /shell/chap05 [root@server ~]# vim /shell/chap05/for1.sh #!/bin/bash echo for1: for ip in 192.168.168.10 192.168.168.20 do echo $ip done echo for2: for ip in 192.168.168.{10..20..2} do echo $ip done [root@server ~]# bash /shell/chap05/for1.sh for1: 192.168.168.10 192.168.168.20 for2: 192.168.168.10 192.168.168.12 192.168.168.14 192.168.168.16 192.168.168.18 192.168.168.20示例2:
bash[root@server ~]# vim /shell/chap05/for2.sh #!/bin/bash sum=0 for i in {1..100..2} do sum=$[$sum+$i] done echo sum=$sum sum1=0 for j in $(seq 1 2 100) do sum1=$[$sum1+$j] done echo sum1=$sum1 [root@server ~]# bash /shell/chap05/for2.sh sum=2500 sum1=2500示例3:
bash[root@server ~]# vim /shell/chap05/for3.sh #!/bin/bash for file in $(ls -F / | grep /$) do echo $file done [root@server ~]# bash /shell/chap05/for3.sh afs/ boot/ dev/ etc/ home/ media/ mnt/ opt/ proc/ root/ run/ shell/ srv/ sys/ tmp/ usr/ var/ # ls -F :用于将目录内的文件按照文件类型进行归类显示,会在不同类别的文件名尾部增加不同的标识符,目录以/结尾、链接文件以@结尾、可执行文件以*结尾、普通文件无符号 # grep /$ :表示以/结尾的行 -
不带列表的for循环:for不提供循环列表,shell将从命令行获取循环列表数据。
bash#格式1:此种写法等同于格式2的写法 for var do command done #格式2: for var in $@或$* do command donebash[root@server ~]# vim /shell/chap05/for4.sh #!/bin/bash echo for1: for num do echo $num done echo for2: for num in $* do echo $num done [root@server ~]# bash /shell/chap05/for4.sh 1 2 3 4 5 for1: 1 2 3 4 5 for2: 1 2 3 4 5 -
基于C语言风格的for循环
bash
for ((expression1;expression2;expression3))
#for ((i=1;i<=30;i++))
do
command
done
bash
[root@server ~]# vim /shell/chap05/for5.sh
#!/bin/bash
for ((i=1;i<=10;i++))
do
if id test$i &> /dev/null
then
echo "test$i 已存在!"
else
useradd test$i
echo "123456" | passwd --stdin test$i &> /dev/null
fi
done
[root@server ~]# bash /shell/chap05/for5.sh
5.2 while循环
当条件成立则继续执行循环体里面的语句
bash
#用法1:表达式为真则继续循环,为假停止循环
while expression
do
command
done
#用法2:命令执行后返回状态码为0则为真,继续循环
while 命令
do
command
done
#用法3:死循环
while true
do
command
done
#用法4:死循环
while :
do
command
done
使用while循环读取文件内容:
bash
#写法1:exec < file将file文件中的内容读到标准输入中,read a表示从标准输入读取内容给变量a
#!/bin/bash
exec < file
while read a
do
echo $a
done
#写法2:使用cat读取文件,通过管道符进入while循环处理
#!/bin/bash
cat file | while read a
do
echo $a
done
#写法3:在while循环尾部使用输入重定向指定输入数据
#!/bin/bash
while read a
do
echo $a
done < file
示例1:
bash
[root@server ~]# vim /shell/chap05/while1.sh
#!/bin/bash
i=1
while [ "$i" -le 10 ]
do
if id test$i &> /dev/null
then
userdel -r test$i
else
echo "test$i 账户已删除"
fi
let i++
done
[root@server ~]# bash /shell/chap05/while1.sh
示例2:猜商品价格,通过变量RANDOM获取随机整数并控制20以内,提示用户猜测商品价格,猜测时需要记录次数,猜中后退出程序。
bash
[root@server ~]# vim /shell/chap05/while2.sh
#!/bin/bash
# RANDOM是一个环境变量,产生[1,32767]的整数,对20取余是控制随机数在1-19间
PRICE=$((RANDOM%20))
count=0
while true # 恒真执行
do
read -p "请输入[1-20]间的商品价格: " INT
let count++
if [ "$INT" -eq "$PRICE" ]
then
echo "恭喜,你猜对了!"
echo "你使用了$count次机会."
break # 跳出while循环
elif [ "$INT" -gt "$PRICE" ]
then
echo "你输入的商品价格高了."
else
echo "你输入的商品价格低了."
fi
done
[root@server ~]# bash /shell/chap05/while2.sh
请输入[1-20]间的商品价格: 3
你输入的商品价格低了.
请输入[1-20]间的商品价格: 5
恭喜,你猜对了!
你使用了2次机会.
示例3:逐行读取 ip.txt 文件里的 IP 地址,然后 ping 测试每个 IP 是否通。
bash
[root@server ~]# cat > /shell/chap05/ip.txt <<EOF
192.168.168.1
192.168.168.2
192.168.168.3
8.8.8.8
www.baidu.com
EOF
[root@server ~]# vim /shell/chap05/while3.sh
#!/bin/bash
# 定义要读取的文件
FILE="/shell/chap05/ip.txt"
# while 循环逐行读取文件
cat $FILE | while read line
do
# 输出当前读取的内容
echo "正在检测:$line"
# 执行 ping 命令
ping -c 2 -w 3 $line &> /dev/null
# 判断是否通
if [ $? -eq 0 ];then
echo "$line 可以连通"
else
echo "$line 无法连通"
fi
echo "-------------------------"
done
[root@server ~]# bash /shell/chap05/while3.sh
正在检测:192.168.168.1
192.168.168.1 可以连通
-------------------------
正在检测:192.168.168.2
192.168.168.2 可以连通
-------------------------
正在检测:192.168.168.3
192.168.168.3 无法连通
-------------------------
正在检测:8.8.8.8
8.8.8.8 可以连通
-------------------------
正在检测:www.baidu.com
www.baidu.com 可以连通
-------------------------
5.3 until循环
当条件成立则终止循环,条件不成立则执行循环中的语句。与while循环的执行条件相反
bash
until 条件表达式
do
command
done
#死循环:
until false
do
command
done
bash
[root@server ~]# vim /shell/chap05/until.sh
#!/bin/bash
i=1
until [ "$i" -gt 10 ] # i>10 ,注意,条件要相反
do
if id test$i &> /dev/null
then
userdel -r test$i
else
echo "test$i 账户已删除"
fi
let i++
done
[root@server ~]# bash /shell/chap05/until.sh
5.4 select循环
select循环语句的主要功能是创建菜单,在执行带有select循环语句脚本时,输出会按照数字顺序的列表显示一个菜单,并显示提示符(默认是#?),同时等待用户输入数字选择。
bash
select 变量名 in 菜单值列表
do
statement1
statement2
...
done
示例1:
bash
[root@server ~]# vim /shell/chap05/select1.sh
#!/bin/bash
select mysql_version in 5.1 5.6
do
echo $mysql_version
done
[root@server ~]# bash /shell/chap05/select1.sh
1) 5.1
2) 5.6
#? 1
5.1
#? 2
5.6
示例2:
bash
[root@server ~]# vim /shell/chap05/select2.sh
#!/bin/bash
#设置提示符字符串
PS3='Choose your favorite fruit: '
select fruit in "Apples" "Bananas" "Pears" "Watermelons" "Grapes"
do
echo
echo "Your favorite fruit is $fruit."
break
done
[root@server ~]# bash /shell/chap05/select2.sh
1) Apples
2) Bananas
3) Pears
4) Watermelons
5) Grapes
Choose your favorite fruit: 5
Your favorite fruit is Grapes.
5.5 循环控制
- 跳出循环:
- break:立即跳出当前循环
- continue:跳出本次循环,立即开始下一次循环
- 退出程序:exit
示例1:
bash
#没有任何循环控制语句
[root@server ~]# vim /shell/chap05/test.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/test.sh
111
222
333
11
111
222
333
22
1
111
222
333
11
111
222
333
22
2
#添加break语句
[root@server ~]# vim /shell/chap05/break1.sh
[root@server ~]# cat /shell/chap05/break1.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
if [ "$k" -eq 222 ];then
break
fi
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/break1.sh
111
11
111
22
1
111
11
111
22
2
#添加continue语句
[root@server ~]# vim /shell/chap05/continue1.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
if [ "$k" -eq 222 ];then
continue
fi
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/continue1.sh
111
333
11
111
333
22
1
111
333
11
111
333
22
2
#break后面有数字,跳出多层循环
[root@server ~]# vim /shell/chap05/break2.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
if [ "$k" -eq 222 ];then
break 2
fi
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/break2.sh
111
1
111
2
#continue后面有数字,继续第n层循环
[root@server ~]# vim /shell/chap05/continue2.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
if [ "$k" -eq 222 ];then
continue 2
fi
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/continue2.sh
111
111
1
111
111
2
#exit后面不管跟不跟数字,都会退出脚本,exit后面的数字表示脚本执行后的状态码
[root@server ~]# vim /shell/chap05/exit.sh
#!/bin/bash
for i in {1..2}
do
for j in 11 22
do
for k in 111 222 333
do
if [ "$k" -eq 222 ];then
exit 2
fi
echo $k
done
echo $j
done
echo $i
done
[root@server ~]# bash /shell/chap05/exit.sh
111
[root@server ~]# echo $?
2