0
点赞
收藏
分享

微信扫一扫

linux shell脚本练习30-36

向上的萝卜白菜 2024-10-11 阅读 28
shell运维

来自 阿铭linux视频号

练习30 打印方块

写一个shell脚本,交互式,根据提示,需要用户输入一个数字作为参考,最终打印出一个正方形。
正方形的组成使用特殊字符■,可以直接打印出来。
示例,如果用户输入数字为5,则最终显示的效果为
■ ■ ■ ■ ■
■ ■ ■ ■ ■
■ ■ ■ ■ ■
■ ■ ■ ■ ■
■ ■ ■ ■ ■

cat >30.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

read -p "please input a number:" sum
a=`echo $sum | sed 's/[0-9]//g'`
if [ -n "$a" ]
  then 
    echo "请输入一个纯数字"
    exit 1
fi

for n in `seq $sum`
do 
   for m in `seq $sum`
   do
     if [ $m -lt $sum ]
      then 
       echo -n "■ "
      else 
       echo "■"
     fi
   done
done
EOF

练习31 打印三角

用户输入一个数字,然后打印一个三角形,比如用户输入5,打印如下图形:
    ★
   ★ ★
  ★ ★ ★
 ★ ★ ★ ★
★ ★ ★ ★ ★

cat >31.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

#死循环,如果用户输入的不是纯数字,那就重新输入
while true
do
  read -p "please input the lenth: " n
  #判断有没有输入字符
  if [ -z $n ]
    then 
      echo "要输入一个数字"
      continue
     else 
      #用户输入了字符,要判断输入的字符是不是纯数字
       n1=`echo $n | sed 's/[0-9]//g'`
        if [ -n "$n1" ]
          then 
            echo "你输入的不是纯数字,重新输入"
            #如果输入的不是纯数字,再次循环
            continue
           else 
             #如果是纯数字,退出循环
             break
        fi
  fi
done

#i为行,j为列
for i in `seq 1 $n`
do
  #先打印空格,第一行空格为n-1,第二行为n-2,一直到0
  #这里用n-i来表示
  j=$[$n-$i]
  for m in `seq $j`
  do
   #用echo -n为了不换行
   echo -n " "
  done
   #打印完空格,开始打印 ★ + 空格
   #第一行打印1个,第二行打印2个,一直到n个
     for p in `seq 1 $i`
     do
      echo -n "★ "
     done
     #因前面不换行,所以最后要换行,这里直接echo即可
     echo
done
EOF

练习32  监控主机存活

写一个shell脚本,监控远程的一台机器(假设IP为192.168.77.181)的存活状态,当发现宕机时发一封邮件给自己
核心命令
ping -c10 192.168.77.181 

发邮件脚本 
cat >mail2.py<<'EOF'
#!/usr/bin/python
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
import sys
mail_host = 'smtp.163.com'
mail_user = 'abcdefg@xx.com'
mail_pass = '1111111'
mail_postfix = '163.com'
def send_mail(to_list,subject,content):
    me = "zabbix 监控告警平台"+"<"+mail_user+"@"+mail_postfix+">"
    msg = MIMEText(content, 'plain', 'utf-8')
    msg['Subject'] = subject
    msg['From'] = me
    msg['to'] = to_list
    try:
        s = smtplib.SMTP()
        s.connect(mail_host)
        s.login(mail_user,mail_pass)
        s.sendmail(me,to_list,msg.as_string())
        s.close()
        return True
    except Exception,e:
        print str(e)
        return False
if __name__ == "__main__":
    send_mail(sys.argv[1], sys.argv[2], sys.argv[3])
EOF

cat >32.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

IP="192.168.77.181"
email="934352862@qq.com"

n=`ping -c5 $IP| grep 'packet'| awk -F '%' '{print $1}' | awk '{print $NF}'`
if [ -z "$n" ]
 then
   echo "脚本有问题"
   exit 1
  else 
   n1=`echo $n| sed 's/[0-9]//g'`
   if [ -n "$n1" ]
    then 
     echo "脚本有问题"
     exit 1
   fi
fi

if [ $n -ge 20 ]
 then 
  echo "机器$IP宕机,丢包率是${n}%"
  #phthon mail.py $email "机器$IP宕机,丢包率是${n}%"
 else
  echo "机器$IP正常,丢包率是${n}%"
fi
EOF

练习33  备份nysql数据库脚本

