shell 练习题-05

发布于 2018-05-21  98 次阅读


01

题目:

在服务器上,写一个监控脚本。

每隔 10s 去检测一次服务器上的 httpd 进程数,如果大于等于 500 的时候,就需要自动重启一下 apache 服务,并检测启动是否成功?

若没有正常启动还需再一次启动,最大不成功数超过 5 次则需要发邮件通知管理员,并且以后不需要再检测!

如果启动成功后,1 分钟后再次检测 httpd 进程数,若正常则重复之前操作(每隔 10s 检测一次),若还是大于等于 500,那放弃重启并需要发邮件给管理员,然后自动退出该脚本。假设其中发邮件脚本为之前咱们使用的 mail.py

脚本:

#!/bin/bash

check()

{

    n=0

    for i in `seq 1 5`

#这里定义了这个 check 函数的内容会循环运行 5 次

    do

    /usr/local/apache2/bin/apachectl restart 2> /tmp/apache.err

#因为 check 函数是由 while 循环语句块调用的,在 while 循环语句块中,是当重启 httpd 后,查询上一句命令的运行状态不为 0(则运行失败),才会运行 check 函数,这里就需要再次重启 httpd,并把错误记录输出到指定文件

    if [ $? -ne 0 ]

    then

        n=$[$n+1]

    else

        break

    fi

#这里判断再次重启 httpd 的语句是否运行正确,即是否为 0,不为 0 的话就"$n+1"并返回上面再次重启 httpd,如果为 0 的话,则跳出 for 循环,继续运行 while 循环语句块中接下来的操作

    done

    if [ $n -eq 5 ]

    then

        python mail.py "runfali@outlook.com" "httpd service down" `cat /tmp/apache.err`

        exit

    fi

#这里还需要判断$n 的值是否等于 5,如果等于 5 的话,就直接发告警邮件,结束整个脚本,若不等于 5 的话,则继续运行循环,直至运行成功(这时也会跳出 for 循环,继续运行 while 循环语句块中接下来的操作)或者等于 5 为止

}

#定义一个函数 check,这个函数主要功能是定义计数器



while [1]

do

    t_n=`ps -C httpd --no-heading | wc -l`

#取得 httpd 的进程数

    if [ $t_n -ge 500 ]

    then

        /usr/local/apache2/bin/apachectl restart

#这里先判断 httpd 进程数是否大于等于 500,是的话就重启 httpd

        if [ $? -ne 0 ]

        then

            check

        fi

        sleep 60

#这里判断上一句命令的运行状态是否不等于 0,是的话就调用 check 函数,然后休眠 60 秒,其中 check 函数会把 httpd 重启 5 次(上一句命令的运行状态使用$?判断,为 0 则运行成功,不为 0 则运行失败)

        t_n=`ps -C httpd --no-heading | wc -l`

#这里接着重启 httpd 后,再次获取 httpd 的进程数

        if [ $t_n -ge 500 ]

        then

            python mail.py "runfali@outlook.com" "httpd service somth wrong" "the httpd process is budy."

            exit

        fi

#再次判断 httpd 的进程数是否大于等于 500,还是大于等于 500 的话,就直接把邮件并退出整个脚本

    fi

    sleep 10

#假如再次获取 httpd 的进程数不大于等于 500 的话,就休眠 10 秒,重新运行整个脚本

done

#使用 while 循环判断 httpd 的进程数

02

题目:

需求: 根据 web 服务器上的访问日志,把一些请求量非常高的 ip 给拒绝掉!

分析: 我们要做的,不仅是要找到哪些 ip 请求量不合法,并且还要每隔一段时间把之前封掉的 ip(若不再继续请求了)给解封。 所以该脚本的关键点在于定一个合适的时间段和阈值。

比如, 我们可以每一分钟去查看一下日志,把上一分钟的日志给过滤出来分析,并且只要请求的 ip 数量超过 100 次那么就直接封掉。 而解封的时间又规定为每半小时分析一次,把几乎没有请求量的 ip 给解封!

参考日志文件片段:

47.104.50.22 117.34.28.13 [15/May/2018:00:03:25 +0800] www.itwordsweb.com "/" 200 "-" "Baidu-YunGuanCe-SLABot(ce.baidu.com)"

117.34.28.13 - [15/May/2018:00:03:26 +0800] www.itwordsweb.com "/" 200 "-" "Baidu-YunGuanCe-SLABot(ce.baidu.com)"

