Shell阶段05 for循环, 示例(批量创建用户, 批量探测主机脚本,分库分表备份, 随机点名, 判断主从异常), shell批量执行
方式一
for 变量名 in 列表;do
循环体
done
方式二
for 变量 in 取值列表 do 循环体 done 但条件为真,则执行循环体,如果条件为假,则结束循环。 #取值列表,很多种取值方法,默认以空白字符为分隔符 [root@shell01 scripts]# vim for-1.sh #!/bin/bash for i in file1 file2 file3 do echo "$i" done [root@shell01 scripts]# sh for-1.sh file1 file2 file3 #取值列表出现空格,要用引号。特殊字符要用转义字符 [root@shell01 scripts]# vim for-2.sh #!/bin/bash for i in 'file1 test' \( file2 file3 #file1 test是一个字符串,用单引号/双引号包起来。\转义 do echo "$i" done #根据变量进行取值 [root@shell01 scripts]# vim for-3.sh #!/bin/bash List="file1 file2 file3" for i in $List do echo "$i" done #通过命令取值 [root@shell01 scripts]# vim for-4.sh #!/bin/bash for i in $(cat /etc/hosts) do echo "$i" done #自定义分隔符 IFS=: #以冒号为分隔符 [root@shell01 scripts]# vim for-5.sh #!/bin/bash IFS=: for i in $(cat /etc/passwd | head -1) do echo "$i" done #指定多个分隔符 IFS=':;/' #这里有特殊字符,要用引号引起来 [root@shell01 scripts]# vim for-6.sh #!/bin/bash IFS=':;/' #这里有特殊字符,要用引号引起来 for i in $(cat test.txt) do echo $i done #以换行符作为分隔符 IFS=$'\n' [root@shell01 scripts]# vim for-7.sh #!/bin/bash IFS=$'\n' for i in $(cat /etc/hosts) do echo $i done #C语言风格的for (了解) [root@shell01 scripts]# vim for-8.sh #!/bin/bash for i in {1..10} do echo $i done [root@shell01 scripts]# vim for-8.sh #!/bin/bash for ((i=0;i<10;i++)) #C语言格式,用双括号 do echo $i done #定义多个变量,输入1-9的升序和降序 #C语言风格 for ((a=1,b=9;a<10;a++,b--)) do echo $a $b done #正常怎么写 a=0 b=10 for i in {1..9} do let a++ let b-- echo $a $b done
1.通过一个文件,进行批量创建用户 [root@shell01 scripts]# vim user.txt abc abd abe [root@shell01 scripts]# vim sh-1.sh #!/bin/bash for i in $(cat user.txt) do #判断用户是否存在 id $i &>/dev/null if [ $? -eq 0 ];then echo "用户${i}已经存在该系统! 无需再次创建!" else useradd $i &>/dev/null if [ $? -eq 0 ];then echo "用户${i}创建成功" else echo "用户${i}创建失败" fi fi done
通过输入的用户名批量创建和用户
[root@ubuntu2204 ~]# cat createuser.sh
#!/bin/bash
[ $# -eq 0 ] && { echo "Usage: createuser.sh USERNAME ..." ;exit 1 ; }
# user+空格表示所有输入的参数为user
for user ;do
id $user &> /dev/null && echo $user is exist || { useradd $user ; echo $user is created; }
done
2.根据读入文件内容,进行批量创建用户,user:pass 创建用户并创建相对应的密码 1.从文件中进行取值 2.先把用户调用出来,判断用户是否存在 3.存在则提示已经存在,不要再去设置密码 4.不存在则进行创建,再创建密码 5.显示创建结果 [root@shell01 scripts]# vim user.txt aaa:thjoir bbb:reggba ccc:sfvfse [root@shell01 scripts]# vim sh-1.sh #!/bin/bash for i in $(cat user.txt) do #1.需要把用户和密码进行分开 User=$(echo $i| awk -F: '{print $1}') Pass=$(echo $i| awk -F: '{print $2}') #2.判断用户是否存在 id $User &>/dev/null if [ $? -eq 0 ];then echo "用户${User}已经存在!" else useradd $User &>/dev/null && echo $Pass |passwd --stdin $User &>/dev/null if [ $? -eq 0];then echo "用户${User}创建成功! 并且密码初始化成功!" else echo "用户${User}创建失败!" fi fi done #生成10位随机密码 [root@shell01 scripts]# echo $RANDOM|md5sum|cut -c 1-10 527020af16
#批量执行
{
}&
3.批量的探测主机是否在存活状态及22端口是否开放 1.使用循环,进行批量探测1..254的主机位 2.将能连通的主机追加到一个文件中 3.根据这个文件中可连通的IP地址,再次进行测试22的远程端口是否开放 4.将22端口开放的主机也追加到一个文件中,以备查看 # telnet 10.0.0.7 22命令是交互操作的,shell里不方便使用 # 用nmap查看远程主机端口号 返回是open 状态,说明是开发连接的 [root@shell01 ~]# nmap -p22 10.0.0.7 ... PORT STATE SERVICE 22/tcp open ssh #open状态,开放连接 MAC Address: 00:0C:29:A2:22:35 (VMware) ... [root@shell01 ~]# nmap -p22 10.0.0.7|grep 22/ |awk '{print $2}' open [root@shell01 scripts]# vim for-7.sh #!/bin/bash #1.调用函数库 [ -f /etc/init.d/functions ] && source /etc/init.d/functions || echo "函数库文件不存在!" #2.清空之前所探测的结果存放的文件 Ip_log=/tmp/ip.log Port_log=/tmp/port.log >$Ip_log >$Port_log #3.进入循环探测 for i in {1..254} do { Ip=10.0.0.$i #测试IP地址的连通性 ping -c1 -W1 $Ip &>/dev/null if [ $? -eq 0 ];then action "$Ip is OK! " /bin/true echo "$Ip is OK! " >>$Ip_log fi } & sleep 0.03 #防止格式错乱,等待下 done wait #等待后台进程完成 echo "IP地址扫描完成..............." echo "端口扫描开始.........." for i in $(awk '{print $1}' $Ip_log) do State=$(nmap -p22 $i |grep 22/ | awk '{print $2}') if [ $State == 'open' ];then action "$i 的22端口是开放的" /bin/true echo "$i Port 22 is Open!" >> $Port_log else action "$i 的22端口没有开放的" /bin/false fi done [root@shell01 scripts]# time sh for-7.sh #通过time可以获取执行时间 10.0.0.2 is OK! [ OK ] 10.0.0.7 is OK! [ OK ] 10.0.0.254 is OK! [ OK ] IP地址扫描完成............... 端口扫描开始.......... 10.0.0.2 的22端口是开放的 [ OK ] 10.0.0.7 的22端口是开放的 [ OK ] 10.0.0.254 的22端口没有开放的 [FAILED] real 0m10.680s user 0m0.771s sys 0m1.065s
#备份world库 mysqldump -uroot -p123 -B world >world.sql #备份world库下的city表 mysqldump -uroot -p123 world city >world_city.sql #备份到哪里 /backup/mysql #备份之后表名称 库名_时间.sql 库名_表名_时间.sql #命令行下进行取库名 [root@shell01 ~]# mysql -uroot -p123 -e "show databases;" |sed 1d information_schema mysql ... #不要schema的库 [root@shell01 ~]# mysql -uroot -p123 -e "show databases;" |sed 1d |grep -v ".*_schema" #取表名 [root@shell01 ~]# mysql -uroot -p123 -e "use wordpress;show tables;" |sed 1d [root@shell01 scripts]# vim for-2.sh #!/bin/bash #1.定义变量 Db_User=root Db_Pass=123 Date=$(date+%F) Db_name=$(mysql -u$Db_User -p$Db_Pass -e "show databases;" |sed 1d |grep -v ".*_schema") for Datebase_Name in $Db_name do #2.判断单独的数据库备份目录是否存在 Back_Dir=/backup/$Database_Name [ -d $Back_Dir ] || mkdir -p $Back_Dir #3.备份数据库 mysqldump -u$Db_User -p$Db_Pass --single-transaction -B $Datebase_Name >$Back_Dir/${Datebase_Name}_${Date}.sql if [ $? -eq 0 ];then echo -e "\033[42;37m${Datebase_Name}数据库备份成功! \033[0m]" else echo -e "\033[41;37m${Datebase_Name}数据库备份失败! \033[0m]" fi #开始备份表 Tb_name=$(mysql -u$Db_User -p$Db_Pass -e "use $Datebase_Name;show tables;" |sed 1d) for Table_Name in $Tb_name do mysqldump -u$Db_User -p$Db_Pass --single-transaction $Datebase_Name $Table_Name >$Back_Dir/${Datebase_Name}_${Table_Name}_${Date}.sql if [ $? -eq 0 ];then echo -e "\033[42;37m${Datebase_Name}数据库下的${Table_Name}表备份成功! \033[0m]" else echo -e "\033[41;37m${Datebase_Name}数据库下的${Table_Name}表备份成功! \033[0m]" fi done done
#26个人,生成1-26的随机数 [root@shell01 scripts]# echo $((RANDOM % 26 + 1)) [root@shell01 scripts]# vim random-2.sh #!/bin/bash #1.定义变量,人员总数 Number=$(wc -l student.txt |awk '{print $1}') #2.进行循环,循环多少次,自定义循环多少次 read -p "请输入你要对脚本进行多少次循环:" Num #3.进行循环 for i in $(seq $Num) do #4.随机取得一个数字,但是此数字不能大于文件的总行数。 Stu_Num=$((RANDOM % $Number + 1)) #5.循环一次,就打印一次人员的名单 sed -n "${Stu_Num}p" student.txt #6.等待0.5秒之后,继续打印 sleep 0.5 done #7.打印出最后一次循环的人员名单 Stu_Name=$(sed -n "${Stu_Num}p" student.txt) echo -e "天选子: \033[32m$Stu_Num\033[0M"
1.主从复制的环境 2.进行判断主从 3.主从正常,输出 4.不正常发邮件报警 5.简单处理一些故障 #发送邮件命令 [root@db02 ~]# echo "test" | mail -s '123' XXX@qq.com #在从库判断主从状态是否正常 mysql -uroot -p123 -e "show slave status\G" |grep "Slave_IO_Runing" |awk '{print $2}' yes mysql -uroot -p123 -e "show slave status\G" |grep "Slave_SQL_Runing" |awk '{print $2}' yes [root@db02 ~]# vim mysql_zhucong.sh #!/bin/bash #1.定义变量 IO_Status=$(mysql -uroot -p123 -e "show slave status\G" |grep "Slave_IO_Runing" |awk '{print $2}') SQL_Status=$(mysql -uroot -p123 -e "show slave status\G" |grep "Slave_SQL_Runing" |awk '{print $2}') #2.判断主从异常情况 if [[ $IO_Status == "Yes" && $SQL_Status == "Yes" ]];then echo "数据库主从复制正常!" else #3.判断IO线程 if [ ! $IO_Status == "Yes" ];then mysql -uroot -p123 -e "show slave status\G" |grep "Last_IO" >/tmp/mysql_io_err.log mail -s "数据库主从复制IP线程出错! $(date +%F-%H:%M) " XXX@qq.com< /tmp/mysql_io_err.log if [ $? -eq 0 ];then echo "数据库主从复制IO线程报错邮件发送成功!" else echo "数据库主从复制IO线程报错邮件发送失败!" fi fi #4.判断SQL线程 出错细致化 if [ ! $SQL_Status == "Yes" ];then SQL_Err_Status=$(mysql -uroot -p123 -e "show slave status\G" |grep "Last_SQL_Errno" |awk '{print $2}') case $SQL_Err_Status in 1007) echo "数据库主从复制SQL线程出现1007错误! 脚本尝试跳过这次错误! " mysql -uroot -p123 -e "stop slave;set global sql_slave_skip_counter=1;start slave;" sleep 3 SQL_Status=$(mysql -uroot -p123 -e "show slave status\G" |grep "Slave_SQL_Runing" |awk '{print $2}') if [ $SQL_Status == "Yes" ];then echo "尝试跳过了这次错误! 数据库主从复制恢复正常!" else mysql -uroot -p123 -e "show slave status\G" |grep "Last_SQL" >/tmp/mysql_sql_err.log mail -s "数据库主从复制SQL线程出错! $(date +%F-%H:%M) " XXX@qq.com< /tmp/mysql_sql_err.log if [ $? -eq 0 ];then echo "数据库主从复制SQL线程报错邮件发送成功!" else echo "数据库主从复制SQL线程报错邮件发送失败!" fi fi ;; 1032) mysql -uroot -p123 -e "show slave status\G" |grep "Last_SQL" >/tmp/mysql_sql_err.log mail -s "数据库主从复制SQL线程出错! $(date +%F-%H:%M) " XXX@qq.com< /tmp/mysql_sql_err.log if [ $? -eq 0 ];then echo "数据库主从复制SQL线程报错邮件发送成功!" else echo "数据库主从复制SQL线程报错邮件发送失败!" fi ;; *) mysql -uroot -p123 -e "show slave status\G" |grep "Last_SQL" >/tmp/mysql_sql_err.log mail -s "数据库主从复制SQL线程出错! $(date +%F-%H:%M) " XXX@qq.com< /tmp/mysql_sql_err.log if [ $? -eq 0 ];then echo "数据库主从复制SQL线程报错邮件发送成功!" else echo "数据库主从复制SQL线程报错邮件发送失败!" fi exit esac fi fi
循环 until
格式: until CONDITION; do COMMANDS; done until CONDITION; do 循环体 done 说明: 进入条件: CONDITION 为false 退出条件: CONDITION 为true 例: [root@ubuntu2204 ~]# sum=0;i=1;until ((i>100));do let sum+=i;let i++;done;echo $sum 5050 [root@ubuntu2204 ~]# sum=0;i=1;until ! ((i<=100));do let sum+=i;let i++;done;echo $sum 5050
循环控制语句 continue
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
[root@ubuntu2204 ~]# cat continue_for.sh for i in {1..4}; do for j in {a..c};do if [ $j = 'b' ]; then continue 2 #跳过当前循环的上一层循环的此次循环 fi echo $i $j done echo done [root@rocky ~]# sh continue_for.sh 1 a 2 a 3 a 4 a
循环控制语句 break
break [N]:提前结束第N层整个循环,最内层为第1层
[root@ubuntu2204 ~]# cat continue_for.sh for i in {1..4}; do for j in {a..c};do if [ $j = 'b' ]; then break 2 #打破当前循环的上一层循环 fi echo $i $j done echo done [root@rocky ~]# sh continue_for.sh 1 a
循环控制 shift 命令
shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift
[root@ubuntu2204 ~]# cat shift.sh #!/bin/bash until [ -z "$1" ]; do echo "$@ " shift done [root@ubuntu2204 ~]# bash s.sh a b c d e f g a b c d e f g b c d e f g c d e f g d e f g e f g f g g #shift 2 #每次移2位,但如果只剩一位就无法移动,需要做判断 [root@ubuntu2204 ~]# cat shift2.sh #!/bin/bash while [ -n "$1" ];do echo $1 shift 2 if [ $? -ne 0 ];then break fi done
eval内置命令
可以把带变量的命令再次展开
eval执行分两个步骤: 第一步:执行变量的替换。 第二步:执行替换后的命令。 [root@rocky dev]# abc=6 [root@rocky dev]# echo {1..6} 1 2 3 4 5 6 [root@rocky dev]# echo {1..$abc} {1..6} [root@rocky dev]# eval echo {1..$abc} 1 2 3 4 5 6