20.16 shell中的函数(上)

 

函数就是一段代码整理到了一个小单元中,给这个小单元起一个名字,用到这段代码时直接调用这个小单元即可

 

一般函数格式:

function f_name(){

      command

}

 

定义的函数名最好不与shell中的关键词冲突(forwhiledo等);

后期需要调用某个函数时直接敲函数名即可;

 

[root@hyc-01-01 shell]# vim function.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 b b c e f

 

[root@hyc-01-01 shell]# sh -x function.sh

+ inp b b c

+ echo 'the first par is b'

the first par is b

+ echo 'the second par is b'

the second par is b

+ echo 'the third par is c'

the third par is c

+ echo 'the script name is function.sh'

the script name is function.sh

+ echo 'the quantity of par is 5'

the quantity of par is 5

$后跟数字表示第几个参数,如$1表示函数inp()的第一个参数;

$0表示脚本名称;

共有3个参数;

打印出的信息中,$11,$2a,$32,$#会统计参数的个数;

 

[root@hyc-01-01 shell]# vim function.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 $1 $2 $3

此时写在inp()函数外面的$1,$2,$3表示脚本function.sh的第一、第二、第三个参数

 

[root@hyc-01-01 shell]# sh -x function.sh 1

+ inp 1

+ echo 'the first par is 1'

the first par is 1

+ echo 'the second par is '

the second par is

+ echo 'the third par is '

the third par is

+ echo 'the script name is function.sh'

the script name is function.sh

+ echo 'the quantity of par is 1'

the quantity of par is 1

执行脚本时指定一个参数1

结果显示此时第一个参数为1,其余参数为空;

参数总共只有一个;

 

20.17 shell中的函数(下)

 

若想调用某个函数那么在调用语句之前必须先定义该函数

 

计算1+10

[root@hyc-01-01 shell]# vim sum.sh

#!/bin/bash

sum() {

    s=$[$1+$2]

    echo $s

}

sum 1 10

 

[root@hyc-01-01 shell]# sh -x sum.sh

+ sum 1 10

+ s=11

+ echo 11

11

 

[root@hyc-01-01 shell]# ifconfig|grep -A1 "ens33: "|awk '/inet/ {print $2}'

[root@hyc-01-01 shell]# ifconfig|grep -A1 "ens33: "|grep 'inet' |awk '{print $2}'

192.168.31.129

[root@hyc-01-01 shell]# ifconfig

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500

        inet 192.168.31.129  netmask 255.255.255.0  broadcast 192.168.31.255

        inet6 fe80::d46b:4589:4da1:2f34  prefixlen 64  scopeid 0x20<link>

        ether 00:0c:29:4d:9d:95  txqueuelen 1000  (Ethernet)

        RX packets 42396  bytes 3599222 (3.4 MiB)

        RX errors 0  dropped 0  overruns 0  frame 0

        TX packets 53172  bytes 18299829 (17.4 MiB)

        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

写脚本时应不断对脚本进行调试,直到得到预想的结果;

ifconfig|grep -A1 "ens33: "表示过滤出包含ens33的行以及它的下一行;

这里为ens33:后跟一个空格,这样可以过滤掉像ens33:0这样的网卡;

awk

grep 'inet' |awk '{print $2}' 过滤出包含inet的行,截取第二段

awk '/inet/ {print $2}'过滤出包含inet的行,截取第二段

 

输入网卡名判断网卡ip

[root@hyc-01-01 shell]# vim ip.sh

#!/bin/bash

ip()

{

   ifconfig|grep -A1 "$1: "|awk '/inet/ {print $2}'

}

read -p "please input the eth name  " eth

ip $eth

 

[root@hyc-01-01 shell]# sh -x ip.sh

+ read -p 'please input the eth name  ' eth

please input the eth name  ens33

+ ip ens33

+ ifconfig

+ grep -A1 'ens33: '

+ awk '/inet/ {print $2}'

192.168.31.129

改进脚本:

1 若输入的网卡不存在如何处理?

2 输入的网卡无ip如何处理?

 

