掌握for循环语句的基本语法结构
掌握while和until循环语句的基本语法结构
能会使用RANDOM产生随机数
理解嵌套循环
一、随机数 关键词:一切都是未知数,永远不知道明天会抽什么风 :wind_chime::sweat_smile:
1. 如何生成随机数? 系统变量 :RANDOM ,默认会产生0~32767的随机整数
前言: 要想调用变量,不管你是什么变量都要给钱,而且是美元:heavy_dollar_sign:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 打印一个随机数 echo $RANDOM 查看系统上一次生成的随机数 RANDOM=28325 产生0 ~1 之间的随机数 echo $ [$RANDOM %2 ] 产生0 ~2 之间的随机数 echo $ [$RANDOM %3 ] 产生0 ~3 之间的随机数 echo $ [$RANDOM %4 ] 产生0 ~9 内的随机数 echo $ [$RANDOM %10 ] 产生0 ~100 内的随机数 echo $ [$RANDOM %101 ] 产生50 -100 之内的随机数 echo $ [$RANDOM %51 +50 ] 产生三位数的随机数 echo $ [$RANDOM %900 +100 ]
2. 实战案例 ㈠ 随机产生以139开头的电话号码 具体需求1:
写一个脚本,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行。
① 思路
产生1000个电话号码,脚本需要循环1000次 FOR WHILE UNTIL
139+8位,后8位随机产生,可以让每一位数字都随机产生 echo $[$RANDOM%10]
将随机产生的数字分别保存到变量里,然后加上139保存到文件里
② 落地实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 file=/shell03/phonenum.txt for ((i=1 ;i<=1000 ;i++))do n1=$ [$RANDOM %10 ] n2=$ [$RANDOM %10 ] n3=$ [$RANDOM %10 ] n4=$ [$RANDOM %10 ] n5=$ [$RANDOM %10 ] n6=$ [$RANDOM %10 ] n7=$ [$RANDOM %10 ] n8=$ [$RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " >> $file done for i in {1 ..1000 }do n1=$ [RANDOM %10 ] n2=$ [RANDOM %10 ] n3=$ [RANDOM %10 ] n4=$ [RANDOM %10 ] n5=$ [RANDOM %10 ] n6=$ [RANDOM %10 ] n7=$ [RANDOM %10 ] n8=$ [RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " >> phonenum.txt done i=1 while [ $i -le 1000 ]do n1=$ [$RANDOM %10 ] n2=$ [$RANDOM %10 ] n3=$ [$RANDOM %10 ] n4=$ [$RANDOM %10 ] n5=$ [$RANDOM %10 ] n6=$ [$RANDOM %10 ] n7=$ [$RANDOM %10 ] n8=$ [$RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " >> phonenum.txt let i++ done continue :继续,跳过本次循环,执行下一次循环break :打断,执行循环体外的代码do..done外exit :退出程序for i in {1 ..1000 }do n1=$ [$RANDOM %10 ] n2=$ [$RANDOM %10 ] n3=$ [$RANDOM %10 ] n4=$ [$RANDOM %10 ] n5=$ [$RANDOM %10 ] n6=$ [$RANDOM %10 ] n7=$ [$RANDOM %10 ] n8=$ [$RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " >> phonenum.txt done for ((i=1 ;i<=1000 ;i++))do n1=$ [$RANDOM %10 ] n2=$ [$RANDOM %10 ] n3=$ [$RANDOM %10 ] n4=$ [$RANDOM %10 ] n5=$ [$RANDOM %10 ] n6=$ [$RANDOM %10 ] n7=$ [$RANDOM %10 ] n8=$ [$RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " |tee -a phonenum.txt done count=0 while truedo n1=$ [$RANDOM %10 ] n2=$ [$RANDOM %10 ] n3=$ [$RANDOM %10 ] n4=$ [$RANDOM %10 ] n5=$ [$RANDOM %10 ] n6=$ [$RANDOM %10 ] n7=$ [$RANDOM %10 ] n8=$ [$RANDOM %10 ] echo "139$n1 $n2 $n3 $n4 $n5 $n6 $n7 $n8 " |tee -a phonenum.txt && let count++ if [ $count -eq 1000 ];then break fi done
㈡ 随机抽出5位幸运观众 具体需求:
在上面的1000个手机号里抽奖5个幸运观众,显示出这5个幸运观众。
但只显示头3个数和尾号的4个数,中间的都用*代替
① 思路
确定幸运观众所在的行 0-1000 随机找出一个数字 $[$RANDOM%1000+1]
将电话号码提取出来 head -随机产生行号 phonenum.txt |tail -1
显示前3个和后4个数到屏幕 echo 139****
② 落地实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 phone=/shell03/phonenum.txt for ((i=1 ;i<=5 ;i++))do line=`wc -l $phone |cut -d ' ' -f1 ` luck_line=$ [RANDOM %$line +1 ] luck_num=`head -$luck_line $phone |tail -1 ` echo "139****$ {luck_num:7:4}" echo $luck_num >> luck.txt done file=/shell04/phonenum.txt for i in {1 ..5 }do file_num=`wc -l $file |cut -d ' ' -f1 ` line=`echo $ [$RANDOM %$file_num +1 ]` luck=`head -n $line $file |tail -1 ` echo "139****$ {luck:7:4}" && echo $luck >> /shell04/luck_num.txt done for ((i=1 ;i<=5 ;i++))do file=phonenum.txt line=`cat phonenum.txt |wc -l ` 1000 luckline=$ [$RANDOM %$line +1 ] phone=`cat $file |head -$luckline |tail -1 ` echo "幸运观众为:139****$ {phone:7:4}" done 或者 phone=phonenum.txt for ((i=1 ;i<=5 ;i++))do num=`wc -l phonenum.txt |cut -d ' ' -f1 ` line=`echo $ [$RANDOM %$num +1 ]` luck=`head -$line $phone |tail -1 ` sed -i "/$luck /d" $phone echo "幸运观众是:139****$ {luck:7:4}" done
㈢ 批量创建用户(密码随机产生) 需求: 批量创建5个用户,每个用户的密码为一个随机数
① 思路
循环5次创建用户
产生一个密码文件来保存用户的随机密码
从密码文件中取出随机密码赋值给用户
② 落地实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 echo user0{1 ..5 }:itcast$ [$RANDOM %9000 +1000 ] for ((i=1 ;i<=5 ;i++))do user=`head -$i user_pass.file|tail -1 |cut -d : -f1 ` pass=`head -$i user_pass.file|tail -1 |cut -d : -f2 ` useradd $user echo $pass |passwd --stdin $user done 或者 for i in `cat user_pass.file`do user=`echo $i |cut -d : -f1 ` pass=`echo $i |cut -d : -f2 ` useradd $user echo $pass |passwd --stdin $user done echo user0{1 ..3 }:itcast$ [$RANDOM %9000 +1000 ] while read user passdo useradd $user echo $pass |passwd --stdin $user done < user_pass.file pwgen工具产生随机密码: [root @server shell04 ] Meep5ob1aesa [root @server shell04 ] user01:Bahqu9haipho user02:Feiphoh7moo4 user03:eilahj5eth2R [root @server shell04 ] user01:eiwaShuZo5hi user02:eiDeih7aim9k user03:aeBahwien8co
二、嵌套循环 关键字:大圈套小圈
:clock3:时钟 :分针与秒针,秒针转⼀圈(60格),分针转1格。循环嵌套就是外层循环⼀次,内层循环⼀轮。
一个循环体内又包含另一个完整 的循环结构,称为循环的嵌套。
每次外部循环都会触发内部循环,直至内部循环完成,才接着执行下一次的外部循环。
for循环、while循环和until循环可以相互 嵌套。
1 2 3 4 5 6 7 8 9 for ((i=1 ;i<=5 ;i++))do for (()) do done done
1. 应用案例 ㈠ 打印指定图案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 12 123 1234 12345 5 54 543 5432 54321 外部循环:打印换行,并且换5 行 ,循环5 次 内部循环:打印54321 数字 for ((y=5 ;y>=1 ;y--))do for ((x=5 ;x>=1 ;x--)) do echo -n $x done echo done
㈡ 落地实现1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 X轴: for ((i=1 ;i<=5 ;i++));do echo -n $i ;doneY轴: 负责打印换行 for ((y=1 ;y<=5 ;y++))do for ((x=1 ;x<=$y ;x++)) do echo -n $x done echo done for ((y=1 ;y<=5 ;y++))do x=1 while [ $x -le $y ] do echo -n $x let x++ done echo done
㈢ 落地实现2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 Y轴:打印换行 X轴:打印数字 5 -1 y=5 while (( $y >= 1 ))do for ((x=5 ;x>=$y ;x--)) do echo -n $x done echo let y-- done for (( y=5 ;y>=1 ;y--))do for (( x=5 ;x>=$y ;x--)) do echo -n $x done echo done y=5 while [ $y -ge 1 ]do for ((x=5 ;x>=$y ;x--)) do echo -n $x done echo let y-- done y=1 until (( $y >5 ))do x=1 while (( $x <= $y )) do echo -n $ [6 -$x ] let x++ done echo let y++ done y=1 while (( $y <= 5 ))do for ((x=5 ;x>=6 -$y ;x--)) do echo -n $x done echo let y++ done 课后打印: 54321 5432 543 54 5
2. 课堂练习 打印九九乘法表(三种方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 1 *1 =1 1 *2 =2 2 *2 =4 1 *3 =3 2 *3 =6 3 *3 =9 1 *4 =4 2 *4 =8 3 *4 =12 4 *4 =16 1 *5 =5 2 *5 =10 3 *5 =15 4 *5 =20 5 *5 =25 1 *6 =6 2 *6 =12 3 *6 =18 4 *6 =24 5 *6 =30 6 *6 =36 1 *7 =7 2 *7 =14 3 *7 =21 4 *7 =28 5 *7 =35 6 *7 =42 7 *7 =49 1 *8 =8 2 *8 =16 3 *8 =24 4 *8 =32 5 *8 =40 6 *8 =48 7 *8 =56 8 *8 =64 1 *9 =9 2 *9 =18 3 *9 =27 4 *9 =36 5 *9 =45 6 *9 =54 7 *9 =63 8 *9 =72 9 *9 =81 Y轴:循环9 次,打印9 行空行 X轴:循环次数和Y轴相关;打印的是X和Y轴乘积 $ [] $ (()) for ((y=1 ;y<=9 ;y++))do for ((x=1 ;x<=$y ;x++)) do echo -ne "$x *$y =$ [$x *$y ]\t" done echo echo done y=1 while [ $y -le 9 ]do x=1 while [ $x -le $y ] do echo -ne "$x *$y =$ [$x *$y ]\t" let x++ done echo echo let y++ done 或者 for i in `seq 9 `do for j in `seq $i ` do echo -ne "$j *$i =$ [$i *$j ]\t" done echo echo done 或者 y=1 until [ $y -gt 9 ]do x=1 until [ $x -gt $y ] do echo -ne "$x *$y =$ [ $x *$y ]\t" let x++ done echo echo let y++ done
三、阶段性补充总结 1. 变量定义 1 2 3 4 5 6 7 1)变量名=变量值 echo $变量名 echo ${变量名} 2)read -p "提示用户信息:" 变量名 3) declare -i/-x/-r 变量名=变量值
2. 流程控制语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 )if [ 条件判断 ];then command fi 2 ) if [ 条件判断 ];then command else command fi 3 ) if [ 条件判断1 ];then command1 elif [ 条件判断2 ];then command2 else command3 fi
3. 循环语句 1 2 3 4 目的:某个动作重复去做,用到循环 for while until
4. 影响shell程序的内置命令 1 2 3 4 5 6 7 8 exit 退出整个程序break 结束当前循环,或跳出本层循环continue 忽略本次循环剩余的代码,直接进行下一次循环shift 使位置参数向左移动,默认移动1 位,可以使用shift 2 : true false
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 以下脚本都能够实现用户自定义输入数字,然后脚本计算和: [root @MissHou shell04 ] sum=0 while [ $ do let sum =$sum +$1 shift done echo sum =$sum [root @MissHou shell04 ] sum =0 for i do let sum =$sum +$i done echo sum =$sum
5. 补充扩展expect expect 自动应答 tcl语言
需求1: A远程登录到server上什么都不做
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 spawn ssh root@10.1 .1.1 expect { "(yes/no)?" { send "yes\r" ;exp_continue } "password:" { send "123456\r" } } interact //交互 脚本执行方式: 1 )定义变量set ip 10.1 .1.1 set pass 123456 set timeout 5 spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } interact 2 )使用位置参数set ip [ lindex $argv 0 ] set pass [ lindex $argv 1 ] set timeout 5 spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } interact
需求2: A远程登录到server上操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 set ip 10.1 .1.1 set pass 123456 set timeout 5 spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } expect "#" send "rm -rf /tmp/*\r" send "touch /tmp/file{1..3}\r" send "date\r" send "exit\r" expect eof
需求3: shell脚本和expect结合使用,在多台服务器上创建1个用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 [root @server shell04 ] 10.1 .1.1 123456 10.1 .1.2 123456 1 . 循环 useradd username2 . 登录远程主机——>ssh——>从ip.txt文件里获取IP和密码分别赋值给两个变量3 . 使用expect程序来解决交互问题while read ip passdo /usr/bin/expect <<-END &>/dev/null spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } expect "#" { send "useradd yy1;rm -rf /tmp/*;exit\r" } expect eof END echo "$ip 服务器用户创建完毕" done < ip.txt cat ip.txt|while read ip pass do { /usr/bin/expect <<-HOU spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } expect "#" send "hostname\r" send "exit\r" expect eof HOU }& done wait echo "user is ok...." 或者 while read ip passdo { /usr/bin/expect <<-HOU spawn ssh root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } expect "#" send "hostname\r" send "exit\r" expect eof HOU }& done<ip.txt wait echo "user is ok...."
四、综合案例 1. 实战案例1 ㈠ 具体需求 写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上
说明:主机和密码文件已经提供
10.1.1.1:123456
10.1.1.2:123456
㈡ 案例分析
跳板机上的yunwei用户生成秘钥对
判断账号是否存在 (id yunwei)
判断该用户是否有密钥对文件 [ -f xxx ]
判断expect程序是否安装
判断局域网内主机是否ping通(循环判断|for while until)
循环判断 for while
循环体do……done ping 主机 如果ping通 调用expect程序自动应答推送公钥
测试验证是否免密登录成功
检查服务器上ssh服务端口号
把公钥推送成功的主机的信息保存到文件
关闭防火墙和selinux
日志记录
推送公钥需要自动应答expect
㈢ 落地实现 ① 代码拆分 功能1:管理员root创建yunwei用户和安装expect软件包
1 2 3 4 5 6 7 8 9 10 { id yunwei [ $ ? -ne 0 ] && useradd yunwei && echo 123 |passwd --stdin yunwei } &>/dev/null rpm -q expect [ $ ? -ne 0 ] && yum -y install expect && echo "expect软件已经成功安装"
功能2:判断主机是否ping通并且yunwei用户推送公钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 home_dir=/home/yunwei [ ! -f $home_dir /.ssh /id_rsa.pub ] && ssh-keygen -P '' -f id_rsa &>/dev/null ip_txt=$home_dir /ip.txt for i in `cat $ip_txt `do ip=`echo $i |cut -d : -f1 ` pass=`echo $i |cut -d : -f2 ` ping -c1 $ip &>/dev/null if [ $ ? -eq 0 ];then echo $ip >> ~/ip_up.txt /usr/bin/expect <<-END &>/dev/null spawn ssh-copy -id root@ $ip expect { "(yes/no)" { send "yes\n" ;exp_continue } "password:" { send "$pass \n" } } expect eof END else echo $ip >> $home_dir /ip_down.txt fi done remote_ip=`head -1 ~/ip_up.txt` ssh root@ $remote_ip hostname [ $ ? -eq 0 ] && echo "公钥推送成功"
② 最终实现
环境准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 jumper-server 有yunwei用户 yunwei用户sudo授权: visudo root ALL=(ALL) ALL yunwei ALL=(root) NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf / 解释说明: 1 )第一个字段yunwei指定的是用户:可以是用户名,也可以是别名。每个用户设置一行,多个用户设置多行,也可以将多个用户设置成一个别名后再进行设置。2 )第二个字段ALL指定的是用户所在的主机:可以是ip,也可以是主机名,表示该sudo设置只在该主机上生效,ALL表示在所有主机上都生效!限制的一般都是本机,也就是限制使用这个文件的主机;一般都指定为"ALL" 表示所有的主机,不管文件拷到那里都可以用。比如:10.1 .1.1 =...则表示只在当前主机生效。3 )第三个字段(root)括号里指定的也是用户:指定以什么用户身份执行sudo,即使用sudo后可以享有所有root账号下的权限。如果要排除个别用户,可以在括号内设置,比如ALL=(ALL,!oracle,!pos)。4 )第四个字段ALL指定的是执行的命令:即使用sudo后可以执行所有的命令。除了关机和删除根内容以外;也可以设置别名。NOPASSWD: ALL表示使用sudo的不需要输入密码。5 )也可以授权给一个用户组 %admin ALL=(ALL) ALL 表示admin组里的所有成员可以在任何主机上以任何用户身份执行任何命令
脚本实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 [ ! -f /home /yunwei /.ssh /id_rsa ] && ssh-keygen -P '' -f ~/.ssh/id_rsa tr ':' ' ' < /shell04/ip.txt|while read ip pass do { ping -c1 $ip &>/dev/null if [ $ ? -eq 0 ];then echo $ip >> ~/ip_up.txt /usr/bin/expect <<-END &>/dev/null spawn ssh-copy -id root@ $ip expect { "yes/no" { send "yes\r" ;exp_continue } "password:" { send "$pass \r" } } expect eof END fi }& done wait echo "公钥已经推送完毕,正在测试...." remote_ip=`tail -1 ~/ip_up.txt` ssh root@ $remote_ip hostname &>/dev/null test $ ? -eq 0 && echo "公钥成功推送完毕"
2. 实战案例2 写一个脚本,统计web服务的不同连接状态个数
找出查看网站连接状态的命令 ss -natp|grep :80
如何统计不同的状态 循环去统计,需要计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 declare -A array1 states=`ss -ant |grep 80 |cut -d ' ' -f1 ` for i in $states do let array1[$i ]++ done for j in $ {!array1[@ ]}do echo $j: $ {array1[$j ]} done