140.205.9.21 203.208.60.177 [15/May/2018:00:03:43 +0800] www.itwordsweb.com "/?s=%E8%8A%B1%E7%94%9F%E6%97%A5%E8%AE%B0v1.0%E3%80%90%E5%A8%81%E4%BF%A1gylm555%E3%80%91" 200 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

140.205.9.57 131.253.25.236 [15/May/2018:00:03:53 +0800] www.itwordsweb.com "/wp-content/plugins/wpdiscuz/utils/captcha/captcha.php?key=c5af9a50ce38a8" 200 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b"

47.104.50.42 131.253.27.16 [15/May/2018:00:03:55 +0800] www.itwordsweb.com "/wp-content/plugins/wpdiscuz/utils/captcha/captcha.php?key=c5af9a50ce39cb" 200 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b"

47.104.50.56 131.253.25.253 [15/May/2018:00:04:01 +0800] www.itwordsweb.com "/wp-content/plugins/wpdiscuz/assets/third-party/font-awesome-5.0.6/webfonts/fa-solid-900.ttf" 200 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b"

脚本:

#!/bin/bash

logfile=/data/logs/access.log

d1=`date -d "-1 minute" +%H:%M`

#获取前一分钟的时间

d2=`date +%M`

#获取当前分钟

ipt=/sbin/iptables

ips=/tmp/ips.txt

block()

{

    grep "$d1:"$logfile | awk '{print $1}' | sort -n | uniq -c | sort -n > $ips

ips=/tmp/ips.txt

block()

{

    grep "$d1:"$logfile | awk '{print $1}' | sort -n | uniq -c | sort -n > $ips

#使用 grep 截取前一分钟的日志信息,使用 awk 截取第一列,然后使用 sort -n 按数字顺序排序,再使用 uniq -c 删除重复数据并统计相同的数据数目,>最后再使用 sort -n 按数字顺序排序并写入到指定文件

    for ip in `awk '$1>100 {print $2}' $ips`

#使用 for 循环,获取第一列数值大于 100 的 ip 并赋值给 ip 变量(在上一步中,把每个 ip 的重复数和地址都写入到了指定文件了)

    do

        $ipt -I INPUT -p tcp --dport 80 -s $ip -j REJECT

        echo "`date +%F-%T`$ip" >> /tmp/badip.txt

    done

#把获取到的 ip 变量设置为禁止访问 80 端口(这时会是一个 ip 地址,而这个 ip 地址在上一分钟出现超过了 100 次)

#最后还要把这个被禁止的 ip 地址写入到指定文件中

}

#定义封 IP 的函数 block

unblock()

{

    for i in `$ipt -nvL INPUT --line-numbers | grep '0.0.0.0/0' | awk '$2<10 {print $1}' | sort -nr`

#列出 iptables 中的 INPUT 表的信息并显示序号,使用 grep 截取跟 ip 有关的信息,使用 awk 截取数据包小于 10 的信息并把序号打印出来,使用 sort -nr 以数字排序(这里是倒序排序),最后把得出的序号一个一个赋值给变量 i

    do

        $ipt -D INPUT $i

    done

    $ipt -Z

#使用 iptables -D 把获取到的变量 i(此时是一个序号)删除,最后还要使用 iptables -Z 把 iptables 的计数器清零

}

#定义解封 IP 的函数 unblock

if [ $d2 == "00" ] || [ $d2 == "30" ]

#这里判断当前时间的分钟是否是 00 分或者 30 分

then

    unlock

    lock

#是 00 分或者 30 分的话,就先运行解封 ip 的函数,再运行封 ip 的函数

else

    lock

#不是 00 分或者 30 分的话,就运行封 ip 的函数

fi

03

题目:

请详细查看如下几个数字的规律,并使用 shell 脚本输出后面的十个数字。

10 31 53 77  105 141 …….

试题解析:

我想大多数人都会去比较这些数字的差值:

10  31  53  77  105  141

21   22   24   28   36

但是这个差值看,并没有什么规律,而我们再仔细看的时候,发现这个差值的差值是有规律的:

10  31  53  77  105  141

21   22   24   28   36

1      2     4     8

脚本:

#!/bin/bash

m=10

n=20

for i in `seq 0 15`

do

    echo i=$i

    echo m=$m

    echo n=$n

    echo x=$x

    x=$[2**i]

    m=$[$m + $n + $x]

    echo $m

done