• (六)shell编程之循环控制语句


    循环

    将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
    重复运行次数

    循环次数事先已知

    循环次数事先未知

    常见的循环的命令:for, while, until

    循环 for

    格式1:

    for NAME [in WORDS ... ] ; do COMMANDS; done
    
    #方式1
    for 变量名 in 列表;do
       循环体
    done
    
    #方式2
    for 变量名 in 列表
    do
       循环体
    done
    

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

    如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@"
    for 循环列表生成方式:
    直接给出列表
    整数列表:

    {start..end}
    $(seq [start [step]] end)
    

    返回列表的命令:

    $(COMMAND)
    

    使用glob,如:*.sh

    变量引用,如:$@,$*,$#

    范例:面试题,计算1+2+3+...+100 的结果

    [root@centos8 ~]# sum=0;for i in {1..100};do let sum+=i;done ;echo sum=$sum
    sum=5050
    [root@centos8 ~]# seq -s+ 100|bc5050
    5050
    [root@centos8 ~]# echo {1..100}|tr ' ' +|bc
    5050
    [root@centos8 ~]# seq 100|paste -sd +|bc
    5050
    

    范例: 100以内的奇数之和

    [root@centos8 ~]# sum=0;for i in {1..100..2};do let sum+=i;done;echo sum=$sum
    sum=2500
    [root@centos8 ~]# seq -s+ 1 2 100| bc
    2500
    [root@centos8 ~]# echo {1..100..2}|tr ' ' + | bc
    2500
    

    范例: 批量创建用户

    #!/bin/bash
    # 
    #********************************************************************
    #Author:        xuanlv
    #QQ:            360956175
    #Date:          2021-06-10
    #FileName:     create_user.sh
    #URL:           https://www.cnblogs.com/xuanlv-0413/
    #Description:      The test script
    #Copyright (C):     2021 All rights reserved
    #********************************************************************
    [ $# -eq 0 ] && { echo "Usage: createuser.sh USERNAME ..."; exit 1; }
    for user ;do
       id $user &> /dev/null && echo $user is exist || { useradd $user ; echo $user is created; }
    done
    

    范例: 批量创建用户和并设置随机密码

    #!/bin/bash
    # 
    #********************************************************************
    #Author:        xuanlv
    #QQ:            360956175
    #Date:          2021-06-10
    #FileName:     user_for.sh
    #URL:           https://www.cnblogs.com/xuanlv-0413/
    #Description:      The test script
    #Copyright (C):     2021 All rights reserved
    #********************************************************************
    for i in {1..10};do
      useradd user$i
      PASS=`cat /dev/urandom | tr -dc '[:alnum:]' | head -c12`
      echo $PASS | passwd --stdin user$i &> /dev/null
      echo user$i:$PASS >> /data/user.pass
      echo "user$i is created"
    done
    

    范例:面试题,要求将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下

    #1.创建YYYY-MM-DD格式的目录,当前日期一年前365天到目前共365个目录,里面有10个文件.log后缀的
    文件
    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    PDIR=/data/tests
    for i in {1..365};do
      DIR=`date -d "-$i day" +%F`
      mkdir -p $PDIR/$DIR
      cd $PDIR/$DIR
      for j in {1..10};do
         touch $RANDOM.log
      done
    done
    
    #2.将上面的目录移动到YYYY-MM/DD/下
    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    DIR=/data/tests
    cd $DIR || { echo 无法进入 $DIR;exit 1; }
    for subdir in * ;do
      YYYY_MM=`echo $subdir | cut -d"-" -f1,2`
      DD=`echo $subdir | cut -d"-" -f3`
      [ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD &> /dev/null
      mv $subdir/* $YYYY_MM/$DD
    done
    rm -rf $DIR/*-*-*
    
    #执行
    [root@localhost ~]# bash for_dir.sh
    [root@localhost ~]# ll /data/tests/
    [root@localhost ~]# bash sum_dir.sh
    [root@localhost ~]# tree /data/tests/
    

    格式2

    双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格
    的变量操作
    I=10;((I++))

    for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    
    for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
    do
      循环体
    done
    

    说明:
    控制变量初始化:仅在运行到循环代码段时执行一次
    控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

    循环 while

    格式:

    while COMMANDS; do COMMANDS; done
    
    while CONDITION; do
      循环体
    done
    

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

    进入条件:CONDITION为 true

    退出条件:CONDITION为 false

    无限循环

    while true; do
      循环体
    done
    
    while : ; do
      循环体
    done
    

    范例:

    [root@centos8 ~]# sum=0;i=1;while ((i<=100));do let sum+=i;let i++;done;echo $sum
    5050
    

    范例:监控磁盘使用率

    [root@centos8 ~]# cat while_diskcheck.sh
    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    WARNING=80
    while :;do
      USE=`df | sed -rn '/^/dev/sd/s#.* ([0-9]+)%.*#1#p' | sort -nr | head -n1`
      if [ $USE -gt $WARNING ];then
         echo Disk will be full from `hostname -I` | mail -s "disk warning" xxx@qq.com
      fi
      sleep 10
    done
    

    范例: 防止Dos攻击的脚本

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    WARNING=10
    touch deny_hosts.txt
    while true;do
       ss -nt | sed -nr '1!s#.* ([0-9.]+):[0-9]+ *#1#p' | sort | uniq -c | sort |
    while read count ip;do
          if [ $count -gt $WARNING ];then
            echo $ip is deny
            grep -q "$ip" deny_hosts.txt || { echo $ip >> deny_hosts.txt; iptables -A INPUT -s $ip -j REJECT; }
          fi
       done
       sleep 10
    done
    

    循环 until

    格式:

    until COMMANDS; do COMMANDS; done
    
    until CONDITION; do
      循环体
    done
    

    说明:
    进入条件: CONDITION 为false
    退出条件: CONDITION 为true

    范例:

    [root@centos8 ~]# sum=0;i=1;until ((i>100));do let sum+=i;let i++;done;echo $sum
    5050
    

    无限循环

    until false; do
       循环体
    Done
    

    循环控制语句 continue

    continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

    格式:

    while CONDITION1; do
      CMD1
      ...
      if CONDITION2; then
         continue
      fi
      CMDn
      ...
    done
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    for ((i=0;i<10;i++));do
       for((j=0;j<10;j++));do
          [ $j -eq 5 ] && continue 2
          echo $j
       done
       echo ---------------------------
    done
    
    输出结果:
    0
    1
    2
    3
    4
    0
    1
    2
    3
    4
    0
    1
    2
    3
    4
    

    循环控制语句 break

    break [N]:提前结束第N层整个循环,最内层为第1层

    格式:

    while CONDITION1; do
      CMD1
      ...
      if CONDITION2; then
         break
      fi
      CMDn
      ...
    done
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    for ((i=0;i<10;i++));do
       for((j=0;j<10;j++));do
           [ $j -eq 5 ] && break 2
           echo $j
       done
       echo ---------------------------
    done
    
    # 执行
    [root@centos8 script]# bash break_for.sh
    0
    1
    2
    3
    4
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    NUM=$[RANDOM%10]
    while read -p "输入 0-9 之间的数字: " INPUT ;do
      if [ $INPUT -eq $NUM ];then
         echo "恭喜你猜对了!"
         break
      elif [ $INPUT -gt $NUM ];then
         echo "数字太大了,重新猜!"
      else
         echo "数字太小了,重新猜!"
      fi
    done
    

    循环控制 shift 命令

    shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
    参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    while [ $You can't use 'macro parameter character #' in math mode# -gt 0 ] 
    do
      echo $*
      shift
    done
    
    ./doit.sh a b c d e f g h
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    until [ -z "$1" ]
    do
      echo "$1"
      shift
    done
    echo
    
    ./shfit.sh a b c d e f g h
    

    while 特殊用法 while read

    while 循环的特殊用法,遍历文件或文本的每一行

    格式:

    while read line; do
       循环体
    done < /PATH/FROM/SOMEFILE
    

    说明:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

    范例:

    [root@centos8 ~]# echo long | read X ; echo $X
    [root@centos8 ~]# echo long | while read X ; do echo $X;done
    long
    [root@centos8 ~]# echo long | { read X ; echo $X; }
    long
    [root@centos8 ~]# echo long | ( read X ; echo $X )
    long
    [root@centos8 ~]# echo long wang zhang | ( read X Y Z; echo $X $Y $Z )
    long wang zhang
    [root@centos8 ~]# echo long wang zhang | while read X Y Z; do echo $X $Y $Z;done
    long wang zhang
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    WARNING=80
    MAIL=root@xxx.com
    df |sed -nr "/^/dev/sd/s#^([^ ]+) .* ([0-9]+)%.*#1 2#p"| while read DEVICE
    USE;do
      if [ $USE -gt $WARNING ] ;then
         echo "$DEVICE will be full,use:$USE" | mail -s "DISK WARNING" $MAIL
      fi
    done
    

    范例:

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    MAX=3
    lastb | sed -rn '/ssh:/s@.* ([0-9.]{1,3}{3}[0-9]{1,3}) .*@1@p'| sort | uniq -c
    | while read count ip ;do
      if [ $count -gt $MAX ];then
         iptables -A INPUT -s $ip -j REJECT
      fi
    done
    

    范例:查看/sbin/nologin的shell类型的用户名和UID

    #!/bin/bash
    # Date: 2021-06-10
    # Author: lvxuan
    while read line ;do
      if [[ "$line" =~ /sbin/nologin$ ]] ;then
         echo $line | cut -d: -f1,3
      fi
    done < /etc/passwd
    

    循环与菜单 select

    格式:

    select NAME [in WORDS ... ;] do COMMANDS; done
    
    select variable in list ;do
      循环体命令
    done
    

    说明:

    select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准错误上,并显示 PS3 提示
    符,等待用户输入
    用户输入菜单列表中的某个数字,执行相应的命令
    用户输入被保存在内置变量 REPLY 中
    select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c
    退出循环
    select 经常和 case 联合使用
    与 for 循环类似,可以省略 in list,此时使用位置参量
    
  • 相关阅读:
    Jquery Ajax 调用 WebService
    Dapper.NET
    HTML5 canvas标签
    SQL内外左右交叉连接
    水晶报表纵向重复
    AngularJS 菜鸟
    什么是MVC框架?
    伪类和伪元素的区别
    常用的本地存储-----cookie篇
    JavaScript中基本数据类型和引用数据类型的区别
  • 原文地址:https://www.cnblogs.com/xuanlv-0413/p/14881436.html
Copyright © 2020-2023  润新知