shell使用循环

 1. for循环

  脚本在执行任务的时候,总会遇到需要循环执行的时候,比如说我们需要脚本每隔五分钟执行一次ping的操作,除了计划任务,我们还可以使用脚本来完成,那么我们就用到了循环语句。

 1.1 for循环语法1 -- for .. in ..

        for var in value1 value2 ...
    do
      要执行的代码块
   done

#!/bin/bash

#1 for直接赋值
#for var in 1 2 3 4 5

#2 使用命令赋值
#for var in `seq 1 2 9`

#3 使用字符串赋值(这个字符串可以是使用命令后的结果)
for var in hello linux, hello c,java and more
  do
    echo $var
    sleep 0.5
done

#上面第3个的执行结果如下:
  [root@haha shell_0411]# sh for_1.sh 
  hello
  linux,
  hello
  c,java
  and
  more

  也可以 for ..;do 连起来使用

#!/bin/bash

for var in 1 2 3 4 5;do    
    echo $var
    sleep 0.5
done

 1.2 for循环语法2 -- C式

  for ((变量;条件;自增减运算 ))
    do

      要执行的代码块
  done

#!/bin/bash

#for循环使用单个变量
for ((i=1;i<10;i++))
  do
    echo $i
done


echo "for sysle with more var"

#for循环使用多个变量
for ((a=1,b=9;a<10,b>0;a++,b--))
  do
    echo $a -- $b
done

  得出来的结果如下:

[root@haha shell_0411]# sh for_c_style.sh 
1
2
3
4
5
6
7
8
9
for sysle with more var
1 -- 9
2 -- 8
3 -- 7
4 -- 6
5 -- 5
6 -- 4
7 -- 3
8 -- 2
9 -- 1

  1.3 for死循环

  for ((;;))
  do
    要执行的代码块
  done

  1.4 for循环break和continue

  continue:跳过循环中的某次循环,继续执行下次循环

  break:跳出当前循环,继续执行循环体之外的代码

    break N:break后面跟数字,可以一次性跳出N层循环。嵌套循环从内到外依次是第1层、第2层、第3层....例如 break 2,就表示跳出内外两层循环(当前循环以及外面一层循环)。 

  continue和break的基本用法如下:

#!/bin/bash
# 用户输入什么就输出什么,如果输入为0就跳过,输入为q就退出

for ((;;))
  do
    read -p "char: " ch
    if [ $ch -eq 0 ]
      then
        continue
    elif [ $ch == "q" ]
      then
        break
    else
      echo "当前输入为:$ch"
    fi
done

  break N 的用法:脚本中的 break 2,就表示跳出本层以及本层之外的那层循环,总共两层循环, 如:

#!/bin/bash
#如果用户输入0就跳出当前循环,如果输入q程序直接退出

for ((;;))
  do
    echo "外循环开始>>>"
    for ((;;))
      do
        read -p "内循环请输入:" ch
        if [ $ch == "q" ]
          then
            break 2
        elif [ $ch == 0 ]
          then
            break
        else
          echo "您输入的为:$ch"
        fi
    done
done

  for循环练习:

  例1: 写一个监控某个主机是否存活的脚本

  脚本中的命令说明:

    1、ping -c1 -w1 中 -c1是指ping的次数,-w是指执行的超时时间,单位为秒
    2、&>/dev/null 是指标准输出和错误输出都输出到/dev/null上,而不在界面上显示

#!/bin/bash
#监控某个主机存活的脚本

for ((;;))
  do
    ping -c1 $1 &>/dev/null
    if (($? == 0))
      then
        echo -e "$1的主机还存活着,当前时间为: `date "+%F %H:%M:%S"`"
      else
        echo -e "$1的主机已经失去联系,当前时间为: `date "+%F %H:%M:%S"`"
    fi
    sleep 5
done

 执行脚本: bash monitor_service.sh 192.168.17.137

  输出结果如下:

 [root@haha shell_0413]# bash monitor_service.sh 192.168.17.137
 192.168.17.137的主机还存活着,当前时间为: 2020-04-16 00:00:04
 192.168.17.137的主机还存活着,当前时间为: 2020-04-16 00:00:09

   例2: 输入一个ip文件,检查该文件中有哪些能用的ip,并记录下来

   串行版: 

      注意: >ip.log 先清日志内容

#!/bin/bash
#输入一个ip文件,检查该文件中有哪些能用的ip,并记录下来

>ip.log
for ip in `cat $1`
  do
    ping_flag="down"
    ping -c1 -w3 $ip &>/dev/null
    if [ $? -eq 0 ]; then
        ping_flag="up"
    fi
    echo "the $ip is $ping_flag!" | tee -a ip.log