写一个shell脚本,用来备份数据库,首先在本地服务器上保存一份数据,然后再远程拷贝一份,本地保存一周的数据,远程保存一个月。
假定,我们知道Mysql root账号的密码,要备份的库为dz,本地备份目录为/bak/mysql,
远程服务器ip为192.168.123.30,远程提供了一个rsync服务,备份地址是192.168.123.30::backup
写完脚本后,需要加入cron中,每天凌晨3点执行,cron这部分不用考虑

cat >33.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

#当脚本执行到某一步有问题,立即退出脚本,后续部分不再执行了
set -e

#%w本周的第几天,新产生的会覆盖旧的,正好保留一周;
d1=`date +%w`
#%d本月的第几天,新的会覆盖旧的,正好保留一月
d2=`date +%d`

local_bakdir=/bak/mysql
remote_bakdir=192.168.123.30::backup

bak()
{
  echo  "mysql backup begin at `date`"
  echo "执行mysqldump,备份文件为$local_bakdir/dz.sql.$d1"
  mysqldump -uroot -p123456 dz >$local_bakdir/dz.sql.$d1
  echo "远程拷贝到$remote_bakdir/dz.sql.$d2"
  rsync -az $local_bakdir/dz.sql.$d1 $local_bakdir/dz.sql.$d2
  echo "mysql backup end at `date`"
}
#bak函数执行过程的日志,输出到日志文件
bak >>${local_bakdir}/mysqlbak.log 2>>${local_bakdir}/mysqlbak.err

#关闭set -e功能
set +e
<<'COMMENT'
set -e命令用于设置shell的退出行为,脚本执行出错,立即退出,而不是继续执行后续的命令
在条件语句(如if或while)中执行的,或者是在后台运行的(使用&),或者是在管道(|)中,那么即使命令失败,set -e也不会导致脚本退出
COMMENT
EOF

练习34  wc -l  行数  wc -L 长度   shell中的变量$i赋给awk中的j

写一个脚本,打印出这句话中字母数小于6的单词
Bash also interprets a number of multi-character options.

cat >34.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

#将这句话赋值给变量c
c="Bash also interprets a number of multi-character options."
#以空白字符或-或.作为分割符,看一共有多少段
#获取单词的个数,+的意思空格可以有多个
n=`echo $c|awk -F '[ +-.]' '{print NF}'`

#这里要注意,最后一段为空,并非单词,需要排除掉
for i in `seq $[$n-1]` 
do 
  #遍历所有单词
  w=`echo $c|awk -F '[ +-.]' -v j=$i '{print $j}'`
  #获取单词的长度
  l=`echo $w|wc -L`
  if [ $l -lt 6 ]
    then 
      echo "单词 $w 长度小于6" 
  fi
done
<<'COMMENT'
awk -v  j=$i  shell中的变量$i赋给awk中的j
wc -l  行数  wc -L 长度
COMMENT
EOF

练习35 检测服务状态

写一个shell监控脚本,要求如下
1)每隔10s去检测一次服务器上的httpd进程数,如果大于等于500的时候,就需要自动重启一下apache服务,并检测启动是否成功
2)若没有正常启动还需再一次启动,最大不成功数超过5次则需要立即发邮件通知管理员,并且以后不需要再检测
3)如果启动成功后,1分钟后再次检测httpd进程数,若正常则重复之前操作(每隔10s检测一次),若还是大于等于500,
那放弃重启并需要发邮件给管理员,然后自动退出该脚本。
4)其中发邮件脚本为mail.py
发邮件脚本 
cat >mail2.py<<'EOF'
#!/usr/bin/python
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
import sys
mail_host = 'smtp.163.com'
mail_user = 'abcdefg@xx.com'
mail_pass = '1111111'
mail_postfix = '163.com'
def send_mail(to_list,subject,content):
    me = "zabbix 监控告警平台"+"<"+mail_user+"@"+mail_postfix+">"
    msg = MIMEText(content, 'plain', 'utf-8')
    msg['Subject'] = subject
    msg['From'] = me
    msg['to'] = to_list
    try:
        s = smtplib.SMTP()
        s.connect(mail_host)
        s.login(mail_user,mail_pass)
        s.sendmail(me,to_list,msg.as_string())
        s.close()
        return True
    except Exception,e:
        print str(e)
        return False
if __name__ == "__main__":
    send_mail(sys.argv[1], sys.argv[2], sys.argv[3])
EOF

