Shell学习笔记(8)-流程控制之IF语句

流程控制

命令的结束状态
    Bash Shell Script可由许多命令组成。每一个命令执行后,都会传回一个结束状态值,如果执行成功,传回0,如果执行失败,则传回非0值。执行失败,也分成许多状态,例如:某个命令执行失败,产生严重的信号n,则其结束状态传回值为128+n。如果执行命令时,发现该命令不存在,则传回值为127。命令存在但没有执行权,则传回值126。
    Bash的内置变量$?,用来存储每个命令执行后传回的状态值。如执行noexe.sh时,Bash在搜寻路径中找不到这个Script,结束状态变量$?的值为127。


条件判断
    示例:
    if grep -q ^ols3 /etc/passwd; then
        echo 'ols3这个账号存在'
    fi

    使用grep命令寻找/etc/passwd文件中是否有ols3这个关键词出现在行首(以^表示),如果有,表示该帐号存在,就显示存在的信息。(grep -q的-q表示grep之后不在输出端输出)

if-then-else语法规则
    语法一:
    if 条件测试; then
        命令区域
    fi

    示例:if (( 2 < 10 )); then echo '真'; fi
    备注:如果if then放在同一行,则then前需要加;,如果命令区域和fi放在同一行,则fi前需要加;

    语法二:
     if 条件测试; then
        命令区域1
    else
        命令区域2
    fi

    示例:
    if [ -d /root/tmp ]; then
        echo '/root/tmp 目录存在.'
    else
        echo '/root/tmp 目录不存在.'
    fi

    语法三:
    if 条件测试1; then
        命令区域1
    elif 条件测试2; then
        命令区域2
    else
        命令区域3
    fi

    示例:
    #! /bin/Bash

    declare -i a b
    a=$1; b=$2

    if ((a<b)); then
        echo "$a小于$b"
    elif ((a>b)); then
        echo "$a大于$b"
    else
        echo "$a等于$b"
    fi
    备注:在此例中,(())是Bash的复合命令(compound command),内置算式。((算式))可对算式的运算结果传回真假值:如果算式的结果非0,则结束状态传回0,表示该算式主真;如果算式的结果为0,则结束状态传回1,表示该版式为假。它的意义同于 let "算式"

