shell脚本实例(六)

【脚本77】监控cpu使用率

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

  • 思路:
    用top -bn1 命令,取当前空闲cpu百份比值(只取整数部分),然后用100去剑这个数值。

  • 参考代码:

#!/bin/bash

while :
do
    idle=`top -bn1 |sed -n '3p' |awk '{print $5}'|cut -d . -f1`
    use=$[100-$idle]
    if [ $use -gt 90 ]
    then 
        echo "cpu use percent too high."
        #发邮件省略
    fi
    sleep 10
done

【脚本78】获取子进程

  • 说明:
    本shell题目是一个网友在公众号中提问的,正好利用这个每日习题的机会拿出来让大家一起做一做。

给出一个进程PID,打印出该进程下面的子进程以及子进程下面的所有子进程。(只需要考虑子进程的子进程,再往深层次则不考虑)

  • 参考代码:
#!/bin/bash

read -p "please input a pid number: " p
ps -elf > /tmp/ps.log

is_ppid(){
    awk '{print $5}' /tmp/ps.log > /tmp/ps1.log
    if ! grep -qw "$1" /tmp/ps1.log
    then
        echo "PID $1 不是系统进程号,或者它不是父进程"
    return 1
    fi
}

is_ppid $p

if [ $? -eq "1" ]
then
    exit
fi

print_cpid(){
    p=$1
    awk -v p1=$p '$5 == p1 {print $4}' /tmp/ps.log |sort -n |uniq >/tmp/p1.log
    n=`wc -l /tmp/p1.log|awk '{print $1}'`
    if [ $n -ne 0 ]
    then
        echo "PID $p 子进程 pid 如下:"
        cat /tmp/p1.log
    else
    echo "PID $p 没有子进程"
    fi
}

print_cpid $p

for cp in `cat /tmp/p1.log`
do
    print_cpid $cp
done

另外,一条命令查询的方法是:

pstree -p pid

【脚本79】自动添加项目

  • 需求背景:
    服务器上,跑的lamp环境,上面有很多客户的项目,每个项目就是一个网站。 由于客户在不断增加,每次增加一个客户,就需要配置相应的mysql、ftp以及httpd. 这种工作是重复性非常强的,所以用脚本实现非常合适。

mysql增加的是对应客户项目的数据库、用户、密码,ftp增加的是对应项目的用户、密码(使用vsftpd,虚拟用户模式),httpd就是要增加虚拟主机配置段。

  • 参考代码:
#!/bin/bash

webdir=/home/wwwroot
ftpudir=/etc/vsftpd/vuuser
mysqlc="/usr/bin/mysql -uroot -xxxxxx"
httpd_config_f="/usr/local/apache2/conf/extra/httpd-vhosts.conf"

add_mysql_user()
{
        mysql_p=`mkpasswd -s 0 -l 12`
        echo "$pro $mysql_p" >/tmp/$pro.txt
        $mysqlc <<EOF
        grant all on $p.* to "$pro"@'127.0.0.1' identified by "$mysql_p";
EOF
}

add_ftp_user()

{
        ftp_p=`mkpasswd -s 0 -l 12`
        echo "$pro" >> /root/login.txt
        echo "$ftp_p" >> /root/login.txt
        db_load -T -t hash -f /root/login.txt  /etc/vsftpd/vsftpd_login.db
        cd $ftpudir
        cp aaa $pro   //这里的aaa是一个文件,是之前的一个项目,可以作为配置模板
        sed -i "s/aaa/$pro/" $pro  //把里面的aaa改为新的项目名字
        /etc/init.d/vsftpd restart
}

config_httpd()

{
        mkdir $webdir/$pro
        chown vsftpd:vsftpd $webdir/$pro
        echo -e "<VirtualHost *:80> \n     DocumentRoot "/home/internet/www/$pro/" \n     ServerName $dom \n    #ServerAlias \n</VirtualHost> " >> $httpd_config_f
        /usr/local/apache2/bin/apachectl graceful
}

read -p "input the project name: " pro
read -p "input the domain: " dom

add_mysql_user
add_ftp_user
config_httpd

【脚本80】计算器

用shell写一个简易计算器,可以实现加、减、乘、除运算,假如脚本名字为1.sh,执行示例:./1.sh 1 + 2

  • 参考代码:
