shell编程流程控制

前言:

在linux shell中,通常我们将一些命令写在一个文件中就算是一个shell脚本了,但是如果需要执行更为复杂的逻辑判断,我们就需要使用流程控制语句来支持了。
所谓流程控制既是通过使用流程控制语句对程序流程的选择、循环、转向和返回等进行控制。流程控制是所有编程语言分重要组成部分,linux shell同样有一套自己的流程控制语句,其中主要包括条件语句(if),循环语句(for,while),选择语句(case)。本文将会对这几种语句进行介绍同时引用示例便于大家理解。文章也会涉及到循环控制语句的介绍,以及while循环的一些常用的特殊用法,快来一起学习吧!

一、条件选择if语句

单分支

if 判断条件;then 
	条件为真的分支代码 
fi 

双分支

if 判断条件; then 
   条件为真的分支代码 
else 
   条件为假的分支代码 
fi

多分支

if 判断条件1; then 
   条件为真的分支代码 
elif 判断条件2; then 
   条件为真的分支代码 
elif 判断条件3; then 
   条件为真的分支代码 
else 
   以上条件都为假的分支代码 
fi 

逐条件进行判断,第一次遇为“真”条件时,执行其分支, 而后结束整个if语句

二、条件判断case语句:

case 变量引用 in 		#变量的引用加$
PAT1) 
	分支1 
	;;
PAT2) 
	分支2 
	;;
... 
\*) 
	默认分支 
	;; 
esac

case支持glob风格的通配符:
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b

练习:编写脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息

[root@CentOS6 bin]#vim iduser.sh 
  1 #!/bin/bash
  2 #---------------+--------------------------------------+
  3 # ☆ Author      : huxiaoqi
  4 # ☆ Email       : 345304057@qq.com
  5 # ☆ Blog        : http://www.cnblogs.com/qige2017/
  6 # ☆ Tel         : 13598859921
  7 # ☆ Create time : 2017-08-28
  8 # ☆ Filename    : iduser.sh
  9 # ☆ Version     : 1.2.1 
 10 #---------------+--------------------------------------+
 11 read -p "Please input the user name: " username	#交互式输入用户名,复制给username
 12 if id $username &>/dev/null ;then	#条件判断用户输入的用户名是否存在
 13     echo "$username is exist"	#用户名已存在满足条件,打印exist
 14 else
 15     echo "user$username is cresting.."
 16     sleep 1
 17     useradd $username &> /dev/null	#用户名不存在就创建用户
 18     finger $username	#查看用户相关信息
 19 fi      

三、for循环:

for 变量名 in 列表;do 
循环体 
done
[root@CentOS7 ~]#for id in {10..1..2};do echo The number is $id ;done
The number is 10	#列表也可以`seq 2 2 10` 
The number is 8		#同样表示2到10步进2
The number is 6		#因为是命令所以用反引号引起来
The number is 4
The number is 2

执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执 行一次循环体; 直到列表中的元素耗尽,循环结束
列表生成方式:

  1. 直接给出列表
  2. 整数列表:
    (a) {start..end}
    (b) $(seq [start [step]] end)
  3. 返回列表的命令
    $(COMMAND)
  4. 使用glob,如:*.sh
  5. 变量引用; $@, $*

练习:用for实现

1、添加10个用户user1-user10,密码为8位随机字符

[root@CentOS6 bin]#vim useradd10.sh 
#!/bin/bash
> /root/user.log	#创建并每次清空密码记录文件
for i in {1..10};do		#1-10 循环10次
     if id user$i &> /dev/null ;then		#判断用户是否存在	
         echo user$i is exist
         exit 1		#若存在则退出脚本,有漏洞可以用后边的知识跳过本次循环
     fi
     useradd user$i &> /dev/null && echo user$i is created
     passwd=`cat /dev/urandom  | tr -dc 'a-cA-Z0-9' |head -c 8`
		#取/dev/urandom文件中的随机字符,tr -dc 'a-cA-Z0-9' |head -c 8 过滤删		除除了大小写字母以及数字的字符,并取前八个(cat /dev/urandom每次生成的随机		 数都不一样)。并且赋值passwd变量。
     echo $passwd | passwd --stdin  user$i &> /dev/dull
     passwd -e user$i &> /dev/null
 		#将用户的密码修改为$passwd,并设置强制登录修改密码
     echo user$i:$passwd >> /root/user.log
 		#将用户名和对应的用户密码重定向到/root/user.log中
