zoukankan      html  css  js  c++  java
  • 5.Shell 流程控制语句

    1.流程控制语句

      通过if、for、while、case这4种流程控制语句来学习编写难度更大、功能更强的Shell脚本

    4.3.1 if条件测试语句:

      if条件测试语句可以让脚本根据实际情况自动执行相应的命令。从技术角度来讲,if语句分为单分支结构、双分支结构、多分支结构;

      if条件语句的单分支结构由if、then、fi关键词组成,而且只在条件成立后才执行预设的命令,相当于口语的“如果……那么……”。单分支的if语句属于最简单的一种条件判断结构,

    语法格式如图4-17所示:

      

      示例:下面使用单分支的if条件语句来判断/media/cdrom文件是否存在,若存在就结束条件判断和整个Shell脚本,反之则去创建这个目录:

    [root@linux ~]# vim mkcdrom.sh
    #!/bin/bash
    DIR="/media/cdrom"
    if [ ! -e $DIR ]
    then
    mkdir -p $DIR
    fi

      顺利执行完脚本文件后没有任何输出信息,但是可以使用ls命令验证/media/cdrom目录是否已经成功创建:

    [root@linux ~]# bash mkcdrom.sh
    [root@linux ~]# ls -d /media/cdrom
    /media/cdrom

      if条件语句的双分支结构由if、then、else、fi关键词组成,它进行一次条件匹配判断,如果与条件匹配,则去执行相应的预设命令;反之则去执行不匹配时的预设命令,

    相当于口语的“如果……那么……或者……那么……”。if条件语句的双分支结构也是一种很简单的判断结构,语法格式如图4-18所示:

      

      下面使用双分支的if条件语句来验证某台主机是否在线,然后根据返回值的结果,要么显示主机在线信息,要么显示主机不在线信息。这里的脚本主要使用ping命令来测试

    与对方主机的网络联通性,而Linux系统中的ping命令不像Windows一样尝试4次就结束,因此为了避免用户等待时间过长,需要通过-c参数来规定尝试的次数,并使用-i参数定义

    每个数据包的发送间隔,以及使用-W参数定义等待超时时间。 

    [root@linux ~]# vim chkhost.sh
    #!/bin/bash
    ping -c 3 -i 0.2 -W 3 $1 &> /dev/null
    if [ $? -eq 0 ]
    then
    echo "Host $1 is On-line."
    else
    echo "Host $1 is Off-line."
    fi

      $?变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则$?变量会显示数字0,反之则显示一个非零的数字(可能为1,也可能为2,取决于系统版本)。

    因此可以使用整数比较运算符来判断$?变量是否为0,从而获知那条语句的最终判断情况。这里的服务器IP地址为192.168.10.10,我们来验证一下脚本的效果: 

    [root@linux ~]# bash chkhost.sh 192.168.10.10
    Host 192.168.10.10 is On-line.
    [root@linux ~]# bash chkhost.sh 192.168.10.20
    Host 192.168.10.20 is Off-line.

      if条件语句的多分支结构由if、then、else、elif、fi关键词组成,它进行多次条件匹配判断,这多次判断中的任何一项在匹配成功后都会执行相应的预设命令,相当于口语的“如果……那么……

    如果……那么……”。if条件语句的多分支结构是工作中最常使用的一种条件判断结构,尽管相对复杂但是更加灵活,语法格式如图4-19所示:

      

      下面使用多分支的if条件语句来判断用户输入的分数在哪个成绩区间内,然后输出如Excellent、Pass、Fail等提示信息。在Linux系统中,read是用来读取用户输入信息的命令,

    能够把接收到的用户输入信息赋值给后面的指定变量,-p参数用于向用户显示一定的提示信息。在下面的脚本示例中,只有当用户输入的分数大于等于85分且小于等于100分,才输

    出Excellent字样;若分数不满足该条件(即匹配不成功),则继续判断分数是否大于等于70分且小于等于84分,如果是,则输出Pass字样;若两次都落空(即两次的匹配操作都失

    败了),则输出Fail字样:  

    4.3.3 while条件循环语句

      while条件循环语句是一种让脚本根据某些条件来重复执行命令的语句,它的循环结构往往在执行前并不确定最终执行的次数,完全不同于for循环语句中有目标、有范围的使用场景。

    while循环语句通过判断条件测试的真假来决定是否继续执行命令,若条件为真就继续执行,为假就结束循环。while语句的语法格式如图4-21所示。

      

      接下来结合使用多分支的if条件测试语句与while条件循环语句,编写一个用来猜测数值大小的脚本Guess.sh。该脚本使用$RANDOM变量来调取出一个随机的数值(范围为0~32767),

    将这个随机数对1000进行取余操作,并使用expr命令取得其结果,再用这个数值与用户通过read命令输入的数值进行比较判断。这个判断语句分为三种情况,分别是判断用户输入的数值是等

    于、大于还是小于使用expr命令取得的数值

      while条件循环语句中的条件测试始终为true,因此判断语句会无限执行下去,直到用户输入的数值等于expr命令取得的数值后,这两者相等之后才运行exit 0命令,终止脚本的执行

    [root@linux ~]# vim Guess.sh
    #!/bin/bash
    PRICE=$(expr $RANDOM % 1000)
    TIMES=0
    echo "商品实际价格为0-999之间,猜猜看是多少?"
    while true
    do
    read -p "请输入您猜测的价格数目:" INT
    let TIMES++
    if [ $INT -eq $PRICE ] ; then
    echo "恭喜您答对了,实际价格是 $PRICE"
    echo "您总共猜测了 $TIMES 次"
    exit 0
    elif [ $INT -gt $PRICE ] ; then
    echo "太高了!"
    else
    echo "太低了!"
    fi
    done

      在这个Guess.sh脚本中,我们添加了一些交互式的信息,从而使得用户与系统的互动性得以增强。而且每当循环到let TIMES++命令时都会让TIMES变量内的数值加1,用来统计循环总计

    执行了多少次。这可以让用户得知总共猜测了多少次之后,才猜对价格

    [root@linux ~]# bash Guess.sh
    商品实际价格为0-999之间,猜猜看是多少?
    请输入您猜测的价格数目:500
    太低了!
    请输入您猜测的价格数目:800
    太高了!
    请输入您猜测的价格数目:650
    太低了!
    请输入您猜测的价格数目:720
    太高了!
    请输入您猜测的价格数目:690
    太低了!
    请输入您猜测的价格数目:700
    太高了!
    请输入您猜测的价格数目:695
    太高了!
    请输入您猜测的价格数目:692
    太高了!
    请输入您猜测的价格数目:691
    恭喜您答对了,实际价格是 691
    您总共猜测了 9 次

     

    4.3.3 for条件循环语句

     

      for循环语句允许脚本一次性读取多个信息,然后逐一对信息进行操作处理,当要处理的数据有范围时,使用for循环语句再适合不过了。for循环语句的语法格式如图4-20所示:

     

     

     

      接下来编写Shell脚本Example.sh。在脚本中使用read命令读取用户输入的密码值,然后赋值给PASSWD变量,并通过-p参数向用户显示一段提示信息,告诉用户正在输入的

     

    内容即将作为账户密码。在执行该脚本后,会自动使用从列表文件users.txt中获取到所有的用户名称,然后逐一使用“id 用户名”命令查看用户的信息,并使用$?判断这条命令是

     

    否执行成功,也就是判断该用户是否已经存在。

     

      需要多说一句,/dev/null是一个被称作Linux黑洞的文件,把输出信息重定向到这个文件等同于删除数据(类似于没有回收功能的垃圾箱),可以让用户的屏幕窗口保持简洁:

     

    [root@linux ~]# vim Example.sh
    #!/bin/bash
    read -p "Enter The Users Password : " PASSWD
    for UNAME in `cat users.txt`
    do
    id $UNAME &> /dev/null
    if [ $? -eq 0 ]
    then
    echo "Already exists"
    else
    useradd $UNAME &> /dev/null
    echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null
    if [ $? -eq 0 ]
    then
    echo "$UNAME , Create success"
    else
    echo "$UNAME , Create failure"
    fi
    fi
    done

     

      执行批量创建用户的Shell脚本Example.sh,在输入为账户设定的密码后将由脚本自动检查并创建这些账户。由于已经将多余的信息通过输出重定向符转移到了/dev/null黑洞文件中,

     

    因此在正常情况下屏幕窗口除了“用户账户创建成功”(Create success)的提示后不会有其他内容。

     

      在Linux系统中,/etc/passwd是用来保存用户账户信息的文件。如果想确认这个脚本是否成功创建了用户账户,可以打开这个文件,看其中是否有这些新创建的用户信息。 

     

    [root@linux ~]# bash Example.sh
    Enter The Users Password : linux
    andy , Create success
    barry , Create success
    carl , Create success
    duke , Create success
    eric , Create success
    george , Create success
    [root@linux ~]# tail -6 /etc/passwd
    andy:x:1001:1001::/home/andy:/bin/bash
    barry:x:1002:1002::/home/barry:/bin/bash
    carl:x:1003:1003::/home/carl:/bin/bash
    duke:x:1004:1004::/home/duke:/bin/bash
    eric:x:1005:1005::/home/eric:/bin/bash
    george:x:1006:1006::/home/george:/bin/bash

     

      尝试让脚本从文本中自动读取主机列表,然后自动逐个测试这些主机是否在线。首先创建一个主机列表文件ipadds.txt:

     

    [root@linux ~]# vim ipadds.txt
    192.168.10.10
    192.168.10.11
    192.168.10.12

     

      然后前面的双分支if条件语句与for循环语句相结合,让脚本从主机列表文件ipadds.txt中自动读取IP地址(用来表示主机)并将其赋值给HLIST变量,从而通过判断ping命令执行后的返

     

    回值来逐个测试主机是否在线。脚本中出现的$(命令)是一种完全类似于第3章的转义字符中反引号`命令`的Shell操作符,效果同样是执行括号或双引号括起来的字符串中的命令

     

    [root@linux ~]# vim CheckHosts.sh
    #!/bin/bash
    HLIST=$(cat ~/ipadds.txt)
    for IP in $HLIST
    do
    ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
    if [ $? -eq 0 ] ; then
    echo "Host $IP is On-line."
    else
    echo "Host $IP is Off-line."
    fi
    done
    [root@linux ~]# ./CheckHosts.sh
    Host 192.168.10.10 is On-line.
    Host 192.168.10.11 is Off-line.
    Host 192.168.10.12 is Off-line.

     

    4.3.4 case条件测试语句

      case条件测试语句和switch语句的功能非常相似!case语句是在多个范围内匹配数据,若匹配成功则执行相关命令并结束整个条件测试;而如果数据不在所列出的范围内,则会去执

    行星号(*)中所定义的默认命令。case语句的语法结构如图4-22所示

      

      示例:编写脚本Checkkeys.sh,提示用户输入一个字符并将其赋值给变量KEY,然后根据变量KEY的值向用户显示其值是字母、数字还是其他字符

    [root@linux ~]# vim Checkkeys.sh
    #!/bin/bash
    read -p "请输入一个字符,并按Enter键确认:" KEY
    case "$KEY" in
    [a-z]|[A-Z])
    echo "您输入的是 字母。"
    ;;
    [0-9])
    echo "您输入的是 数字。"
    ;;
    *)
    echo "您输入的是 空格、功能键或其他控制字符。"
    esac
    [root@linux ~]# bash Checkkeys.sh
    请输入一个字符,并按Enter键确认:6
    您输入的是 数字。
    [root@linux ~]# bash Checkkeys.sh
    请输入一个字符,并按Enter键确认:p
    您输入的是 字母。
    [root@linux ~]# bash Checkkeys.sh
    请输入一个字符,并按Enter键确认:^[[15~
    您输入的是 空格、功能键或其他控制字符。

      

  • 相关阅读:
    SpringBoot实现原理
    常见Http状态码大全
    forward(转发)和redirect(重定向)有什么区别
    1094. Car Pooling (M)
    0980. Unique Paths III (H)
    1291. Sequential Digits (M)
    0121. Best Time to Buy and Sell Stock (E)
    1041. Robot Bounded In Circle (M)
    0421. Maximum XOR of Two Numbers in an Array (M)
    0216. Combination Sum III (M)
  • 原文地址:https://www.cnblogs.com/yaboya/p/9085116.html
Copyright © 2011-2022 走看看