cat >35.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

#定义重启并检测apache服务的函数
check_service()
{
  #n为一个计数器,初始值为0
  n=0
  #尝试重启apache 3次
  for i in `seq 1 3`
   do
    /usr/sbin/apachectl restart restart 2>/tmp/apache.err
    if [ $? -ne 0 ]
      then 
        ##如果apache启动不成功,计数器加1
        n=$[$n+1]
        sleep 5
       else
        #如果apache启动成功,直接退出for循环
        break
    fi
   done
   #3次都没有成功,就要发邮件了
   if [ $n -eq 3 ]
     then 
       python mail.py "123@qq.com" "httpd service down" `cat /tmp/apache.err`
       exit 0
   fi
}
#监控脚本为一个死循环,每隔10s检测一次
while true
do
  #计算https进程数量
  p_n=`ps -C httpd --no-heading | wc -l`
  #如果进程数大于等于500
  if [ ${p_n} -ge 500 ]
    then
      #重启apache
      /usr/sbin/apachectl restart restart
      #如果重启失败,需要运行check_service函数,该函数会尝试重启3次,3次都失败则发邮件,并退出脚本
      if [ $? -ne 0 ]
        then 
          check_service
      fi
       #休眠60秒,继续检测httpd进程数
       sleep 60
       p_n=`ps -C httpd --no-heading | wc -l`
       #如果进程数还是大于等于500,则发邮件告警
       if [ ${p_n} -ge 500 ]
         then 
           python mail.py "123@qq.com" "httpd service down" `cat /tmp/apache.err`
           exit 0 
       fi
  fi
  sleep 10
done
EOF

练习36  自动封IP

写一个shell脚本,需求:
根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉
并且每隔半小时把不再发起请求或者请求量很小的ip给解封
假设:一分钟内请求量高于100次的IP视为不正常请求。访问日志路径为/data/logs/access_log
日志示例
192.168.77.1 - - [11/Aug/2024:17:28:24 +0800] "GET / HTTP/1.1" 403 3539 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko
) Chrome/125.0.0.0 Safari/537.36"

cat >36.sh<<'EOF'
#!/bin/bash
#auth:alibaby007
#version:v1
#date:2024-08-08

#定义封IP的函数
block_ip()
{ 
  #上一分钟
  t1=`date -d "-1 min" +%Y:%H:%M`
  log=/data/logs/access_log
  #将上一分钟的日志截取出来定向输入到/tmp/tmp_last_min.log
  egrep "$t1:[0-9]+" $log >/tmp/tmp_last_min.log
  #把IP访问次数超过100次的计算出来,写入到临时文件
  awk '{print $1}' /tmp/tmp_last_min.log | sort -n | uniq -c | awk '$1>100 {print $2}' >/tmp/bad_ip.list
  #看临时文件的行数
  n=`wc -l /tmp/bad_ip.list | awk '{print $1}'`
  #如果临时文件行数为0,说明前面没有过滤出IP,否则就是过滤出来了
  if [ $n -ne 0 ]
   then
     #遍历所有满足条件的IP,然后封掉这些IP
     for ip in `cat /tmp/bad_ip.list`
     do
       iptables -I INPUT -s $ip -j REJECT
     done
  fi
  #删除临时文件
  rm -f tmp/tmp_last_min.log /tmp/bad_ip.list
}
#定义解封IP的函数
unlock_ip()
{
  #将包数少于5个的IP计入IP白名单临时文件里
  iptables -nvL INPUT | sed '1d' | awk '$1<5 {print $8}' >/tmp/good_ip.list
  #计算白名单临时文件行数
  n=`wc -l /tmp/good_ip.list | awk '{print $1}'`
  #如果文件不为空
  if [ $n -ne 0 ]
   then 
     #遍历所有IP,一次解封
     for ip in `cat /tmp/good_ip.list`
     do
       iptables -D INPUT -s $ip -j REJECT
     done
  fi
  #最后需要将iptables统计的流量计数器清空,从零开始
  iptables -Z
  #删除临时文件
  rm -f /tmp/good_ip.list
}
#获取当前时间中的分钟
t=`date +%M`

#如果分红为0或者30,也就是说每隔半小时会执行封IP的函数
#先解封,再封
if [ $t == "00" ] || [ $t == "30" ]
 then 
   unblock_ip
   block_ip
  else
   block_ip
fi
EOF


举报

相关推荐

0 条评论