shell编程 - 条件分支流程控制

        接上一节课问题,系统信息生成器脚本如何适应运行脚本的用户权限呢?我们要在脚本中赋予新的功能,即根据测试结果来改变脚本执行的方向。用编程术语来说,就是要求脚本有分支功能。

使用if

if语句的语法格式如下:

if commands;then
    commands
elif commands;then
    commands
else
    commands
fi

退出状态

        命令(自己编写的脚本、函数)执行完毕后都会向操作系统发送一个数值,称之为“退出状态”。这个值是一个0~255的整数,用来表示命令执行成功还是失败。数值0表示执行成功,其他数值表示执行失败。

        有些命令使用不同的退出值来诊断不同的错误,可以在对应命令man手册中Exit Status段落中查看详细的命令退出值描述。

        shell提供了一个可以检测退出状态的参数 $?

        shell提供了两个内置命令,除了以一个0或1退出状态来结束执行。true命令总是表示执行成功,false命令总是表示执行失败。

#!/bin/bash
true
echo $? # 输出退出状态值 0

false
echo $? # 输出退出状态值 1

       if语句真正做的事情是评估命令的成功或者失败。

#!/bin/bash
if true;then echo "It's true";fi # 输出It's true
if false;then echo "It's true";fi # 不会输出任何信息

# 当if命令后有一系列的命令,那么则根据最后一个命令的执行状态来进行评估
if false;true;then echo "It's true";fi # 输出It's true
if true;false;then echo "It's true";fi # 不会输出任何信息

使用test命令 

        经常和if一起使用的命令是test。test会执行各种检查和比较。该命令有两种等价形式

test expression

 与

[ expression ]

        这里expression是一个表达式,其结果是true或者false。当为true时,test命令返回一个0退出状态;当表达式结果为false时,test命令的退出状态是1。

文件表达式

文件表达式用于评估文件的各类状态

表达式成为true的条件
file1 -ef file2file1和file2拥有相同的信息节点编号(这两个文件通过硬链接指向同一个文件)
file1 -nt file2file1比file2新
file1 -ot file2file1比file2旧
-b filefile存在并且是一个块(设备)文件
-c filefile存在并且是一个字符(设备)文件
-d filefile存在并且是一个目录
-e filefile存在
-f filefile存在并且是一个普通文件
-L filefile存在并且是一个符号链接
-p filefile存在并且是一个命名管道
-r filefile存在并且可读
-w filefile存在并且可写
-x filefile存在并且可执行
-s filefile存在并且其长度大于0

 下列脚本可用来演示某些文件表达式

#!/bin/bash

# test-file:Evaluate the status of a file

FILE=~/.bashrc

if [ -e "$FILE" ];then
    if [ -f "$FILE" ];then
        echo "$FILE is a regular file."
    fi
    if [ -d "$FILE" ];then
        echo "$FILE is a directory."
    fi
    if [ -r "$FILE" ];then
        echo "$FILE is readable."
    fi
    if [ -w "$FILE" ];then
        echo "$FILE is writable."
    fi
    if [ -x "$FILE" ];then
        echo "$FILE is executable/searchable."
    fi
else
    echo "$FILE does not exist."
    exit 1
fi
exit

 以上脚本会评估赋值给常量FILE的文件,并显示评估结果。

类似的,通常在return命令中包含一个整数参数,shell函数可以返回一个退出状态。把上述脚本转换为一个shell函数,从而能够在一个更大的程序中使用,可以将exit命令替换为return命令。

test_file(){

    # test-file:Evaluate the status of a file

    FILE=~/.bashrc

    if [ -e "$FILE" ];then
        if [ -f "$FILE" ];then
            echo "$FILE is a regular file."
        fi
        if [ -d "$FILE" ];then
            echo "$FILE is a directory."
        fi
        if [ -r "$FILE" ];then
            echo "$FILE is readable."
        fi
        if [ -w "$FILE" ];then
            echo "$FILE is writable."
        fi
        if [ -x "$FILE" ];then
            echo "$FILE is executable/searchable."
        fi
    else
        echo "$FILE does not exist."
        return 1
    fi
}

字符串表达式

表达式成为true的条件
stringstring不为空
-n stringstring长度大于0
-z stringstring长度等于0

string1=string1

