每日磁盘情况

【题目要求】

请按照这样的日期格式(xxxx-xx-xx)每日生成一个文件,

例如生成的文件名为2017-12-20.log, 

并且把磁盘的使用情况写到到这个文件中,

不用考虑cron,仅仅写脚本即可

【习题答案】

本题答案:


#! /bin/bash

d=`date +%F`

logfile=$d.log

df -h > $logfile

需求升级:


#!/bin/bash

d=`date +%F`

dir=/data/logs/disklog

if [ ! -d $dir ]

then

    mkdir -p $dir

fi

df -h > $dir/$d.log

find $dir/ -mtime +365 |xargs rm

统计IP访问流量

题目要求

有日志1.log,部分内容如下

112.111.12.248 – [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com “/seccode.php?update=0.5593110133088248″ 200″http://formula-x.haotui.com/registerbbs.php” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)”
61.147.76.51 – [25/Sep/2013:16:08:31 +0800]xyzdiy.5d6d.com “/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71″ 301″http://xyzdiy.5d6d.com/thread-1435-1-23.html” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)”

统计出每个IP访问量有多少

核心要点

awk、sort、uniq命令

参考答案

awk '{print $1}' 1.log|sort |uniq -c |sort -n -r

所有进程占用内存和

题目要求

写一个脚本计算一下linux系统所有进程占用内存大小的和。

核心要点

  • ps命令用法
  • for循环
  • 加法运算

参考答案

sum=0
#过过滤掉TIME COMMAND的行
mem=$(ps aux|grep -v 'TIME COMMAND'|awk '{print $4}')

for i in $mem
do
        sum=$(echo "$sum+$i"|bc)  #小数计算要用bc命令
done
echo "所有进程一共占用$sum内存"

机器存活状态

题目要求

设计一个脚本,监控远程的一台机器(假设ip为180.163.26.39)的存活状态,当发现宕机时发一封邮件给你自己。

核心要点

ping -c10 180.163.26.39 通过ping来判定对方是否在线

发邮件脚本

参考答案

#ping 服务器宕机情况
ip=www.baidu.com
n=$(ping $ip -c5 |grep packets|awk -F "%" '{print $1}' |awk '{print $NF}')
if [ -z "$n" ]
then
    echo "脚本有问题。"
    python3 /root/py/mail.py  $mail "检测机器存活脚本$0有问题" "获取变量的值为空"
    exit
else
        n1=$(echo $n|sed 's/[0-9]//g')
    if [ -n "$n1" ]
    then
        echo "脚本有问题。"
        python3 /root/py/mail.py  $mail "检测机器存活脚本$0有问题" "获取变量的值不是纯数字"
        exit
    fi
fi

mail=71718132@qq.com

while :

do
   if [ $n -gt 50 ];then
           python3 /root/py/mail.py $mail  "机器宕机" "丢包率是$n%"
 else
       echo "服务器没有问题"
       break
   fi
sleep 10
done

找文件改名

题目要求

找到/123目录下所有后缀名为.txt的文件

 1. 批量修改.txt为.txt.bak

 2. 把所有.bak文件打包压缩为123.tar.gz

 3. 批量还原文件的名字,即把增加的.bak再删除

核心要点

  • find用来查找所有.txt文件
  • tar打包一堆文件
  • 还原文件名用for循环

参考答案


#!/bin/bash

find /123/ -type f -name "*.txt" > /tmp/txt.list 

for f in `cat /tmp/txt.list`

do

    mv $f  $f.bak

done

#find /123/ -type f -name *.txt |xargs -i mv {} {}.bak 

#find /123/ -type f -name *.txt -exec mv {} {}.bak \;

for f in `cat /tmp/txt.list`

do

    echo $f.bak

done > /tmp/txt.bak.list 

tar -czvf 123.tar.gz `cat /tmp/txt.bak.list |xargs `

for f in `cat /tmp/txt.list`

do 

    mv $f.bak $f

done 

判断80端口存活情况

题目要求

写一个脚本,判断本机的80端口(假如服务为httpd)是否开启着,如果开启着什么都不做,如果发现端口不存在,那么重启一下httpd服务,
并发邮件通知你自己。脚本写好后,可以每一分钟执行一次,也可以写一个死循环的脚本,30s检测一次。

核心要点

  • 检测80端口使用nmap -p 80 127.0.0.1或者netstat -lntp|grep -w 80
  • 重启httpd服务的命令要知道
  • 发邮件脚本依然使用mail.py

参考答案

#!/bin/bash
m=123@123.com
while :
do
    n=`netstat -lntp |grep ':80 '|wc -l`
    if [ $n -eq 0 ]
    then
        /usr/local/apache2/bin/apachectl -k restart 2>/tmp/apache.err
        python mail.py $m "80端口关闭" "已经重启httpd服务"
        pn=`pgrep -l httpd|wc -l`
    if [ $pn -eq 0 ]
    then
        python mail.py $m "httpd重启失败" "`head -1 /tmp/apache.err`"
    fi
    fi
    
    sleep 30
done

备份数据库并传到远程服务器

题目要求

设计一个shell脚本来备份数据库,首先在本地服务器上保存一份数据,然后再远程拷贝一份,本地保存一周的数据,远程保存一个月。

假定,我们知道mysql root账号的密码,要备份的库为discuz,本地备份目录为/bak/mysql, 远程服务器ip为192.168.123.30,
远程提供了一个rsync服务,备份的地址是 192.168.123.30::backup  . 写完脚本后,需要加入到cron中,每天凌晨3点执行。

核心要点

  • 备份数据库的命令
  • 同步到远程去的命令
  • 本地一周,可以用date +%w做为后缀,远程一个月可以用date +%d做为后缀

参考答案

#!/bin/bash
d1=`date +%w`
d2=`date +%d`
local_bakdir=/bak/mysql
remote_bakdir=192.168.123.30::backup

exec 1> /tmp/mysqlbak.log  2>/tmp/mysqlbak.err
echo "mysql bakcup begin at `date`"
mysqldump -uroot -pxxxx discz > $local_bakdir/discuz.sql.$d1
rsync -az $local_bakdir/discuz.sql.$d1 $remote_bakdir/discuz.sql.$d2
echo "mysql backup end at `date`"

检查nginx 502状态

题目要求

服务器上跑的是LNMP环境,近期总是有502现象。502为网站访问的状态码,200正常,502错误是nginx最为普遍的错误状态码。

由于502只是暂时的,并且只要一重启php-fpm服务则502消失,但不重启的话,则会一直持续很长时间。

所以有必要写一个监控脚本,监控访问日志的状态码,一旦发生502,则自动重启一下php-fpm。

我们设定:

1)access_log  /data/log/access.log

