美文网首页
bash高级进程

bash高级进程

作者: JevonWei | 来源:发表于2017-07-08 20:00 被阅读0次

    bash脚本编程:

      过程式编程语言
          顺序执行   
          选择执行   
          循环执行   
      循环执行:必须有进入条件和退出条件  
    
    • 函数:结构化编程及代码重用

      function

    选择执行:

    if 判断条件;then   
        条件为真的分支代码   
    fi   
        
    if 判断条件;then
        添加为真的分支代码
    else 
        条件为假的分支代码
    fi
    
    
    eg:    
        新建用户
        #!/bin/bash
        ## 如果脚本参数小于1,则退出   
        if [ $# -lt 1 ];then
            echo "At least one argument"
            exit 1
        fi
    
        ## 判断$1用户是否存在,用户不存在则创建  
        if id $1 &> /dev/null;then
            echo "$1 exists"
            exit 0
        else 
            useradd $1
            [ $? -eq 0 ] && echo "$1" | passwd --stdin $1 &> /dev/null || exit 1 
        fi 
    

    多分支

    if  判断条件 1 ; then
        条件为真的分支代码
    elif  判断条件 2 ; then
        条件为真的分支代码
    elif  判断条件 3 ; then
        条件为真的分支代码
    else
        以上条件都为假的分支代码
    fi
    
    • 逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if

    循环

    • 循环执行
    将某代码段重复运行多次
    重复运行多少次:
        循环次数事先已知
        循环次数事先未知
        有进入条件和退出条件
    
    • for, while, until

    for循环语法:

      for  NAME in LIST;do 
          循环体   
      done
    
    • 执行机制
      依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束

    • 循环列表生成方式:

    (1)直接给出列表
    (2)整数列表   
        {start..end}
        $(seq [start [step]]end)
    (3)glob(统配路径下的所有文件)如:*.sh
        /etc/rc.d/rc3.d/k*
    (4)返回列表的命令
        $(COMMAND)
    (5)变量引用:
        $@,$*
    

    eg:

    通过ping命令探测172.17.250.1-254范围内的所有主机的在线状态    
    #!/bin/bash 
    net='172.17.253'
    uphost=0
    downhost=0
    for i in {1..20};do
        ping -c 1 -v 1 ${net}.$i &> /dev/null
        if [ $? -eq 0 ];then
            echo "${net}.$i is up"
            let uphost++
        else 
            echo "${net}.$i is down"
            let downhost++
        fi
    done 
    echo "Up host:$uphost"
    echo "Down host:$downhost"
    

    while循环:

    while CONDITON;do
        循环体
    done
    
    CONDITION:循环控制列表:进入循环之前,先做一次判断;每一次循环之后会再次做判断    
        条件为“true”,则执行一次循环:直到条件测试状态为“false”终止循环;
        因此:CONDITION一般应该有循环控制变量,而此变量的值会在循环体不断的被修正
    进入条件:CONDITION 为true
    退出条件:CONDITION 为false
    

    示例

    1 . 求100以内所有正整数之和

    declare -i sum=0
    declare -i i=1
    
    while [ $i -le 100 ];do
        let sum+=$i
        let i++
    done
    
    echo "i=$i"
    echo "Summary:$sum"
    

    2 . 添加10个用户

    declare -i i=1
    declare -i users=0
    while [ $i -le 1 ];do
        if ! id user$i &> /dev/null;then
            useradd user$i
            echo "Add user:user$i"
            let users++
        fi
        let i++
    done
    echo "Add $users users"
    

    3 . 通过ping命令探测172.17.253.1-254范围的所有主机的在线状态:(用while循环)

    declare -i i=1
    declare -i uphosts=0
    declare -i downhosts=0
    net='172.17.253'
    
    while [ $i -le 20 ];do
        if ping -c 1 -w 1 $net.$i &> /dev/null;then 
            echo "$net.$i is up"
            let uphosts++
        else 
            echo "$net.$i is downhosts"
            let downhosts++
        fi 
        let i++
    done 
    echo "Up hosts:$uphosts"
    echo "Down host:$downhosts"
    

    4 . 打印九九乘法表:(分别使用for和while循环实现)

    for语句
    
        for j in {1..9};do
            for i in $(seq 1 $j);do
                echo -n -e  "${i}X${j}=$[$i*$j]\t"
            done
            echo 
        done
    
    while语句   
    
        declare -i i=1
        declare -i j=1
    
        while [ $j -le 9 ];do
            while [ $i -le $j ];do
                echo -e -n "${i}X${j}=$[$i*$j]\t"
                let i++
            done 
            echo 
            let i=1
            let j++
        done
    

    5 . 利用RANDOM生成10个随机数字,输出这10个数字,并显示其中的最大值和最小值

    #!/bin/bash
    declare -i max=0
    declare -i min=0
    declare -i i=1
    
    #max=$rand
    #min=$rand 
    
    while [ $i -le 9 ];do
        rand=$RANDOM
        echo $rand
    
        if [ $i -eq 1 ];then
            max=$rand
            min=$rand
        fi
        if [ $rand -gt $max ];then 
            max=$rand
        fi
        if [ $rand -lt $min ];then
            min=$rand
        fi
        let i++
    done  
    
    echo "MAX:$max"
    echo "MIN:$min"
    

    unil

    unil COMDITION;do
        循环体
    done
    循环条件为:false
    退出条件为:true
    

    示例

    1 . 求100以内所有正整数之和

    /bin/bash
    #!
    declare -i i=1
    declare -i sum=0
    
    until [ $i -gt 100 ];do
        let sum+=$i 
        let i++
    done
    echo "Sum:$sum" 
    

    2 . 打印九九乘法表

    #!/bin/bash
    # filename timetale3.sh
    # author:danran 
    # time is 2017-06-22
    declare -i j=1
    declare -i i=1
    
    until [ $j -gt 9 ];do
        until [ $i -gt $j ];do
            echo -n -e "${i}X${j}=$[$i*$j]\t"
            let i++
        done
        echo 
        let i=1
        let j++
    done 
    

    循环控制语句(用于循环体中)

    continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
        while CONDTITION1;do
            CMD1
            ...
            if CONDITION;then
                continue
            fi
            CMDn
            ...
        done
    
    
    
    
    break [N]:提前结束循环
    break [N] :提前结束第N 层循环,
        while CONDTITION1;do
            CMD1
            ...
            if CONDITION;then
                break
            fi
            CMDn
            ...
        done
    

    示例

    求100以内所有偶数之和,要求循环遍历100以内的所有正整数

    #!/bin/bash
    # filename even.sh
    # author:danran 
    # time is 2017-06-22
    
    declare -i i=0
    declare -i sum=0
    until [ $i -gt 100 ];do
        let i++
        if [ $[i%2] -eq 1 ];then
            continue
        fi
        let sum+=$i
    done
    echo "Even sum:$sum"
    

    创建死循环

    while true;do
        循环体
    done
    
    until false;do
        循环体
    done
    

    示例

    每隔3秒钟到系统上获取已经登录的用户的信息:如果docker登录了,则记录于日志中,并退出

    read -p "Enter a user name: " username
    
    while true;do
        if who | grep "^$username" &> /dev/null;then
            break
        fi
        sleep 3
    done
    echo "$username logged on" >> /tmp/user.log
    
    法二
    #!/bin/bash
    #
    read -p "Enter a user name: " username
    
    until who | grep "^$username" &> /dev/null;do
        sleep 3
    done
    echo "$username logged on" >> /tmp/user.log
    

    练习

    写一个脚本:完成如下任务:

    (1)显示一个菜单   
        cpu)show cpu information:
        mem)show memory information
        disk)show disk information quit)quit
    (2)提示用户选择选项     
    (3)显示用户选择的内容    
    进一步的:
        用户选择,并显示完成后不退出脚本;而是提示用户继续选择显示其内容:直到使用quit方始退出;
    
    法一    
    #!/bin/bash
    # filename sysinfo.sh
    # author:danran 
    # time is 2017-06-22
    cat << EOF
    cpu) show cpu information
    mem) show memory information
    disk)show disk information 
    quit)quit
    ============================
    EOF
    
    read -p "Enter a option: " option
    while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
        read -p "Wrong option.Enter again: " option
    done
    
    if [ "$option" == 'cpu' ];then
        lscpu
    elif [ "$option" == 'mem' ];then
        cat /proc/meminfo
    elif [ "$option" == 'disk' ];then
        fdisk -l
    else 
        echo "Quit"
        exit 0
    fi
    

    条件判断:case语句

    case 变量引用 in
    PAT1)
        分支1
        ;;
    PAT2)
        分支2
        ;;
    ...
    *)
        默认分支
        ;;
    easc
    
    • case 支持glob 风格的通配符:
    *:任意长度任意字符
    ?:任意单个字符
    []:指定范围内的任意单个字符
    a|b:a或b  
    

    法二

    #!/bin/bash
    # filename sysinfo.sh
    # author:danran 
    # time is 2017-06-22
    cat << EOF
    cpu) show cpu information
    mem) show memory information
    disk)show disk information 
    quit)quit
    ============================
    EOF
    
    read -p "Enter a option: " option
    while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
        read -p "Wrong option.Enter again: " option
    done
    
    case "$option" in
    cpu)
        lscpu
        ;;
    mem)
        cat /proc/meminfo
        ;;
    disk)
        fdisk -l
        ;;
    *)
        echo "Quit.."
        exit 0
        ;;
    esac
    

    练习:写一个脚本,完成如下要求

    (1)脚本可接受参数,start,stop,restart,status
    (2)如果参数非此四者之一,提示使用格式后报错退出
    (3)如果是start,则创建/var/lock/subsys/SCRIOT_NAME,并显示“启动成功”
        考虑:如果事先已经启动过一次,该如何处理
    (4)如果是stop:则删除/vat/lock/subsys/SCRIPT_NAME,并显示“停止完成”
        考虑:如果事先已经停止过了;g该如何处理
    (5)如果是restart,则先stop,再start;
        考虑:如果本来没有start,再如何处理   
    (6)如果是status,则
        如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is running...”;
        如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...”;
    其中:SCRIPT_NAME为当前脚本名  
    

    循环控制shift命令

    shift [n]

    用于将参量列表list 左移指定次数,缺省为左移一次。

    • 参量列表list一旦被移动,最左端的那个参数就从列表中删除。while到循环遍历位置参量列表时,常用到shift
    • ./doit.sh a b c d e f g h
    • ./shfit.sh a b c d e f g h

    示例:

    doit.sh
        #!/bin/bash
        # Name:doit.sh
        # Purpose:shift through command line arguments
        # Usage:doit.sh [args]
        while [ $# -gt 0 ] # or (( $# > 0 ))
        do
            echo $*
            shift
        done
    
    shift.sh
        #!/bin/bash
        #step through all the positional parameters
        until [ -z "$1" ]
        do
            echo "$1"
            shift
        done
        echo
    

    特殊用法

    • while 循环的特殊用法(遍历文件的每一行):
    while read line; do
        循环体
    done < /PATH/FROM/SOMEFILE
    
    • 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
    • 练习
      扫描/etc/passwd文件每一行,如发现GECOS 字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功。
    • 示例:
    #!/bin/bash
    while read passwdline
    do
        uid=`echo $passwdline | cut -d: -f3`
        user=`echo $passwdline | cut -d: -f1`
        [ "uid" -ge 1000 ] && echo "$user is common user" || echo "$user is system user"
    done < /etc/passwd
    unset passwdline uid user
    
    • 双小括号方法,即((…))格式,也可以用于算术运算
    • 双小括号方法也可以使bash Shell 实现C 语言风格的变量操作
    I=10
    ((I++))
    
    • for循环的特殊格式:
    for (( 控制变量初始化; 条件判断表达式; 控制变量的修正表达式))
    do
        循环体
    done
    
    • 控制变量初始化:仅在运行到循环代码段时执行一次
    • 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
    • 示例:求100以内的所有正奇数之和
    #!/bin/bash
    sum=0
    for i in {1..100..2};do
        let sum+=i
    done
    echo sum=$sum
    
    #!/bin/bash
    for ((sum=0,i=1;i<=100;i+=2 ));do
        let sum+=i
    done
    echo sum=$sum
    
    #!/bin/bash
    sum=0;
    i=1;
    while [ $i -le 100 ];do
        let sum+=1
        let i+=2
    done
    echo sum=$sum
    

    2 . 求100以内的正整数之和

    #!/bin/bash
    declare -i sum=0
    for ((i=1;i<=100;i++));do
        let sum+=$i
    done
    echo "Sum:$sum"
    

    3 . 打印九九乘法表:

    #!/bin/bash
    # filename multi.sh
    # author:danran 
    # time is 2017-06-22
    for ((j=1;j<=9;j++));do
        for((i=1;i<j;i++));do
            echo -e -n "$[i]X$[j]=$[$i*$j]\t"
        done
        echo
    done
    

    select循环与菜单

    select variable in list
    do
        循环体命令
    done
    
    • select循环主要用于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入
    • 用户输入菜单列表中的某个数字,执行相应的命令
    • 用户输入被保存在内置变量REPLY中

    select与case

    • select用是个无限循环,因此要记住用 break命令退用出循环,或用exit按命令终止脚本。也可以按ctrl+c退出循环
    • select和经常和case联合使用
    • 与for循环类似,可以省略inlist,此时使用位置参量
    • 示例:创建菜单
    #!/bin/bash
    PS3="Please choose your menu: "
    select menu in work home office exit 
    do
        case $menu in 
        work)
            echo "go work"
            ;;
        home)
            echo "go home"
            ;;
        office)
            echo "go office"
            ;;
        *)
            echo unknow
            break
        esac
        echo your choose is $menu
        echo "Your input is $REPLY"
    done
    

    信号捕捉trap

    • trap ' 触发指令' 信号
      自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
    • trap '' 信号
      忽略信号的操作
    • trap '-' 信号
      恢复原信号的操作
    • trap -p
      列出自定义信号操作

    trap示例

    #!/bin/bash
    trap 'echo “signal:SIGINT"' int
    trap -p  \\打印trap自定义命令
    for((i=0;i<=10;i++))
    do
        sleep 1
        echo $i
    done
    
    trap '' int  //int信号设置为空
    trap -p   \\打印trap自定义命令
    for((i=11;i<=20;i++))
    do
        sleep 1
        echo $i
    done
    
    trap '-' int  //恢复int信号的操作
    trap -p   \\打印trap自定义命令
    for((i=21;i<=30;i++))
    do
        sleep i
        echo $i
    done

    相关文章

      网友评论

          本文标题:bash高级进程

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