美文网首页
26. 流程控制

26. 流程控制

作者: 独木舟的木 | 来源:发表于2019-02-06 00:47 被阅读3次

    [TOC]

    if 分支结构

    if 语句的语法:

    if commands; then
         commands
    [elif commands; then
         commands...]
    [else
         commands]
    fi
    

    示例代码:

    x=5
    if [ $x = 5 ]; then
        echo "x equals 5."
    else
        echo "x does not equal 5."
    fi
    

    退出状态

    当命令执行完毕后,命令(包括我们编写的脚本和 shell 函数)会给系统发送一个值,叫做退出状态。 这个值是一个 0 到 255 之间的整数,说明命令执行成功或是失败。按照惯例,一个零值说明成功,其它所有值说明失败。 Shell 提供了一个参数($?),我们可以用它检查退出状态。

    echo $?
    
    • true 命令总是执行成功,而 false 命令总是执行失败

    测试

    经常与 if 一块使用的命令是 test。这个 test 命令执行各种各样的检查与比较。它有两种等价模式:

    test expression
    

    比较流行的格式是:

    [ expression ]
    

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

    文件表达式

    测试文件表达式 如果为真
    file1 -ef file2 file1 和 file2 拥有相同的索引号(通过硬链接两个文件名指向相同的文件)。
    file1 -nt file2 file1 新于 file2。
    file1 -ot file2 file1 早于 file2。
    -b file file 存在并且是一个块(设备)文件。
    -c file file 存在并且是一个字符(设备)文件。
    -d file file 存在并且是一个目录。
    -e file file 存在。
    -f file file 存在并且是一个普通文件。
    -g file file 存在并且设置了组 ID。
    -G file file 存在并且由有效组 ID 拥有。
    -k file file 存在并且设置了它的 “sticky bit”。
    -L file file 存在并且是一个符号链接。
    -O file file 存在并且由有效用户 ID 拥有。
    -p file file 存在并且是一个命名管道。
    -r file file 存在并且可读(有效用户有可读权限)。
    -s file file 存在且其长度大于零。
    -S file file 存在且是一个网络 socket。
    -t fd fd 是一个定向到终端/从终端定向的文件描述符 。 这可以被用来决定是否重定向了标准输入/输出错误。
    -u file file 存在并且设置了 setuid 位。
    -w file file 存在并且可写(有效用户拥有可写权限)。
    -x file file 存在并且可执行(有效用户有执行/搜索权限)。

    示例代码:

    #!/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
    

    注意:

    1. 在表达式中参数 FILE 是怎样被引用的。引号并不是必需的,但这是为了防范空参数。如果FILE 的参数展开 是一个空值,就会导致一个错误(操作符将会被解释为非空的字符串而不是操作符)。
    2. 注意脚本末尾的 exit 命令。 这个 exit 命令接受一个单独的,可选的参数,其成为脚本的退出状态。
    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 语句来代替 exit 命令, 以得到期望的行为。
            return 1
        fi
    }
    

    字符串表达式

    测试字符串表达式 如果为真...
    string string 不为 null。
    -n string 字符串 string 的长度大于零。
    -z string 字符串 string 的长度为零。
    string1 = string2 string1 和 string2 相同。单或双等号都可以,不过双等号更受欢迎。
    string1 == string2 同上
    string1 != string2 string1 和 string2 不相同。
    string1 > string2 sting1 排列在 string2 之后。
    string1 < string2 string1 排列在 string2 之前。

    ⚠️ 当与 test 一块使用的时候, < 和 > 表达式操作符必须用引号引起来(或者是用反斜杠转义)。

    整形表达式

    测试整数表达式 如果为真...
    integer1 -eq integer2 integer1 等于 integer2.
    integer1 -ne integer2 integer1 不等于 integer2.
    integer1 -le integer2 integer1 小于或等于 integer2.
    integer1 -lt integer2 integer1 小于 integer2.
    integer1 -ge integer2 integer1 大于或等于 integer2.
    integer1 -gt integer2 integer1 大于 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
    

    更现代的测试版本

    目前的 bash 版本包括一个复合命令,作为加强的 test 命令替代物。它使用以下语法:

    [[ expression ]]
    

    这个 [[ ]] 命令非常相似于 test 命令(它支持所有的表达式),但是增加了一个重要的新的字符串表达式:

    string1 =~ regex
    

    如果 string1 匹配扩展的正则表达式 regex,其返回值为真。
    [[ ]]添加的另一个功能是==操作符支持类型匹配,正如路径名展开所做的那样。

    (()) - 为整数设计

    除了[[ ]]复合命令之外,bash 也提供了 (( )) 复合命名,其有利于操作整数。它支持一套完整的算术计算。

    (( )) 被用来执行算术真测试。如果算术计算的结果是非零值,则一个算术真测试值为真。

    结合表达式

    逻辑操作符 测试 [[ ]] and (( ))
    AND -a &&
    OR -o ||
    NOT ! !

    控制操作符 - 分支的另一种方法

    bash 支持两种可以执行分支任务的控制操作符。这个 &&(AND)||(OR)操作符作用如同复合命令 [[ ]] 中的逻辑操作符。这是语法:

    # 先执行 command1,并且只有 command1 执行成功后,才会执行 command2。
    command1 && command2
    

    # 先执行 command1,并且只有 command1 执行失败后, 才会执行 command2
    command1 || command2
    

    示例代码:

    mkdir temp && cd temp
    

    while/util 循环

    while 命令的语法是:

    while commands; do commands; done
    

    和 if 一样, while 计算一系列命令的退出状态。只要退出状态为零,它就执行循环内的命令。
    示例代码:

    #!/bin/bash
    # while-count: display a series of numbers
    count=1
    while [ $count -le 5 ]; do
        echo $count
        count=$((count + 1))
    done
    echo "Finished."
    

    跳出循环

    bash 提供了两个内部命令,它们可以用来在循环内部控制程序流程。

    • break 命令立即终止一个循环, 且程序继续执行循环之后的语句。
    • continue 命令导致程序跳过循环中剩余的语句,且程序继续执行 下一次循环。

    case 分支

    Bash 的多选复合命令称为 case。它的语法规则如下所示:

    case word in
        [pattern [| pattern]...) commands ;;]...
    esac
    

    示例代码:

    #!/bin/bash
    # case-menu: a menu driven system information program
    clear
    echo "
    Please Select:
    1. Display System Information
    2. Display Disk Space
    3. Display Home Space Utilization
    0. Quit
    "
    read -p "Enter selection [0-3] > "
    case $REPLY in
        0)  echo "Program terminated."
            exit
            ;;
        1)  echo "Hostname: $HOSTNAME"
            uptime
            ;;
        2)  df -h
            ;;
        3)  if [[ $(id -u) -eq 0 ]]; then
                echo "Home Space Utilization (All Users)"
                du -sh /home/*
            else
                echo "Home Space Utilization ($USER)"
                du -sh $HOME
            fi
            ;;
        *)  echo "Invalid entry" >&2
            exit 1
            ;;
    esac
    
    case 模式 描述
    a) 若单词为 “a”,则匹配
    [[:alpha:]]) 若单词是一个字母字符,则匹配
    ???) 若单词只有 3 个字符,则匹配
    .txt) 若单词以 “.txt” 字符结尾,则匹配
    ) 匹配任意单词。把这个模式做为 case 命令的最后一个模式,是一个很好的做法, 可以捕捉到任意一个与先前模式不匹配的数值;也就是说,捕捉到任何可能的无效值。

    位置参数

    可以用位置参数来访问命令行中的内容。

    [me@linuxbox ~]$ posit-param a b c d
    $0 = /home/me/bin/posit-param # 即使不带命令行参数,位置参数 $0 总会包含命令行中出现的第一个单词,也就是已执行程序的路径名。
    $1 = a # 第一个参数是 a
    $2 = b
    $3 = c
    $4 = d
    $5 =
    $6 =
    $7 =
    $8 =
    $9 =
    
    • 注意: 实际上通过参数展开方式你可以访问的参数个数多于 9 个。只要指定一个大于 9 的数字,用花括号把该数字括起来就可以。 例如 {10},{55}, ${211},

    确定参数个数

    shell 还提供了一个名为 $#,可以得到命令行参数个数的变量。

    shift - 访问多个参数的利器

    for 循环

    语法一:

    for variable [in words]; do
        commands
    done
    

    语法二:最新版本的 bash 已经添加了第二种格式的 for 命令语法,该语法相似于 C 语言中的 for 语法格式:

    for (( expression1; expression2; expression3 )); do
        commands
    done
    

    示例代码:

    report_home_space () {
        local format="%8s%10s%10s\n"
        local i dir_list total_files total_dirs total_size user_name
        if [[ $(id -u) -eq 0 ]]; then
            dir_list=/home/*
            user_name="All Users"
        else
            dir_list=$HOME
            user_name=$USER
        fi
        echo "<H2>Home Space Utilization ($user_name)</H2>"
        for i in $dir_list; do
            total_files=$(find $i -type f | wc -l)
            total_dirs=$(find $i -type d | wc -l)
            total_size=$(du -sh $i | cut -f 1)
            echo "<H3>$i</H3>"
            echo "<PRE>"
            printf "$format" "Dirs" "Files" "Size"
            printf "$format" "----" "-----" "----"
            printf "$format" $total_dirs $total_files $total_size
            echo "</PRE>"
        done
        return
    }
    

    相关文章

      网友评论

          本文标题:26. 流程控制

          本文链接:https://www.haomeiwen.com/subject/kcivsqtx.html