shell

shell-循环语句-for-while

2020-12-05  本文已影响0人  linux_豪哥

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
上一篇下一篇

猜你喜欢

热点阅读