#!/bin/bash

if [ $# -ne 3 ] 
then
    echo "参数个数不为3"
    echo "当使用乘法时,需要加上脱义符号,例如 $0 1 \* 2"
    exit 1;
fi

num1=`echo $1|sed 's/[0-9.]//g'` ;
if [ -n "$num1" ] 
then
    echo "$1 不是数字" ;
    exit 1
fi

num3=`echo $3|sed 's/[0-9.]//g'` ;
if [ -n "$num3" ]
then
    echo "$3 不是数字" ;
    exit 1
fi

case $2 in
  +)
    echo "scale=2;$1+$3" | bc
    ;;

  -)
    echo "scale=2;$1-$3" | bc 
    ;;

  \*)
    echo "scale=2;$1*$3" | bc 
    ;;

  /)
    echo "scale=2;$1/$3" | bc 
    ;;

  *)
   echo  "$2 不是运算符"
   ;;
esac

【脚本81】判断没有文件

判断所给目录内哪些二级目录下没有text.txt文件。

有text.txt文件的二级目录,根据文件计算选项中单词数最大的值(选项间以|分割,单词间以空格分隔)。

假如脚本名字为1.sh, 运行脚本的格式为 ./1.sh 123 root,其中123为目录名字,而root为要计算数量的单词。

  • 说明:
    这个shell脚本题目出的有点歧义。 原题给的描述不是很清楚,我另外又改了一下需求,依然不是很清晰。在这里我再做一个补充: 对于有test.txt的目录,计算出该test.txt文件里面所给出单词的次数。不用找最大。

  • 参考代码:

#!/bin/bash

