shell的流程控制不可为空
一、if语句
(一)if
if 语句语法格式:
if condition; then
command
fi
写成一行:
if condition; then command; fi
末尾的 fi 就是 if 倒过来
(二)if else
if else 语法格式:
if condition; then
command
else
command
fi
(三)if else-if else
if else-if else 语法格式:
if condition; then
command
elif condition; then
command
else
command
fi
实例
以下实例判断两个变量是否相等:
#!/bin/bash
a=10
b=2
if (( a == b )); then
echo "a 等于 b"
elif (( a > b )); then
echo "a 大于 b"
elif (( a < b )); then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
二、case语句
case … esac 为多选择语句,与其他语言中的 switch … case 语句类似,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case … esac 语句,esac(就是 case 反过来)作为结束标记。
可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case … esac 语法格式如下:
case 值 in
模式1)
command
;;
模式2)
command
;;
*)
command
;;
esac
case 工作方式如上所示,值后面必须为单词 in,每一模式必须以右括号结束。值可以为变量或常数,匹配发现值符合某一模式后,其间所有命令开始执行直至 ;;。
值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
如果要匹配多个分支,那么要把;;改成;&
case 值 in
a)
;&
b)
command
;;
*)
;;
esac
当匹配a或b时都执行command
也可以使用|把模式连在一起
case var in
a|b)
command
;;
*)
;;
esac
实例
下面的脚本提示输入 1 到 4,与每一种模式进行匹配:
#!/bin/bash
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
输出结果
输入 1 到 4 之间的数字:
你输入的数字为:
1
你选择了 1
三、for语句
分为列表for循环、不带列表的for循环以及类C的for循环
(一)带列表的for循环
带列表的for循环用于执行一定次数的循环(循环次数等于列表元素个数)
其语法结构如下:
for VARIABLE in list; do
command
done
写成一行:
for var in list; do command; done
实例
1.带列表
#!/bin/bash
for FRUIT in apple orange banana pear; do
echo "$FRUIT is John's favorite"
Done
echo "No more fruits"
#运行结果
apple is John's favorite
orange is John's favorite
banana is John's favorite
pear is John's favorite
No more fruits
2.使用变量替换
上面脚本的写法并不是最好的,因为一旦列表元素改变了,你就不得不去改相应的for循环语句块。好的习惯是将列表定义为一变量,然后在for中使用该变量。按照这种方法可以将上面的脚本修改成下面的形式:
#!/bin/bash
#将列表定义到一个变量中以后有任何修改只需要修改该变量即可
fruits="apple orange banana pear"
for FRUIT in ${fruits}; do
echo "$FRUIT is John's favorite"
done
echo "No more fruits"
3.使用命令替换
使用命令替换生成列表,下面的例子可以针对1到100的求和进行计算
#!/bin/bash
sum=0
for VAR in `seq 1 100`
#for VAR in $(seq 1 100)
do
((sum+=VAR))
done
echo "Total: $sum"
#运行结果
Total: 5050
下面的例子中会利用ls的输出作为in的列表
#!/bin/bash
for VAR in $(ls); do
ls -l $VAR
done
(二)不带列表的for循环
语法格式如下所示:
for VARIABLE; do
command
done
读者一定会诧异,既然没有列表,那么如何向这个for循环传递变量值呢?实际上,使用不带列表的for循环时,需要在运行脚本时通过参数的方式给for循环传递变量值。
1.指定参数
#!/bin/bash
for VARIABLE; do
echo -n "$VARIABLE"
done
echo
#运行时向脚本传入参数
[root@localhost ~]# bash for_list06.sh 1 2 3
1 2 3
2.可利用特殊变量$@改写上述结构,使其变成下面的形式,功能是完一样的。
#!/bin/bash
for VARIABLE in $@; do
echo -n $VARIABLE
done
#运行时传入参数
[root@localhost ~]# bash for_list07.sh 1 2 3
(三)类C的for循环
Shell支持类C的for循环
语法结构如下:
for ((expression1; expression2; expression3)); do
command
done
其中,expression1为初始化语句一般用作变量定义和初始化
expression2为判断表达式用于测试表达式返回值并以此控制环返回值为真则循环继续返回值为假时则退出循环
expression3用于变量值修改从而影响expression2的返回值并以此影响环行为。
1.下面的脚本演示了使用for语句控制的10次循环。
#!/bin/bash
for ((i=1; i<=10; i++)); do
echo -n "$i "
done
echo
#运行结果
1 2 3 4 5 6 7 8 9 10
2.使用类C的for循环还有其他的好处:可以在初始化expression1的同时初始化多个变量另外还可以在expression3中同时修改多个变量的值每个expression中的多条语句之间使用逗号隔开。
示例如下:
#!/bin/bash
for ((i=1, j=100; i<=10; i++, j--)); do
echo "i=$i j=$j "
done
[root@localhost ~]# bash c_for02.sh
i=1 j=100
i=2 j=99
i=3 j=98
i=4 j=97
i=5 j=96
i=6 j=95
i=7 j=94
i=8 j=93
i=9 j=92
i=10 j=91
3.下面是使用类C的for循环的示例在该示例中同时计算了1到100的和以及1到100的奇数和。
#!/bin/bash
#sum01用于计算1到100的和
#sum02用于计算1到100的奇数和
sum01=0
sum02=0
for ((i=1, j=1; i<=100; i++, j+=2)); do
((sum01+=i))
#由于j值增长速度比i快所以必须在过程中测试j值不大于100
if (( j < 100 )); then
((sum02+=j))
fi
done
echo "sum01=$sum01"
echo "sum02=$sum02"
#运行结果
[root@localhost ~]# bash c_for03.sh
sum01=5050
sum02=2500
4.无限循环
[root@localhost ~]# cat c_for05.sh
#!/bin/bash
for ((;1;)); do
echo "infinite loop"
done
四、while语句
while 循环用于不断执行一系列命令,也用于从输入文件中读取数据。
其语法格式为:
while condition; do
command
done
1.实例
#!/bin/bash
int=1
while (( $int<=5 )); do
echo $int
((int++))
done
运行脚本,输出:
1
2
3
4
5
2.按行读取文件
[root@localhost ~]# cat student_info.txt
John 30 Boy
Sue 28 Girl
Wang 25 Boy
Xu 23 Girl
[root@localhost ~]# cat while04.sh
#!/bin/bash
while read LINE; do
NAME=`echo $LINE | awk '{print $1}'`
AGE=`echo $LINE | awk '{print $2}'`
Sex=`echo $LINE | awk '{print $3}'`
echo "My name is $NAME, I'm $AGE years old, I'm a $Sex"
done < student_info.txt
#运行结果
[root@localhost ~]# bash while04.sh
My name is John, I'm 30 years old, I'm a Boy
My name is Sue, I'm 28 years old, I'm a Girl
My name is Wang, I'm 25 years old, I'm a Boy
My name is Xu, I'm 23 years old, I'm a Girl
3.使用管道的按行读取
[root@localhost ~]# cat while04.sh
#!/bin/bash
cat student_info.txt | while read LINEdo
NAME=`echo $LINE | awk '{print $1}'`
AGE=`echo $LINE | awk '{print $2}'`
Sex=`echo $LINE | awk '{print $3}'`
echo "My name is $NAME, I'm $AGE years old, I'm a $Sex"
done
虽然上面两段代码的功能看似一致但这两种方式是有细微不同的:使用重定向符的while只会产生一个Shell,而使用管道的脚本在运行时会产生3个Shell,第一个Shell是cat,第二个Shell是管道,第三个Shell是while
4.从标准输入循环读取行
echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM; do
echo "是的!$FILM 是一个好网站"
done
运行脚本,输出类似下面:
按下 <CTRL-D> 退出
输入你最喜欢的网站名:菜鸟教程
是的!菜鸟教程 是一个好网站
5.无限循环
while ((1)); do
command
done
while true; do
command
done
while :; do
command
done
实例
我们可以利用while的无限循环实时的监测系统进程以保证系统中的关键应用一直处于运行状态。
#!/bin/bash
while true; do
HTTPD_STATUS=`service httpd status | grep running`
if [ -z "$HTTPD_STATUS" ]; then
echo "HTTPD is stopped, try to restart"
service httpd restart
else
echo "HTTPD is running, wait 5 sec until next check"
fi
sleep 5
done
6.do while
shell中没有do while形式,但是可以用以下形式实现:
while true; do
command
condition || break
done
五、until语句
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
until 语法格式:
until condition; do
command
done
condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
1.实例
#!/bin/bash
a=0
until [ ! $a -lt 10 ]; do
echo $a
a=`expr $a + 1`
done
运行结果:
输出结果为:
0
1
2
3
4
5
6
7
8
9
2.无限循环
和while的无限循环相反,until的无限循环的条件是判断为假。
其写法有如下两种:
#方法一
until ((0)); do
command
done
#方法二
until false; do
command
done
3.do until
until false; do
command
condition && break
done
和while无限循环对比可发现只要将while((1))改为until((0)),或将while true改为until false,就可以实现while和until无限循环的相互转换。
六、select语句
select是一种菜单扩展循环方式其语法和带列表的for循环非常类似
基本结构如下:
select MENU in list; do
command
done
当程序运行到select语句时会自动将列表中的所有元素生成为可用1、2、3等数选择的列表并等待用户输入。用户输入并回车后,select可判断输入并执行后续命令。如果用户在等待输入的光标后直接按回车键,select将不会退出而是再次生成列表等待输入
1.示例如下:
[root@localhost ~]# cat select01.sh
#!/bin/bash
echo "Which car do you prefer?"
select CAR in Benz Audi VolksWagen; do
break
done
echo "You chose $CAR"
#运行结果
[root@localhost ~]# bash select01.sh
Which car do you prefer?
1) Benz
2) Audi
3) VolksWagen
#? #此处尝试直接回车结果select再次生成了列表等待输入
1) Benz
2) Audi
3) VolksWagen
#? 2#此处选择2,程序会退出select并继续执行后面的语
You chose Audi
通过上面的例子可以发现,select有判断用户输入的功能所以select经常和case语句合并使用。
2.下面的例子使用select确认用户的输入并交由case处理之后将根据不同输入执行不同代码段。代码中使用了“|”符表示选Saturday和Sunday的效果是一致的。
[root@localhost ~]# cat select02.sh
#!/bin/bash
select DAY in Mon Tue Wed Thu Fri Sat Sun
do
case $DAY in
Mon) echo "Today is Monday";;
Tue) echo "Today is Tuesday";;
Wed) echo "Today is Wednesday";;
Thu) echo "Today is Thursday";;
Fri) echo "Today is Friday";;
Sat|Sun) echo "You can have a rest today";;
*) echo "Unknown input, exit now" && break;;
esac
done
#运行结果
[root@localhost ~]# bash select02.sh
1) Mon
2) Tue
3) Wed
4) Thu
5) Fri
6) Sat
7) Sun
#? 1
Today is Monday
#? 6
You can have a rest today
#? 7
You can have a rest today
#? 8
Unknown input, exit now
七、跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。
(一)break命令
break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
1.实例
#!/bin/bash
while :; do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
执行以上代码,输出结果为:
输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束
(二)continue
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
1.实例
#!/bin/bash
while :; do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done
运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “游戏结束” 永远不会被执行。