2)脚本死循环,每10s检测一次(假设每10s钟的日志条数为300左右)

3)重启php-fpm的方法是  /etc/init.d/php-fpm restart

核心要点

  • 用curl检测状态码是否是502或者通过分析访问日志判断状态码的比率
  • 重启php-fpm服务的命令

参考答案

#!/bin/bash
log=/data/log/access.log
while :
do
502_n=`tail -n 300 $log |grep -c ' 502 '`
if [ -z "$502_n" ]
then
    exit
fi

if [ $502_n -gt 100 ]
then
    /etc/init.d/php-fpm restart >/dev/null 2>/tmp/php-fpm.err
    fpm_p_n=`pgrep -l php-fpm|wc -l`
    if [ $fpm_p_n -eq 0 ]
    then
        python mail.py xxx@xx.com "php-fpm重启失败" "`head -1 /tmp/php-fpm.err`"
        exit
    fi
fi
sleep 10
done

sed命令包含字母行删掉

题目要求

把一个文本文档的前5行中包含字母的行删除掉,同时把6到10行中的全部字母删除掉。

核心要点

sed命令

参考答案

#!/bin/bash
sed -n '1,5'p 1.txt |sed '/[a-zA-Z]/d'
sed '1,5d' 1.txt |sed '1,5s/[a-zA-Z]//g'

找出字母数小于6的单词

题目要求

用shell打印下面这句话中字母数小于6的单词。
Bash also interprets a number of multi-character options.

核心要点

  • for循环遍历所有单词
  • wc -L获取字符串长度

参考答案

#!/bin/bash
c="Bash also interprets a number of multi-character options."
n=`echo $c|awk -F '[ +-.]' '{print NF}'`
for ((i=1;i<$n;i++))
do
    l=`echo $c|awk -F '[ +-.]' -v j=$i '{print $j}'|wc -L`
    if [ $l -lt 6 ]
    then
        echo $c|awk -F '[ +-.]' -v j=$i '{print $j}'
    fi
done

case按数字执行对应命令

题目要求

写一个脚本实现如下功能: 
输入一个数字,然后运行对应的一个命令。

显示命令如下:

cmd meau*  1 - date 2 - ls 3 - who 4 - pwd
当输入1时,会运行date, 输入2时运行ls, 以此类推。

核心要点

  • case判断

参考答案

#!/bin/bash
echo "*cmd meau**  1 - date 2 - ls 3 - who 4 - pwd"
read -p "Please input a number: " n
if [ -z "$n" ]
then
    echo "请输入一个纯数字,范围1-4."
    exit
fi

n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
    echo "请输入一个纯数字,范围1-4."
    exit
fi

case $n in 
    1)
    date
    ;;
    2)
    ls
    ;;
    3)
    who
    ;;
    4)
    pwd
    ;;
    *)
    echo "请输入1-4的数字"
        ;;
esac

批量创建用户产生随机密码

题目要求

用shell脚本实现如下需求:

添加user_00 – user_09 10个用户,并且给他们设置一个随机密码,密码要求10位包含大小写字母以及数字,注意需要把每个用户的密码记录到一个日志文件里。
 
提示:

  1. 随机密码使用命令 mkpasswd
  2. 在脚本中给用户设置密码,可以使用echo 然后管道passwd命令

核心要点

  • seq实现数字递增
  • mkpasswd产生随机字符

参考答案

#!/bin/bash
for i in `seq -w 00 09`   #-w选项:指定输出数字同宽
do
    useradd user_$i
    p=`mkpasswd -l 10 -s 0 `   #产生随机密码,mkpasswd命令,yum install expect
    echo "user_$i $p" >> /tmp/pass.tmp
    echo $p |passwd --stdin user_$i
done

检测apache服务,发送邮件

题目要求

在服务器上,写一个监控脚本,要求如下:

  1. 每隔10s去检测一次服务器上的httpd进程数,如果大于等于500的时候,就需要自动重启一下apache服务,并检测启动是否成功?
  2. 若没有正常启动还需再一次启动,最大不成功数超过5次则需要立即发邮件通知管理员,并且以后不需要再检测!
  3. 如果启动成功后,1分钟后再次检测httpd进程数,若正常则重复之前操作(每隔10s检测一次),若还是大于等于500,那放弃重启并需要发邮件给管理员,然后自动退出该脚本。假设其中发邮件脚本为之前使用的mail.py

核心要点

  • pgrep -l httpd或者ps -C httpd --no-heading检查进程
  • for循环5次计数器

参考答案

#!/bin/bash
check_service()
{
    n=0
    for i in `seq 1 5`
    do
        /usr/local/apache2/bin/apachectl restart 2>/tmp/apache.err
        if [ $? -ne 0 ]
        then
            n=$[$n+1]
        else
            break
        fi
    done
    if [ $n -eq 5 ]
    then
        ##下面的mail.py参考https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py
        python mai.py "123@qq.com" "httpd service down" `cat /tmp/apache.err`
        exit
    fi
}   
while true
do
    t_n=`ps -C httpd --no-heading |wc -l`
    if [ $t_n -ge 500 ]
    then
        /usr/local/apache2/bin/apachectl restart
        if [ $? -ne 0 ]
        then
            check_service
        fi
        sleep 60
        t_n=`ps -C httpd --no-heading |wc -l`
        if [ $t_n -ge 500 ]
        then
            python mai.py "123@qq.com" "httpd service somth wrong" "the httpd process is busy."
            exit
        fi
    fi
    sleep 10
