十四、shell中的函数(上)、(下)
shell允许将一组命令集或语句形成一个可用块,这些块就称为函数。shell的函数的好处就是只需定义一次,后面就可以随意调用执行了。
注意:函数要先定义才可以被调用,也就是说,函数要放在调用语句的前面。
函数的格式:
function 函数名(){
语句
}
其中:function可以省略
注意:跟其他C、C++、JAVA等编程语言不同的是,()里不能有参数(也就是实参)。
例1:
[root@node2 ~]# vim functiondemo01.sh#!/bin/bash#函数的定义sum(){ sum=$[$1+$2] echo "sum=$sum"}#函数的调用sum 3 5
测试:
[root@node2 ~]# sh functiondemo01.shsum=8[root@node2 ~]#
例2:获取某个网卡的ip
[root@node2 ~]# vim funcip.sh#!/bin/bashcutip(){ ip addr | grep "\<$1\>" | grep 'inet' | cut -d'/' -f1 | awk '{print $2}'}read -p "请输入网卡名称:" ethcutip $eth
测试:
[root@node2 ~]# sh funcip.sh请输入网卡名称:ens33192.168.10.206[root@node2 ~]#
十五、shell中的属组
1、数组的基础
定义数组:a=(1 2 3 4)
打印数组:echo ${b[@]}、echo ${b[*]}
[root@node2 ~]# a=(1 2 3 4)[root@node2 ~]# echo ${a[@]}1 2 3 4[root@node2 ~]# echo ${a[*]}1 2 3 4[root@node2 ~]#
查看数组的某一个元素:
[root@node2 ~]# echo ${a[0]}1[root@node2 ~]# echo ${a[1]}2[root@node2 ~]#
数组下标从0开始。
显示数组的参数个数:echo ${#b[@]}
[root@node2 ~]# echo ${#a[@]}4[root@node2 ~]#
数组赋值:
[root@node2 ~]# a[4]="haha"[root@node2 ~]# echo ${a[@]}1 2 3 4 haha[root@node2 ~]#
删除数组的某个元素:
[root@node2 ~]# unset a[3][root@node2 ~]# echo ${a[@]}1 2 3 haha[root@node2 ~]#
删除数组:
[root@node2 ~]# unset a[root@node2 ~]# echo ${a[@]}[root@node2 ~]#
2、数组分片
从第一个元素开始,截取3个:
[root@node2 ~]# a=(`seq 1 5`)[root@node2 ~]# echo ${a[@]:0:3}1 2 3[root@node2 ~]#
从第二个元素开始,截取4个
[root@node2 ~]# echo ${a[@]:1:4}2 3 4 5[root@node2 ~]#
从倒数第二个开始,截取2个:
[root@node2 ~]# echo ${a[@]:0-2:2}4 5[root@node2 ~]#
数组替换:
把5换成haha
[root@node2 ~]# echo ${a[@]/5/haha}1 2 3 4 haha[root@node2 ~]# b=(${a[@]/5/haha})[root@node2 ~]# echo ${b[@]}1 2 3 4 haha[root@node2 ~]#
十六、告警系统需求分析
告警系统:
需求:使用shell定制各种告警工具,但需要统一化管理、规范化管理。
思路:指定一个脚本包,包含主程序、子程序、配置文件、邮件引擎、输出日志等。
主程序:作为整个脚本的入口
配置文件:是一个控制中心,用来开关各个子程序,指定各个相关联的日志文件
子程序:真正的监控脚本,用来监控各个指标
邮件引擎:定义发邮件的服务器、发邮件人及其密码
输出日志:整个监控系统要有输出日志。
十七、告警系统主脚本
一般而言,shell脚本放在/usr/local/sbin/目录下更好。
根据前面的规划,创建相关目录:
[root@node2 ~]# mkdir /mon/{bin,conf,shares,mail,log} -p[root@node2 ~]#
主脚本main.sh内容:
[root@node2 ~]# vim /mon/bin/main.sh#!/bin/bash#是否发送邮件export send=1#过滤ip地址export addr=`ip addr | grep '\' | awk 'NR==2{print $2}' | sed 's#\/.*##g'`#当前目录dir=`pwd`#只需要最后一个目录last_dir=`echo $dir | awk -F'/' '{print $NF}'`#脚本使用了相对路径,执行脚本要在/mon/bin目录中,不然监控脚本、邮件和日志等可能找不到if [ $last_dir == "bin" ] || [ $last_dir == "bin/" ];then conf_file="../conf/mon.conf"else echo "you shoud cd bin dir。" exitfiexec 1 >> ../log/mon.log 2>> ../log/error.logecho "`date +%F' '%T` load average:"/bin/bash ../shares/load.sh#先检查配置文件中是否需要监控502if grep -q 'to_mon_502=1' $conf_file;then export log=`grep 'logfile=' $conf_file | awk -F'=' '{print $2}' | sed 's/[[:space:]]*//g‘` /bin/bash ../shares/502.shfi
十八、告警系统配置文件
配置文件:/mon/conf/mon.conf
[root@node2 ~]# vim /mon/conf/mon.conf#监控mysql#定义mysql服务器地址、端口、用户和密码to_mon_cdb=0 #0不监控,1为监控db_ip=192.168.10.206db_port=3306db_user=rootdb_pass=##httpdto_mon_httpd=0 #0为不监控,1为监控#phpto_mon_php_socket=0#http_code_502 日志路径to_mon_502=1logfile=/mydata/log/access.log#request_count 日志路径、域名 to_mon_request_count=0req_log=/mydata/log/haha/access.logdomainname=haha
十九、告警系统监控项目
子脚本:/mon/shares/load.sh
监控系统负载
[root@node2 ~]# vim /mon/shares/load.sh#!/bin/bash#获取系统负载load=`uptime | awk -F'average:' '{print $2}' | cut -d',' -f1 | sed 's/[[:space:]]*//g' | cut -d. -f1`#如果负载大于20并且设置了发邮件的话(send=1),就发邮件if [ $load -gt 20 ] && [ $send -eq "1" ];then echo "$addr `date +%T load is $load`" >../log/load.tmp /bin/bash ../mail/mail.sh xxxx@163.com "$addr\_load $load" `cat ../log/load.tmp`fiecho "`date +%T` load is $load"
send在主脚本中定义。
子脚本:/mon/shares/502.sh
监控502
[root@node2 ~]# vim /mon/shares/502.sh#!/bin/bashd=`date -d "-1 min" +%H:%M`c_502=`grep :$d: $log | grep '502' | wc -l`if [ $c_502 -gt 10 ] && [ $send == "1" ];then echo "$addr $d 502 count is $c_502" >../log/502.tmp /bin/bash ../mail/mail.sh $addr\_502 $c_502 ../log/502.tmpfiecho "`date +%T` 502 $c_502"
子脚本:/mon/shares/disk.sh
监控磁盘使用
[root@node2 ~]# vim /mon/shares/disk.sh#!/bin/bashrm -f ../log/disk.tmpfor r in `df -h | awk -F'[ %]+' '{print $5}' | grep -v Use`do if [ $r -gt 90 ] && [ $send -eq "1" ];then echo "$addr `date +%T` disk useage is $r" >> ../log/disk.tmp fi if [ -f ../log/disk.tmp ];then df -h >> ../log/disk.tmp /bin/bash ../mail/mial.sh $addr\_disk $r ../log/disk.tmp echo "`date +%T` disk useage is nook!" else echo "`date +%T` disk useage is ok!" fidone
二十、告警系统邮件引擎(上)、(中)、(下)
邮件脚本1:/mon/mail/mail.py
[root@node2 ~]# vim /mon/mail/mail.py#!/usr/bin/env python#-*- conding:UTF-8 -*-import os,sysimport getoptimport smtplibfrom email.MIMEText import MIMETextfrom email.MIMEMultipart import MIMEMutilpartfrom subprocess import *def send163mail(username,password,mailfrom,mailto,subject,content): gserver = 'smtp.163.com' gport = 25 try: msg = MIMEText(unicode(content).encode('utf-8')) msg['from'] = mailfrom msg['to'] = mailto msg['Reply-To'] = mailfrom msg['Subject'] = subject smtp = smtplib.SMTP(gserver,gport) smtp.set_debuglevel(0) smtp.ehlo() smtp.login(username,password) smtp.sendmail(mailfrom,mailto,msg.as_string()) smtp.close() except Exception,err: print "Send mail failed. Error: %s" %errdef main(): to = sys.argv[1] subject = sys.argv[2] content = sys.argv[3] send163mial('xxxx@163.com','密码',to,subject,content)if __name__ == "__main__" main()
邮件脚本2:/mon/mail/mail.sh
[root@node2 ~]# vim /mon/mail/mail.sh#!/bin/bashlog=$1t_s=`date +%s`t_s2=`date -d "2 hours ago"+%s`if [ ! -f /tmp/$log ];then echo $t_s2 > /tmp/$logfit_s2=`tail -1 /tmp/$log | awk '{print $1}'`echo $t_s >> /tmp/$logv=$[$t_s-$t_s2]echo $vif [ $v -gt 3600 ];then ../mail/mial.py $1 $2 $3 echo "0" > /tmp/$log.txtelse if [ ! -f /tmp/$log.txt ];then echo "0" > /tmp/$log.txt fi nu=`cat /tmp/$log.txt` nu2=$[$nu+1] echo $nu2 > /tmp/$log.txt if [ $nu2 -gt 10 ];then ../mail/mail.py $1 "trouble continue 10 min $2" "$3" echo "0" > /tmp/$log.txt fifi
二十一、运行告警系统
[root@node2 bin]# pwd/mon/bin[root@node2 bin]# sh -x main.sh + export send=1+ send=1++ ip addr++ grep '\'++ awk 'NR==2{print $2}'++ sed 's#\/.*##g'+ export addr=192.168.10.206+ addr=192.168.10.206++ pwd+ dir=/mon/bin++ echo /mon/bin++ awk -F/ '{print $NF}'+ last_dir=bin+ '[' bin == bin ']'+ conf_file=../conf/mon.conf+ exec 1[root@node2 bin]#