20.18 shell中的数组

 

数组:由一串字符串或数字形成的变量

定义数组:

[root@hyc-01-01 ~]# b=(1 2 3)

打印数组:

[root@hyc-01-01 ~]# echo ${b[@]}

1 2 3

[root@hyc-01-01 ~]# echo ${b[*]}

1 2 3

查看数组中某个元素的值:

[root@hyc-01-01 ~]# echo ${b[0]}

1

[root@hyc-01-01 ~]# echo ${b[1]}

2

[root@hyc-01-01 ~]# echo ${b[2]}

3

数组中元素的下标从0开始,分别为第0个元素、第1个元素、第2个元素

获取数组中元素的个数:

[root@hyc-01-01 ~]# echo ${#b[*]}

3

[root@hyc-01-01 ~]# echo ${#b[@]}

3

给数组重新赋值:

[root@hyc-01-01 ~]# b[3]=a

[root@hyc-01-01 ~]# echo ${#b[@]}

4

[root@hyc-01-01 ~]# echo ${b[@]}

1 2 3 a

覆盖数组中原来的元素:

[root@hyc-01-01 ~]# b[3]=aaa

[root@hyc-01-01 ~]# echo ${b[@]}

1 2 3 aaa

删除元素:

[root@hyc-01-01 ~]# echo ${b[@]}

1 2 3 aaa

[root@hyc-01-01 ~]# unset b[3] 删除下标为3的元素

[root@hyc-01-01 ~]# echo ${b[@]}

1 2 3

[root@hyc-01-01 ~]# unset b 删除整个数组b

[root@hyc-01-01 ~]# echo ${b[@]}

 

截取部分数组:

[root@hyc-01-01 ~]# a=(`seq 1 10`)

[root@hyc-01-01 ~]# echo ${a[*]}

1 2 3 4 5 6 7 8 9 10

[root@hyc-01-01 ~]# echo ${a[@]:3:4} 从下标为3的元素开始截取,截取4个元素

4 5 6 7

[root@hyc-01-01 ~]# echo ${a[@]:0-3:2} 从倒数第3个元素开始截取2

8 9

数组替换:

[root@hyc-01-01 ~]# echo ${a[@]/8/6}

1 2 3 4 5 6 7 6 9 10

将数组a中的元素8替换为6

[root@hyc-01-01 ~]# a=(${a[@]/8/6})

[root@hyc-01-01 ~]# echo ${a[@]}

1 2 3 4 5 6 7 6 9 10

 

20.19 告警系统需求分析

 

Shell项目

项目:告警系统

需求:

监控需求:

1 当监控项比较冷门,zabbix等监控工具中不包含该监控项时,需要用户自定义监控脚本

2 C/S架构中服务器与客户端网络出现问题,无法将监控数据上报服务端,可以编写用于监控的shell脚本,此时监控系统是分布式的,用户需要在每一台被监控的机器上编辑shell脚本,每一台机器都可以做到独立监控,不需要依赖其他机器

告警需求:

当服务器多或告警频繁时,假如每分钟检测一次,若每分钟都出问题,那么每分钟都会发出较多邮件,所以需要做告警收敛

 

指定一个包含主程序、子程序、配置文件、邮件引擎、输出日志等的脚本包

脚本包中包含:

主程序:是整个脚本的入口,整个系统的命脉

配置文件:一个监控中心,用于开关 各个子程序,指定各个关联的日志文件

子程序:真正的监控脚本,用于监控各种指标

邮件引擎:用一个python程序实现,可以定义发邮件服务器、发邮件人、发件人密码

输出日志:整个监控系统的日志输出

 

要求:

机器角色多样,但所有机器都要部署同样的监控系统;

无论机器角色,整个程序框架都是一致的;

根据机器角色不同,定制不同的配置文件

 

主目录(mon):

bin

 main.sh 主脚本

conf

 mon.conf 配置文件

shares

 load.sh 502.sh 监控子脚本

mail

 mail.py mail.sh 邮件

log

 mon.log err.log 记录日志