done

web访问日志访问高的IP拒绝掉

题目要求

需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉!并且每隔半小时把不再发起请求或者请求量很小的ip给解封。
 
假设: 

  1. 一分钟内请求量高于100次的IP视为不正常请求。
  2. 访问日志路径为/data/logs/access_log。

用第2例中的1.log作为演示日志

核心要点

  • 统计ip访问次数,排序
  • 如何标记每隔半小时
  • iptables计数器是一个重要的判断指标
  • 函数(封IP、解封IP)

参考答案

#!/bin/bash
block_ip()
{
t1=`date -d "-1 min" +%Y:%H:%M`
log=/data/logs/access_log

egrep "$t1:[0-9]+" $log > /tmp/tmp_last_min.log
awk '{print $1}' /tmp/tmp_last_min.log |sort -n |uniq -c|sort -n |awk '$1>100 {print $2}' > /tmp/bad_ip.list 
n=`wc -l /tmp/bad_ip.list|awk '{print $1}'`
if [ $n -ne 0 ]
then
    for ip in `cat /tmp/bad_ip.list`
    do
    iptables -I INPUT -s $ip -j REJECT
    done
fi
}

unblock_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
    for ip in `cat /tmp/good_ip.list`
    do
    iptables -D INPUT -s $ip -j REJECT
    done
    fi
    iptables -Z
}

t=`date +%M`
if [ $t == "00" ] || [ $t == "30" ]
then
   unblock_ip
   block_ip
else
   block_ip
fi

找出数字规律输出后面的数字

题目要求

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

10 31 53 77  105 141 …….

核心要点

  • 计算两个数值之间的差值

参考答案

#!/bin/bash
x=10
y=21
for i in `seq 0 15`
do 
    echo $x
    x=$[$x+$y]
    z=$[2**$i]
    y=$[$y+$z]
done

检测磁盘分区和inode使用率

题目要求

写一个shell脚本,检测所有磁盘分区使用率和inode使用率并记录到以当天日期为命名的日志文件里,当发现某个分区容量或者inode使用量大于85%时,发邮件通知你自己。

参考答案

#!/bin/bash
dir=/tmp/disk
d=`date +%F`
mail=123@123.com

[ -d $dir ] || mkdir $dir

df >> $dir/$d.log
df -i >> $dir/$d.log

df|sed '1d' |awk -F ' +|%' '$5>=85 {print $7}' > $dir/df.tmp
df -i|sed '1d' |awk -F ' +|%' '$5>=85 {print $7}' > $dir/df_i.tmp

n1=`wc -l $dir/df.tmp|awk '{print $1}'`
n2=`wc -l $dir/df_i.tmp|awk '{print $1}'`

tag=0
if [ $n1 -gt 0 ]
then
    if [ $n2 -gt 0 ]
    then
    tag=11
    else
    tag=10
    fi
else
    if [ $n2 -gt 0 ]
    then
    tag=01
    else
    tag=00
    fi
fi

case $tag in
    11)
    python mail.py $mail "磁盘空间和inode使用率高于85%" "`cat $dir/df.tmp $dir/df_i.tmp|xargs`"
        ;;
    10)
    python mail.py $mail "磁盘空间使用率高于85%" "`cat $dir/df.tmp|xargs`"
    ;;
    01)
    python mail.py $mail "磁盘inode使用率高于85%" "`cat $dir/df_i.tmp|xargs`"
    ;;
    *)
    ;;
esac

检测目录有无上传新文件

题目要求

有一台服务器作为web应用,有一个目录(/data/web/attachment)不定时地会被用户上传新的文件,但是不知道什么时候会上传。所以,需要我们每5分钟做一次检测是否有新文件生成。

请写一个shell脚本去完成检测。检测完成后若是有新文件,还需要将新文件的列表输出到一个按年、月、日、时、分为名字的日志里。

参考答案

#!/bin/bash
basedir=/data/web/attachment
t=`date +%Y%m%d%H%M`

find $basedir/ -type f -mmin -5 > /tmp/file.list
n=`wc -l /tmp/file.list|awk '{print $1}'`
if [ $n -lt 0 ]
then
   mv /tmp/file.list /tmp/$t.list
fi

常用命令TOP10

题目要求

写一个shell脚本来看看你使用最多的命令是哪些,列出你最常用的命令top10。

参考答案

cat ~/.bash_history |sort |uniq -c |sort -nr |head

histoy |awk '{print $2}'|sort |uniq -c |sort -nr |head

curl网站是否正常

题目要求

写一个shell脚本,通过curl -I 返回的状态码来判定所访问的网站是否正常。
比如,当状态码为200时,才算正常。

参考答案

#!/bin/bash
#这个脚本用来判断一个网址是否正常
#作者:猿课-阿铭 www.apelearn.com
#日期:2018-11-01

url="http://www.apelearn.com/index.php"
mail_user=306798658@qq.com

code=`curl -I $url 2>/tmp/curl.err|head -1|awk '{print $2}'`
if [ -z "$code" ]
then
    python mail.py $mail_user "$url访问异常" "`cat /tmp/curl.err`"
    exit
elif [ $code != "200" ]
then
    curl -I $url &> /tmp/curl.log
    python mail.py $mail_user "$url访问异常 状态码$code" "`/tmp/curl.log`" 
fi

打包小于5kb的文件

题目要求

将用户家目录(考虑到执行脚本的用户可能是普通用户也可能是root)下面小于5KB的文件打包成tar.gz的压缩包,并以当前日期为文件名前缀,例如,2018-03-15.tar.gz。

参考答案

#!/bin/bash
#这个脚本用来打包用户家目录下小于5k的文件