done

   并行版:

    注意:{}& 是采用并行的方式并放在后台执行;

          wait 是等待后台所有ip都检查完再往下走。

#!/bin/bash
#输入一个ip文件,检查该文件中有哪些能用的ip,并记录下来

>ip.log
for ip in `cat $1`
  do
     {
      ping_flag="down"
      ping -c1 -w3 $ip &>/dev/null
      if [ $? -eq 0 ]; then
        ping_flag="up"
      fi
      echo "the $ip is $ping_flag!" | tee -a ip.log
     }&
done
wait
echo "finish..."

   例3: 按照用户文件来添加用户和密码

    注意:1. IFS=$':' 或  $'-'  或  $'/'  或...  来重新定义分隔符;

       2. 为什么要重新定义分隔符?

         for line in `cat  adduser.txt`  ==> 转为for循环时为  for line in user1  123123  user2  123456  user3  123321,默认的分隔符为 空格, 不重新定义分隔符的话就按照空格分开,则 $password 为空。

#!/bin/bash
#添加adduser.txt中的用户和密码

# 判断是否有参数传进来
if [ $# == 0 ]; then
    echo "error info: `basename $0 need a detail argument!`"
    exit 1
fi

# 判断传进来的参数是不是一个具体文件
if [ ! -f $1 ]; then
    echo "error info: it mast be a file, not directory!"
    exit 2
fi

# 希望for处理文件时按照回车符分割,而不是空格或tab空格,可以用 IFS 重新定义分隔符
# 以换行为分隔符,这块必须是单引号,不然会被转义
IFS=$'\n'

for line in `cat $1`
do
    if [ ${#line} == 0 ]; then
        echo "Nothing to do"
        continue
    fi
    user=`echo $line | awk '{print $1}'`
    password=`echo $line | awk '{print $2}'`
    id $user &>/dev/null
    if [ $? == 0 ]; then
        echo "user $user already exists!"
    else
        useradd $user
        echo $password | passwd --stdin $user &>/dev/null
        if [ $? == 0 ]; then
            echo "$user is created"
        fi
  fi
done

  对于处理文件的操作时,while 比 for 循环好用,不用考虑分隔符,while 是逐行读文件,对行数据进行操作。

2. while循环

 2.1 while 语法

    while [ condition ]     #注意,条件为真while才会循环,条件为假,while停止循环
    do
      commands
    done

 2.2 while 或 for 取舍?

  知道循环次数就可以用for,比如说一天需要循环24次;如果不知道代码要循环多少次,那就用while。

 2.3 用while处理文件更方便

  用for循环处理文件,在遍历时会因为空格的存在,要重新指定分隔符;但是while处理文件时,逐行读取文件内容。如上 for 循环的最后一个例子。

  使用 while 循环对for循环的例3重新编写:

#!/bin/bash
#使用while对adduser.txt内容处理,添加用户

while read line
do
    if [ ${#line} == 0 ]; then
        echo "Nothing to do!"
        continue
    fi
    user=`echo $line | awk '{print $1}'`
    password=`echo $line | awk '{print $2}'`
    id $user &>/dev/null
    if [ $? == 0 ]; then
        echo "user $user is already exists!"
    else
        useradd $user
        echo $password | passwd --stdin $user &>/dev/null
        if [ $? == 0 ]; then
            echo "$user has been created"
        fi
    fi
done < adduser.txt

 2.4 while死循环 -- while :  或  while true

    注意:let start++ 或 start=$((start+1))  都可以实现累加。

#!/bin/bash

start=1
while [ $start -le 10 ]
do
    if [ $start == 5 ]; then
#        let start++
        start=$((start+1))
        continue
    else
        echo "start = $start"
    fi
#    let start++
    start=$((start+1))
done

 3. shell内置命令 -- shift

 shift:将所有的位置参数向左移n位,默认是shift 1,即位置参数向左移一位;shift 2时,位置参数个数必须是2的整数倍。

#!/bin/bash
# 用shift实现位置参数左移

while [ $# -ne 0 ];do
    let sum+=$1
    shift 
done

echo "sum is : $sum"

 调用脚本时, sh filename.sh 1 2 3 4 5,第一个位置参数$1为1,每执行一次while循环,遇到while,就会将参数1 2 3 4 5向左移一位,变成2 3 4 5,第一个位置参数$1变成2,以此类推,直至$1没有值,循环结束。

posted @ 2020-05-05 11:03  恐水的鱼  Views(717)  Comments(0Edit  收藏  举报