条件测试
    if条件判断中,条件测试的结果是真是假,就看其传回的值是否为0。
    条件测试的写法,有以下10种:

     执行某一个命令的结果
    这里的命令,可包括管道命令,例如:命令1|命令2|命令3,称为pipeline,其结束状态为最后一个命令执行的结果。
    示例:
    #! /bin/Bash
    if grep -q "rm" fn.sh; then
        echo "find rm command"
    else
        echo "not find."
    fi
    在条件测试中,执行的命令是:grep -q "rm" fn.sh,它是寻找fn.sh文件里是否含有关键词rm。选项-q表示不显示,仅借助$?来传回执行结果.

     传回某一命令执行结果的相反值
    其形式为: ! 命令(注意: !和命令之间要有空格符隔开)
    示例:
    #! /bin/Bash

    if ! grep -q "rm" fn.sh; then
        echo "not find."
    else
        echo "find rm command."
    fi
    在条件测试中,如果找不到关键词,就传回0(真值),找到了,则传回1(假值)

     使用复合命令:((算式))
    如果算式的运算结果不为0,则传回真值(0),否则如果运算结果为0,则传回假值(1).

     使用Bash关键词 [[ ]]组成的式子: [[ 判断式 ]]
    判断式会传回真假值,传回0为真,非0为假.[[的后面,]]的前面,都至少含有一个以上的空格符。
    示例:
    #!/bin/sh

    if [[ str > xyz ]]; then
        echo "字符串str比较大"
    else
        echo "字符串str比较小"
    fi
    
     使用内置命令: test判断式
    test是Bash的内置命令,可传回“判断式”的结果,真值传回0,假值传回1。
    #! /bin/Bash

    if test "str" \> "xyz"; then
        echo "字符串str比较大"
    else
        echo "字符串str比较小"
    fi
    备注:>对Bash而言是特殊字符,要用\转义。
    
    使用内置命令: []
    []和test的用法是相同的,示例如下:
    if [ "str" \> "xyz" ]; then
        echo "字符串str比较大"
    else
        echo "字符串str比较小"
    fi

     使用 -a、-o进行了逻辑组合:
    [ -r filename -a -x filename ]  //如果filename可读且可执行,则为真。-a为“且”
    [ -r filename -o -x filename ]  //如果filename可读或可执行,则为真。-o为“或”

     命令1 && 命令2
    命令1执行结果为真,才会执行命令2,如果两个皆为真,则传回真值0,否则传回假值1。
    示例:
    #! /bin/Bash

    a=20
    if grep -q "rm" fn.sh && [ $a -lt 100 ] ; then
        echo "ok"
    else
        echo "not ok"
    fi

    &&的特性,经常拿来当做是一种隐形的if语法。例如:
    [ -z "$PS1" ] && return
    这行程序代码的意思是:先判断$PS变量值是否为空,如果是,就执行return命令,由子shell环境返回到父Shell,这等于是结束执行该Script。作用等同于下列语句:
    if [ -z "$PS1" ]; then
        return
    fi

     命令1||命令2
    ||称为逻辑的OR,其动作方式是:如果"命令1"执行结果为假,才会执行"命令2";如果两个之中有一个为真,则传回真值0,否则传回假值1。
    ||的特性,也可当做是一种隐形的if语法。例如:
    prefix="/home"
    defpath="/usr/local/bin"
    [ -z ${prefix:-} ] || prefix=${defpath%/*}
    因$prefix非空,所以,${prefix:-}变量扩展的传回值为prefix的变量值,[ -z ${prefix:-} ]对空值的条件测试失败,其结果为假,根据||的特性,会接着执行prefix=${defpath%/*},它会由$defpath后方删去符合样式/*的最短字符串,即删去/bin,因此,$prefix的值为/usr/local。
    等效的if语句如下:
    prefix="/home"
    defpath="/usr/local/bin"
    if [ ! -z ${prefix:-} ]; then
        prefix=${defpath%/*}
    fi

     &&和||合用
    &&和||合用,也可以有if-then-else的效果,例如:
    [ -n ${DEBUG:-} ] && set -v || set +v
    这行程序代码,使用-n测试变量DEBUG是否有设非空值,如果有,表示要进行了排错,接着执行逻辑AND的下一条指令:set -v;如果无,则不进行排错,而改执行逻辑OR的下一个指令:set +v,它会把显示程序代码的功能关闭.
    if [ -n "$DEBUG" ]; then
        set -v
    else
        set +v
    fi
    往后,凡是"[ 判断式 ]&&指令1||指令2"的形式,就被视为一种隐形的if-then-else的语法。

    小结:
    在上述这些条件测试的方法中,[[]]和test、[]的意思和用法是相近的,但[[]]比test和[]更自由一点,因为[[]]不必担心某些Bash特殊字符对运算符的影响,不必定一堆字符的怪符号,如[[ str < xyz ]]是正确的语法,但在[]中却要写成[ str \< xyz ],这种陷阱很容易忘记。在[[]]中,<、>、&&、||等都可以自由地使用,不必使用转义字符。
    除了[[]]之外,在Bash中,(())也不必理会上述提到的特殊字符的影响。在[[ 判断式 ]]中,如果使用==或!=,且在这两个运算符右方的字符串没有加上单引号或双引号,则==和!=会视为想要对比该字符串所形成的"样式",如果相符,传回0,如果不符,传回1。

    示例1:
    #! /bin/Bash

    a="str"
    if [[ $a == ??? ]]; then
        echo "Match."   //用$a的值对比样式???
    fi

    if[[ $a == "???" ]]; then //判断$a和字符串???是否相等.

    示例2:
    #! /bin/Bash

    str='abc 123 987 what u want.'
    if [[ "$str" == *[.?\!] ]]; then
        echo "变量str是一字符串,则最后一个字符是 '.'、'?'或'!'其中一个字符."
    fi
    \!是使用\转义!的特殊含意(!原是调用某一历史指令的意思)

    自Bash3.2版开始,支持在[[]]中运用新的对比运算符=~,用法和perl的正则表达式差不多,请参考13.1节正则表达式中的说明。


条件判断式的真假值
    关于文件属性的条件判断式,详见<<实战linux_shell编程与服务器管理>>P195,对应PDF P211页.
    示例:

    #! /bin/Bash

    [ -e "/etc/hosts" ] || (echo '/etc/hosts文件不存在'; exit 1)
    if [ "$?" -eq 1 ]; then
        exit
    fi
    echo '/etc/hosts文件存在,后续处理继续执行下去....'

    备注:使用-e判断/etc/hosts这个文件是否存在,如果不存在,则()开启一个子shell,显示文件不存在的信息,然后传回离去状态值1。如果离去状态为1,就结束script.

    关于字符串的条件判断式,详见<<linux_shell编程与服务器管理>>P197,对应PDF P213页。
    示例1:

    #! /bin/Bash

    if [ "$LOGNAME" != "root" ]; then
        echo '本程序须使用root权限执行.'
        exit 1
    fi

    echo '现在你正以root权限执行本程序...'

    在对比字符串时,最好把变量名称用双引呈含括,以免变量内容为空时造成语法错误。
    为了提高移植性,让script可在其他shell环境中执行,如传统的Bourne shell会利用以下技术来判断字符串是否相等,以避免空值变量造成语法错误:
    
    #! /bin/Bash

    NAME=$1

    if[X"$NAME" = X"Joy" ]; then
        echo '你是Joy.'
    else
        echo '你不是Joy.'
    fi
    这样可以保证语法完整。这里的X,可换成其他任一英文字符。

    关于算式的条件判断式,详见<<linux_shell编程与服务器管理>>P200,对应PDF P216页。

    关于Bash选项的条件判断式,详见<<linux_shell编程与服务器管理>>P200,对应PDF P216页。

    #! /bin/Bash

    set -o

    if [ -o history ]; then
        echo 'Bash选项history开启.'
    else
        echo 'Bash选项history关闭.'
    fi

case条件判断

    语法规则:
    case 待测项 in
        样式串行1) 命令区域1;;
        样式串行2) 命令区域2;;
        样式串行3) 命令区域3;;
        *) 命令区域;;
    esac

    示例:
    #!/bin/sh

    shopt -s nocasematch    //让Bash在对比样式时忽略大小写

    read yname

    case $yname in
        Jack | John | Joe)
            echo 'Well...'
            echo "Long time no see"
            echo "How do you do ?" ;;
        (Mary|May)    //()和)是一样的
            echo 'Nice to meet you.';;
        C*)     echo 'Long time no see.';;
        *)      echo 'Hi!';;
    esac

    高级样式
    case语法中,是否执行某一个命令区域,需要待测项目是否符合“样式”。Bash的样式,可由以下组件组成,称为样式串行:
    1) 字符串: 如Jack
    2) 通配符: 比如*表示任意长度的字符串,也包括空字符串;C*表示以C字符开头的字符串;????表示4个字符的字符串
    3) 字符集合: 如[p-r]im,表示pim、qim、rim。
    4) 项目分隔符 |

    另外,如果Bash的选项extglob有打开,例如 shopt -s extglob,那么Bash还支持几种高级的样式对比,详见文档
    ? * + @ !




你可能感兴趣的:(Shell学习笔记(8)-流程控制之IF语句)