t=`date +%F`
cd $HOME
tar czf $t.tar.gz `find ./ -type f -size -5k|xargs`

统计10点到12点来访IP最多

题目要求

已知nginx访问的日志文件在/usr/local/nginx/logs/access.log内,请统计下早上10点到12点 来访ip最多的是哪个?

参考日志


111.199.186.68 -- [15/Sep/2017:09:58:37 +0800]  "//plugin.php?id=security:job" 200 "POST //plugin.php?id=security:job HTTP/1.1""http://a.lishiming.net/forum.php?mod=viewthread&tid=11338&extra=page%3D1%26filter%3Dauthor%26orderby%3Ddateline" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36"

203.208.60.208 -- [15/Sep/2017:09:58:46 +0800] "/misc.php?mod=patch&action=ipnotice&_r=0.05560809863330207&inajax=1&ajaxtarget=ip_notice" 200 "GET /misc.php?mod=patch&action=ipnotice&_r=0.05560809863330207&inajax=1&ajaxtarget=ip_notice HTTP/1.1""http://a.lishiming.net/forum.php?mod=forumdisplay&fid=65&filter=author&orderby=dateline" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36"

参考答案


#!/bin/bash

#这个脚本用来分析Nginx访问日志

export LANG=en

log="/usr/local/nginx/logs/access.log"

t=`date +%d/%b/%Y:1[01]:[0-5][0-9]:`

egrep "$t" $log|awk '{print $1}' |sort -n |uniq -c |sort -n |tail -1 |awk '{print $2}'

题目要求

将文件内所有的单词的重复次数计算出来,只需要列出重复次数最多的10个单词。

参考答案


#!/bin/bash

#这个脚本用来找出重复的单词


for w in `sed 's/[^a-zA-Z]/ /g' 1.txt`

do

    echo $w

done |sort |uniq -c |sort -nr|head

把a文件有的b文件没有的行找出来

题目要求

有两个文件a.txt和b.txt,需求是,把a.txt中有的但b.txt中没有的行找出来,并写入到c.txt,然后计算c.txt文件的行数。

参考答案


#!/bin/bash

#这个脚本用来比较文件差异


cat a.txt|while read line

do

    if ! grep -q "$line" b.txt

    then

echo $line

    fi

done >c.txt

wc -l c.txt

进程名字中含有"aming"的进程关闭

题目要求

把当前用户下所有进程名字中含有"aming"的进程关闭。

参考答案


#!/bin/bash

#这个脚本用来杀进程

ps -u $USER|awk '$NF ~ /aming/ {print $1}' |xargs kill

监控服务器CPU使用率

题目要求

用shell写一个监控服务器cpu使用率的监控脚本。

参考答案

#!/bin/bash
#这个脚本用来计算CPU使用率
while :

do

    cpu_i=`top -bn1 |grep 'Cpu(s):'|sed 's/^%//'|awk -F ' +|%' '{print $8}'`

    cpu_u=`echo 100-$cpu_i|bc`

    if [ $cpu_u -gt 90 ]

    then

       m_mail cpu  #发送邮件 函数没写

    fi

    sleep 60

done

自动登录服务器杀掉tomcat 进程

题目要求

linux系统中,目录/root/下有一个文件ip-pwd.ini,内容如下:


10.111.11.1,root,xyxyxy

10.111.11.2,root,xzxzxz

10.111.11.3,root,123456

10.111.11.4,root,xxxxxx

......

文件中每一行的格式都为linux服务器的ip,root用户名,root密码,请用一个shell批量将这些服务器中的所有tomcat进程kill掉。

参考答案


#!/bin/bash

#这个脚本用来批量杀tomcat进程

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-12

cat > kill_tomcat.expect <<EOF

#!/usr/bin/expect

set passwd [lindex \$argv 0]

set host [lindex \$argv 1]

spawn ssh root@\$host

expect {

    "yes/no" { send "yes\r"; exp_continue}

    "password:" { send "\$passwd\r" }

}

expect "]*"

send "killall java\r"

expect "]*"

send "exit\r"

EOF

chmod a+x kill_tomcat.expect

cat ip-pwd.ini|while read line

do

    ip=`echo $line |awk -F ',' '{print $1}'`

    pw=`echo $line |awk -F ',' '{print $3}'`

    ./kill_tomcat.expect $pw $ip

done

等额本金和等额本息

题目要求

贷款有两种还款的方式:等额本金法和等额本息法,简单说明一下等额本息法与等额本金法的主要区别:

等额本息法的特点是:每月的还款额相同,在月供中"本金与利息"的分配比例中,前半段时期所还的利息比例大、本金比例小,还款期限过半后逐步转为本金比例大、利息比例小。所支出的总利息比等额本金法多,而且贷款期限越长,利息相差越大。

等额本金法的特点是:每月的还款额不同,它是将贷款额按还款的总月数均分(等额本金),再加上上期剩余本金的月利息,形成一个月还款额,所以等额本金法第一个月的还款额最多 ,而后逐月减少,越还越少。所支出的总利息比等额本息法少。

两种还款方式的比较不是我们今天的讨论范围,我们的任务就是做一个贷款计算器。其中:

等额本息每月还款额的计算公式是:

每月还款额=[贷款本金×月利率×(1+月利率)^还款月数]÷[(1+月利率)^还款月数-1]

等额本金每月还款额的计算公式是:

每月还款额=贷款本金÷贷款期数+(本金-已归还本金累计额)×月利率

参考答案


#!/bin/bash

#这个脚本用来实现简易的房贷计算器

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-12

read -p "请输入贷款总额(单位:万元):" sum_w

read -p "请输入贷款年利率(如年利率为6.5%,直接输入6.5):" y_r

read -p "请输入贷款年限(单位:年):" y_n

echo "贷款计算方式:"

echo "1)等额本金计算法"

echo "2)等额本息计算法"

read -p "请选择贷款方式(1|2)" type

#贷款总额

