shell-循环语句-for-while

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容