Shell阶段05 for循环, 示例(批量创建用户, 批量探测主机脚本,分库分表备份, 随机点名, 判断主从异常), shell批量执行

循环语句之for循环

方式一
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

 

For循环场景示例

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

 

posted @ 2024-05-29 14:37  战斗小人  阅读(75)  评论(0编辑  收藏  举报