sum=`echo "scale=2;$sum_w*10000 " | bc -l`

#年利率

y_r2=`echo "scale=6;$y_r/100 " | bc -l`

#月利率

m_r=`echo "scale=6;$y_r2/12 " | bc -l`

#期数

count=$[$y_n*12]

echo "期次 本月还款额 本月利息 未还款额"

jin()

{

    #月还款本金m_jin=贷款总额sum/期数count

    m_jin=`echo "scale=2;($sum/$count)/1 " | bc -l`

    #定义未还本金r_jin(第一期应该是贷款总额)

    r_jin=$sum

    for((i=1;i<=$count;i++))

    do

        #本月利息m_xi=剩余本金*月利率

        m_xi=`echo "scale=2;( $r_jin*$m_r)/1"|bc -l`

        #本月还款m_jinxi=月还本金m_jin+本月利息m_xi

        m_jinxi=`echo "scale=2;( $m_jin+$m_xi)/1"|bc -l`

        #已还款本金jin=月还本金m_jin*期数i

        jin=`echo "scale=2;( $m_jin*$i)/1"|bc -l`

        #剩余本金r_jin=贷款总额sum-已还本金jin

        r_jin=`echo "scale=2;( $sum-$jin)/1"|bc -l`

        if [ $i -eq $count ]

        then

            #最后一月的还款额应该是每月还款本金+本月利息+剩余本金

            m_jinxi=`echo "scale=2;( $m_jin+$r_jin+$m_xi)/1"|bc -l`

            #最后一月的剩余本金应该是0

            r_jin=0

        fi

        echo "$i  $m_jinxi  $m_xi  $r_jin"

     done   

}

xi()

{

    #每期还款m_jinxi=(贷款总额sum*月利率m_r*((1+月利率m_r)^期数count))/(((1+月利率m_r)^期数count)-1)

    m_jinxi=`echo "scale=2;(($sum*$m_r*((1+$m_r)^$count))/(((1+$m_r)^$count)-1))/1 " | bc -l`

    #定义未还本金r_jin(第一期应该是贷款总额)

    r_jin=$sum

    for((i=1;i<=$count;i++))

    do

        #本期利息m_xi=剩余本金r_jin*月利率m_r

        m_xi=`echo "scale=2;( $r_jin*$m_r)/1"|bc -l`

        #本期本金m_jin=本期本息m_jinxi-本期利息m_xi

        m_jin=`echo "scale=2;($m_jinxi-$m_xi)/1 " | bc -l`

        #未还本金r_jin=上期未还本金r_jin-本期应还本金m_jin

        r_jin=`echo "scale=2;($r_jin-$m_jin)/1 " | bc -l`

        if [ $i -eq $count ]

        then

            #最后一月本息m_jinxi=本期本金m_jin+未还本金r_jin

            m_jinxi=`echo "scale=2;($m_jin+$r_jin)/1 " | bc -l`

            #最后一月的剩余本金应该是0

            r_jin="0.00"

        fi

        echo "$i $m_jinxi $m_xi $r_jin"

    done

}

case $type in

    1) 

        jin

        ;;

    2) 

xi

        ;;

    *) 

exit 1

        ;;

esac

检测磁盘io

题目要求

阿里云的机器,今天收到客服来的电话,说服务器的磁盘io很重。于是登录到服务器查看,并没有发现问题,所以怀疑是间歇性地。正要考虑写个脚本的时候,幸运的抓到了一个线索,造成磁盘io很高的幕后黑手是mysql。此时去show processlist,但未发现有问题的队列。原来只是一瞬间。只好继续来写脚本,思路是,每5s检测一次磁盘io,当发现问题去查询mysql的processlist。

参考答案


#!/bin/bash

#这个脚本用来监控磁盘IO

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-12

if ! while iostat &>/dev/null

then

    yum install -y sysstat

fi

while :

do

    t=`date +%T`

    iostat -xd 1 5 |grep '^sda'> /tmp/io.log

    sum=`awk '{sum=sum+$NF} END {print sum}' /tmp/io.log`

    a=`echo "scale=2;$sum/5"|bc`

    b=`echo $a|cut -d . -f 1`

    if [ $b -gt 90 ]

    then

mysql -uroot -pxxxx -e "show processlist" > mysql_$t.log

    fi

    sleep 1

done 

A服务器文件自动同步到B,C服务器

题目要求

需求背景是:

一个业务,有3台服务器(A,B,C)做负载均衡,由于规模太小目前并未使用专业的自动化运维工具。有新的需求时,开发同事改完代码会把变更上传到其中一台服务器A上。但是其他2台服务器也需要做相同变更。

写一个shell脚本,把A服务器上的变更代码同步到B和C上。

其中,你需要考虑到不需要同步的目录(假如有tmp、upload、logs、caches)

参考答案


#!/bin/bash

#这个脚本用来代码上线

dir=/data/wwwroot/www.aaa.com

B_IP=1.1.1.1

C_IP=2.2.2.2

rs()

{

    rsync -azP --exclude="logs"

    --exclude="tmp" --exclude="upload"

    --exclude="caches" $dir/ $1:$dir/

}

read -p "该脚本将会把本机的$dir下的文件同步到$B_IP和$C_IP上,是否要继续?y|n" c

case $c in 

    y|Y)

rs B_IP

rs C_IP

;;

    n|N)

exit

   ;;

    *)

echo "你只能输入y或者n."

        ;;

esac

tomcat自带脚本无法关掉,shell脚本关掉

题目要求

在生产环境中,经常遇到tomcat无法彻底关闭,也就是说用tomcat自带shutdown.sh脚本无法将java进程完全关掉。所以,需要借助shell脚本,将进程杀死,然后再启动。

写一个shell脚本,实现上述功能。彻底杀死一个进程的命令是 kill -9 pid。

参考答案


#!/bin/bash

#这个脚本用来彻底杀死Tomcat进程

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-14

dir=/usr/local/tomcat/bin/

java_pc()

