Shell脚本编程基础 三 使用结构化命令

结构化命令允许我们改变程序执行的顺序,在某些条件下执行一些命令而在其他条件下跳过另一些命令。

(1)使用if-then语句

  • 结构化命令中,最基本的类型就是if-then语句,其格式如下:
    if command
    then
    commands
    fi
    bash shell 的if语句会运行if行定义的那些命令。如果该命令的退出状态码是0(该命令成功运行),位于then部分的命令就会被执行;否则,then部分的命令就不会被执行,bash shell会继续执行脚本中的下一条命令。

    
    #cat test1
    
    
    #!/bin/bash
    
    
    #testing if statement
    
    if date
    then
    echo  "is a good day!"
    fi

    运行结果是:

    ./test1
    Sun May 14 18:39:55 CST 2017
    is a good day!
    
    #cat test1
    
    
    #!/bin/bash
    
    
    # testing a bad command
    
    if abdca
    then
    echo  "is a good day!"
    fi
    echo "outside of the if statement"

    运行结果是:

    
    #./test1
    
    ./test1: line 3: abdca: command not found
    outside of the if statement
    • 在这个例子中,我们在if语句中放了一个不能工作的命令。由于这个命令不能正常运行,所以其返回一个非0的退出状态码,bash shell 会跳过then部分的echo语句。注意,运行if语句中的那个命令所生成的错误信息仍然会显示在脚本的输出中。后续讲解如何避免这种情况的发生。
  • then部分可以有多个命令。bash shell 会将这部分命令当成一个块,在if语句行中的命令返回退出状态码为0时执行这块命令,否则跳过这块命令:

    cat test1
    
    #!/bin/bash
    
    
    # testing mutiple commands in the then section
    
    testuser=xiaoyu1
    if grep $testuser /etc/passwd
    then
      echo The bash files for user $testuser are:
      ls -a /home/$testuser/shell
    fi

    运行结果是:

    
    #./test1
    
    xiaoyu1:x:1001:1001::/home/xiaoyu1:/bin/bash
    The bash files for user xiaoyu1 are:
    .  ..  date_who  pathfile  test1  test2  test3  test4  test6  test7

(2)if-then-else语句

  • 格式为:
    if command
    then
    commands
    else
    commands
    fi

  • 当if语句中的命令返回的退出状态码为0时,then部分中的命令会被执行;当if语句中的命令返回的退出状态码非0时,bash shell 会执行else部分中的命令。

#cat test2
#!/bin/bash
# testing mutiple commands in the then section
testuser=badtest
if grep $testuser /etc/passwd
then
  echo The bash files for user $testuser are:
  ls -a /home/$testuser/shell
else
  echo "The user name $testuser does not on this system"
fi

执行结果是:

#./test2
The user name badtest does not on this system

(3)嵌套if

  • 有时需要检查脚本代码中的多个条件。不需要写多个分立的if-then语句,可以用else部分的替代版本,elif。
    elif会通过另一个if-then语句来延续else部分:

    if command1
    then 
      commands
    elif command2
    then
      more commands
    fi

    elif语句行提供了另一个需要测试的命令,类似于原始的if语句。如果elif后的命令的退出状态码是0,则bash会执行第二个then语句部分的命令。

  • 我们可以继续将多个elif语句串联起来,形成一个大的if-then-elif嵌套组合:

    if command1
    then 
      command set 1
    elif command2
    then
      command set 2
    elif command3
    then
      command set 3
    elif command4
    then
      command set 3
    fi

    每块命令都会根据哪个命令会返回退出状态0来执行。注意,bash shell会以此执行if语句,只有第一个返回状态码0的语句中的then部分会被执行(此时,被执行的then之后的所有语句都不会被执行)。后续将介绍如何使用case命令替换嵌套多个if-then语句。