done

[root@CentOS6 ~]#cat user.log 
user1:THUU66I0
批量创建用户
[root@CentOS6 ~]#echo user{1..10} |xargs -n1 useradd
批量删除用户
[root@CentOS6 ~]#echo user{1..10} |xargs -n1 userdel -r

2、计算100以内所有能被3整除的整数之和

步进思路:
[root@CentOS6 bin]#vim be3.sh 
#!/bin/bash
sum=0	#进入循环之前总合为0
for i in `seq 3 3 100`;do #以3开始步进3到100,既取出所有3-100被三整除的数
    sum=$[i+sum]	#进入循环以后,sum自增方括号内是数值运算不用加空格
 其他写法:let sum+=i 或者sum=$((i+$sum)) 小括号方括号内均为数值运算$可以省略
done    
echo $sum
取模思路:
sum1=0
for ii in `seq 1 100`;do
    if [ $((ii%3)) -eq 0 ];then	#若返回值为0则继续执行任务
 #计算机只支持整数运算,若ii的值不能被3整除则返回值为假,既不等于0
    sum1=$[ii+sum1]
    fi
done
echo sum1 is: $sum1
tr思路:
echo {3..100..3}|tr ' ' +|bc
seq思路:
seq -s +  3 3 100  |bc	#-s:指定分隔符为+号

3、打印九九乘法表

for l in `seq 9`;do			#l:行数循环9次
    for q in `seq $l`;do	#q列数嵌套循环,每行的列数=当前行数
    p=$[q*l]				#p为乘积
    echo -n "$q*$l=$p "		#内层循环,也就是每一行内的循环echo不换行
    done
echo						#外层循环要换行
done
[root@CentOS6 bin]#99.sh
1*1=1 
1*2=2 2*2=4 
1*3=3 2*3=6 3*3=9 
1*4=4 2*4=8 3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 

4、打印等腰三角形

[root@CentOS6 bin]#vim triangle.sh 
#!/bin/bash
read -p "please input the storey of the triangle: " n
for l in `seq $n` ; do	#命令的引用可以用反引号或者$()
    for s in `seq $((n-l))`; do	#空格数=总行数减当前行数,bash中的算术运算:var=$((算术表达式))或者 var=$[算术表达式] 
    echo -n " "
    done
    for t in `seq $((2*l-1))`;do	#星数=当前行数*2-1
    echo -n "*"
    done
    echo		#每次最外层循环后换行
done
[root@CentOS6 bin]#triangle.sh 
please input the storey of the triangle: 5
    *
   ***
  *****
 *******
*********

四、while循环

用法展示:

while CONDITION; do 
		循环体 
done

CONDITION:循环控制条件;进入循环之前,先做一次判 断;每一次循环之后会再次做判断;条件为“true”,则执行 一次循环;直到条件测试状态为“false”终止循环 。
因此:CONDTION一般应该有循环控制变量;而此变量的值 会在循环体不断地被修正。
进入条件:CONDITION为true
退出条件:CONDITION为false

练习:用while循环实现

1、编写脚本,提示请输入网络地址,如192.168.0.0,判断 输入的网段中主机在线状态,并统计在线和离线主机各多少

[root@CentOS6 bin]#vim whileip.sh 
#!/bin/bash
read -p "please input the ip(eg:172.18.0.1): " ip
network=`echo $ip |cut -d "." -f1-3`	#C类地址前三位为网络id
i=1		#ip一般从1开始
up=0
down=0
while [ $i -le 254 ];do		#255作为网段内的广播ip,所以取1-254之内的循环
    if ping -c1 -w1 $network.$i > /dev/null;then  #ping一次一秒
            echo $network.$i is up!
            let up++	#统计开机主机数
    else
            echo $network.$i is down!
            let down++	#统计关机主机数
    fi
    let i++