{

    pgrep java|wc -l

}

cd $dir

./shutdown.sh

count=0

while [ $count -lt 5 ]

do

    n=`java_pc`

    if [ $n -gt 0 ]

    then

killall java

count=$[$count+1]

sleep 1

    else

break

    fi

done

n=`java_pc`

if [ $n -gt 0 ]

then 

    killall -9 java

fi

n=`java_pc`

if [ $n -gt 0 ]

then

    echo "Tomcat无法强制杀死。"

    exit

fi

cd $dir

./startup.sh

查询指定域名的过期时间

题目要求

写一个shell脚本,查询指定域名的过期时间,并在到期前一周,每天发一封提醒邮件。

参考答案


#!/bin/bash

#这个脚本用来检查域名是否到期

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-14

mail_u=admin@admin.com

#当前日期时间戳,用于和域名的到期时间做比较

t1=`date +%s`

#检测whois命令是否存在,不存在则安装jwhois包

is_install_whois()

{

    which whois >/dev/null 2>/dev/null

    if [ $? -ne 0 ]

    then

yum install -y epel-release

        yum install -y jwhois

    fi

}

notify()

{

    #e_d=`whois $1|grep 'Expiry Date'|awk '{print $4}'|cut -d 'T' -f 1`

    e_d=`whois $1|grep 'Expiration'|tail -1 |awk '{print $5}' |awk -F 'T' '{print $1}'`

    #如果e_d的值为空,则过滤关键词'Expiration Time'

    if [ -z "$e_d" ]

    then

        e_d=`whois $1|grep 'Expiration Time'|awk '{print $3}'`

    fi

    #将域名过期的日期转化为时间戳

    e_t=`date -d "$e_d" +%s`

    #计算一周一共有多少秒

    n=`echo "86400*7"|bc`

    e_t1=$[$e_t-$n]

    e_t2=$[$e_t+$n]

    if [ $t1 -ge $e_t1 ] && [ $t1 -lt $e_t ]

    then

        python mail.py  $mail_u "Domain $1 will  to be expired." "Domain $1 expire date is $e_d."

    fi

    if [ $t1 -ge $e_t ] && [ $t1 -lt $e_t2 ]

    then

        python mail.py $mail_u "Domain $1 has been expired" "Domain $1 expire date is $e_d." 

    fi

}

#检测上次运行的whois查询进程是否存在

#若存在,需要杀死进程,以免影响本次脚本执行

if pgrep whois &>/dev/null

then

    killall -9 whois

fi

is_install_whois

for d in aaa.com bbb.com  aaa.cn

do

    notify $d

done

本机公钥到对方机器上

题目要求

写一个shell脚本,当我们执行时,提示要输入对方的ip和root密码,然后可以自动把本机的公钥增加到对方机器上,从而实现密钥认证。

参考答案


#!/bin/bash

#这个脚本用来自动配置密钥认证

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-14

read -p "输入一个IP地址: " ip

read -p "输入此机器的root密码: " pasd

is_install()

{

    if ! rpm -q $1 &>/dev/null

    then

yum installl -y $1

    fi

}

is_install openssh-clients

is_install expect

if [ ! -f ~/.ssh/id_rsa.pub ]

then

    echo -e "\n" |ssh-keygen  -P ''

fi

cat > key.expect <<EOF

#!/usr/bin/expect

set host [lindex \$argv 0]

set passwd [lindex \$argv 1]

spawn ssh-copy-id root@\$host

expect {

    "yes/no" { send "yes\r"; exp_continue}

    "password:" { send "\$passwd\r" }

}

expect eof

EOF

chmod a+x key.expect

./key.expect $ip $pasd

部署mysql主从

题目要求

用shell脚本实现,部署mysql主从,假设两台机器上已经安装了mysql,并且目前无新库。

参考答案


#!/bin/bash

#这个脚本用来配置MySQL主从同步


#!/bin/bash

master_ip=192.168.100.12

slave_ip=192.168.100.13

mysqlc="mysql -uroot -paminglinux"

check_ok()

{

    if [ $? -ne 0 ]

    then

        echo "$1 出错了。"

        exit 1

    fi

}

f_exist()

{

    d=`date +%F%T`

    if [ -f $1 ]

    then

        mv $1 $1_$d

    fi

}

## 设置主mysql配置

if ! grep '^server-id' /etc/my.cnf

then

    sed -i '/^\[mysqld\]$/a\server-id = 1001' /etc/my.cnf

fi

if ! grep '^log-bin.*=.*' /etc/my.cnf

then

    sed -i '/^\[mysqld\]$/a\log-bin = aminglinux' /etc/my.cnf

fi

sed -i '/^log-bin.*/a\binlog-ignore-db = mysql ' /etc/my.cnf

/etc/init.d/mysqld restart

check_ok "主上重启mysql"

## 登录mysql,授权用户、锁表以及show master status。

$mysqlc <<EOF

    grant replication slave on *.* to 'repl'@$slave_ip identified by 'yourpassword';

    flush tables with read lock;

EOF

$mysqlc -e "show master status" > /tmp/master.log

file=`tail -1 /tmp/master.log|awk '{print $1}'`

pos=`tail -1 /tmp/master.log|awk '{print $2}'`

## 创建在从上配置和操作的脚本

f_exist /tmp/slave.sh

cat > /tmp/slave.sh << EOF

#!/bin/bash

if ! grep '^server-id' /etc/my.cnf

then

    sed -i '/^\[mysqld\]$/a\server-id = 1002' /etc/my.cnf

fi

/etc/init.d/mysqld restart

check_ok "从上重启mysql"

$mysqlc  <<EOF

    stop slave;

    change master to master_host="$master_ip", master_user="repl", master_password="yourpassword", master_log_file="$file", master_log_pos=$pos;

    start slave;

EOF 

EOF

## 创建传输slave.sh的expect脚本

f_exist /tmp/rs_slave.expect

cat > /tmp/rs_slave.expect <<EOF

