zoukankan      html  css  js  c++  java
  • Shell从入门到精通进阶之四:流程控制

    流程控制是改变程序运行顺序的指令。

    4.1 if语句

    4.1.1 单分支

    if 条件表达式; then
        命令
    fi

    示例:

    #!/bin/bash
    N=10
    if [ $N -gt 5 ]; then
        echo yes
    fi
    # bash test.sh
    yes

    4.1.2 双分支

    if 条件表达式; then
        命令
    else
        命令
    fi

    示例1:

    #!/bin/bash
    N=10
    if [ $N -lt 5 ]; then
        echo yes
    else
        echo no
    fi
    # bash test.sh
    no

    示例2:判断crond进程是否运行

    #!/bin/bash
    NAME=crond
    NUM=$(ps -ef |grep $NAME |grep -vc grep)
    if [ $NUM -eq 1 ]; then
        echo "$NAME running."
    else
        echo "$NAME is not running!"
    fi

    示例3:检查主机是否存活

    #!/bin/bash
    if ping -c 1 192.168.1.1 >/dev/null;then 
            echo "OK."
    else 
            echo "NO!"
    fi

    if语句可以直接对命令状态进行判断,就省去了获取$?这一步!

    4.1.3 多分支

    if 条件表达式; then
        命令
    elif 条件表达式; then
        命令
    else
        命令
    fi

    当不确定条件符合哪一个时,就可以把已知条件判断写出来,做相应的处理。

    示例1:

    #!/bin/bash
    N=$1
    if [ $N -eq 3 ]; then
       echo "eq 3"
    elif [ $N -eq 5 ]; then
       echo "eq 5"
    elif [ $N -eq 8 ]; then
       echo "eq 8"
    else
       echo "no"
    fi

    如果第一个条件符合就不再向下匹配。

    示例2:根据Linux不同发行版使用不同的命令安装软件

    #!/bin/bash
    if [ -e /etc/redhat-release ]; then
       yum install wget -y
    elif [ $(cat /etc/issue |cut -d' ' -f1`) =="Ubuntu" ]; then
       apt-get install wget -y
    else
       Operating system does not support.
       exit
    fi

    4.2 for语句

    for 变量名 in 取值列表; do
        命令
    done

    示例:

    #!/bin/bash
    for i in {1..3}; do
        echo $i
    done
    # bash test.sh
    1
    2
    3

    for的语法也可以这么写:

    #!/bin/bash
    for i in $@; {
        echo $i
    }
    # bash test.sh 1 2 3
    1
    2
    3

    默认for循环的取值列表是以空白符分隔,也就是第一章讲系统变量里的$IFS:

    #!/bin/bash
    for i in 12 34; do
        echo $i
    done
    # bash test.sh
    12
    34

    如果想指定分隔符,可以重新赋值$FS变量:

    #!/bin/bash
    OLD_IFS=$IFS
    IFS=":"
    for i in $(head -1 /etc/passwd); do
       echo $i
    done
    IFS=$OLD_IFS   # 恢复默认值
    # bash test.sh   
    root
    x
    0
    0
    root
    /root
    /bin/bash

    for循环还有一种C语言风格的语法:

    #!/bin/bash
    for ((i=1;i<=5;i++)); do
        echo $i
    done

    示例1:检查多个主机是否存活

    #!/bin/bash
    for ip in 192.168.1.{1..254}; do
       if ping -c 1 $ip >/dev/null; then
           echo "$ip OK."
       else
           echo "$ip NO!"
       fi
    done

    示例2:检查多个域名是否可以访问

    #!/bin/bash
    URL="www.baidu.com www.sina.comwww.jd.com"
    for url in $URL; do
       HTTP_CODE=$(curl -o /dev/null -s -w %{http_code} http://$url)
       if [ $HTTP_CODE -eq 200 -o $HTTP_CODE -eq 301 ]; then
           echo "$url OK."
       else
           echo "$url NO!"
       fi
    done

    4.3 while语句

    while 条件表达式; do
        命令
    done

    示例1:

    #!/bin/bash
    N=0
    while [ $N -lt 5 ]; do
        let N++
        echo $N
    done
    # bash test.sh
    1
    2
    3
    4
    5

    当条件表达式为true时,终止循环。

    示例2:条件表达式为true,将会产生死循环

    #!/bin/bash
    while [ 1 -eq 1 ]; do
        echo "yes"
    done

    也可以条件表达式直接用true:

    #!/bin/bash
    while true; do
        echo "yes"
    done

    还可以条件表达式用冒号,冒号在Shell中的意思是不做任何操作。但状态是0,因此为true:

    #!/bin/bash
    while :; do
        echo "yes"
    done

    示例3:在死循环中,满足条件终止循环

    #!/bin/bash
    N=0
    while true; do
        let N++
        if [ $N -eq 5 ]; then
            break
        fi
        echo $N
    done
    # bash test.sh
    1
    2
    3
    4

    里面用了if判断,并用了break语句,它是跳出循环。与其关联的还有一个continue语句,它是跳出本次循环。

    示例4:举例子说明continue用法

    #!/bin/bash
    N=0
    while [ $N -lt 5 ]; do
        let N++
        if [ $N -eq 3 ]; then
            continue
        fi
        echo $N
    done
    # bash test.sh
    1
    2
    4
    5

    当变量N等于3时,continue跳过了当前循环,没有执行下面的echo。

    注意:continue与break语句只能循环语句中使用。

    示例5:逐行处理文本

    文本内容:

    # cat a.txt
    a b c
    1 2 3
    x y z

    要想使用while循环逐行读取a.txt文件,有三种方式:

    方式1:
    #!/bin/bash
    cat ./a.txt | while read LINE; do
        echo $LINE
    done
    方式2:
    #!/bin/bash
    while read LINE; do
        echo $LINE
    done < ./a.txt
    方式3:
    #!/bin/bash
    exec < ./a.txt  # 读取文件作为标准输出
    while read LINE; do
        echo $LINE
    done

    与while关联的还有一个until语句,它与while不同之处在于,是当条件表达式为false时才循环,实际使用中比较少,这里不再讲解。

    4.4 case语句

    case语句一般用于选择性来执行对应部分块命令。

    case 模式名 in
        模式1)
            命令
            ;;
        模式2)
            命令
            ;;
        *)
            不符合以上模式执行的命令
    esac

    每个模式必须以右括号结束,命令结尾以双分号结束。

    示例:根据位置参数匹配不同的模式

    #!/bin/bash
    case $1 in
        start)
            echo "start."
            ;;
        stop)
            echo "stop."
            ;;
        restart)
            echo "restart."
            ;;
        *)
            echo "Usage: $0 {start|stop|restart}"
    esac  
     
    # bash test.sh
    Usage: test.sh {start|stop|restart}
    # bash test.sh start
    start.
    # bash test.sh stop
    stop.
    # bash test.sh restart
    restart.

    上面例子是不是有点眼熟,在Linux下有一部分服务启动脚本都是这么写的。

    模式也支持正则,匹配哪个模式就执行那个:

    #!/bin/bash
    case $1 in
        [0-9])
            echo "match number."
            ;;
        [a-z])
            echo "match letter."
            ;;
        '-h'|'--help')
            echo "help"
        *)
            echo "Input error!"
            exit
    esac   
    # bash test.sh 1
    match number.
    # bash test.sh a
    match letter.
    # bash test.sh -h
    help
    # bash test.sh --help
    help

    模式支持的正则有:*、?、[ ]、[.-.]、|。后面有章节单独讲解Shell正则表达式。

    4.5 select语句

    select是一个类似于for循环的语句。

    select 变量 in 选项1 选项2; do
        break
    done

    示例:

    #!/bin/bash
    select mysql_version in 5.1 5.6; do
        echo $mysql_version
    done
    # bash test.sh
    1) 5.1
    2) 5.6
    #? 1
    5.1
    #? 2
    5.6

    用户输入编号会直接赋值给变量mysql_version。作为菜单用的话,循环第二次后就不再显示菜单了,并不能满足需求。

    在外面加个死循环,每次执行一次select就break一次,这样就能每次显示菜单了:

    #!/bin/bash
    while true; do
        select mysql_version in 5.1 5.6; do
            echo $mysql_version
            break
        done
    done
    # bash test.sh
    1) 5.1
    2) 5.6
    #? 1
    5.1
    1) 5.1
    2) 5.6
    #? 2
    5.6
    1) 5.1
    2) 5.6

    如果再判断对用户输入的编号执行相应的命令,如果用if语句多分支的话要复杂许多,用case语句就简单多了。

    #!/bin/bash
    PS3="Select a number: "
    while true; do
        select mysql_version in 5.1 5.6 quit; do
            case $mysql_version in
                5.1)
                    echo "mysql 5.1"
                    break
                    ;;
                5.6)
                    echo "mysql 5.6"
                    break
                    ;;
                quit)
                    exit
                    ;;
                *) 
                    echo "Input error, Please enter again!"
                    break
            esac
        done
    done
    # bash test.sh
    1) 5.1
    2) 5.6
    3) quit
    Select a number: 1
    mysql 5.1
    1) 5.1
    2) 5.6
    3) quit
    Select a number: 2
    mysql 5.6
    1) 5.1
    2) 5.6
    3) quit
    Select a number: 3

    如果不想用默认的提示符,可以通过重新赋值变量PS3来自定义。这下就比较完美了!

  • 相关阅读:
    【咸鱼教程】基于系统时间的计时器DateTimer(不受FPS影响)
    【咸鱼教程】Egret实现摇一摇功能
    【咸鱼教程】可自动滚动的聊天文本框
    【咸鱼教程】虚拟摇杆
    【咸鱼教程】一个简单的画布(阴阳师画符)
    【咸鱼教程】震屏效果
    【咸鱼教程】一个简单的弹出二级菜单UIPopupMenu
    【咸鱼教程】微信网页授权(获取用户头像、昵称等)
    【咸鱼教程】TextureMerger1.6.6 三:Bitmap Font的制作和使用
    【咸鱼教程】TextureMerger1.6.6 二:Sprite Sheet的制作和使用
  • 原文地址:https://www.cnblogs.com/521football/p/10435564.html
Copyright © 2011-2022 走看看