zoukankan      html  css  js  c++  java
  • 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 "33[43m  33[0m"
                else					#当$flag为奇数数打印红色
                    echo -n -e "33[41m  33[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流程控制的知识就介绍到这儿啦,怎么样,看完是不是觉得文章真的是又简单易懂又实用呢?希望以上的内容能给你带来帮助,有疑问以及要指正的错误,请留言吧!

  • 相关阅读:
    mysql总结
    git总结
    转:如何判断一家公司的好坏
    路越走越窄,尤其做技术的
    百度面试总结
    背叛
    which和whereis 命令
    bzoj3263 陌上花开 CDQ模板
    bzoj 2653middle
    暑假第十九测
  • 原文地址:https://www.cnblogs.com/qige2017/p/7444680.html
Copyright © 2011-2022 走看看