#!/usr/bin/expect

set passwd "aminglinux"

spawn rsync -a /tmp/slave.sh root@$slave_ip:/tmp/slave.sh

expect {

    "yes/no" { send "yes\r"}

    "password:" { send "\$passwd\r" }

}

expect eof

EOF

## 执行expect脚本

chmod +x /tmp/rs_slave.expect

/tmp/rs_slave.expect

check_ok "传输slave.sh"

## 创建远程执行命令的expect脚本

f_exist /tmp/exe.expect

cat > /tmp/exe.expect <<EOF

#!/usr/bin/expect

set passwd "aminglinux"

spawn ssh root@$slave_ip

expect {

    "yes/no" { send "yes\r"}

    "password:" { send "\$passwd\r" }

}

expect "]*"

send "/bin/bash /tmp/slave.sh\r"

expect "]*"

send "exit\r"

EOF

## 执行expect脚本

chmod +x /tmp/exe.expect

/tmp/exe.expect

check_ok "远程执行slave.sh"

## 主上解锁表

$mysqlc -e "unlock tables"

管理docker容器,启动/关闭/删除容器

题目要求

写一个脚本,实现一键管理docker容器,比如启动、关闭、删除容器等操作。

要求:

1. 脚本支持启动全部容器、关闭全部容器、删除全部容器

2. 需要提示用户如何使用该脚本,需给出范例

参考答案


#!/bin/bash

#这个脚本用来管理docker容器


while true

do

    read -p "请输入你要执行的操作:(stop/start/rm) " opt

    if [ -z "$opt" ]

    then

        echo "请输入要执行的操作。"

        continue

    else

        break

    fi

done

docker ps -a |awk '{print $1}' > /tmp/id.txt

case $opt in

  stop)

    for id in `cat /tmp/id.txt`

    do

        docker stop $id

    done

    ;;

  start)

    for id in `cat /tmp/id.txt`

    do

        docker start $id

    done

  rm)

    for id in `cat /tmp/id.txt`

    do

        read -p "将要删除容器$id,是否继续?(y|n)" c

        case $c in

          y|Y)

            docker rm -f $id

            ;;

          n|N)

            echo "容器$id不会被删除。"

            ;;

          *)

            echo "你只能输入'y'或者'n'。"

            ;;

        esac

    done

  *)

    echo "你只能输入start/stop/rm。"

    ;;

esac

一键安装配置samba服务,共享目录

题目要求

写个shell脚本,能够实现一键安装并配置samba服务,执行该脚本时需要带一个参数,为共享的目录,目录若不存在,需自动创建。

要求,任何人都可以访问,且不用密码,并且目录是只读的。

参考答案


#!/bin/bash

#这个脚本用来一键安装并配置samba


if [ "$#" -ne 1 ]

then

    echo "运行脚本的格式为:$0 /dir/"

    exit 1

else

    if ! echo $1 |grep -q '^/.*'

    then

        echo "请提供一个绝对路径。"

        exit 1

    fi

fi

if ! rpm -q samba >/dev/null

then

    echo "将要安装samba"

    sleep 1

    yum install -y samba

    if [ $? -ne 0 ]

    then

        echo "samba安装失败"

        exit 1

    fi

fi

cnfdir="/etc/samba/smb.conf"

cat >> $cnfdir <<EOF

[share]

        comment = share all

        path = $1

        browseable = yes

        public = yes

        writable = no

EOF

if [ ! -d $1 ]

then

    mkdir -p $1

fi

chmod 777 $1

echo "test" > $1/test.txt

#假设系统为CentOS7

systemctl start smb

if [ $? -ne 0 ]

then

    echo "samba服务启动失败,请检查配置文件是否正确。"

else

    echo "samba配置完毕,请验证。"

fi

新的磁盘自动格式化,搭载

题目要求

我们使用的云主机,购买一块云盘后,默认并不是挂载状态的,用shell写一个脚本,只要把盘符和挂载点以参数的形式提供给脚本,该脚本就可以自动格式化、挂载。

要求:

1. 不用分区,直接格式化

2. 格式化为ext4文件系统类型

参考答案


#!/bin/bash

#这个脚本用来自动挂载磁盘