if [ $# -ne 2 ]
then
    echo "useage $0 dir word"
    exit 1
fi

if [ -d $1 ]
then
    cd $1
else
    echo "$1目录不存在"
    exit 1
fi

for f in `ls $1`
do
    if [ -d $f ]
    then
    if [ -f $f/test.txt ]
    then
        n=`grep -cw "$2" $f/test.txt`
        echo "$1/$f/test.txt 里面有$n$2"
    else
        echo "$1/$f 下面没有test.txt"
        fi
    fi
done

【脚本82】打印正方形

交互式脚本,根据提示,需要用户输入一个数字作为参数,最终打印出一个正方形。

在这里我提供一个linux下面的特殊字符■,可以直接打印出来。

  • 示例:
    如果用户输入数字为5,则最终显示的效果为:
■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■
  • 参考代码:
#!/bin/bash

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

【脚本83】问候用户

写一个脚本,依次向/etc/passwd中的每个用户问好,并且说出对方的ID是什么:

Hello,root,your UID is 0.

  • 参考命令:
awk -F ':' '{print "Hello,"$1",your uid is "$3.}' /etc/passwd

【脚本84】按要求处理文本

linux系统 /home目录下有一个文件test.xml,内容如下:

<configuration>
    <artifactItems>
        <artifactItem>
       <groupId>zzz</groupId>
       <artifactId>aaa</artifactId>
    </artifactItem>
    <artifactItem>
       <groupId>xxx</groupId>
       <artifactId>yyy</artifactId>
    </artifactItem>
    <!-- </artifactItem><groupId>some groupId</groupId> 
       <version>1.0.1.2.333.555</version> </artifactItem>-->
    </artifactItems>
</configuration>

请写出shell脚本删除文件中的注释部分内容,获取文件中所有artifactItem的内容,并用如下格式逐行输出 artifactItem:groupId:artifactId

  • 分析:
    这个文件比较特殊,但是却很有规律。注释部分内容其实就是<!– –>中间的内容,所以我们想办法把这些内容删除掉就ok了。而artifactItem的内容,其实就是获取<artifactItem></artifactItem>中间的内容。然后想办法用提到的格式输出即可。

  • 参考代码:

#!/bin/bash

egrep -v '<!--|-->' 1.txt |tee 2.txt  //这行就是删除掉注释的行
grep -n 'artifactItem>' 2.txt |awk '{print $1}' |sed 's/://' > /tmp/line_number.txt
n=`wc -l /tmp/line_number.txt|awk '{print $1}'`

get_value(){
    sed -n "$1,$2"p 2.txt|awk -F '<' '{print $2}'|awk -F '>' '{print $1,$2}' > /tmp/value.txt
    nu=`wc -l /tmp/value.txt|awk '{print $1}'`
    for i in `seq 1 $nu`
    do
        x=`sed -n "$i"p /tmp/value.txt|awk '{print $1}'`
        y=`sed -n "$i"p /tmp/value.txt|awk '{print $2}'`
        echo artifactItem:$x:$y
    done
}

n2=$[$n/2]

for j in `seq 1 $n2`
do
    m1=$[$j*2-1]
    m2=$[$j*2]
    nu1=`sed -n "$m1"p /tmp/line_number.txt`
    nu2=`sed -n "$m2"p /tmp/line_number.txt`
    nu3=$[$nu1+1]
    nu4=$[$nu2-1]
    get_value $nu3 $nu4
done

【脚本85】判断函数

请使用条件函数if撰写一个shell函数 函数名为 f_judge,实现以下功能:

当/home/log 目录存在时 将/home目录下所有tmp开头的文件或目录移/home/log 目录。
当/home/log目录不存在时,创建该目录,然后退出。

  • 参考代码:
#!/bin/bash

f_judge (){
    if [ -d /home/log ]
    then 
        mv /home/tmp* /home/log/
    else
        mkdir -p /home/log
        exit
    fi
}

【脚本86】批量杀进程

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

10.111.11.1,root,xyxyxy

10.111.11.1,root,xzxzxz

10.111.11.1,root,123456

10.111.11.1,root,xxxxxx

……

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

  • 讲解:
    有了ip,用户名和密码,剩下的就是登录机器,然后执行命令了。批量登录机器,并执行命令,咱们课程当中有讲过一个expect脚本。所以本题就是需要这个东西来完成。

首先编辑expect脚本 kill_tomcat.expect:

#!/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"

编辑完后需要给这个文件执行权限:

chmod a+x kill_tomcat.expect

然后编辑shell脚本:

#!/bin/bash
n=`wc -l ip-pwd.ini`
for i in `seq 1 $n`
do
    ip=`sed -n "$n"p ip-pwd.ini |awk -F ',' '{print $1}'`
    pw=`sed -n "$n"p ip-pwd.ini |awk -F ',' '{print $3}'`
    ./kill_tomcat.expect $pw $ip
done

【脚本87】处理日志

写一个脚本查找/data/log目录下,最后创建时间是3天前,后缀是*.log的文件,打包后发送至192.168.1.2服务上的/data/log下,并删除原始.log文件,仅保留打包后的文件

  • 参考代码:
#!/bin/bash

find /data/log -name “*.log” -mtime +3 > /tmp/file.list
cd /data/log
tar czvf log.tar.gz `cat /tmp/file.list|xargs`
rsync -a log.tar.gz  192.168.1.2:/data/log  # 这一步需要提前做一个免密码登录
for f in `cat /tmp/file.list`
do
    rm -f $f
done

【脚本88】处理文本

有如下文本,其中前5行内容为

1111111:13443253456
2222222:13211222122
1111111:13643543544
3333333:12341243123
2222222:12123123123

用shell脚本处理后,按下面格式输出:

[1111111]
13443253456
13643543544
[2222222]
13211222122
12123123123
[3333333]
12341243123
  • 参考代码:
#! /bin/bash

sort -n filename |awk -F ':' '{print $1}'|uniq >id.txt

for id in `cat id.txt`; do
        echo "[$id]"
        awk -v id2=$id -F ':' '$1==id2 {print $2}' filename  
        #另外的方式为: awk -F ':' '$1=="'$id'" {print $2}' filename  
done

【脚本89】清理日志

  • 要求:
    两类机器一共300多台,写个脚本自动清理这两类机器里面的日志文件。在堡垒机批量发布,也要批量发布到crontab里面。

A类机器日志存放路径很统一,B类机器日志存放路径需要用匹配(因为这个目录里除了日志外,还有其他文件,不能删除。匹配的时候可用.log)

A类:/opt/cloud/log/ 删除7天前的
B类: /opt/cloud/instances/ 删除15天前的

要求写在一个脚本里面。不用考虑堡垒机上的操作,只需要写出shell脚本。

  • 参考代码:
#!/bin/bash

dir1=/opt/cloud/instances/ 
dir2=/opt/cloud/log/

  if [ -d $dir1 ];then
      find $dir1 -type f -name "*.log" -mtime +15 |xargs rm -f
  elif [ -d $dir2 ];then
      find $dir2 -type f -mtime +7 |xargs rm -f
  fi

【脚本90】

贷款有两种还款的方式:等额本金法和等额本息法

简单说明一下等额本息法与等额本金法的主要区别:

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

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

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

其中:等额本息每月还款额的计算公式是:
[贷款本金×月利率×(1+月利率)还款月数]÷[(1+月利率)还款月数-1]

  • 参考代码:
#!/bin/bash

read -p "请输入贷款总额(单位:万元):" dkzewy
read -p "请输入贷款年利率(如年利率为6.5%,直接输入6.5):" dknll
read -p "请输入贷款年限(单位:年):" dknx
echo "贷款计算方式:"
echo "1)等额本金计算法"
echo "2)等额本息计算法"
read -p "请选择贷款方式(1|2)" dkfs
dkze=`echo "scale=2;$dkzewy*10000 " | bc -l`
dkll=`echo "scale=6;$dknll/100 " | bc -l`
dkyll=`echo "scale=6;$dkll/12 " | bc -l`
dkqc=$[$dknx*12]
echo "期次 本月还款额 本月利息 未还款额"

debjjsf()
{
    yhbj=`echo "scale=2;($dkze/$dkqc)/1 " | bc -l`
    whbj=$dkze
    for((i=1;i<=$dkqc;i++))
    do
        bylx=`echo "scale=2;($whbj*$dkyll)/1 " | bc -l`
        bybx=`echo "scale=2;($yhbj+$bylx)/1 " | bc -l`
        yhke=`echo "scale=2;($yhbj*$i)/1 " | bc -l`
        whbj=`echo "$dkze-$yhke " | bc -l`
        if [ $i -eq $dkqc ]
        then
            yhbj=`echo "scale=2;($yhbj+$whbj)/1 " | bc -l`
            whbj="0.00"
            bybx=`echo "scale=2;($yhbj+$bylx)/1 " | bc -l`
        fi
        echo "$i $bybx $bylx $whbj"
    done
}

debxjsf()
{
    bybx=`echo "scale=2;(($dkze*$dkyll*((1+$dkyll)^$dkqc))/(((1+$dkyll)^$dkqc)-1))/1 " | bc -l`
    whbj=$dkze
    for((i=1;i<=$dkqc;i++))
    do
        bylx=`echo "scale=2;($whbj*$dkyll)/1 " | bc -l`
        yhbj=`echo "scale=2;($bybx-$bylx)/1 " | bc -l`
        whbj=`echo "scale=2;($whbj-$yhbj)/1 " | bc -l`
        if [ $i -eq $dkqc ]
        then
            bybx=`echo "scale=2;($yhbj+$whbj)/1 " | bc -l`
            whbj="0.00"
        fi
        echo "$i $bybx $bylx $whbj"
    done
}

case $dkfs in
    1) debjjsf
       ;;
    2) debxjsf
       ;;
    *) exit 1
       ;;
esac

【脚本91】监控磁盘io

阿里云的机器,今天收到客服来的电话,说服务器的磁盘io很重。于是登录到服务器查看,并没有发现问题,所以怀疑是间歇性地。

正要考虑写个脚本的时候,幸运的抓到了一个线索,造成磁盘io很高的幕后黑手是mysql。此时去show processlist,但未发现队列。原来只是一瞬间。

只好继续来写脚本,思路是,每5s检测一次磁盘io,当发现问题去查询mysql的processlist。

  • 提示:
    你可以用iostat -x 1 5 来判定磁盘的io,主要看%util

  • 参考代码:

#!/bin/bash

while :
do
    n=`iostat -x 1 5 |tail -n3|head -n1 |awk '{print $NF}'|cut -d. -f1`
    if [ $n -gt 70 ]
    then
        echo "`date` util% is $n%" >>/tmp/mysql_processlist.log
        mysql -uroot -pxxxxxx -e "show  full processlist" >> /tmp/mysql_processlist.log
    fi
    sleep 5
done

   转载规则


《shell脚本实例(六)》 helen 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录