小破站学习笔记
一切都是未知数
系统变量:RANDOM,默认产生0-32767的随机整数
打印一个随机数
echo $RANDOM
产生0-1之间的随机数
echo $[RANDOM%2]
产生0-2之间的随机数
echo $[RANDOM%3]
产生0-10之间的随机数
echo $[RANDOM%11]
产生1-50之间的随机数
0-49
echo $[RANDOM%50+1]
产生50-100之间的随机数
0-50
echo $[RANDOM%51+50]
产生10-99之间的随机数
0-89
echo $[RANDOM%90+10]
产生100-999之间的随机数
0-899
echo $[RANDOM%900+100]
实战案例
- 随机产生以139开头的号码1000个
思路:循环1000次 139后面的每个数都是随机的
#!/bin/bash
file=/zss.txt
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" >> $file
let i++
done
##cat zss.txt | sort -u | wc -l
- 随机抽取5位幸运观众
从1000个手机号抽取5个 号码只显示前3位和后4位
思路:确定幸运观众所在的行 随机数
将号码提取出 head -899 zss.txt | tail -1
显示前3个和后4个 echo 139****1234
#!/bin/bash
phone=/zss.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 zss.txt | tail -1`
#显示到屏幕
echo "139****${luck_num:7:4}"
echo $luck_num >> luck.txt
#删除已经被抽取的幸运观众号码
sed -i "/$luck_num/d" $phone
done
- 批量创建用户 密码随机生成
思路:循环5次创建 产生一个文件用来 保存随机密码 赋值
#!/bin/bash
echo user0{1..5}:zss$[RANDOM%9000+1000]#@~|tr ' ' '\n' >> user_pass.file
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
for i in {1..5};do echo $i;done
for ((i=1;i<=5;i++));do echo $i;done
while
i=1;while [ $i -le 5 ];do echo $i;let i++;done
i=1;while (( $i <= 5 ));do echo $i;let i++;done
until
i=1;until (( $i > 5 ));do echo $i;let i++;done
嵌套循环
一个循环体内又包含另一个完整的循环结构,称为循环的嵌套
每次外部循环都会触发内部循环,直至内部循环完成,才会执行下一次外部循环
for while until 都可以互相嵌套
应用实例
1
12
123
1234
12345
#!/bin/bash
for y in {1..5}
do
for ((i=1;i<=$y;i++))
do
echo -n $i
#不换行
done
echo
#换行
done
for ((y=1;y<=5;y++))
do
x=1
while (($x<=$y))
do
echo -n $x
let x++
done
echo
done
5
54
543
5432
54321
#!/bin/bash
for y in {1..5}
do
for ((i=1;i<=$y;i++))
do
echo -n $i
done
echo
done
#外部打印换行 内部打印54321
阶段型总结
- 变量的定义
变量名=变量值
echo $变量名
echo ${变量名}
read -p "提示用户信息:" 变量名
#交互式
declare -i/-x/-r 变量名=变量值
#定义变量类型
- 流程控制语句
if [ 条件判断 ];then
command
fi
if [ 条件判断 ];then
command
else
command
fi
if [ 条件判断1 ];then
command
elif [ 条件判断2 ];then
command2
else
command3
fi
- 循环语句
目的:某个动作要重复去做
for
while
until
- 影响shell程序的内置命令
exit 退出整个程序
break 结束当前循环,或跳出本层循环
continue 忽略本次循环剩下的代码,直接进入下一次循环
shift 使位置参数向左移动,默认移动一位,可以使用shirt 2 向左移动2位
#!/bin/bash
sum=0
while [ $# -ne 0 ]
do
let sum=$sum+$1
#shift
shift 2
done
echo sum=$sum
- 补充扩展expect
expect 自动应答 tcl语言
需求:A远程登录到server上什么都不做
#!/usr/bin/expect
#开启一个程序
spawn ssh root@192.168.0.160
#捕获相关内容
expect {
"(yes/no)?" { send "yes\r";exp_continue }
"password:" { send "zss@123\r" }
}
interact //交互
#脚本执行方式
#./expect1.sh
#/zss/expect1.sh
#expect -f expect1.sh
定义变量
#!/usr/bin/expect
set ip 192.168.0.160
set pass zss@123
set timeout 5
spawn ssh root@$ip
expect {
"(yes/no)?" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
interact
需求2:A远程登录到server上操作
#!/usr/bin/expect
set ip 192.168.0.160
set pass zss@123
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
#使用位置参数
#!/usr/bin/expect
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
需求3:shell脚本和expect结合使用,在多台服务器上创建1个用户
思路:循环for
远程登陆 ssh
从文件获取ip和密码 expect
解决交互问题
for i in `wc -l ip.txt|cut -d ' ' -f1`
do
done
ip.txt
192.168.0.150 zss@123
192.168.0.160 zss@123
#!/bin/bash
while read ip pass
#定义ip pass 2个变量 来自于文件ip.txt
do
#调用expect
/usr/bin/expect <<-END &>/dev/null
#- 不加的话 下面的END要顶格写
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 服务器yy1用户创建完毕"
done < ip.txt
#cat >> file << !
#sadasd
#adadasdasd
#!
- 需求4:推送公钥给别的所有服务器
- 1.用户生成密钥对
账号是否存在id
判断该用户是否有密钥对文件-f
- 2.判断expect是否存在
- 3.判断局域网内主机是否ping通
循环判断for while
do...done
ping主机 通 expect自动应答推送公钥 - 4.推送公钥给可以ping的主机
验证是否免密登录成功
循环判断主机是否ping通
检查服务器上ssh服务
推送成功 保存文件
关闭防火墙和selinux
日志记录
推送公钥需要自动应答expect
ssh-keygen
ssh-copy-id root@192.168.0.160
ssh-keygen -P '' -f ~/.ssh/id_rsa
#!/bin/env bash
# 实现批量推送公钥
id zss &>/dev/null
[ $? -ne 0 ] && useradd zss && echo 123|passwd --stdin zss
#判断用户是否存在
rpm -q expect
[ $? -ne 0 ] && yum -y install expect && echo "expect软件安装成功"
/usr/bin/expect <<-END
spawn su - zss
expect "~]$\r"
send { "[ ! -f /home/zss/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f id_rsa &>/dev/null;\r" }
expect eof
END
[ ! -f /home/zss/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f id_rsa
#!/bin/env bash
# 实现批量推送公钥
#id zss &>/dev/null
#[ $? -ne 0 ] && useradd zss && echo 123|passwd --stdin zss
#判断用户是否存在
#rpm -q expect
#[ $? -ne 0 ] && yum -y install expect && echo "expect软件安装成功"
#判断expect软件是否安装
[ ! -f /home/zss/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f ~/.ssh/id_rsa &>/dev/null
#判断公钥是否存在
tr ':' ' ' < /home/zss/zss/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
set timeout 10
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 "$ip 公钥已经发送完毕"
#测试
#sleep 15
remote_ip=`tail -1 ./ip_up.txt`
ssh root@$remote_ip hostname &>/dev/null
test $? -eq 0 && echo "公钥推送完毕"
难搞呦还有点小瑕疵
- visudo
root ALL=(ALL) ALL
zss ALL=(root) NOPASSWD:ALL,!/sbin/shoudown
#除了关机的所有权限 一般不这样写 只允许某些个别的命令
- 需求5:统计web服务的不同连接状态的个数
涉及到下一个数组的知识点
1.找出查看网站连接状态的命令ss -natp |grep :80 |cut -d ' ' -f1
2.如何统计出不同的状态 循环去统计
#!/bin/bash
declare -A array1
state=`ss -ant|grep 80|cut -d' ' -f1`
for i in $states
do
let arry1[$i]++
done
#统计
#通过遍历数组里的索引和元素打印出来
for j in ${!arry1[@]}
do
$j:${arry1[$j]}
done