Linux shell脚本 流程控制
shell脚本的流程分为三种,顺序执行,选择执行和循环执行。顺序执行就是按照脚本中语句的顺序依次执行各条语句,每一个回车和“;”都代表了下一条命令,而选择执行是通过选择语句来对命令进行有选择的定向执行,循环执行是在特定的条件下重复执行命令。这三种执行流程在使用时可以灵活的套嵌,来满足我们的需求
一.顺序执行
顺序执行是一个大的框架,脚本里的所有命令都可以看做是在顺序执行中嵌套其他的流程
例如
#!/bin/bash sum=0 while [ $# -gt 0 ];do sum=$[$(cat $1 | wc -l) + $sum] shift done echo $sum
上面的代码执行顺序是
- sum=0
- while到倒数第二行的done
- echo $sum
其中上面的第二部分while是循环执行的语句,从while到done可以看做一个整体。这就是一个顺序嵌套循环,在while语句看做一个整体的前提下,命令按照从上到下的顺序依次执行也就是顺序执行。
二.选择执行(if/case)
1.if
if是选择执行语句的一种,其格式为:
1 if 判断条件 ;then
2 判断条件为真时要执行的命令
3 elif 判断条件 ;then
4 判断条件为真时要执行的命令
5 else
6 当以上所有判断都为假时要执行的命令
7 fi
解释:
第一行的“if”告诉计算机,我的if语句开始了,“判断条件”告诉计算机什么情况下要执行下面的命令,“;”告诉计算机我的判断条件结束了,“then”告诉计算机接下来该执行命令了,“;then”也可以理解为固定格式。
第二行就是第一行告诉计算机要执行的命令
第三行的“elif”就是else if的意思,意思是如果第一行“if”的判断为假,则继续判断之后“elif”的判断条件
第四行是“elif”判断为真时要执行的命令
第五行的意思是当上面所有的判断都为假的时候则执行下面的命令
第六行要写所有的判断都为假的时候执行的命令
第七行告诉计算机我要结束我的if语句了
在if语句的格式中第三四行可以根据需求写无数次,第一二七行必须写而且只能写一次,第五六行最多有一次不过可以不写,当if语句中有多个elif时,计算机会逐条对判断条件金星判断,并执行第一次为真的判断条件的命令,如果都为假,有else则执行else后的命令,五else则直接跳出if语句
例如
#!/bin/bash a=$1 if [ $a -eq 1 ];then echo h elif [ $a -eq 2 ];then echo i elif [ $a -eq 3 ];then echo j elif [ $a -eq 4 ];then echo k else echo F fi
解释:
在这个脚本中我把a赋值为输入的第一个参数,并依此进行判断,如果a和1相等则输出h,如果a和2相等则输出i,如果a和3相等则输出j,如果a和4相等则输出k,如果a和1,2,3,4,都不相等则输出F
2.case
case是另一中选择执行语句,其格式为:
- case 变量 in
- 判断值) 执行的命令;;
3. 判断值) 执行的命令;;
4. *)执行的命令;;
5. esac
解释:
第一行的case告诉计算机我的case语句开始了“变量”是我们要判断的数据可以是数数值也可以是字符串等等,“in”可以理解为固定格式
第二行的判断值是我们判断的依据,“)”是固定格式,告诉计算机我的判断值结束了,后面是这个判断值对应的命令“;;”告诉计算机我的执行命令到此结束,这整个一行的意思是,如果第一行的变量和我的判断值相等则执行后面的命令
第三行同第二行
第四行*代表所有的值,由于case语句是按顺序依次判断的,所以写在最后的*)意思就是上面的判断值和变量都不相等时执行之后的命令
第五行告诉计算机我的case语句结束了
case是按照从上至下的顺序依次判断,可根据需求将“判断值) 执行的命令;;”写任意条,而判断则会遍历这些直到遇到变量和判断值相等,执行命令并退出case,“*)执行的命令”可根据需要不写,效果是如果上面的判断值和变量都不相等则什么都不执行直接退出case
举例:
#!/bin/bash case $1 in man)echo "男人";; woman)echo "女人";; [1-9])echo "数字";; [[:alpha:]])echo "字母";; *)echo "fault";; esac
解释:
这个脚本中我把输入的第一个参数当作变量,并依次和下面的判断值作比较,当输入值为man时输出“男人”当输入值为woman时输出为“女人”当输入为数字时输出为“数字”,当输入为字母时输出为“字母”,当输入不是上面的这些情况时输出为“fault”
三.循环执行(for/while)
1.for
for循环格式:
1.for 变量 in 列表 ;do
2. 循环体
3. done
运行机制:
依次将列表中的元素赋值给变量,每赋值一次执行一次循环体,直到列表的元素用尽,循环结束
解释:
第一行的“for”告诉计算机我的for循环语句开始了,“变量”是设置的一个参数用于循环,也可以在循环体中使用,“in 列表”告诉计算机我要用于循环的元素列表,“do”告诉计算机接下来是循环体也就是要执行的命令
第二行的“循环体”也就是我们要执行的命令
第三行的“done”告诉计算机循环体结束,进行下一次循环,如果没有元素了则退出for循环
for循环中列表的书写方式:
(1) 直接给出列表 a b c
(2) 整数列表:
(a) {start..end} {1..10}
(b) $(seq [start [step]] end) $(seq 10)
(3) 返回列表的命令
$(COMMAND)
(4) 使用glob,如:*.sh
(5) 变量引用;
$@, $*
举例:
#!/bin/bash for n in $(seq 10);do echo $n done
解释:
这个脚本效果是输出1到10,每一次循环,都会按顺序从列表“$(seq 10)”中读取一个值赋给n,并执行echo命令,所以在每一次循环中n的值都不一样,所以每次输出的值也就不一样。
另外for循环也可以写成c语言的形式,其格式为:
for ((i=0;i<b;i++));do
循环体
done
其中i是我们的循环变量,i=0是把i的初始值设为0,i<b,b是我们设置的一个数值,用来告诉循环什么时候停止,i++的意思是每次循环i自加1
2.while
while循环格式
- while CONDITION ;do
- 循环体
- done
运行机制:
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件
为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
解释:
第一行“while”告诉计算机while循环开始,“CONDITION”是循环控制条件,控制循环,告诉计算机什么时候结束,“do”开始执行循环体
第二行“循环体”也就是我们要执行的命令
第三行“done”执行循环体结束并进入下一次循环,如果达到控制条件则退出循环
举例:
#!/bin/bash n=1 while [ $n -le 5 ];do echo $n let n++ done
解释:
这个脚本效果是输出1到5,我先赋值n为1,在while循环中,控制条件是“[ $n -le 5 ]”意思是n小于等于5,所以第一行的意思是当n小于等于5的时候执行下面的循环体,循环体是输出n的值,“let n++”的意思是让n自加1,也就是每循环依次n就会加1,它和控制条件配合来限制循环次数
3.循环控制语句(continue/break/shift)
1)continue
continue[N] 用于循环体中意思是结束第N层循环,直接进入下一轮的判断,N默认为1
举例:
首先我写了一个两层for循环嵌套的脚本,最外层的会执行五次,每次执行会先输一个序号来告诉我们这是第几次的输出,然后执行内层的for循环,第二个for循环的作用是输出abc,“echo \ ”的作用是输出一个换行
#!/bin/bash for n in {1..5};do echo -n $n for m in a b c;do echo -n $m done echo \ done
执行结果
[root@centos7 bin]# . a.sh 1abc 2abc 3abc 4abc 5abc
然后我们加入一个if语句,其执行的命令为continue。加入后在执行内层for循环语句的时候先判断变量m的值是否为b,如果为b则执行continue,跳出本次循环也就不会在执行if语句后的输出语句,跳出本次循环后直接进入下一个内层的for循环
#!/bin/bash for n in {1..5};do echo -n $n for m in a b c;do if [ $m == b ];then continue fi echo -n $m done echo \ done
执行结果
[root@centos7 bin]# . a.sh 1ac 2ac 3ac 4ac 5ac
我们现在把continue后加一个2,加入后每当变量m的值为b就会跳出两层循环,也就是直接进入外层for的下一个循环,所以输出序号和a后直接进入下一个循环
#!/bin/bash for n in {1..5};do echo -n $n for m in a b c;do if [ $m == b ];then continue 2 fi echo -n $m done echo \ done
执行结果
[root@centos7 bin]# . a.sh 1a2a3a4a5a[root@centos7 bin]#
2)break
break N 用于循环体中,提前结束第N层循环,最内层为第一层
举例:
还是上面的例子,我们把continue换成break,换成break后每当变量m为b时则跳出整个内层的for循环,然后执行外层for循环的“echo \ ”之后进行下一次的外层for循环
#!/bin/bash for n in {1..5};do echo -n $n for m in a b c;do if [ $m == b ];then break fi echo -n $m done echo \ done
执行结果
[root@centos7 bin]# . a.sh 1a 2a 3a 4a 5a
然后我们在break后加上2,使之直接跳出两层循环,当第一次变量m的值为b时跳出两层for循环也就是直接运行结束
执行结果
[root@centos7 bin]# . a.sh 1a[root@centos7 bin]#
3)shift
shift n 将参数列表向左移动n位,前n位已溢出则直接从列表中删除
举例
#!/bin/bash while [ $# -gt 0 ];do echo $* shift done
解释:
“$#”是传递给脚本的参数个数,“$*”是传递给脚本的全部参数,当参数个数大于0时输出所有参数并将参数左移
执行结果
[root@centos7 bin]# . a.sh a b c d e a b c d e b c d e c d e d e e