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