zoukankan      html  css  js  c++  java
  • Bash脚本编程学习笔记06:条件结构体

    简介

    在bash脚本编程中,条件结构体使用if语句和case语句两种句式。

    if语句

    单分支if语句

    if TEST; then
        CMD
    fi

    TEST:条件判断,多数情况下可使用test命令来实现,返回值为0的话则执行CMD,否则就离开该条件结构体,脚本继续往下执行。

    [root@c7-server ~]# cat test.sh
    #!/bin/bash
    if id zwl &> /dev/null; then
        echo "User zwl exists."
    fi
    [root@c7-server ~]# bash test.sh 
    User zwl exists.

    双分支if语句

    if TEST; then
      
    CMD-TRUE else
      
    CMD-FALSE fi

    为真执行CMD-TRUE,为假执行CMD-FALSE。

    [root@c7-server ~]# cat test.sh
    #!/bin/bash
    read -p "Pleas input a user name:" name
    if id $name &> /dev/null; then
        echo "User $name exists."
    else
        echo "User $name doesn't exists."
    fi
    [root@c7-server ~]# bash test.sh 
    Pleas input a user name:zwl
    User zwl exists.
    [root@c7-server ~]# bash test.sh 
    Pleas input a user name:alongdidi
    User alongdidi doesn't exists.

    多分支if语句

    if TEST1; then
        CMD1
    elif TEST2; then
        CMD2
    elif TEST3; then
        CMD3
    ...
    else
        CMD-LAST
    fi

    当TEST1为真时执行CMD1,否则判断TEST2;当TEST2为真时执行CMD2,否则判断TEST3;以此类推,都不符合条件的话则执行CMD-LAST。

    判断文件类型的示例。

    #!/bin/bash
    read -p "Please input only a absolute file path:" file
    
    if [ -z $file ]; then
        echo "You must input something."
        exit 2
    fi
    
    if [ ! -e $file ]; then
        echo "No such file $file"
    elif [ -d $file ]; then
        echo "File $file is a directory."
    elif [ -L $file ]; then
        echo "File $file is a symbolic."
    elif [ -b $file ]; then
        echo "File $file is a block special file."
    elif [ -c $file ]; then
        echo "File $file is a character special file."
    elif [ -S $file ]; then
        echo "File $file is a socket file."
    elif [ -f $file ]; then
        echo "File $file is a regular file."
    else
        echo "File is unrecognized."
    fi

    执行示例。

    [root@c7-server ~]# bash test.sh 
    Please input only a absolute file path:
    You must input something.
    [root@c7-server ~]# bash test.sh 
    Please input only a absolute file path:passwd
    No such file passwd
    [root@c7-server ~]# bash test.sh 
    Please input only a absolute file path:/etc/passwd        
    File /etc/passwd is a regular file
    [root@c7-server ~]# bash test.sh 
    Please input only a absolute file path:/root/
    File /root/ is a directory.
    [root@c7-server ~]# bash test.sh 
    Please input only a absolute file path:/etc/rc.local
    File /etc/rc.local is a symbolic.

    字符链接文件也可以被认为是普通文件(regular),因此建议将普通文件的判定放置在较靠后的位置。

    注意:if语句是可以嵌套的。

    [root@c7-server ~]# cat test.sh
    #!/bin/bash
    if [ -e /dev/sda ]; then
        if [ -b /dev/sda ]; then
            echo "It's a block file."
        fi
    fi
    [root@c7-server ~]# bash test.sh
    It's a block file.

    其他示例

    编写一个脚本,仅可接收一个参数,此参数应是一个用户名称。判断该用户名是否存在,若存在则输出用户的信息,否则就创建该用户并设置默认密码(password)。

    #!/bin/bash
    
    if [ $# -ne 1 ];then
        echo "You must input just one argument!"
        exit 2
    fi
    
    if id $1 &> /dev/null; then
        id $1
    else
        useradd $1
        echo "password" | passwd --stdin $1 &> /dev/null
    fi

    编写一个脚本,接收两个数值类参数,并输出其中较大的那个。

    #!/bin/bash
    
    if [ $# -ne 2 ]; then
        echo "Please input exact two number arguments."
        exit 1
    fi
    
    if [ $1 -eq $2 ]; then
        echo "Number $1 and $2 are equal."
    elif [ $1 -gt $2 ]; then
        echo "The greater is $1."
    else
        echo "The greater is $2."
    fi

    编写一个脚本,接收一个用户名作为参数,并判断其奇偶性。

    [root@c7-server ~]# cat even_odd_if.sh 
    #!/bin/bash
    
    if [ $# -ne 1 ]; then
        echo "You must input just one argument."
        exit 1
    fi
    
    var=$[$(id -u $1)%2]
    if [ $var -eq 0 ]; then
        echo "The UID of $1 is even."
    else
        echo "The UID of $1 is odd."
    fi

    编写一个脚本,接收两个文件名作为参数,返回文件的行数以及判断哪个文件的行数比较多。

    #!/bin/bash
    
    if [ $# -ne 2 ]; then
        echo "You must input exat 2 arguments."
        exit 1
    fi
    
    if [ ! -e $1 -o ! -e $2 ]; then
        echo "File $1 or/and $2 doesn't/don't exist[s]."
        exit 2
    fi
    
    line1=$(wc -l $1 | cut -d " " -f 1)
    line2=$(wc -l $2 | cut -d " " -f 1)
    echo "The lines of $1 is $line1"
    echo "The lines of $2 is $line2"
    
    if [ $line1 -gt $line2 ]; then
        echo "$1 has more lines."
    elif [ $line1 -lt $line2 ]; then
        echo "$2 has more lines."
    else
        echo "They have same lines."
    fi

    编写一个脚本,传递一个用户名作为参数给脚本,判断用户的类型。

    UID=0:管理员

    UID=1~999:系统用户

    UID=1000+:普通用户

    #!/bin/bash
    
    if [ $# -ne 1 ]; then
        echo "You must input exact one argument."
        exit 1
    fi
    
    if ! id $1 &> /dev/null; then
        echo "You must input an existed username."
        exit 2
    fi
    
    userId=$(id -u $1)
    if [ $userId -eq 0 ]; then
        echo "$1 is a admin user."
    elif [ $userId -lt 1000 ]; then
        echo "$1 is a system user."
    else
        echo "$1 is a normal user."
    fi

    编写一个脚本,展示一个菜单供用户选择,菜单告知用户脚本可以显示的系统信息。

    #!/bin/bash
    
    cat << EOF
    disk) Show disk infomation.
    mem) Show memory infomation.
    cpu) Show cpu infomation.
    *) QUIT!
    EOF
    
    read -p "Your option is: " option
    if [ -z $option ]; then
        echo "You input nothing,QUIT!"
        exit 1
    elif [ $option == disk ]; then
        fdisk -l
    elif [ $option == mem ]; then
        free -m
    elif [ $option == cpu ]; then
        lscpu
    else
        echo "You input a illegal string,QUIT now!"
    fi

    在后面学习了循环之后,可以加上循环,使得用户在输入错误的情况下,反复让用户输入直到输入正确的选项。

    #!/bin/bash
    
    cat << EOF
    disk) Show disk infomation.
    mem) Show memory infomation.
    cpu) Show cpu infomation.
    *) Again!
    EOF
    
    read -p "Your option is: " option
    
    while [ "$option" != disk -a "$option" != mem -a "$option" != cpu -o "$option" == "" ]; do
        echo "You input a illegal string. Usage {disk|mem|cpu}, case sensitive."
        read -p "Your option is: " option
    done
    
    if [ $option == disk ]; then
        fdisk -l
    elif [ $option == mem ]; then
        free -m
    elif [ $option == cpu ]; then
        lscpu
    fi

    这个脚本的难点我觉得在于while循环中的判断应该怎么写,$option是否应该加引号、字符串匹配右边的字符(如disk)是否需要加引号、使用单中括号还是双中括号、使用单引号还是双引号。我也是一遍遍试直到瞎猫碰到死耗子才写出来符合自己需求的bash代码。

    具体涉及的难点包括但《Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量》文章开头说的那些,因此这里无法为大家做到准确的分析。

    case语句

    像上述脚本中,我们反复对一个变量做字符串等值比较并使用了多分支的if语句。此类情况我们完全可以使用case语句来代替,使其更容易看懂。

    其官方语法如下:

    case word in
        [ [(] pattern [| pattern]…) command-list ;;]…
    esac

    case会将word和pattern进行匹配,一旦匹配到就执行对应的command-list,并且退出。

    pattern基于bash的模式匹配,即glob风格。

    pattern至少一个,可以有多个使用“|”分隔。

    pattern+command-list成为一个子句(clause),如下。

    [(] pattern [| pattern]…) command-list ;;

    每个子句,都会以“;;”或者“;&”或者“;;&”结束。基本上只会使用“;;”。

    ;;:决定了一旦word第一次匹配到了pattern,就执行对应的command-list,并且退出。
    ;&和;;&:而这两个是不会在第一次匹配到就立刻退出的,还会有其他后续的动作,几乎很少用到,有需要的可以去看手册。

    word在匹配前会经历:波浪符展开、参数展开、命令替换、算术展开和引号去除。

    pattern会经历:波浪符展开、参数展开、命令替换和算术展开。

    当word的值是一个通配符的时候,表示默认的case。类似多分支if语句最后的else。

    来个官方示例,简单易懂。

    #!/bin/bash
    
    echo -n "Enter the name of an animal: "
    read ANIMAL
    echo -n "The $ANIMAL has "
    case $ANIMAL in
      horse | dog | cat) echo -n "four";;
      man | kangaroo ) echo -n "two";;
      *) echo -n "an unknown number of";;
    esac
    echo " legs."

    学会了case语句后,我们就可以对上面的多分支if语句的最后一个示例(显示系统信息的)进行改写,改为case语句的。应该不难,这里不演示了,我们尝试新的脚本。

    我们尝试写一个bash服务类脚本,常见于CentOS 6系列的系统中的/etc/rc.d/init.d/目录下。

    • 脚本的名称一般就是服务名称,不会带“.sh”。
    • 服务脚本一般会创建一个空文件作为锁文件,若此文件存在则表示服务处于运行状态;反之,则服务处于停止状态。
    • 脚本只能接收四种参数:start, stop, restart, status。
    • 我们并不会真正启动某进程,只要echo即可。启动时需创建锁文件,停止时需删除锁文件。
    • 适当加入条件判断使得脚本更健壮。
    #!/bin/bash
    #
    # chkconfig: - 50 50
    # Description: test service script
    #
    
    prog=$(basename $0)
    lockfile="/var/lock/subsys/$prog"
    
    case $1 in
        start)
            if [ -e $lockfile ]; then
                echo "The service $prog has already started."
            else
                touch $lockfile
                echo "The service $prog starts finished."
            fi
        ;;
        stop)
            if [ ! -e $lockfile ]; then
                echo "The service $prog has already stopped."
            else
                rm -f $lockfile
                echo "The service $prog stops finished."
            fi
        ;;
        restart)
            if [ -e $lockfile ]; then
                rm -f $lockfile
                touch $lockfile
                echo "The service $prog restart finished."
            else
                touch $lockfile
                echo "The service $prog starts finished."
            fi
        ;;
        status)
            if [ -e $lockfile ]; then
                echo "The service $prog is running."
            else
                echo "The service $prog is not running."
            fi
        ;;
        *)
            echo "Usage: $prog {start|stop|restart|status}"
            exit 1
        ;;
    esac

    脚本编写完成后,要放入服务脚本所在的目录、给予权限、加入服务管控(chkconfig),最后就可以使用service命令进行测试了。

    ~]# cp -av case_service.sh /etc/rc.d/init.d/case_service
    ‘case_service.sh’ -> ‘/etc/rc.d/init.d/case_service’
    ~]# chmod a+x /etc/rc.d/init.d/case_service
    ~]# chkconfig --add case_service
    ~]# chkconfig case_service on

    像这个服务类的脚本,我们在重启时,可能执行先停止后启动,也可能执行启动。这些在启动和停止时都有已经写好的代码了。如果可以将代码进行重用的话,就可以减少很多代码劳动。这就是之后要介绍的函数。

  • 相关阅读:
    dpdk优化相关 转
    常用的TCP Option
    c10k C10M
    Linux惊群效应详解
    bloomfilter 以及count min sketch
    Squid 搭建正向代理服务器
    Openflow的架构+源码剖析 转载
    Hyperscan与Snort的集成方案
    动态图
    psutil 模块
  • 原文地址:https://www.cnblogs.com/alongdidi/p/bash_conditional_construct.html
Copyright © 2011-2022 走看看