string1==string2

string1和string2相等。单等号和多等号都可以使用,但是双等号使用的更多
string1!=string2string1和string2不相等
#!/bin/bash

# test-string: evaluate the value of a string

ANSWER=maybe

if [ -z "$ANSWER" ];then
    echo "There is no answer" >&2
    exit 1
fi
if [ "$ANSWER" = "yes" ];then
    echo "The answer is YES."
elif [ "$ANSWER" = "no" ];then
    echo "The answer is NO."
elif [ "$ANSWER" = "maybe" ];then
    echo "The answer is MAYBE."
else
    echo "The answer is UNKONWN."
fi

 通过使用elif,我们可以建立一个更复杂的逻辑测试。

整数表达式

整数判断操作

表达式成为true的条件
integer1 -eq integer2integer1和integer2相等
integer1 -ne integer2integer1和integer2不相等
integer1 -lt integer2integer1小于integer2
integer1 -gt integer2integer1大于integer2
integer1 -le integer2integer1小于等于integer2
integer1 -ge integer2integer1大于等于integer2

一个演示整数表达式的脚本

#!/bin/bash

#test-integer:evaluate the value of an integer

INT=-5

if [ -z "$INT" ];then
    echo "INT is empty." >&2
    exit 1
fi

if [ $INT -eq 0 ];then
    echo "INT is zero."
else
    if [ $INT -lt 0 ];then
        echo "INT is negative."
    else
        echo "INT is positive."
    fi
    if [ $((INT%2)) -eq 0 ];then
        echo "INT is even."
    else
        echo "INT is odd."
    fi
fi

增强的test命令

语法格式:

[[ expression ]]

         expression是一个表达式,其结果为true或false。[[ ]]命令和[ ]功能类似,[ ]的表达式它都能支持。

        除此之外,[[ expression ]]有两个更显著的特性:

  1. 增加了一个新的字符串表达式 string1=~regexp;
            如果string1与正则表达式regexp相匹配,则返回true。该特性为执行数据验证功能提供了许多可能性。上面的脚本程序,如果常量INT包含整数以外的其他值,脚本就会执行失败。
            可以使用[[ ]]和=~字符串表达式操作符 解决以上问题
    #!/bin/bash
    
    # test-integer2: evaluate the value of an integer
    
    INT=~-5
    
    if [[ "$INT" =~ ^-?[0-9]+$ ]];then
        if [ $INT -eq 0 ];then
            echo "INT is zero."
        else
            if [ $INT -lt 0 ];then
                echo "INT is negative."
            else
                echo "INT is positive."
            fi
            if [ $((INT % 2)) -eq 0 ];then
                echo "INT is even."
            else
                echo "INT is odd."
            fi
        fi
    else
        echo "INT is not an integer." >&2
        exit 1
    fi

    起到了限制只能是整数并且同样消除了空值的可能性。

  2. ==操作符支持模式匹配。
    该特性在评估文件或者路径名时非常有用
    #!/bin/bash
    
    FILE=foo.bar
    
    if [[ $FILE == foo.* ]];then
        echo "$FILE match pattern 'foo.*'"
    fi

(())为整数设计

        (())专为操作整数的复合命令。该命令支持一套完整的算术计算。

使用(())可以简化上面的脚本,注意观察区别

#!/bin/bash

# test-integer2a: evaluate the value of an integer

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]];then
    if ((INT == 0));then
        echo "INT is zero."
    else
        if ((INT < 0));then
            echo "INT is negative."
        else
            echo "INT is positive."
        fi
        if (( ((INT % 2)) == 0 ));then
            echo "INT is even."
        else
            echo "INT is odd."
        fi
    fi
else
    echo "INT is not an integer" >&2
    exit 1
fi

 (())直接用小于号、大于号、等号用来测试相等性;

 (())复合命令只能处理整数,所以它可以通过名字来识别变量,不需要执行变量扩展操作。

组合表达式

        可以将表达式组合起来,执行更严格的真值测试。组合表达式是通过逻辑运算符组合起来的。

        test和[[ ]]使用不同的操作符来表示NOT AND OR这三种逻辑运算符。

Operationtest - [ ][[]]和(())

AND

-a&&
OR-o||
NOT!!

 下面一个脚本用来检测一个整数是否属于某个范围内的值

