• 【shell】shell编程(四)-循环语句


      上篇我们学习了shell中条件选择语句的用法。接下来本篇就来学习循环语句。在shell中,循环是通过for, while, until命令来实现的。下面就分别来看看吧。

    for

    for循环有两种形式:

    for-in语句

    基本格式如下:

    for var in list 
    do
        commands
    done

    list代表要循环的值,在每次循环的时候,会把当前的值赋值给var(变量名而已,随意定), 这样在循环体中就可以直接通过$var获取当前值了。

    先来一个例子吧:

    #!/bin/bash
    for str in a b c d e
    do
        echo $str
    done    

    以上会根据空格将abcde分割,然后依次输出出来。

    如果以上例子不是以空格分割,而是以逗号(,)分割呢?

    #!/bin/bash
    list="a,b,c,d,e"
    for str in $list
    do 
        echo $str
    done

    结果输出a,b,c,d,e

      造成这个结果的原因是:for...in循环默认是循环一组通过空格或制表符(tab键)或换行符(Enter键)分割的值。这个其实是由内部字段分隔符配置的,它是由系统环境变量IFS定义的。当然,既然是由环境变量定义的,那当然也就能修改啊。

    另一个根据用户名杀死进程(强制退出用户)的例子:

      首先输入用户命,如果用户未root提示不能杀死root,否则杀死相关进程

    #!/bin/bash
    #input username and kill relactive process for kill user
    echo "please input username for kill"
    read username
    #if username is root ,exit
    if [ ${username} = 'root' ]
            then
            echo "root can not kill"
            exit 1
    fi
    #get user PID
    PID=`/usr/bin/ps -aux | /usr/bin/grep qlq | /usr/bin/awk '$1="qlq" {print $2}'`
    for killpid in $PID
    do
            kill -9 $killpid
    done
    echo "killed ok!"

    另外 一个利用for in 实现ls的功能:

    #!/bin/bash
    #for xx in xxx usage
    for pd in $(/usr/bin/ls /root/sshDemo/)
    do
            echo $pd
    done

      上面$(/usr/bin/ls /root/sshDemo/)本身返回的就是一行一行的数据,所以可以用做集合

     结果:

    [root@VM_0_12_centos sshDemo]# ./testFor.sh
    addUserBatch.sh
    delUserBatch.sh
    killUser.sh
    testApache.sh
    testFile.sh
    testFor.sh
    testKuohao.sh
    testNum.sh
    testSelect.sh
    testShift.sh

    修改IFS值

    #!/bin/bash
    #定义一个变量oldIFS保存未修改前的IFS的值
    oldIFS=$IFS
    #修改IFS值,以逗号为分隔符
    IFS=$','
    list=a,b,c,d,e
    list2="a b c d e"
    for var in $list
    do
        echo $var
    done
    for var2 in $list2
    do
        echo $var2
    done
    #还原IFS的值
    IFS=$oldIFS

    以上第一个循环会分别输出abcde几个值。而第二个循环会输出a b c d e(即未处理)。因为我们把IFS的值设置为逗号了, 当然,不一定要是逗号,想设置什么,你说了算!

     

    C语言风格的for循环

    bash中c语言风格的for循环遵循如下格式:

    for (( variable assignment ; condition ; iteration process ))

    一个例子足以说明:

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

    上面例子循环11次,从0到10依次输出。稍微有过编程基础的都对此应该很熟悉。就不做详细阐述了。

    例如:此种风格的for循环批量添加用户的脚本:

    #!/bin/bash
    #adduser batch
    echo "please input username:"
    read username
    echo "please input number to create:"
    read number
    #start to create user
    for(( i=1;i<="${number}";i++ ))
    do
            /usr/sbin/adduser "${username}${i}" > /dev/null 2> /dev/null
    done
    #add finished
    echo "add OK!"
    echo "please input passwd for users"
    read password
    for(( i=1;i<="${number}";i++ ))
    do
            /usr/sbin/usermod -p "${password}" "${username}${i}"  > /dev/null 2> /de
    v/null
    done

    结果:

    [root@VM_0_12_centos sshDemo]# ./addUserBatch.sh
    please input username:
    ppp
    please input number to create:
    20
    add OK!
    please input passwd for users
    123456
    [root@VM_0_12_centos sshDemo]# tail -5 /etc/passwd
    ppp16:x:1017:1017::/home/ppp16:/bin/bash
    ppp17:x:1018:1018::/home/ppp17:/bin/bash
    ppp18:x:1019:1019::/home/ppp18:/bin/bash
    ppp19:x:1020:1020::/home/ppp19:/bin/bash
    ppp20:x:1021:1021::/home/ppp20:/bin/bash
    [root@VM_0_12_centos sshDemo]# tail -5 /etc/shadow
    ppp16:123456:17622:0:99999:7:::
    ppp17:123456:17622:0:99999:7:::
    ppp18:123456:17622:0:99999:7:::
    ppp19:123456:17622:0:99999:7:::
    ppp20:123456:17622:0:99999:7:::

    例如:批量删除用户的脚本:

      解释:去passwd查找第一列过滤输入的关键词,然后在第一列中查找关键词,如果查到就输出给users,最后循环删除:$?用于判断上一次命令的返回状态码,如果返回0代表正常结束,否则就是失败!

    #!/bin/bash
    #delete user batch
    echo "please input username word to delete"
    read word
    #get All users like word*
    users=`/usr/bin/grep ${word} /etc/passwd | awk -F: -v word1=${word} 'index($1,wo
    rd1)>0 {print $1}'`
    if [ "${users}" = '' ]
     then
            echo "user is does not exist!"
            exit 1
    fi
    for username in ${users}
    do
            /usr/sbin/userdel -rf ${username} > /dev/null 2>/dev/null
    done
    if [ "0" = "$?" ]
            then
            echo "delete ok!"
    else
            echo "delete failed!"
    fi

    while循环

      如果你习惯了其它语言的while循环,那么到这儿你又会发现这个while循环有点变态了。与其它编程语言while的不同在于:在bash中的while语句,看起来似乎是结合了if-then语句(参考上一篇)和for循环语句。其基本格式如下:

    while test command 
    do
        other commands
    done
     

    与if-then语句一样,后面接test命令,如果test后面的命令的退出状态码为0. 那么就进入循环,执行do后面的逻辑。要注意在do后面的逻辑中写条件,避免死循环。

    既然是接test命令,那么一切都可以参考if-then的test

    示例一:

    #!/bin/bash
    flag=0
    while test $flag -le 10
    do
        echo $flag
        # 如果没有这句,那么flag的值一直为0,就会无限循环执行
        flag=$[$flag + 1]
    done

    以上判断flag是否大于或者等于10, 如果满足条件,那么输出当前flag的值,然后再将flag的值加1。最终输出的结果为0到10的结果。

    结合上一篇文章test的写法,我们还可以将以上示例变形为如下:

    示例二:

    #!/bin/bash
    flag=0
    while [ $flag -le 10 ]
    do
        echo $flag
        flag=$[$flag + 1]
    done
     

    示例三:

    flag=0
    while (( $flag <= 10 ))
    do
        echo $flag
        flag=$[$flag + 1]
    done
     
    • shift指令:  参数左移,每执行一次,参数序列顺次左移一个位置,$#的值减一。用于分别处理每个参数,移出去的参数不再可用。
      例如:shift+while循环实现求和:
    #!/bin/bash
    #shift useage
    if [ $# -eq 0 ]
            then
            echo "please input the parameters"
            exit 1
    fi
    sum=0
    while [ $# -gt 0 ]
            do
                    sum=$(($sum+$1))
                    shift
            done
    echo "$sum"

    结果:

    [root@VM_0_12_centos sshDemo]# sh -x testShift.sh  1 2 3 5
    + '[' 4 -eq 0 ']'
    + sum=0
    + '[' 4 -gt 0 ']'
    + sum=1
    + shift
    + '[' 3 -gt 0 ']'
    + sum=3
    + shift
    + '[' 2 -gt 0 ']'
    + sum=6
    + shift
    + '[' 1 -gt 0 ']'
    + sum=11
    + shift
    + '[' 0 -gt 0 ']'
    + echo 11
    11

    计算过程:

    1 2 3 5       0
    2 3 5         1
    3 5           3
    5             6
                  11

    总结:对于比较大小的左右都要有空格,例如:[ $# -eq 0 ]

      对于计算值的左右都不能有空格,例如:sum=$(($sum+$1))






    until循环语句

    until语句基本格式如下:

    until test commands
    do
        other commands
    done
     

    在掌握while循环语句之后, until语句就很简单了。until语句就是与while语句恰好相反, while语句是在test命令退出状态码为0的时候执行循环, 而until语句是在test命令退出状态码不为0的时候执行。

    示例:

    #!/bin/bash
    flag=0
    until (( $flag > 10 ))
    do
        echo $flag
        flag=$[ $flag + 1 ]
    done

    以上输出0到10的值。until后面的条件与上面while例子完全相反。

      好啦,到此,我们学完了shell的循环语句啦。不过上面我们写的循环语句都是根据条件执行完毕,如果我们在执行的过程中想退出,该怎么办?接下来就继续看看怎么控制循环语句。

    控制循环

    与其它编程语言一样,shell是通过break和continue命令来控制循环的。下面就分别来看看二者的基本用法:

    break

    1. break用于跳出当前循环

    示例一:

    #!/bin/bash
    for (( flag=0; flag <= 10; flag++ ))
    do
        if (( $flag == 5 ))
        then
            break
        fi
        echo $flag
    done
     

    以上当flag的值为5的时候,退出循环。输出结果为0-4的值。

    1. break用于跳出内层循环

    示例二:

    #!/bin/bash
    flag=0
    while (( $flag < 10 ))
    do
        for (( innerFlag=0; innerFlag < 5; innerFlag++ ))
        do
            if (( $innerFlag == 2 ))
            then
                break
            fi
            echo "innerFlag=$innerFlag"
        done
        echo "outerFlag=$flag"
    done
     

    以上代码在执行内部循环for的时候,当innerFlag值为2的时候就会跳出到外层的while循环, 由于外层循环一直flag都为0, 所以while会成为一个死循环,不停的输出:

    ...

    innerFlag=0

    innerFlag=1

    outerFlag=0

    ...

    1. break用于跳出外层循环

    break 可后接数字,用于表示退出当前循环的外层的第几层循环。

    示例三:

    #!/bin/bash
    flag=0
    while (( $flag < 10 ))
    do
        for (( innerFlag=0; innerFlag < 5; innerFlag++ ))
        do
            if (( $innerFlag == 2 ))
            then
                  # 2表示外面一层循环
                break 2
            fi
            echo "innerFlag=$innerFlag"
        done
        echo "outerFlag=$flag"
    done
     

    与上面例子相比,本例就只是在break后面跟了个数字2,表示退出外面的第一层循环。最终输出:

    innerFlag=0

    innerFlag=1

    continue

    continue表示终止当前的一次循环,进入下一次循环,注意,continue后面的语句不会执行。

    continue的语法与break一样,因此,就只做一个示例演示啦。

    示例:

    flag=0
    while (( $flag <= 10 ))
    do
        if (( $flag == 5 ))
        then
            flag=$[$flag+1]
            continue
        fi
        echo "outerFlag=$flag"
        for (( innerFlag=11; innerFlag < 20; innerFlag++ ))
        do
            if (( $innerFlag == 16 ))
            then
                flag=$[$flag+1]
                continue 2
            fi
            echo "innerFlag=$innerFlag"
        done
    done

      以上例子: 当for循环中innerFlag的值为16的时候会跳到外层while循环,当外层循环的flag的值为5的时候,会直接跳过本次循环,然后进入下一次循环,因此在输出的结果中,不会出现outerFlag=5的情况。

    接下来可以学习shell学习五:http://www.cnblogs.com/qlqwjy/p/7746009.html

  • 相关阅读:
    TestNG并发测试包
    @Valid的坑
    spring boot 下 spring security 自定义登录配置与form-login属性详解
    在eclipse上搭建springBoot
    分页问题
    谷歌chrome://chrome-urls/
    chrome中清除dns缓存
    pg中的非varchar类型的模糊搜索
    spring中用xml配置构造注入的心得
    Flask-Limiter使用详细说明
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/7746001.html
Copyright © 2020-2023  润新知