20.16/20.17 shell中的函数

函数,是一个子shell,代码段,定义完函数后可以引用它。

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

function f_name(){
command
}

函数必须要放在最前面

示例1

1 编写脚本

#!/bin/bash
function inp() {
  echo $1 $2  $3 $0 $#
}
inp 1 a 2


解释:

#!/bin/bash

function inp() {inp        是参数的名字

  echo $1 $2 $3 $0 $#       $1第一个参数,$2第二个参数,$3第三个参数,$0文件的名字,$#统计参数

}

inp 1 a 2            输入函数名称inp直接调用函数,输出结果是 $1=a $2=a $3=2


2 执行输出

[root@AliKvn shell]# sh fun1.sh 
1 a 2 fun1.sh 3
[root@AliKvn shell]# sh -x fun1.sh 
+ inp 1 a 2
+ echo 1 a 2 fun1.sh 3
1 a 2 fun1.sh 3


编写第二种脚本

[root@AliKvn shell]# vim fun1.sh 
#!/bin/bash
function inp() {
  echo "the first par is $1" 
  echo "the second par is $2"
  echo "the triple par is $3" 
  echo "the script is $0"
  echo "total par is $#"
}
inp 1 a 2 3 adf

参数解释:

inp 1 a 2 3 adf 调用inp的时候,由于没有调用$4 $5,所以这里第四个参数3 第五个参数adf是不会显示的,因为函数没有执行他们。


以上脚本,正确的输出结果应该是与echo里面除了$参数之外的参数对应,就是说 正常的话 应该输出是对应的.

执行过程

[root@AliKvn shell-re]# sh fun1.sh
the first par is 1
the second par is a
the triple par is 2
the script is fun1.sh
total par is 5
[root@AliKvn shell-re]# sh -x fun1.sh
+ inp 1 a 2 3 adf
+ echo 'the first par is 1'
the first par is 1
+ echo 'the second par is a'
the second par is a
+ echo 'the triple par is 2'
the triple par is 2
+ echo 'the script is fun1.sh'
the script is fun1.sh
+ echo 'total par is 5'
total par is 5

另一种编写方法,输出$1

[root@AliKvn shell]# vim fun2.sh 
#!/bin/bash
function inp() {
  echo "the first par is $1" 
  echo "the second par is $2"
  echo "the triple par is $3" 
  echo "the script is $0"
  echo "total par is $#"
}
inp $1 $2 $3

解释:

inp $1 $2 $3    $1表示fun2.sh的第一个参数,$2表示fun2.sh的第二个参数,$3表示fun2.sh的第三个参数...

sh fun2.sh执行过程

[root@AliKvn shell-re]# sh fun2.sh 1
the first par is 1
the second par is
the tri par is
the script name is fun2.sh
total number is 1

[root@AliKvn shell-re]# sh fun2.sh 1 2
the first par is 1
the second par is 2
the tri par is
the script name is fun2.sh
total number is 2

[root@AliKvn shell-re]# sh fun2.sh 1 2 3
the first par is 1
the second par is 2
the tri par is 3
the script name is fun2.sh
total number is 3


示例2 

用意环境这个函数用来定义加法


编写脚本

#!/bin/bash
sum() {
        s=$[$1+$2]
        echo $s
}
sum 1 10



脚本解释:

s=$[$1+$2]  函数的第一个参数跟第二个参数相加

sum 1 10    调用sum函数,$1+$2=1+10,因为第一个函数1 第二个是10

脚本整个意思就是, s=$[$1+$2]两个函数相加$1+$2(相当于1+10),最后把$s打印出来,其实$s就是他们相加的和


示例3

用意环境:用来显示IP地址的脚本.


编写脚本

#!/bin/bash/
ip()
{
ifconfig |grep -A1 "$1: " |awk '/inet/ {print $2}'
}
read -p "plz input the eth name: " eth
ip $eth

解释:

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