(4)test命令

  • test命令提供了在if-then语句中测试不同条件的途径(跟命令的退出状态码无关的条件)。如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0,接着就会执行then语句;否则,test命令退出并返回退出状态码1,then语句就会被跳过。
  • test命令的格式为:test condition

    • condition是test命令要测试的一些列参数和值。当用在if-then语句中时,test命令格式如下:
    if test condition
    then
      commands
    fi
    • bash shell 提供了另一种在if-then语句中声明test命令的方法:

      if [ condition ]
      then
        commands
      fi
    • 方括号定义了test命令中用到的条件。注意,必须在左括号的右边和右括号的左边各加一个空格,if 和左括号之间也必须有空格;否则会报错。

  • test 命令可以判断3类条件:
    • 数值比较;
    • 字符串比较;
    • 文件比较。
  • test用于数值比较:

    • 下表列出了测试两个值时可用的条件参数:
      这里写图片描述
    • 数值条件测试可用于数字和变量上。例如:
    $cat test8
    
    #!/bin/bash
    
    
    # using numeric test comparisons
    
    var1=10
    var2=11
    
    if [ $var1 -gt 5 ]
    then
      echo "The test value $var1 is greater than 5"
    fi
    
    if [ $var1 -eq $var2 ]
    then 
      echo "The value are equal"
    else
      echo "The value are difference"
    fi

    运行结果如下:

    $./test8
    The test value 10 is greater than 5
    The value are difference
  • 但在测试数值条件时有一个限制。例如:

    $cat test9
    
    #!/bin/bash
    
    
    # testing floating point numbers
    
    var1=`echo "scale=4; 10 / 3" | bc`
    echo "The test value is $var1"
    if [ $var1 -gt 3 ]
    then
      echo "The result is larger than 3"
    fi

    运行结果是:

    $./test9
    The test value is 3.3333
    ./test9: line 5: [: 3.3333: integer expression expected
    • 这个例子是使用了bash计算器来生成一个浮点数并存储在变量 var1 中。下一步,使用了 test 命令来判断这个值。这里显然出错了。
    • 最后一句说明,test 命令无法处理var1 变量中存储的浮点值。
    • 注意,bash shell 能处理的数仅有整数。当使用 bc时,我们可以让shell将浮点值作为字符串值存储进一个变量。如果你只要通过echo显示这个结果,那它可以很好的工作;但它无法再基于数字的函数中工作,例如我们的数值测试条件。尾行恰好说明,不能再test中使用浮点值。
  • test用于字符串比较:
    test命令还可用于对字符串的比较。但对字符串的比较很繁琐,下表列出了可用来比较两个字符串值的函数。
    这里写图片描述
    接下来会详细说明不同的字符串比较功能:

    • 字符串相等性:
      字符串的相等和不等的条件是,两个字符串的值是否相同:

      $cat test10
      
      #!/bin/bash
      
      
      # testing string equality
      
      testuser=root
      
      if [ $USER = $testuser ]
      then
        echo "welcome $testuser"
      fi

      运行结果是:

      $./test10
      welcome root

      比较字符串的相等性时,test 的比较会将所有的标点和大写也考虑在内。

    • 字符串的顺序:

      • 大于小于符号必须转义(在前面添加),否则shell会把它们当做重定向符号而把字符串值当做文件名;

        
        #!/bin/bash
        
        
        var1=baseball
        var2=hockey
        
        if [ $var1 \> $var2 ]
        then
          echo "$var1 is greter than $var2"
        else
          echo "$var1 is less than $var2"
        fi
      • 大于小于顺序和sort命令所采用的排序方式不同;

        
        #!/bin/bash
        
        
        var1=Testing
        var2=testing
        
        if [ $var1 \> $var2 ]
        then
          echo "$var1 is greter than $var2"
        else
          echo "$var1 is less than $var2"
        fi
      • 在test命令根据ASCII 数值排序;sort命令使用系统的本地化语言设置中定义的顺序排序。对于英语,本地化设置指定了在排序顺序中小写字母出现在大写字母的前面。

    • 字符串大小:

      • -n 和 -z 参数用来检查一个变量是否为空:
        
        #!/bin/bash
        
        val1=testing
        val2=''
        
        if [ -n "$val1" ]
        then
          echo "The string '$val1' is not empty"
        else
          echo "The string '$val1' is empty"
        fi
        
        if [ -z "$val2" ]
        then
          echo "The string '$val2' is not empty"
        else
          echo "The string '$val2' is empty"
        fi
        
        if [ -z "$val3" ]
        then
          echo "The string '$val3' is not empty"
        else
          echo "The string '$val3' is empty"
        fi
    • 注意:空的和未初始化的变量对shell脚本测试来说可能是灾难性的影响。如果不确定一个变量的内容,最好在数值或字符串比较中使用它之前先通过 -n 或 -z 来测试一下变量是否含有值。

  • 文件比较:
    最后一类测试比较可能是shell编程中最强大且使用最多的比较。test 命令允许你测试Linux文件系统上文件和目录的状态。如下表所示:
    这里写图片描述
    这些条件能够使你在shell脚本中检查文件系统中的文件,并且常用在访问文件的脚本中。

    • 检查目录:

      $cat test111
      
      #!/bin/bash
      
      
      # look before you leap
      
      if [ -d $HOME ]
      then 
        echo "Your HOME directory exists"
        cd $HOME
        ls -a
      else
        echo "There is a problem with your HOME directory"
      fi
    • 检查对象是否存在
      -e 比较允许你在脚本使用对象前检查文件或目录对象是否存在:

      
      #!/bin/bash
      
      
      # checking if a directory exists
      
      if [ -e $HOME ]
      then
        echo "OK on the directory. now to check the file"
        # checking if a file exists.
        if [ -e $HOME/testing ]
        then
          # the file exists. append data to it
          echo "Appending date to existing file"
          date >> $HOME/testing
        else
          # the file does not exist.create a new file
          echo "Creating new file"
          date > $HOME/testing
        fi
      else
        echo "you do not have a HOME directory"
      fi
      
    • 检查文件
      -e 比较适合用于文件和目录。要确定指定的对象是个文件,必须用 -f 比较:

    • 检查是否可读
      在尝试从文件中读取数据之前,最好先测试一下是否能读取文件。可以使用 -r 测试:
    • 检查空文件
      在删除文件时,你首先应该使用 -s 比较来检测文件是否为空。当 -s 比较成功时要特别小心,它说明文件中有数据:
    • 检查是否可写
      -w 比较会判断你是否对文件有可写权限:
    • 检查是否可执行
      -x 比较可以判断你对某个特定文件是否有执行权限。如果你要在shell脚本中运行大量脚本,它很方便:
    • 检查所属关系
      -O 比较可以测试你是否是文件的拥有者(ownership):
    • 检查默认属组关系

      • -G 比较会检查文件的默认组(主组),如果它匹配了用户的默认组,就能通过。由于 -G 比较只会检查默认组而非用户所属的所有组,所以需要注意。

        
        #!/bin/bash
        
        if [ -G $HOME/shell/t19test ]
        then
          echo "You are in the same group as the file"
        else
          echo "The file is not owned by your group"
        fi
        $ls -l t19test 
        -rw-rwxr-- 1 xiaoyu1 xiaoyu1 0 May 16 14:37 t19test
        
        [xiaoyu1@iZ23aoz1vd9Z ~]$./test19
        You are in the same group as the file
        
        #cat /etc/group
        
        ...
        xiaoyu1:x:1001:
        hadoop:x:1002:xiaoyu1
        $chgrp hadoop t19test 
        [xiaoyu1@iZ23aoz1vd9Z shell]$./test19
        The file is not owned by your group
      • 注意:第一次运行脚本时,$HOME/t19test 文件是在xiaoyu1组里,所以-G通过了。下一次,文件的组被改成了hadoop组,虽然xiaoyu1用户也是hadoop组里的成员(运行程序可以看出),但-G比较失败了,因为它只比较默认组(主组),不会去比较其他额外组(附属组)。

    • 检查文件日期

      • 用来比较两个文件创建日期。这在编写安装软件的脚本时非常有用(判断要安装的软件版本是否比系统上已安装的新)。
      • -nt 比较判断某个文件是否比另一个文件更新。如果文件更新,那它会有较近的创建日期。
      • -ot 比较判断某个文件是否比另一个文件更老。如果文件更老,它会有一个更早的创建日期。
      • 注意:比较用到的文件路径是相对于你所运行的脚本的目录来说的。如果要检查的文件可以移动,这可能会造成问题。
      • 注意,另一个问题是这些比较中没有哪个会先检查文件是否存在。

        
        #!/bin/bash
        
        
        # testing file dates
        
        if [ ./badfile1 -nt ./badfile2 ]
        then
          echo "The badfile1 is newer than badfile2"
        else
          echo "The badfile1 is old than badfile2"
        fi

        运行结果

        ./test21
        The badfile1 is old than badfile2
        • 这个例子说明,如果文件不存在,-nt 比较会返回一个无效的条件(非0的退出状态码)。所以,在尝试使用-nt 或 -ot 之前,必须先确认文件存在。

(5)复合条件测试

if-then 语句允许使用布尔逻辑来组合测试。有两种布尔运算符可用:

  • [ condition1 ] && [ condition2 ] (AND,两个条件都满足,才会执行then部分命令)
  • [ condition1 ] || [ condition2 ] (OR,任意一个条件满足,即可执行then部分命令)

(6)if-then的高级特性

  • 使用双尖括号

    • 双尖括号命令允许我们将高级数学表达式放入比较中。test 命令只允许在比较中进行简单的算术操作。双尖括号命令提供了更多编程人员所熟悉的数学符号。尖括号的格式为:
      (( expression ))

      • 术语 expression 可以是任意的数学赋值或比较表达式。除了test命令使用的标准数学运算符,下表给出了双尖括号命令中会用到的其他运算符。
        这里写图片描述
      • 你可以在if语句中使用双尖括号,也可以在脚本中的普通命令里使用来赋值:
      
      #!/bin/bash
      
      val1=10
      
      if (( $val1 ** 2 > 90 ))
      then
        (( val2 = $val1 ** 2 ))
        echo "The square of $val1 is $val2"
      fi
      
      • 注意,双尖括号中的表达式里的大于号不需要转义。
  • 使用双方括号

    • 双方括号命令提供了针对字符串比较的高级特性。命令格式如下: [[ expression ]]
    • 双方括号里的 expression 使用了 test 命令中所采用的标准字符串进行比较。但它还提供了test命令未提供的另一特性,模式匹配(pattern matching)。

      • 在模式匹配中,你可以定义一个正则表达式来匹配字符串值:

        
        #!/bin/bash
        
        
        if [[ $USER == xiao* ]]
        then
          echo "Hello $USER"
        else
          echo "sorry."
        fi
      • 双方括号命令匹配了$USER环境变量来看它是否以字符串xiao开头。如果是,比较通过,shell会执行then部分的命令。

(7)case命令

  • 我们经常会尝试计算一个变量的值或在一组可能值中寻找特定值。在这种情景下,需要写出很长的if-then-else 语句,像这样:

    
    #!/bin/bash
    
    
    if [ $USER = "root" ]
    then
      echo "Welcome $USER"
    elif [ $USER = "xiaoyu" ]
    then
      echo "Welcome $USER"
    elif [ $USER = "testing" ]
    then
      echo "Special testing account"
    elif [ $USER = "user1" ]
    then
      echo "Do not foget to logout when you're done"
    else  
      echo "Sorry.you are not allowed here"
    fi
  • 可以使用case命令改写上面脚本。case命令会检查单个变量列表格式的多个值:
    case variable in
    pattern1 | pattern2) commands1;;
    pattern3) command2;;
    *) default commands;;
    esac

  • case 命令会将制定的变量同不同模式进行比较。如果变量和模式匹配,shell会执行为该模式指定的命令。可以通过|操作符来分割模式,在一行列出多个模式。*会捕获所有跟所有列出的模式都不匹配的值。例如:

    
    #!/bin/bash
    
    
    case $USER in
    root | xiaoyu1)
      echo "Welcome $USER"
      echo "Please enjoy your visit";;
    testing)
      echo "Special testing account";;
    user1)
      echo "Do not foget to logout when you're done";;
    *)
      echo "Sorry.you are not allowed here";;
    esac

(8)小结

  • 结构化命令允许你改变shell脚本的正常执行流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值