done

2、编写脚本,实现打印国际象棋棋盘
思路:

  1. 棋盘分八行八列,外层循环八次表示行数,内层循环八次表示列数
  2. 打印空格加底色实现棋盘效果
  3. 总结规律发现当当前行数与当前列数相加为偶数时打印黄色,当当前行数与当前列数相加为奇数时打印红色
[root@CentOS6 bin]#vim chess.sh 
#!/bin/bash
i=1		#初始行数为1进入循环
while [ $i -le 8 ];do		#行数小于等于8则继续任务
    j=1		#初始列数为1进入内层循环
    while [ $j -le 8 ];do	#列数小于等于8册继续任务
            flag=$[$[i+j]%2]	#标记当前行数当前列数和的奇偶性
            if [ $flag -eq 0 ];then	#当$flag为偶数打印黄色
                echo -n -e "\033[43m  \033[0m"
            else					#当$flag为奇数数打印红色
                echo -n -e "\033[41m  \033[0m"
            fi
            let j++		#列数自增
    done
    let i++				#行数自增
    echo
done

while的无限循环写法

冒号:
ture
两个反引号``
作为while的循环控制条件,返回值永远为真,可以无限循环。

[root@CentOS7 ~]#while true ; do echo hello ; sleep 1 ; done
hello
hello

let 自增赋值坑

之前学习bash算法时有关于自增赋值先后区别的描述,这一区别在while循环用法中得以体现:

[root@CentOS6 bin]#i=0;let i=++i;echo $?
0	#当初始值为0时使用let i=++i 先自增再赋值返回值为真
[root@CentOS6 bin]#i=0;let i=i++;echo $?
1	#当初始值为0时使用let i=++i 先赋值再自增返回值为假

五、until循环

用法展示:

until CONDITION; do 
		循环体
done

原理与while相反:
进入条件: CONDITION 为false
退出条件: CONDITION 为true

练习until:

每隔3秒钟到系统上获取已经登录的用户的信息;如果发 现用户tianbaobao登录,则将登录时间和主机记录于日志 /app/login.log中,并退出脚本

[root@CentOS6 bin]#vim untilwho.sh 
#!/bin/bash
until who | grep "^tianbaobao\>" &>> /app/login.log ; do
	  #用grep过滤who命令以tianbaobao开头的输出结果作为until的条件判断
        sleep 3	#每隔三秒
done

六、循环控制语句continue

在循环任务中,如果遇到continue就跳过本次循环,执行下一次循环
continue后边加参数continue [N]:指定提前结束第N层的本轮循环,而直接进入下一 轮判断;最内层为第1层

while CONDTIITON1; do 
	CMD1 
	... 
	if CONDITION2; then 
		continue	#如果满足条件2执行continue
	fi 
	CMDn 			#跳过接下来的任务,但是继续执行循环任务
	... 
done

七、循环控制语句break

在循环任务中,如果遇到break就结束整个循环任务。
break后边加参数break [N]:指定提前结束第N层循环,最内层为第1层

while CONDTIITON1; do 
	CMD1 
	... 
	if CONDITION2; then 
		break		##如果满足条件2,执行break直接结束整个循环任务
	fi 
	CMDn 
	... 
done

八、循环控制shift命令

shift [n]
用于将参量列表 list 左移指定次数,默认为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删 除。
while 循环遍历位置参量列表时,常用到 shift
示例:

while [ $# -gt 0 ] # or (( $# > 0 )) 
do 
	echo  $* 
	shift 
done

练习shift:

利用shift实现批量创建用户

[root@CentOS6 bin]#vim useraddshift.sh 
#!/bin/bash
while [ $# -gt 0 ] ;do	#如果参数大于零进入循环
    id $1 &> /dev/null && continue	#如果用户已存在就跳过本次循环
    useradd $1 && echo $1 is created
    shift	#移除$1,$2左移成为下次循环的$2
done

九、特殊用法

while循环的特殊用法(遍历文件的每一行):

while read line; do 
循环体 
done < /PATH/FROM/SOMEFILE 

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将 行赋值给变量line

双小括号写法

双小括号方法,即((…))格式,也可以用于算术运算
双小括号方法也可以使bash Shell实现C语言风格的变量操作
I=10
((I++))
for循环的特殊格式:

for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)) 
do 
 	循环体 