用$1参数是针对用于多网卡之下使用,如果只有一个网卡的话,这里写网卡名字就可以.


脚本动作分解,

执行#ifconfig的内容

[root@centos7-01 ~]# ifconfig 
ens33: flags=4163  mtu 1500
        inet 192.168.189.128  netmask 255.255.255.0  broadcast 192.168.189.255
        inet6 fe80::20c:29ff:fe15:5353  prefixlen 64  scopeid 0x20
        ether 00:0c:29:15:53:53  txqueuelen 1000  (Ethernet)
        RX packets 84  bytes 10800 (10.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 142  bytes 15337 (14.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
ens33:0: flags=4163  mtu 1500
        inet 192.168.189.150  netmask 255.255.255.0  broadcast 192.168.189.255
        ether 00:0c:29:15:53:53  txqueuelen 1000  (Ethernet)
ens37: flags=4163  mtu 1500
        inet 192.168.149.147  netmask 255.255.255.0  broadcast 192.168.149.255
        inet6 fe80::df58:834c:af48:5f38  prefixlen 64  scopeid 0x20
        ether 00:0c:29:15:53:5d  txqueuelen 1000  (Ethernet)
        RX packets 1  bytes 243 (243.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 15  bytes 1134 (1.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1  (Local Loopback)
        RX packets 2252  bytes 691000 (674.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2252  bytes 691000 (674.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
下面以ens33为例

#执行# ifconfig |grep -A1 "ens33: ",因为ens33有2个网卡,所以也会把ens33:0给过滤出来
#表示过滤"ens33"这一行,包括和它下一行
[root@centos7-01 ~]# ifconfig |grep -A1 "ens33: "
ens33: flags=4163  mtu 1500
        inet 192.168.189.128  netmask 255.255.255.0  broadcast 192.168.189.255
--
ens33:0: flags=4163  mtu 1500
        inet 192.168.189.150  netmask 255.255.255.0  broadcast 192.168.189.255

#不过滤ens33:0,执行# ifconfig |grep -A1 "ens33: "
[root@centos7-01 ~]# ifconfig |grep -A1 "ens33: "
ens33: flags=4163  mtu 1500
        inet 192.168.189.128  netmask 255.255.255.0  broadcast 192.168.189.255

#ip地址是inet这行,所以,只需过滤这行信息出来
[root@centos7-01 ~]# ifconfig |grep -A1 "ens33: " |grep 'inet'
        inet 192.168.189.128  netmask 255.255.255.0  broadcast 192.168.189.255

#截取过滤了inet这行出来了,下面需要把想要的ip地址给过滤出来
192.168.189.128是我需要的信息,那么它属于第二个字段,所以可以利用awk把它分割过滤出来
[root@centos7-01 ~]# ifconfig |grep -A1 "ens33: " |grep 'inet' |awk '{print $2}'
192.168.189.128

#或者将后面直接grep的用法换成awk
[root@centos7-01 ~]# ifconfig |grep -A1 "ens33: " |awk '/inet/ {print $2}'
192.168.189.128


执行过程:

[root@centos7-01 shell]# sh -x fun3.sh 
+ read -p 'plz input the eth name: ' eth
plz input the eth name: ens33    
+ ip ens33
+ ifconfig
+ grep -A1 'ens33: '
+ awk '/inet/ {print $2}'
192.168.189.128
[root@centos7-01 shell]# sh -x fun3.sh 
+ read -p 'plz input the eth name: ' eth
plz input the eth name: ens33:0
+ ip ens33:0
+ ifconfig
+ grep -A1 'ens33:0: '
+ awk '/inet/ {print $2}'
192.168.189.150
[root@centos7-01 shell]# sh -x fun3.sh 
+ read -p 'plz input the eth name: ' eth
plz input the eth name: ens37    
+ ip ens37
+ ifconfig
+ grep -A1 'ens37: '
+ awk '/inet/ {print $2}'
192.168.149.147


课后练习:

给此脚本添加2个判断条件:

输入的网卡名称是否存在本机

输入的网卡有没有ip地址


20.18 shell中的数组


shell中的数组1 


定义数组 a=(1 2 3); 

打印方法 echo ${a[@]}

[root@centos7-01 shell]# a=(1 2 3)
[root@centos7-01 shell]# echo ${a[@]}
1 2 3

用*可以代替@,不影响输出,效果一样

[root@centos7-01 shell]# echo ${a[*]}
1 2 3

查看某个参数值,0表示第一个

[root@centos7-01 shell]# echo ${a[1]}
2
[root@centos7-01 shell]# echo ${a[2]}
3
[root@centos7-01 shell]# echo ${a[0]}
1

echo ${#a[@]} 获取数组的元素个数 

[root@centos7-01 shell]# echo ${#a[*]}
4



数组赋值

[root@centos7-01 shell]# a[3]=b

打印

[root@centos7-01 shell]# echo ${a[*]}
1 2 3 b

同样,赋值也支持覆盖,更改

[root@centos7-01 shell]# a[3]=bbbb
[root@centos7-01 shell]# echo ${a[*]}
1 2 3 bbbb

a[5]=2; echo ${a[@]} 如果下标不存在则会自动添加一个元素


数组的删除

删除a的第四个参数

[root@centos7-01 shell]# unset a[3]
[root@centos7-01 shell]# echo ${a[*]}
1 2 3


删除整个数组a

[root@centos7-01 shell]# unset a
[root@centos7-01 shell]# echo ${a[*]}


shell中的数组2 

数组分片

a=(`seq 1 10`) 可以 1 循环到 10

[root@centos7-01 shell]# a=(`seq 1 10`)
[root@centos7-01 shell]# echo ${a[*]}
1 2 3 4 5 6 7 8 9 10

上面的输出,截取4-7的数字

[root@centos7-01 shell]# echo ${a[@]:3:4}
4 5 6 7

解释:

# echo ${a[@]:3:4}

因为从4开始截取,4的前面是3,且3是第三个,然后截取3后面的4个参数。


倒数截取

倒数3个数,截取2个(倒数是负数,所以是0- 表示,截取是从左到右)

[root@centos7-01 shell]# echo ${a[@]:0-3:2}
8 9

数组替换

例子:echo ${a[@]/7/6}  7是需要替换的值,6是被替换的值

[root@centos7-01 shell]# echo ${a[*]}
1 2 3 4 5 6 7 8 9 10
[root@centos7-01 shell]# echo ${a[*]/7/6}
1 2 3 4 5 6 6 8 9 10

同样,可以给a赋值为输出后的参数

[root@centos7-01 shell]# echo ${a[*]/7/6}
1 2 3 4 5 6 6 8 9 10
[root@centos7-01 shell]# a=(${a[*]/7/6})
[root@centos7-01 shell]# echo ${a[*]}
1 2 3 4 5 6 6 8 9 10

输出结果一样


20.19 告警系统需求分析


shell项目-告警系统 

  • 需求:使用shell定制各种个性化告警工具,但需要统一化管理、规范化管理

  • 思路:指定一个脚本包,包含主程序、子程序、配置文件、邮件引擎、输出日志等。

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

  • 配置文件:是一个控制中心,用它来开关各个子程序,指定各个相关联的日志文件。

  • 子程序:这个才是真正的监控脚本,用来监控各个指标。

  • 邮件引擎:是由一个python程序来实现,它可以定义发邮件的服务器、发邮件人以及发件人密码。

  • 输出日志:整个监控系统要有日志输出。


要求:我们的机器角色多种多样,但是所有机器上都要部署同样的监控系统,也就说所有机器不管什么角色,整个程序框架都是一致的,不同的地方在于根据不同的角色,定制不同的配置文件。

程序架构:


  • bin下是主程序

  • conf下是配置文件

  • shares下是各个监控脚本

  • mail下是邮件引擎

  • log下是日志