目录
一、shell中的函数
二、shell中的数组
三、shell告警系统
一、shell中的函数
函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段代码时直接调用这个小单元的名字即可。
函数格式:
function f_name() { ##可以省略function
command
}
##函数名不要和shell关键词一样
##定义好的函数直接使用函数名调用
示例一
[root@minglinux-01 /usr/local/sbin] cat function1.sh
#!/bin/bash
function inp(){
echo "The first par is $1"
echo "The second par is $2"
echo "The third par is $3"
echo "The script name is $0"
echo "The quantity of par is $#"
}
inp a b 1 2 3
[root@minglinux-01 /usr/local/sbin] sh function1.sh
The first par is a
The second par is b
The third par is 1
The script name is function1.sh
The quantity of par is 5
示例二
##计算1+2
[root@minglinux-01 /usr/local/sbin] cat function2.sh
#!/bin/bash
sum() {
s=$[$1+$2]
echo $s
}
sum 1 2
[root@minglinux-01 /usr/local/sbin] sh function2.sh
3
示例三
##需求:交互方式输入网卡名后打印该网卡的IP地址
[root@minglinux-01 ~] ifconfig |grep -A1 "ens33"
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.162.130 netmask 255.255.255.0 broadcast 192.168.162.255
[root@minglinux-01 ~] ifconfig |grep -A1 "ens33"|tail -1
inet 192.168.162.130 netmask 255.255.255.0 broadcast 192.168.162.255
[root@minglinux-01 ~] ifconfig |grep -A1 "ens33"|tail -1|awk '{print $1}'
inet
[root@minglinux-01 ~] ifconfig |grep -A1 "ens33"|tail -1|awk '{print $2}'
192.168.162.130
##编写脚本如下
[root@minglinux-01 /usr/local/sbin] cat function3.sh
#!/bin/bash
ip(){
ifconfig |grep -A1 "$1:"|tail -1|awk '{print $2}'
}
read -p "Please input the eth name: " eth
ip $eth
[root@minglinux-01 /usr/local/sbin] sh function3.sh
Please input the eth name: ens33
192.168.162.130
[root@minglinux-01 /usr/local/sbin] sh function3.sh
Please input the eth name: lo
127.0.0.1
二、shell中的数组
定义数组的格式: arr_name=(value1 value2 value3 ...)
调用格式为:${arr_name[@]},
方括号中的 @ 表示所有的元素,也可以用 * 代替
调用数组中某一个元素需要使用元素的下标, 下标从0开始
[root@minglinux-01 /usr/local/sbin] arr=(first second third)
[root@minglinux-01 /usr/local/sbin] echo $arr
first
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
first second third
[root@minglinux-01 /usr/local/sbin] echo ${arr[*]}
first second third
[root@minglinux-01 /usr/local/sbin] echo ${arr[0]}
first
[root@minglinux-01 /usr/local/sbin] echo ${arr[2]}
third
[root@minglinux-01 /usr/local/sbin] echo ${#arr[@]} #获取数组元素个数
3
#数组的赋值
[root@minglinux-01 /usr/local/sbin] arr[3]=fourth
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
first second third fourth
[root@minglinux-01 /usr/local/sbin] arr[3]=4
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
first second third 4
#数组的删除
[root@minglinux-01 /usr/local/sbin] unset arr[3] ##删除数组元素
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
first second third
[root@minglinux-01 /usr/local/sbin] unset arr ##删除数组
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
#数组的分片
[root@minglinux-01 /usr/local/sbin] arr=(`seq 1 10`)
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
1 2 3 4 5 6 7 8 9 10
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]:0:5} #从第一个元素开始截取5个
1 2 3 4 5
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]:0-3:3} #从倒数第三个开始截取3个
8 9 10
#数组的替换
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]/1/a} #仅替换输出内容,实际元素并未改变
a 2 3 4 5 6 7 8 9 a0
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
1 2 3 4 5 6 7 8 9 10
[root@minglinux-01 /usr/local/sbin] arr=(${arr[@]/1/a}) #真正替换数组元素
[root@minglinux-01 /usr/local/sbin] echo ${arr[@]}
a 2 3 4 5 6 7 8 9 a0
三、shell告警系统
-
告警系统需求分析
需求:使用shell定制各种个性化告警工具,但需要统一化管理、规范化管理。
需求场景:
当监控项比较冷门时,zabbix等监控工具中不包含该监控项时,需要用户自定义监控脚本
C/S架构中服务器与客户端网络出现问题,无法将监控数据上报服务端,可以编写用于监控的shell脚本,此时监控系统是分布式的,用户需要在每一台被监控的机器上编辑shell脚本,每一台机器都可以做到独立监控,不需要依赖其他机器
思路:指定一个脚本包,包含主程序、子程序、配置文件、邮件引擎、输出日志等。
主程序:作为整个脚本的入口,是整个系统的命脉。
配置文件:是一个控制中心,用它来开关各个子程序,指定各个相关联的日志文件。
子程序:这个才是真正的监控脚本,用来监控各个指标。
邮件引擎:是由一个python程序来实现,它可以定义发邮件的服务器、发邮件人以及发件人密码
输出日志:整个监控系统要有日志输出。
要求:我们的机器角色多种多样,但是所有机器上都要部署同样的监控系统,也就说所有机器不管什么角色,整个程序框架都是一致的,不同的地方在于根据不同的角色,定制不同的配置文件。
程序架构
(主目录 mon)
________________________________|_____________________________________
| | | | |
bin conf shares mail log
| | | | |
[main.sh] [mon.conf] [load.sh sh] [mail.py mail.sh] [mon.log err.log]
bin下是主程序
conf下是配置文件
shares下是各个监控脚本
mail下是邮件引擎
log下是日志
-
告警系统主脚本
#创建主目录和子目录
[root@minglinux-01 /usr/local/sbin] mkdir mon
[root@minglinux-01 /usr/local/sbin] cd mon
[root@minglinux-01 /usr/local/sbin/mon] ls
[root@minglinux-01 /usr/local/sbin/mon] mkdir bin conf shares mail log
[root@minglinux-01 /usr/local/sbin/mon] ls
bin conf log mail shares
#创建主脚本
#主脚本用于判断某监控项是否需要监控,若需要监控则调用对应项的子脚本
#!/bin/bash
#Written by aming.
# 是否发送邮件的总开关,send为1则以下所有监控项都会发送邮件,系统维护时应关闭
# export表示所有变量都会应用于子脚本中;
export send=1
# 过滤ip地址,告诉用户是哪一台机器发的告警
export addr=`ifconfig |grep -A1 "ens33: "|awk '/inet/ {print $2}'`
dir=`pwd`
# 只需要最后一级目录名
last_dir=`echo $dir|awk -F'/' '{print $NF}'`
# 下面的判断目的是,保证执行脚本的时候,我们在bin目录里,
# 不然监控脚本、邮件和日志很有可能找不到
if [ $last_dir == "bin" ] || [ $last_dir == "bin/" ]; then
conf_file="../conf/mon.conf"
else
echo "you shoud cd bin dir"
exit
fi
exec 1>>../log/mon.log 2>>../log/err.log #输出正确和错误的日志
echo "`date +"%F %T"` load average"
/bin/bash ../shares/load.sh #直接调用子脚本load.sh
#先检查配置文件中是否需要监控502
if grep -q 'to_mon_502=1' $conf_file; then
export log=`grep 'logfile=' $conf_file |awk -F '=' '{print $2}' |sed 's/ //g'`
/bin/bash ../shares/502.sh
fi
-
告警系统配置文件
[root@minglinux-01 /usr/local/sbin/mon/conf] vim mon.conf
1 ## to config the options if to monitor
2 ## 定义mysql的服务器地址、端口以及user、password
3 to_mon_cdb=0 ##0 or 1, default 0,0 not monitor, 1 monitor
4 db_ip=10.20.3.13
5 db_port=3315
6 db_user=username
7 db_pass=passwd
8 ## httpd 如果是1则监控,为0不监控
9 to_mon_httpd=0
10 ## php 如果是1则监控,为0不监控
11 to_mon_php_socket=0
12 ## http_code_502 需要定义访问日志的路径
13 to_mon_502=1
14 logfile=/data/log/xxx.xxx.com/access.log
15 ## request_count 定义日志路径以及域名
16 to_mon_request_count=0
17 req_log=/data/log/www.discuz.net/access.log
18 domainname=www.discuz.net
-
告警系统监控项目
#load.sh内容如下
[root@minglinux-01 /usr/local/sbin/mon/shares] vim load.sh
1 #!/bin/bash
2 ##Writen by aming##
3 load=`uptime |awk -F 'average:' '{print $2}'|cut -d',' -f1|sed 's/ //g' | cut -d. -f1` ##获取最近一分钟的系统负载
4 if [ $load -gt 10 ] && [ $send -eq "1" ] ##当系统负载高于10 且允许发邮件的情况下,发送报警邮件
5 then
6 echo "$addr `date +%T` load is $load" >../log/load.tmp
7 /bin/bash ../mail/mail.sh 331601950@qq.com "$addr\_load:$load" `cat ../log/load.tmp`
8 fi
9 echo "`date +%T` load is $load"
#502.sh内容如下
[root@minglinux-01 /usr/local/sbin/mon/shares] vim 502.sh
1 #!/bin/bash
2 d=`date -d "-1 min" +%H:%M` #变量d为一分钟前的时间
3 c_502=`grep :$d: $log |grep ' 502 '|wc -l`
4 if [ $c_502 -gt 10 ] && [ $send == 1 ]; then
5 echo "$addr $d 502 count is $c_502">../log/502.tmp
6 /bin/bash ../mail/mail.sh $addr\_502 $c_502 ../log/502.tmp
7 fi
8 echo "`date +%T` 502 $c_502"
#disk.sh内容如下
[root@minglinux-01 /usr/local/sbin/mon/shares] vim disk.sh
1 #!/bin/bash
2 ##Writen by aming##
3 rm -f ../log/disk.tmp
4 for r in `df -h |awk -F '[ %]+' '{print $5}'|grep -v Use`
5 do
6 if [ $r -gt 90 ] && [ $send -eq "1" ]
7 then
8 echo "$addr `date +%T` disk useage is $r" >>../log/disk.tmp
9 fi
10 if [ -f ../log/disk.tmp ]
11 then
12 df -h >> ../log/disk.tmp
13 /bin/bash ../mail/mail.sh $addr\_disk $r ../log/disk.tmp
14 echo "`date +%T` disk useage is nook"
15 else
16 echo "`date +%T` disk useage is ok"
17 fi
[root@minglinux-01 /usr/local/sbin/mon/shares] df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda3 28G 7.5G 21G 27% /
devtmpfs 901M 0 901M 0% /dev
tmpfs 911M 0 911M 0% /dev/shm
tmpfs 911M 9.6M 902M 2% /run
tmpfs 911M 0 911M 0% /sys/fs/cgroup
tmpfs 911M 0 911M 0% /tmp
/dev/sda1 197M 140M 58M 71% /boot
tmpfs 183M 0 183M 0% /run/user/0
[root@minglinux-01 /usr/local/sbin/mon/shares] df -h |awk -F '[ %]+' '{print $5}'|grep -v Use
#以一个或多个空格和百分号作为分隔符
已用
27
0
0
2
0
0
71
0
#当语言被修改为en时,最上面一行将显示为英文
[root@minglinux-01 /usr/local/sbin/mon/shares] echo $LANG
zh_CN.UTF-8
[root@minglinux-01 /usr/local/sbin/mon/shares] LANG=en
[root@minglinux-01 /usr/local/sbin/mon/shares] df -h |awk -F '[ %]+' '{print $5}'|grep -v Use
27
0
0
2
0
0
71
0
-
告警系统邮件引擎
[root@minglinux-01 /usr/local/sbin/mon/shares] cp /usr/lib/zabbix/alertscripts/mail.py ../mail/mail.py
#拷贝之前的mail.py
#mail.sh内容如下,用于告警收敛
[root@minglinux-01 /usr/local/sbin/mon/shares] vim mail.sh
1 #!/bin/bash
2 log=$1 #每次执行脚本发邮件都要查找监控项对应的日志
3 t_s=`date +%s`
4 t_s2=`date -d "2 hours ago" +%s`
#2个小时前的时间戳,第一次执行脚本时必须报警,要保证两个时间戳的差值足够大可以满足报警条件
5 if [ ! -f /tmp/$log ]
6 then
7 echo $t_s2 > /tmp/$log #若监控项目日志文件不存在,则创建日志并在日志第一行写入2小时前的时间戳
8 fi
9 t_s2=`tail -1 /tmp/$log|awk '{print $1}'` #日志文件中最后一行的内容作赋值给t_s2,如果是文件刚创建的情况则为第一行(第一行也是最后一行)
10 echo $t_s>>/tmp/$log #将当前时间的时间戳追加到/tmp/$log中
11 v=$[$t_s-$t_s2] #两次时间戳差值
12 echo $v
13 if [ $v -gt 3600 ] #差值大于3600则执行后续操作
14 then
15 ./mail.py $1 $2 $3
16 echo "0" > /tmp/$log.txt
17 else ##时间戳差值不大于3600,则执行以下操作
18 if [ ! -f /tmp/$log.txt ] #log.txt是计数器,若log.txt不存在
19 then
20 echo "0" > /tmp/$log.txt
21 fi
22 nu=`cat /tmp/$log.txt`
23 nu2=$[$nu+1] #
24 echo $nu2>/tmp/$log.txt
25 if [ $nu2 -gt 10 ] #若计数器的值超过10,再次发出告警
26 then
27 ./mail.py $1 "trouble continue 10 min $2" "$3"
28 echo "0" > /tmp/$log.txt #发出告警后将计数器$log.txt重新计数,重置为0
29 fi
30 fi
-
运行告警系统
#可以设置定时任务
[root@minglinux-01 /usr/local/sbin/mon/shares] crontab -e
no crontab for root - using an empty one
* * * * * cd /usr/local/sbin/mon/bin; bash main.sh #每分钟执行一次