done 

控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修 正运算,而后再做条件判断

练习特殊用法:

计算1-100所有数字之和

[root@CentOS6 bin]#vim 1-100sum.sh 
  1 #!/bin/bash
  2 #---------------+--------------------------------------+
  3 # ☆ Author      : huxiaoqi
  4 # ☆ Email       : 345304057@qq.com
  5 # ☆ Blog        : http://www.cnblogs.com/qige2017/
  6 # ☆ Tel         : 13598859921
  7 # ☆ Create time : 2017-08-26
  8 # ☆ Filename    : 1-100sum.sh
  9 # ☆ Version     : 1.2.1 
 10 #---------------+--------------------------------------+
 11 i=1						#初始化
 12 sum=0
 13 while [ $i -le 100 ];do	#i小于等于100既进入循环
 14         let sum+=i		#求和
 15         let i++			#i自增
 16 done
 17 echo usm is: $sum
 18 i=1 sum=0
 19 while [ $i -le 100 ];do
 20         sum=$[i+sum]
 21         let i++
 22 done
 23 echo sum1 is: $sum
 24 for ((sum=0,i=0;i<=100;i++))#利用双小括号写法
#sum,i=0控制变量初始化;i<=100条件判断表达式;i++控制变量修正表达式
 25 do
 26         let sum+=i
 27 done
 28 echo sum2 is: $sum
 29 i=1
 30 sum=0
 31 while ((i<=100))
 32 do
 33         let sum+=i
 34         let i++
 35 done
 36 echo sum3 is: $sum
 37 unset i sum
四种方法
[root@CentOS6 bin]#1-100sum.sh 
usm is: 5050
sum1 is: 5050
sum2 is: 5050
sum3 is: 5050

这个脚本写法比较正规,题头比较完整,变量的初始化以及sunset都有,逻辑清晰有条理,排版合理大家可以参照养成良好的编写脚本的习惯。

十、select循环与菜单

select variable in list 	#variable:变量名
	do 
		循环体命令 
	done

select 循环主要用于创建菜单,按数字顺序排列的 菜单项将显示在标准错误上,并显示 PS3 提示符, 等待用户输入
(PS1:命令行提示符;PS2:多行重定向提示符)
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY中
select 是个无限循环,因此要记住用 break 命令退 出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量

练习select:

制作菜单,要求顾客输入对应食物的编号就显示价格

[root@CentOS6 bin]#vim selectmenu.sh
PS3="Please choose your food: "
select menu in lamian huimian hulatang yangroutang ;do
        case $REPLY in
        1)
                echo "The price is \$10"
                ;;
        2) 
                echo "The price is \$15"
                ;;
        3)      
                echo "The price is \$5"
                ;;
        4)      
                echo "The price is \$20"
                ;;
        *)
                echo "No such food"
               break	#select语句是一个死循环与break配合使用
                ;;
        esac
done
[root@CentOS6 bin]#selectmenu.sh 
1) lamian	#selsct语句自动列出菜单,并且定义用户需要输入的编号
2) huimian	#将用户输入的编号赋值给REPLY
3) hulatang
4) yangroutang
Please choose your food: 1
The price is $10
Please choose your food: 2
The price is $15
Please choose your food: 5
No such food

关于linux shell流程控制的知识就介绍到这儿啦,怎么样,看完是不是觉得文章真的是又简单易懂又实用呢?希望以上的内容能给你带来帮助,有疑问以及要指正的错误,请留言吧!

posted @ 2017-08-28 17:06  奇哥与李妞  阅读(333)  评论(0编辑  收藏  举报