if [ $# -ne 2 ]

then

    echo "Useage $0 盘符 挂载点, 如: $0 /dev/xvdb /data"

    exit 1

fi

if [ ! -b $1 ]

then

    echo "你提供的盘符不正确,请检查后再操作"

    exit 1

fi

echo "格式化$1"

mkfs -t ext4 $1

if [ ! -d $2 ] ;then

        mkdir -p $2

fi

n=`awk '$NF == "$2"' /etc/fstab|wc -l`

if [ $n -eq 0 ]

then

    echo "$1              $2                      ext4   defaults  0  0" >> /etc/fstab

    mount -a

else

    echo "配置文件/etc/fstab中已经存在挂载点$2,请检查一下."

    exit 1

fi

备份数据库里的100个库

题目要求

需求背景:

领导要求小明备份数据库服务器里面的100个库(数据量在几十到几百G),需要以最快的时间完成(5小时内),并且不能影响服务器性能。

参考答案


#!/bin/bash

#这个脚本用来并发备份数据库

##假设100个库的库名、host、port以及配置文件路径存到了一个文件里,文件名字为/tmp/databases.list

##格式:db1 10.10.10.2 3308 /data/mysql/db1/my.cnf

##备份数据库使用xtrabackup(由于涉及到myisam,命令为inoobackupex)

exec &> /tmp/mysql_bak.log

if ! which innobackupex &>/dev/nll

then

    echo "安装xtrabackup工具"

    rpm -ivh http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm  && \ 

    yum install -y percona-xtrabackup-24

    if [ $? -ne 0 ]

    then

        echo "安装xtrabackup工具出错,请检查。"

        exit 1

    fi

fi

bakdir=/data/backup/mysql

bakuser=vyNctM

bakpass=99omeaBHh

function bak_data {

    db_name=$1

    db_host=$2

    db_port=$3

    cnf=$4

    [ -d $bakdir/$db_name ] || mkdir -p $bakdir/$db_name

    innobackupex --defaults-file=$4  --host=$2  --port=$3 --user=$bakuser --password=$bakpass  $bakdir/$1

        if [ $? -ne 0 ]

        then

            echo "备份数据库$1出现问题。"

        fi

}

fifofile=/tmp/$$

mkfifo $fifofile

exec 1000<>$fifofile

thread=10

for ((i=0;i<$thread;i++))

do

    echo >&1000

done

cat /tmp/databases.list | while read line

do

    read -u1000

    {

        bak_data `echo $line`

        echo >&1000

    } &

done

wait

exec 1000>&-

rm -f $fifofile

截取字符

题目要求

利用你学过的知识点,想办法根据要求截取出字符。

字符串var=http://www.aaa.com/root/123.htm

1.取出www.aaa.com/root/123.htm

2.取出123.htm

3.取出http://www.aaa.com/root

4.取出http:

5.取出http://

6.取出root/123.htm

7.取出123

参考答案


#!/bin/bash

#这个脚本用来截取字符串

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-19

var=http://www.aaa.com/root/123.htm

echo "1.取出www.aaa.com/root/123.htm"

echo $var |awk -F '//' '{print $2}'

echo "2.取出123.htm"

echo $var |awk -F '/' '{print $5}'

echo "3.取出http://www.aaa.com/root"

echo $var |sed 's#/123.htm##'

echo "4.取出http:"

echo $var |awk -F '//' '{print $1}'

echo "5.取出http://"

echo $var |awk -F 'www' '{print $1}'

echo "6.取出root/123.htm"

echo $var |awk -F 'com/' '{print $2}'

echo $var |awk -F '/' '{print $4"/"$5}'

echo "7.取出123"

echo $var |sed 's/[^0-9]//g'

字符串合并

题目要求

请把下面的字符串:


zhangsan

y97JbzPru

lisi

5JhvCls6q

xiaowang

Nnr8qt2Ma

laoma

iqMtvC02y

zhaosi

9fxrb4sJD

改为如下:


zhangsan:y97JbzPru

lisi:5JhvCls6q

xiaowang:Nnr8qt2Ma

laoma:iqMtvC02y

zhaosi:9fxrb4sJD

参考答案


#!/bin/bash

#这个脚本用来格式化文本


n=`wc -l test3.txt|awk '{print $1}'`

n2=$[$n/2]

for i in `seq 1 $n2`

do

    i2=$[$i*2]

    j=$[$i2-1]

    l1=`sed -n "$i2"p test3.txt`

    l2=`sed -n "$j"p test3.txt`

    echo $l2:$l1

done

修改rm命令,并做备份

题目要求

linux系统的rm命令太危险,一不小心就会删除掉系统文件。 写一个shell脚本来替换系统的rm命令,要求当删除一个文件或者目录时,都要做一个备份,然后再删除。下面分两种情况,做练习:

1. 简单

假设有一个大的分区/data/,每次删除文件或者目录之前,都要先在/data/下面创建一个隐藏目录,以日期/时间命名,比如/data/.201703271012/,然后把所有删除的文件同步到该目录下面,可以使用rsync -R 把文件路径一起同步

2. 复杂

不知道哪个分区有剩余空间,在删除之前先计算要删除的文件或者目录大小,然后对比系统的磁盘空间,如果够则按照上面的规则创建隐藏目录,并备份,如果没有足够空间,要提醒用户没有足够

的空间备份并提示是否放弃备份,如果用户选择y,则直接删除文件或者目录,如果选择n,则提示未删除,然后退出脚本。

参考答案


1\. 简单

#!/bin/bash

#这个脚本用来自定义rm

#作者:猿课-阿铭 www.apelearn.com

#日期:2018-12-19

filename=$1

big_filesystem=/data/

if [ ! -e $1 ]

then

    echo "$1 不存在,请使用绝对路径"

    exit

fi

d=`date +%Y%m%d%H%M`

read -p "Are U sure delete the file or directory $1? y|n: " c

case $c in 

      y|Y)

          mkdir -p $big_filesystem/.$d && rsync -aR $1 $big_filesystem/.$d/$1 && /bin/rm -rf $1

          ;;

      n|N)

          exit 0

          ;;

      *)

          echo "Please input 'y' or 'n'."

          ;;

esac

2.复杂

#!/bin/bash

#这个脚本用来自定义rm


#!/bin/bash

filename=$1

if [ ! -e $1 ]

then

    echo "$1 不存在,请使用绝对路径"

    exit

fi

d=`date +%Y%m%d%H%M`

f_size=`du -sk $1|awk '{print $1}'`

disk_size=`LANG=en; df -k |grep -vi filesystem|awk '{print $4}' |sort -n |tail -n1`

big_filesystem=`LANG=en; df -k |grep -vi filesystem |sort -n -k4 |tail -n1 |awk '{print $NF}'`

if [ $f_size -lt $disk_size ]

then

    read -p "Are U sure delete the file or directory: $1? y|n: " c

    case $c in 

      y|Y)

          mkdir -p $big_filesystem/.$d && rsync -aR $1 $big_filesystem/.$d/$1 && /bin/rm -rf $1

          ;;

      n|N)

          exit 0

          ;;

      *)

          echo "Please input 'y' or 'n'."

          ;;

     esac

else

    echo "The disk size is not enough to backup the files $1."

    read -p "Do you want to delete $1? y|n: " c

    case $c in

      y|Y)

        echo "It will delete $1 after 5 seconds whitout backup."

        for i in `seq 1 5`; do echo -ne ". "; sleep 1;done

        echo

        /bin/rm -rf $1

        ;;

     n|N)

        echo "It will not delete $1."

        exit 0

        ;;

      *)

        echo "Please input 'y' or 'n'."

        ;;

    esac

fi

标签: shell案例

添加新评论