美文网首页shell
shell-循环语句-for-while

shell-循环语句-for-while

作者: linux_豪哥 | 来源:发表于2020-12-05 19:35 被阅读0次

    1. shell循环语句

    1.1 for循环语句

    1.1.1 语法

    for 变量名  in [ 取值列表 ] 
    do 
        循环体
    done
    

    1.1.2 简单实现

    for n in 1 2 3 4 5
    do
        echo $n
    done
    
    
    for n in `seq 10`                                                                                                        
    do
            echo $n
    done
    

    1.1.3 举例

    计算从1加到100之和

    for ((i=1;i<=100;i++))
    do
        let sum+=i
    done
    echo $sum
    
    
    第二种
    sum1=0
    for i in `seq 100`
    do
        let sum1=$sum1+$i
    done
    echo $sum1
    

    批量创建用户

    #!/bin/sh
    for i in `cat user.txt`
    do
            id $i &>/dev/null
            if [ $? -ne 0 ];then
               useradd $i
               echo "123"|passwd --stdin $i &>/dev/null
               echo "Create $i OK"
            else
               echo "useradd: $i already exists"
            fi
    done
    
    

    测试网段ip连通性

    [root@shell ~]# cat ping.sh
    #!/bin/
    #循环主机
    for i in {1..254}
    do       #并发执行
            {   
            IP=10.0.1.$i
            ping -c1 $IP &>/dev/null
            if [ $? -eq 0 ];then
            echo "$IP" >>ip.txt
            fi
            }&
    done
       wait 
       echo "获取在线IP完成"
    

    1.1.4 并行执行

    &和wait组合可以并行处理,提升效率
    串行

    [root@shell ~]# cat ping.sh
    #!/bin/
    #循环主机
    for i in {1..3}
    do       
            IP=10.0.1.$i
            ping -c1 $IP &>/dev/null
            if [ $? -eq 0 ];then
            echo "$IP" >>ip.txt
            fi
    done 
       echo "获取在线IP完成"
    ======================================
    [root@shell ~]# sh -x ping.sh
    + for i in '{1..3}'
    + IP=10.0.1.1
    + ping -c1 10.0.1.1
    + '[' 1 -eq 0 ']'
    + for i in '{1..3}'
    + IP=10.0.1.2
    + ping -c1 10.0.1.2
    + '[' 0 -eq 0 ']'
    + echo 10.0.1.2
    + for i in '{1..3}'
    + IP=10.0.1.3
    + ping -c1 10.0.1.3
    + '[' 1 -eq 0 ']'
    + echo $'\350\216\267\345\217\226\345\234\250\347\272\277IP\345\256\214\346\210\220'
    获取在线IP完成
    

    并行--使用&和wait

    [root@shell ~]# cat ping.sh
    #!/bin/
    #循环主机
    for i in {1..3}
    do       #并发执行
            {   
            IP=10.0.1.$i
            ping -c1 $IP &>/dev/null
            if [ $? -eq 0 ];then
            echo "$IP" >>ip.txt
            fi
            }&
    done
       wait 
       echo "获取在线IP完成"
    ========================
    [root@shell ~]# sh -x ping.sh
    + for i in '{1..3}'
    + for i in '{1..3}'
    + for i in '{1..3}'
    + wait
    + IP=10.0.1.1
    + ping -c1 10.0.1.1
    + IP=10.0.1.2
    + ping -c1 10.0.1.2
    + IP=10.0.1.3
    + ping -c1 10.0.1.3
    + '[' 0 -eq 0 ']'
    + echo 10.0.1.2
    + '[' 1 -eq 0 ']'
    + '[' 1 -eq 0 ']'
    + echo $'\350\216\267\345\217\226\345\234\250\347\272\277IP\345\256\214\346\210\220'
    获取在线IP完成
    

    1.2 while循环语句

    1.2.1 while循环基础语法

    //当条件测试成立(条件测试为真),执行循环体
    while 条件测试 
    do 
        循环体 
    done
    
    image.png

    1.2.2 简单练习

    打印10到1 再打印1到10

    i=1
    while [ $i -le 10 ] 
    do
        echo $i
        ((i++))
    done
    a=10
    while [ $a -gt 0 ]
    do
        echo $a
        let a-=1                                                                                                             
    done 
    

    1.2.3 while读文件的三种方法

    方式1:在while循环结尾done通过输入重定向指定读取的文件(推荐)。
    while read line
    do
        cmd
    done<FILE
    方式2:使用cat读取文件内容,然后通过管道进入while循环处理。
    cat FILE_PATH|while read line
    do
        cmd
    done
    方式3:采用exec读取文件后,然后进入while循环处理。
    exec <FILE
    sum=0
    while read line
    do
        cmd
    done
    
    

    1.2.4 猜数游戏

    需要用while true死循环

    首先让系统随机生成一个数字,给这个数字定一个范围(1-60),让用户输入猜的数字,对输入进行判断,如果不符合要求,就给予高或低的提示,猜对后则给出猜对用的次数,请用while语句实现。

    分析:
    1)随机数字定一个范围(1-60)
    echo $((RANDOM%60)) 执行脚本后是固定的,例如;50
    
    2)read -p "输入猜数字:" num
    把用户输入的数字和已知的随机数比较。
    
    3)连续猜就需要用while true
    
    random="$((RANDOM%60))"
    count=0
    while true
    do
        read -p "请输入你猜的数字: " num
        let count+=1
        if [ $random -gt $num ]
        then
            echo "哥们,猜低了,请继续。"
        elif [ $random -eq $num ]
        then
              if [ $count -le 3 ]
              then
                  echo "一共用了$count 次,太牛逼了。"
              elif  [ $count -gt 3 ]
              then
                echo "这智商,该学习了,一共猜了$count 次"
            fi
            exit 0
        else
            echo "哥们,猜高了,继续。"
        fi
    done 
    
    

    用while批量创建用户

    文件中每行只有用户名
    [root@shell scripts]# cat while.sh
    #!/bin/bash
    while read line
    do
            id $line &>/dev/null
            if [ $? -eq 0 ];then
               echo "useradd: user $line already exists"
            else
               useradd $line
               if [ $? -eq 0 ];then
                    echo "create $line success"
               fi
            fi
    done<user.txt
    
    
    文件中存在用户名和密码
    [root@shell scripts]# cat user.txt 
    haoge  123
    huage  456
    zhage  000
    
    第一种
    [root@shell scripts]# cat while.sh
    #!/bin/bash
    #!/bin/sh
    while read user
    do
            u=$(echo $user|awk '{print $1}')
            p=$(echo $user|awk '{print $2}')
            id $u &>/dev/null
            if [ $? -ne 0 ];then
                 useradd $u
                 echo $p|passwd --stdin $u &>/dev/null
                 echo "Create $u is ok"
            else
                 echo "useradd: $u already exists"
            fi
    done<user.txt
    第二种
    [root@shell scripts]# cat while.sh
    #!/bin/bash
    #!/bin/sh
    while read user passwd
    do
            id $user &>/dev/null
            if [ $? -ne 0 ];then
                 useradd $user
                 echo $passwd|passwd --stdin $user &>/dev/null
                 echo "Create $user is ok"
            else
                 echo "useradd: $user already exists"
            fi
    done<user.txt
    
    文件中每行想分成多个变量,如果文件中的分隔符不是空格建议使用第一个awk制定分隔符的办法,
    如果是空格分开使用第二种比较方便,因为联系的user.txt中用户和密码是空格分开的,所以两种都可以。
    

    第二种讲解一下
    while读取的文件中每行中每列分隔符是空格可以在while read后面进行多个变量指定

    [root@shell scripts]# cat user.txt 
    haoge  123
    huage  456
    zhage  000
    [root@shell scripts]# cat test.sh 
    #!/bin/sh
    while read user passwd
    do 
     echo $user
     echo $passwd
    done<user.txt
    [root@shell scripts]# sh test.sh
    haoge
    123
    huage
    456
    zhage
    000
    

    1.3 循环控制命令

    exit 退出整个程序
    break 结束当前循环,或跳出本层循环
    continue 忽略本次循环剩余的代码,直接进行下一次循环


    image.png
    例如:刚才上面的猜数游戏就是用到了exit
    [root@shell scripts]# cat test.sh 
    while true
    do
      echo "123"
      exit
      echo "456"
    done
    echo "done..."
    执行后的结果
    [root@shell scripts]# sh test.sh 
    123
    
    break示例=======================
    [root@shell scripts]# cat test.sh 
    while true
    do
      echo "123"
      break
      echo "456"
    done
    echo "done..."
    执行后的结果
    [root@shell scripts]# sh test.sh 
    123
    done...
    continue 示例====================  
    [root@shell scripts]# cat test.sh
    #!/bin/sh
    for i in `seq 5`
    do
         if [ $i -eq 2 ]
         then
         echo $i
         else
         continue 
         fi
         echo 'next'
    done
    [root@shell scripts]# sh test.sh
    2
    next
    

    1.4 日常练习题

    分析Apache访问日志(access_2010-12-8.log),把日志中每行的访问字节数对应字段数字相加,计算出总的访问量。给出实现程序,请用while循环实现。

    sum=0
    while read line
    do
        size=`echo $line|awk '{print $10}'|grep -v -`
        let sum+=size
    done<$1
    echo $sum 
    

    2 expect免交互

    2.1 介绍

    expect是一款自动化的脚本解释型的工具
    脚本开头
    expect脚本一般以#!/usr/bin/expect 开头,类似bash脚本。
    执行脚本不用sh用expect
    expect脚本常常以.exp或者.ex结束。
    expect主要命令
    •   spawn 新建一个进程,这个进程的交互由expect控制
    •   expect 等待接受进程返回的字符串,直到超时时间,根据规则决定下一步操作
    •   send 发送字符串给expect控制的进程
    •   set 设定变量为某个值
    •   exp_continue 重新执行expect命令分支
    •   [lindex $argv 0] 获取expect脚本的第1个参数
    •   [lindex $argv 1] 获取expect脚本的第2个参数
    •   set timeout -1 设置超时方式为永远等待
    •   set timeout 30 设置超时时间为30秒
    •   interact 将脚本的控制权交给用户,用户可继续输入命令
    •   expect eof 等待spawn进程结束后退出信号eof
    
    cat test.sh
    #!/usr/bin/expect
    spawn ssh root@10.0.1.50
    
    expect {
        "yes/no" { send "yes\r"; exp_continue }
        "password:" { send "123456\r" };
    } 
    interact
    
    \r 回车符
    执行
    expect test.sh
    
    2.expect定义变量实现交互方式
    #!/usr/bin/expect
    set ip 10.0.1.50
    set user root
    set password 123456
    set timeout 5
    
    spawn ssh $user@$ip
    
    expect {
        "yes/no" { send "yes\r"; exp_continue }
        "password:" { send "$password\r" };
    } 
    

    密钥登陆脚本(常用)

    #!/bin/bash
    pass_word=123456
    for IP in `cat $1|grep -v ^#`
    do
    /usr/bin/expect << EOF
    set timeout 15
    spawn ssh-copy-id -i $IP
    expect {
            "yes/no" { send "yes\r" }
            "password" { send "$pass_word\r" }
            "Password" { send "$pass_word\r" }
            }
            expect eof
    EOF
    if [ `echo $?` -eq 0 ];
    then
            echo "$IP 免密配置成功"
            echo "$IP 免密配置成功" >> $2
    else
            echo "$IP 免密配置失败"
            echo "$IP 免密配置失败" >> $3
    fi
    done
    
    这个使用的是expect<<EOF的方法 所以按正常脚本的格式操作就可以
    Paword  paword两个匹配的密码防止有的主机是大写带头或者小写开头
    $1 表示ip的文件    $2成功的ip    $3失败的ip
    

    免密登录(详细)

    #交互方式
    interact
    案例
    批量获取在线主机, 进行秘钥批量分发
    cat for_ip.sh 
    #!/usr/bin/bash
    #setup1 拿到IP地址
    >ip.txt
    for i in {1..10}
    do
            ip=10.0.0.$i
            {
            ping -c1 $ip &>/dev/null
            if [ $? -eq 0 ];then
                    echo "$ip" >> ip.txt
            fi
            }&
    done
    #2.生成对应的密钥
            if [ ! -f ~/.ssh/id_rsa ];then
                    ssh-keygen -P "" -f ~/.ssh/id_rsa
            fi
    
    #3.批量分发密钥
            while read line
            do
                    /usr/bin/expect <<-EOF
                            set pass 1
                            set timeout 2
                            spawn ssh-copy-id  $line -f 
                            expect {
                                    "yes/no" { send "yes\r"; exp_continue}
                                    "password:" { send "$pass\r"}
                            }
                            expect eof 
                    EOF
            done<ip.txt
    

    相关文章

      网友评论

        本文标题:shell-循环语句-for-while

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