#!/bin/bash

# test-integer3: determine if an integer is within a
# specified range of values.

MIN_VAL=1
MAX_VAL=100

INT=50

if [[ "$INT" =~ ^-?[0-9]+$ ]];then
    if [[ $INT -ge $MIN_VAL && $INT -le $MAX_VAL ]];then
    # if [[ INT -ge MIN_VAL && INT -le MAX_VAL ]];then
    # if [[ INT > MIN_VAL && INT < MAX_VAL ]];then
    # if (( INT > MIN_VAL && INT < MAX_VAL ));then
    # 用test形式组合表达式
    # if [ $INT -ge $MIN_VAL -a $INT -le $MAX_VAL ]];then
        echo "$INT is within $MIN_VAL to $MAX_VAL"
    else
        echo "$INT is out of range."
    fi
else
    echo "INT is not an integer" >&2
    exit 1
fi

! NOT运算符对表达式的运算结果取反。

下面的脚本将修改判断逻辑,来判断INT的值是否在指定的范围之外 

#!/bin/bash

# test-integer4: determine if an integer is outside a
# specified range of values.

MIN_VAL=1
MAX_VAL=100

INT=50

if [[ "$INT" =~ ^-?[0-9]+$ ]];then
    if [[ ! (INT -ge MIN_VAL && INT -le MAX_VAL) ]];then
    # if [ ! \( $INT -ge $MIN_VAL -a $INT -le $MAX_VAL \) ];then
        echo "$INT is outside $MIN_VAL to $MAX_VAL"
    else
        echo "$INT is in range."
    fi
else
    echo "INT is not an integer" >&2
    exit 1
fi

以上脚本有几点需要注意的:

  1. 组合表达式取反,需要把组合表达式用圆括号括起来,否则根据优先级,!取反只对第一个表达式取反操作,再与第二个表达式取and操作;
  2. [[ ]]中圆括号直接把组合表达式括起来即可。但是对于test需要对()进行转义操作 

test和[[]]命令功能基本一致。哪一个更好呢?test更具通用性,属于POSIX的一部分,[[]]是bash特定的,更容易编码,更易于理解。 

控制运算符-另一种方式的分支

command1 && command2

        对于 && ,先执行command1,只有在command1执行成功时,command2才能够执行。

从实用性考虑,mkdir temp && cd temp

command1 || command2

        对于 || ,先执行command1,只有在command1执行失败时,command2才能够执行。

 [ -d temp] || mkdir temp 判断是否存在目录temp,如果不存在,才会执行创建目录的命令。

这种构造类型可以轻松处理脚本中的错误。我们可以在脚本中这样编辑,[ -d temp ] || exit 1 如果脚本需要目录temp,而这个目录不存在,则这个脚本会终止,并且退出状态为1。

学会了流程控制中的IF分支语句,我们就可以对系统信息报告生成器脚本做以下修正 

#!/bin/bash
 
# Program to output a system information page
 
TITLE="Syatem Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMPT="Generated $CURRENT_TIME,by $USER"
 
report_uptime () {
    cat <<- _EOF_
        <h2>System Uptime</h2>
        <pre>$(uptime)</pre>
    _EOF_
    return
}
 
report_disk_space () {
    cat <<- _EOF_
        <h2>Disk Space Utilization</h2>
        <pre>$(df -h)</pre>
    _EOF_
    return
}

# 主要对report_home_space方法进行执行用户是否具有
# 读取所有主目录的权限判断
report_home_space () {
    if [[ $(id -u) -eq 0 ]];then
        cat <<- _EOF_
                <h2>Home Space Utilization (All Users)</h2>
                <pre>$(du -sh /home/*)</pre>
                _EOF_
    else
        cat <<- _EOF_
                <h2>Home Space Utilization ($USER)</h2>
                <pre>$(du -sh $HOME)</pre>
                _EOF_
    fi
    return
}
 
cat <<- _EOF_
<html>
    <head>
        <title>$TITLE</title>
    </head>
    <body>
        <h1>$TITLE</h1>
        <p>$TIME_STAMPT</p>
        $(report_uptime)
        $(report_disk_space)
        $(report_home_space)
    </body>
</html>
_EOF_

可以关注作者微信公众号,追踪更多有价值的内容!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值