shell编程二

目录

一、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  #每分钟执行一次
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容