shell之循环

1、for循环

  • 语法结构如下:

    1
    2
    3
    4
    5
    # shell风格
    for 变量名 [ in 取值列表 ]
    do
    循环体
    done
    1
    2
    3
    4
    5
    # C语言风格
    for ((初值;条件;步长))
    do
    循环体
    done
    • eg1:for实现批量主机ping探测。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      [root@centos7 shell]# cat pingtest.sh
      #!/usr/bin/bash

      >ip.txt
      # i=2,3,.....
      for i in {2..254}
      do
      {
      ip=192.168.122.$i
      # -W1表示1秒超时,-C1表示ping 1次
      ping -c1 -W1 $ip &>/dev/null
      if [ $? -eq 0 ];then
      # tee既显示在屏幕上,又写到文件里面去
      echo "$ip" |tee -a ip.txt
      fi
      }& # 如果这里不加&,那么该执行脚本的进程会被阻塞在这里,ctrl C都没用
      done
      # 等待之前所有的后台进程执行结束
      wait
      echo "finish"
      [root@centos7 shell]# time sh pingtest.sh # 执行脚本后,可以查看脚本的运行时间
      finish

      real 0m1.905s
      user 0m0.018s
      sys 0m0.974s
    • eg2:ping一个文件中的所有主机。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      [root@centos7 shell]# cat ip.txt
      10.45.1.10
      10.22.11.1
      [root@centos7 shell]# cat pingtest2.sh
      #!/usr/bin/bash
      for ip in `cat ip.txt`
      do
      ping -c1 -W1 $ip &>/dev/null
      if [ $? -eq 0 ];then
      echo "$ip is up"
      else
      echo "$ip is down"
      fi
      done
      wait
      echo "finish"
      [root@centos7 shell]# bash pingtest2.sh
      10.45.1.10 is down
      10.22.11.1 is down
      finish
    • eg3:批量创建账号。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      #!/usr/bin/bash
      while :
      do
      read -p "Please enter prefix & password & num[zhu 123456 5]" prefix pass num
      echo "user information:
      ===========
      user prefix:$prefix
      user pass:$pass
      user num:$num
      ===========
      "
      read -p "Are you sure?[y/n]" action
      if [ "$action" = "y" ];then
      break
      fi
      done

      echo "creat user"

      # seq -w 10等位补齐,01,02......。
      # for i in {1..$num}是错误的
      for i in `seq -w $num`
      do
      user=$prefix$i
      id $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "$user exists"
      else
      useradd $user
      echo "$pass" |passwd --stdin $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "$user is created"
      fi
      fi
      done
    • eg4:从文件中读取账号密码创建账号。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      [root@centos7 shell]# cat user.txt
      zhu 123

      zhu2 456
      [root@centos7 shell]# cat createuser.sh
      #!/usr/bin/bash
      if [ $# -eq 0 ];then
      echo "usage: `basename $0` file"
      exit 1
      fi

      if [ ! -f $1 ];then
      echo "error file"
      exit 2
      fi
      # 希望for循环处理文件按回车分割而不是空格或tab
      # 如果不重新定义分隔符为换行符,那么相当于for line in zhu 123 zhu2 456,即循环4次
      # 如果重新定义了分隔符为换行符,那么相当于for line in "zhu 123" "zhu2 456",即循环2次
      # IFS是for循环内部字段分隔符
      # IFS=$'\n'
      IFS='
      '
      for line in `cat $1`
      do
      if [ ${#line} -eq 0 ];then
      echo "nothing to do"
      continue
      fi
      user=`echo "$line" |awk '{print $1}'`
      pass=`echo "$line" |awk '{print $2}'`
      id $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "user $user already exists"
      else
      useradd $user
      echo "$pass" |passwd --stdin $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "$user is created"
      fi
      fi
      done
      [root@centos7 shell]# bash createuser.sh user.txt
      user zhu already exists
      user zhu2 already exists
    • eg5:for实现批量远程主机ssh配置。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      #!/usr/bin/bash
      # ip.txt内容如下:
      # 10.10.10.10
      # 10.10.10.11
      for i in `cat ip.txt`
      do
      {
      ping -c1 -W1 $ip &>/dev/null
      if [ $? -eq 0 ];then
      # 搜索以#UserDNS开头的行,换成UserDNS no,或者写成sed -ri '/^#UserDNS/c\UserDNS no'
      ssh $ip "sed -ri '/^#UserDNS/cUserDNS no' /etc/ssh/sshd_config"
      ssh $ip "sed -ri '/^#GSSAPIAutentication/cGSSAPIAutentication no' /etc/ssh/sshd_config"
      ssh $ip "systemctl stop firewalld;systemctl disable firewalld"
      ssh $ip "sed -ri '/^SELINUX/cSELINUX=disable' /etc/selinux/config"
      ssh $ip "setenforce 0"
      fi
      }&


      done
      wait
      echo "finish"
    • eg6:计算1+2+……100。

      1
      2
      3
      4
      5
      6
      #!/usr/bin/bash
      for i in {1..100}
      do
      let sum=$sum+$i
      done
      echo "sum:$sum"

2、while和until循环

  • while循环语法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 当条件测试成立(条件测试为真,就是返回值为0),执行循环体
    while 条件测试
    do
    循环体
    done

    # 死循环
    while true
    do
    循环体
    done

    while :
    do
    循环体
    done

    while [ 1 = 1 ]
    do
    循环体
    done
  • until循环语法:

    1
    2
    3
    4
    5
    # 当条件测试成立(条件测试为假),执行循环体
    until 条件测试
    do
    循环体
    done
    • eg1:while实现批量用户创建。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #!/usr/bin/bash
      # user.txt的内容如下
      # zhu
      # zhu2
      # zhu3
      # 输入重定向
      while read user
      do
      id $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "user $user already exits"
      else
      useradd $user
      if [ $? -eq 0 ];then
      echo "$user is created."
      fi
      fi
      done < user.txt
    • eg2:while实现批量用户创建,指定账号密码。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      #!/usr/bin/bash
      # 逐行处理文件的内容,最好优先考虑while,把一行看成变量值,所以要判断空行
      # user.txt的内容如下
      zhu 123
      zhu2 456
      # 输入重定向
      while read line
      do
      # 判断是否为空行
      if [ ${#line} -eq 0 ];then
      echo "这是空行!!!"
      continue
      fi
      user=`echo $line |awk '{print $1}'`
      pass=`echo $line |awk '{print $2}'`
      id $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "user $user already exits"
      else
      useradd $user
      echo "$pass"|passwd --stdin $user &>/dev/null
      if [ $? -eq 0 ];then
      echo "$user is created."
      fi
      fi
      done < user.txt
      echo "all ok"
    • eg3:while实现ping主机探测。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #!/usr/bin/bash
      i=2
      while [ $i -le 254 ]
      do
      {
      ip=192.168.122.$i
      ping -c1 -W1 $ip &>/dev/null # -W1表示1秒超时
      if [ $? -eq 0 ];then
      echo "$ip is up"
      else
      echo "$ip is down"
      fi
      }&

      let i++
      done
      wait # 等待所有的后台进程执行结束,如果不加这里,有些ping执行不成功,就会执行echo "finish"
      echo "finish"
    • eg4:while测试远程主机连接。

      1
      2
      3
      4
      5
      6
      7
      #!/usr/bin/bash
      ip=10.10.10.10
      while ping -c1 -W1 $ip &>/dev/null
      do
      sleep 1
      done
      echo "$ip is down"
    • eg5:while计算1+2+……100。

      1
      2
      3
      4
      5
      6
      7
      8
      #!/usr/bin/bash
      i=1
      while [ $i -le 100 ]
      do
      let sum=$sum+$i
      let i++
      done
      echo "sum:$sum"
    • eg6:until测试远程主机连接。

      1
      2
      3
      4
      5
      6
      7
      #!/usr/bin/bash
      ip=10.10.10.10
      until ping -c1 -W1 $ip &>/dev/null
      do
      sleep 1
      done
      echo "$ip is up"
    • eg7:until实现ping主机探测。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #!/usr/bin/bash
      i=2
      until [ $i -gt 254 ]
      do
      {
      ip=192.168.122.$i
      ping -c1 -W1 $ip &>/dev/null # -W1表示1秒超时
      if [ $? -eq 0 ];then
      echo "$ip is up"
      else
      echo "$ip is down"
      fi
      }&

      let i++
      done
      wait # 等待所有的后台进程执行结束,如果不加这里,有些ping执行不成功,就会执行echo "finish"
      echo "finish"
    • eg8:until计算1+2+……100。

      1
      2
      3
      4
      5
      6
      7
      8
      #!/usr/bin/bash
      i=1
      until [ $i -gt 100 ]
      do
      let sum=$sum+$i
      let i++
      done
      echo "sum:$sum"