文档章节

shell编程

人在艹木中
 人在艹木中
发布于 07/17 19:42
字数 6278
阅读 12
收藏 0

一、shell脚本介绍

shell是一种脚本语言,是用户与Linux操作系统之间沟通的桥梁。常用的shell是bash,shell的分类有sh、csh、ksh等等。

shell可以使用逻辑判断、循环等语法,可以自定义函数,可以实现自动化运维等等。

二、shell脚本结构和执行方法

1、shell脚本结构

·shell脚本名称:命令一般为英文的大、小写字母,不能使用空格、特殊符号来命名,也不建议用纯数字命名

·后缀一般用.sh结尾

·shell脚本内容的首行以#!/bin/bash开头

·变量名尽量使用大写字母,不能以数字、特殊符号开头,字母之间不能用"-",但可以用"_"。

2、第一个shell脚本和执行

脚本名:helloworld.sh

[root@node2 ~]# vim helloworld.sh
#!/bin/bash
#第一个脚本
#
echo "Hello World!"

执行脚本:添加可执行权限:

[root@node2 ~]# chmod +x helloworld.sh 
[root@node2 ~]# 
执行:

[root@node2 ~]# chmod +x helloworld.sh 
[root@node2 ~]# ./helloworld.sh 
Hello World!
[root@node2 ~]# sh helloworld.sh 
Hello World!
[root@node2 ~]# bash helloworld.sh 
Hello World!
[root@node2 ~]# 

OK,执行成功。

脚本的执行:

有执行权限: ./脚本、 sh 脚本  、 bash  脚本

无执行权限: sh 脚本  、 bash  脚本

sh -x :测试脚本

[root@node2 ~]# sh -x helloworld.sh 
+ echo 'Hello World!'
Hello World!
[root@node2 ~]# 

三、date命令用法

用法:date [选项] [+指定格式]

选项:

-d:- --date=STRING, display time described by STRING, not 'now',比如:date -d " -1 day",显示当前时间的前一天时间

date -d "+1 day":一天后

date -d "-1 day":一天前

date -d "+1 month":一月后

-s:指定日期,如:date -s "20180717 22:23:10"

格式:

%Y:年,如2018

%y:年,显示最后2位,如2018显示成18

%m:月,数字

%h:月,英文

%d:日

%H:小时(00-23),24小时制

%I:小时(00-12),12小时制

%M:分

%S:秒

%s:时间戳,从1970年1月1日00:00:00到现在经过多少秒

%T:时:分:秒,如:22:28:26

%w:星期几

%W:今年的第几周

%j:今年中的第几天

%F:年-月-日

cal:显示日历

 

1、查看系统当前时间

[root@node2 ~]# date
Tue Jul 17 22:16:24 CST 2018
[root@node2 ~]# 

2、-d选项

一天前:

[root@node2 ~]# date -d "-1 day"
Mon Jul 16 22:33:49 CST 2018
[root@node2 ~]# 

一天后:

[root@node2 ~]# date -d "+1 day"
Wed Jul 18 22:34:35 CST 2018
[root@node2 ~]# 

一个月前:

[root@node2 ~]# date -d "-1 month"
Sun Jun 17 22:34:59 CST 2018
[root@node2 ~]# 

一年前:

[root@node2 ~]# date -d "-1 years"
Mon Jul 17 22:35:20 CST 2017
[root@node2 ~]# 

一周后:

[root@node2 ~]# date -d "+1 week"
Tue Jul 24 22:36:10 CST 2018
[root@node2 ~]# 

3、时间戳

[root@node2 ~]# date +%s
1531838233
[root@node2 ~]# 

使用@:

[root@node2 ~]# date +%s
1531838233
[root@node2 ~]# date -d @1531838233
Tue Jul 17 22:37:13 CST 2018
[root@node2 ~]# 

将某个日期换成时间戳:

[root@node2 ~]# date +%s -d "20180717 22:40:56"
1531838456
[root@node2 ~]# 

将时间戳换成日期:

[root@node2 ~]# date -d @1531838456
Tue Jul 17 22:40:56 CST 2018
[root@node2 ~]# 

四、脚本中的变量

与C、java不同的是,shell中的变量不需要定义变量类型。

变量赋值:变量名=值,注意:等号两边不能有空格。

name=tom

a=1

变量名的定义:变量名首个字符必须为字母,不能以数字开头,变量名中间不能有空格,不能使用“-”,但可以使用下划线“_”,如:BACK_DIR=/mydata,IP=192.168.10.205

系统内置变量:

$0:当前脚本的名称

$?:上一条命令的执行状态,要么是0,要么是1

$#:当前脚本的参数个数(不包括脚本名本身)

$*:当前脚本的全部参数(不包括脚本名本身)

$n:脚本的第n个参数,n=1,2,3...

$$:程序的PID

环境变量:

PATH:命令所在路径,以冒号分割

HOSTNAME:当前主机名

HOME:用户家目录

ID:当前用户ID

五、逻辑判断

1、if语句

格式1:

if  条件;then  

    语句

fi

格式2:

 

if  条件;then  

     语句

else

     语句

fi

格式3:

 

if  条件;then  

     语句

elif

     语句

fi

例如:

[root@node2 ~]# a=5
[root@node2 ~]# if [ $a -gt 3 ];then
> echo "a大于3"
> else
> echo "a小于3"
> fi
a大于3
[root@node2 ~]# 

2、if逻辑判断逻辑运算符

-f:判断文件是否存在,且是普通文件,如: [ -f haha ]

-d:判断目录是否存在

-eq:等于,用于整型比较,如:[ 1 -eq 3 ]

-ne:不等于,用于整型比较

-gt:大于,用于整型比较

-ge:大于或等于,用于整型比较

-lt:小于,用于整型比较

-le:小于或等于,用于整型比较

-z:是否为空字符串

||:逻辑或

&&:逻辑与

-a:and

-o:or

举例:

-o使用:

[root@node2 ~]# if [ 1 -eq 2 -o 3 -gt 2 ];then
> echo "Ture"
> else
> echo "False"
> fi
Ture
[root@node2 ~]# 

-a使用:

[root@node2 ~]# if [ 1 -eq 2 -a 3 -gt 2 ];then echo "Ture"; else echo "False"; fi
False
[root@node2 ~]# 

&&使用:

[root@node2 ~]# [ 2 -eq 3 ] && echo "haha"
[root@node2 ~]# 

||使用:

[root@node2 ~]# [ 2 -eq 3 ] || echo "haha"
haha
[root@node2 ~]# 

&&:两边为真,结果为真,其他情况为假。俗称:短路与,也就说:只要左边为假,就不需要继续判断了,结果就是假。

||:两边为假,结果为假,其他情况为真。俗称:短路或,也就说:只要左边为真,就不需要继续判断了,结果就是真。

如果只有一个&会有什么结果呢:

[root@node2 ~]# [ 2 -eq 3 ] & echo "haha"
[1] 2782
haha
[root@node2 ~]# 

&:会从左到右执行。不管左边真假。非短路与

六、文件目录属性判断

[ -f 文件名 ] :判断是否是普通文件,且存在

[ -d 文件 ]:判断是否是目录,且存在

[ -e  文件 ] :判断文件或目录是否存在

[ -r  文件 ] :判断文件是否可读

[ -w  文件 ] :判断文件是否可写

[ -x  文件 ] :判断文件是否可执行

例如:

[root@node2 ~]# [ -f haha ] || echo "not found"
not found
[root@node2 ~]# 

文件不存在

[root@node2 ~]# [ -d haha ] || echo "directory not found"
directory not found
[root@node2 ~]# 

目录不存在

属性判断:对当前用户权限判断

[root@node2 ~]# ls
anaconda-ks.cfg  auto_install_zabbix.sh  helloworld.sh  zabbix-3.4.11  zabbix-3.4.11.tar.gz
[root@node2 ~]# [ -x helloworld.sh ] && echo "该文件有执行权限"
该文件有执行权限
[root@node2 ~]# [ -r helloworld.sh ] && echo "该文件可读"
该文件可读
[root@node2 ~]# [ -w helloworld.sh ] && echo "该文件可写"
该文件可写
[root@node2 ~]# 

目录判断:

[root@node2 ~]# [ -d /haha ] || echo "目录不存在"
目录不存在
[root@node2 ~]# [ -d /usr/local/  ] &&  echo "目录存在"
目录存在
[root@node2 ~]# 

七、if特殊用法

if [  -z  "$a" ]:当a的值为空时会怎样

[root@node2 ~]# a=1
[root@node2 ~]# if [ -z "$a" ];then echo "haha"; fi
[root@node2 ~]# unset a
[root@node2 ~]# if [ -z "$a" ];then echo "haha"; fi
haha
[root@node2 ~]# 

if [  -n  "$a" ]:当a的值不为空

[root@node2 ~]# a=1
[root@node2 ~]# if [ -n "$a" ];then echo "haha"; fi
haha
[root@node2 ~]# unset a
[root@node2 ~]# if [ -n "$a" ];then echo "haha"; fi
[root@node2 ~]# 

if grep -q '123' 1.txt;then

[root@node2 ~]# echo "123" >123.txt
[root@node2 ~]# if grep -q '123' 123.txt;then
> echo "lalala"
> fi
lalala
[root@node2 ~]# 

-q:静默模式,也就是不输出屏幕。

判断root用户是否存在:

[root@node2 ~]# if grep -wq 'root' /etc/passwd;then echo "root is exist"; else echo "root is not exist"; fi
root is exist
[root@node2 ~]# 

 

if [ ! -e file ];then

[root@node2 ~]# if [ ! -e haha.txt ];then
> echo 'aaa'
> fi
aaa
[root@node2 ~]#

if((2>1));then

[root@node2 ~]# if ((2>1));then
> echo "True"
> fi
True
[root@node2 ~]# if ((2!=1));then echo "True"; fi
True
[root@node2 ~]# if ((2>=1));then echo "True"; fi
True
[root@node2 ~]# if ((2<1));then echo "True"; fi
[root@node2 ~]# 

注意:

[]中不能使用>、<、==、>=、<=、!=这些符号

(())中可以使用>、<、==、>=、<=、!=符号

在if语句中,要注意空格问题:

[root@node2 ~]# if[2-gt3];then
-bash: syntax error near unexpected token `then'
[root@node2 ~]# 

正确的是:

[root@node2 ~]# if [ 2 -gt 3 ];then echo "haha"; fi
[root@node2 ~]# 

但(())括号中的判断,可以使用空格,也可以不用

[root@node2 ~]# if (( 2 > 1 ));then
> echo "haha"
> fi
haha
[root@node2 ~]# if ((2>=1));then echo "True"; fi
True

八、case判断(上)、(下)

case语法:

case  变量名  in

     value1)

          语句1

          ;;

 value2)

          语句2

          ;;

    ....

        *)

          语句

          ;;

   esac

  例如:

[root@node2 ~]# a=2
[root@node2 ~]# case $a in
> 1)
> echo "a=1"
> ;;
> 2)
> echo "a=2"
> ;;
> *)
> echo "haha"
> ;;
> esac
a=2
[root@node2 ~]# 

case中可以使用|表示或:

[root@node2 ~]# unset a
[root@node2 ~]# a=2
[root@node2 ~]# case $a in
> 1)
> echo "a=1"
> ;;
> 1|2)
> echo "a=1或2"
> ;;
> *)
> echo "haha"
> ;;
> esac
a=1或2
[root@node2 ~]# 

if和case综合使用:输入一个考试分数(整数),判断等级。

[root@node2 ~]# vim score.sh
#!/bin/bash
#输入一个考试分数判断等级

read -p "请输入一个数字:" score

if [ -z "$score" ];then
   echo "请输入一个数字。"
   exit 1
fi
#判断输入的是否是数字
n=`echo $score | sed 's/[0-9]//g'`
if [ ! -z $n ];then
   echo "你输入的不是数字,请输入数字。"
   exit 1
fi
#小于60,大于等于0
if [ $score -lt 60 ] && [ $score -ge 0 ];then
   tag=1
#大于等于60,小于80
elif [ $score -ge 60 ] && [ $score -lt 80 ];then
   tag=2
#大于等于80,小于90
elif [ $score -ge 80 ] && [ $score -lt 90 ];then
   tag=3
#大于等于90,小于等于100
elif [ $score -ge 90 ] && [ $score -le 100 ];then
   tag=4
#其他情况
else
   tag=0
fi
#case判断
case $tag in
   1)
      echo "不及格"
      ;;
   2)
      echo "及格"
      ;;
   3)
      echo "良好"
      ;;
   4)
      echo "优秀"
      ;;
   *)
      echo "输入的数字有误"
      ;;
esac

测试:

[root@node2 ~]# sh score.sh 
请输入一个数字:50
不及格
[root@node2 ~]# sh score.sh 
请输入一个数字:101
输入的数字有误
[root@node2 ~]# sh score.sh 
请输入一个数字:89
良好
[root@node2 ~]# sh score.sh 
请输入一个数字:haha
你输入的不是数字,请输入数字。
[root@node2 ~]# 

此脚本不足的是不能判断小数,比如:

[root@node2 ~]# sh score.sh 
请输入一个数字:87.4
你输入的不是数字,请输入数字。
[root@node2 ~]# 

九、for循环

语法: for  变量名  in  条件;do  语句; done

例如:计算1到100的和

[root@node2 ~]# vim for.sh
#!/bin/bash
sum=0
for i in `seq 1 100`;do
   sum=$[$i+$sum]
done
echo "sum=$sum"

[root@node2 ~]# sh for.sh 
sum=5050
[root@node2 ~]# 

例2:列出/etc/目录中的目录信息

[root@node2 ~]# vim dirlist.sh
#!/bin/bash

cd /etc/
for a in `ls /etc/`
do
   if [ -d $a ];then
       ls -ld $a
   fi
done

测试:

[root@node2 ~]# sh dirlist.sh 
drwxr-xr-x. 2 root root 236 Jun 30 11:17 alternatives
drwxr-x---. 3 root root 43 Jun 30 11:17 audisp
drwxr-x---. 3 root root 83 Jun 30 11:35 audit
drwxr-xr-x. 2 root root 148 Jun 30 11:17 bash_completion.d
drwxr-xr-x. 2 root root 6 Feb 20 23:47 binfmt.d
drwxr-xr-x. 2 root root 6 Jun  6  2017 chkconfig.d
drwxr-xr-x. 2 root root 21 Jun 30 11:17 cron.d
。。。。

十、while循环(上)、(下)

系统负载监控:

[root@node2 ~]# vim whiledemo.sh
#!/bin/bash
while ture
do
   load=`w | head -1 | awk -F 'load average:' '{print $2}'| cut -d. -f1 | sed 's/[[:space:]]*//g'

   if [ $load -gt 10 ];then
      echo "负载较高"
   fi
   sleep 30
done

测试:

[root@node2 ~]# sh -x whiledemo.sh
+ true
++ w
++ cut -d. -f1
++ sed 's/[[:space:]]//g'
++ awk -F 'load average:' '{print $2}'
++ head -1
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 30

判断数字:

[root@node2 ~]# vim whiledemo02.sh
#!/bin/bash

while :
do
   read -p "请输入一个数字:" n
   if [ -z "$n" ];then
      echo "请输入东西,不能为空"
      continue
   fi
   n1=`echo $n | sed 's/[0-9]//g'`
   if [ ! -z "$n1" ];then
      echo "只能输入纯数字"
      continue
   fi
   break
done
echo $n

测试:

[root@node2 ~]# sh whiledemo02.sh
请输入一个数字:52
52
[root@node2 ~]# sh whiledemo02.sh
请输入一个数字:
请输入东西,不能为空
请输入一个数字:h1
只能输入纯数字
请输入一个数字:20
20
[root@node2 ~]# 

十一、break跳出循环

break:可以退出循环

例如:

[root@node2 ~]# vim breakdemo01.sh
#!/bin/bash
while true
do
  read -p "请输入一个整数:" n
  echo "你输入的是:$n"
  if [ $n -eq 2 ];then
     echo "退出脚本"
     break
  fi
done

测试:

[root@node2 ~]# sh breakdemo01.sh
请输入一个整数:4
你输入的是:4
请输入一个整数:6
你输入的是:6
请输入一个整数:7
你输入的是:7
请输入一个整数:2
你输入的是:2
退出脚本
[root@node2 ~]# 

在for中使用break:

[root@node2 ~]# vim breakdemo02.sh
#!/bin/bash
for i in `seq 1 5`
do
   if [ $i == 2 ];then
      break
   fi
   echo $i
done
echo "haha"

测试:

[root@node2 ~]# sh breakdemo02.sh
1
haha
[root@node2 ~]#

十二、continue跳出本次循环

continue跳出本次循环,例如:

[root@node2 ~]# vim continuedemo.sh
#!/bin/bash
for i in `seq 1 5`
do
   if [ $i == 2 ];then
      break
   fi
   echo $i
done
echo "haha"

测试:

[root@node2 ~]# sh continuedemo.sh
1
3
4
5
haha
[root@node2 ~]# 

十三、exit退出整个脚本

exit退出整个脚本,例如:

[root@node2 ~]# vim exitdemo.sh
#!/bin/bash
for i in `seq 1 5`
do
   if [ $i == 2 ];then
      exit
   fi
   echo $i
done
echo "haha"

测试:

[root@node2 ~]# sh exitdemo.sh
1
[root@node2 ~]# 

当i等于2的时候退出脚本,所以后面的语句不会执行。

十四、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.sh
sum=8
[root@node2 ~]# 

例2:获取某个网卡的ip

[root@node2 ~]# vim funcip.sh
#!/bin/bash

cutip()
{
    ip addr | grep "\<$1\>" | grep 'inet' | cut -d'/' -f1 | awk '{print $2}'
}

read -p "请输入网卡名称:" eth
cutip $eth

测试:

[root@node2 ~]# sh  funcip.sh
请输入网卡名称:ens33
192.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 '\<inet\>' | 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。"
     exit
fi
exec 1 >> ../log/mon.log 2>> ../log/error.log
echo "`date +%F' '%T`  load average:"
/bin/bash ../shares/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/[[:space:]]*//g‘`
     /bin/bash ../shares/502.sh
fi

十八、告警系统配置文件

配置文件:/mon/conf/mon.conf

[root@node2 ~]# vim /mon/conf/mon.conf
#监控mysql
#定义mysql服务器地址、端口、用户和密码
to_mon_cdb=0 #0不监控,1为监控
db_ip=192.168.10.206
db_port=3306
db_user=root
db_pass=
##httpd
to_mon_httpd=0 #0为不监控,1为监控
#php
to_mon_php_socket=0
#http_code_502  日志路径
to_mon_502=1
logfile=/mydata/log/access.log
#request_count  日志路径、域名 
to_mon_request_count=0
req_log=/mydata/log/haha/access.log
domainname=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`
fi
echo "`date +%T` load is $load"

send在主脚本中定义。

子脚本:/mon/shares/502.sh

监控502

[root@node2 ~]# vim /mon/shares/502.sh

#!/bin/bash

d=`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.tmp
fi
echo "`date +%T` 502 $c_502"

子脚本:/mon/shares/disk.sh

监控磁盘使用

[root@node2 ~]# vim /mon/shares/disk.sh

#!/bin/bash

rm -f ../log/disk.tmp
for 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!"
    fi
done

二十、告警系统邮件引擎(上)、(中)、(下)

邮件脚本1:/mon/mail/mail.py

[root@node2 ~]# vim /mon/mail/mail.py
#!/usr/bin/env python
#-*- conding:UTF-8 -*-

import os,sys
import getopt
import smtplib
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMutilpart
from 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" %err
def 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/bash
log=$1
t_s=`date +%s`
t_s2=`date -d "2 hours ago"+%s`
if [ ! -f /tmp/$log ];then
   echo $t_s2 > /tmp/$log
fi
t_s2=`tail -1 /tmp/$log | awk '{print $1}'`
echo $t_s >> /tmp/$log
v=$[$t_s-$t_s2]
echo $v
if [ $v -gt 3600 ];then
   ../mail/mial.py $1 $2 $3
   echo "0" > /tmp/$log.txt
else
   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
   fi
fi

二十一、运行告警系统

[root@node2 bin]# pwd
/mon/bin
[root@node2 bin]# sh -x main.sh 
+ export send=1
+ send=1
++ ip addr
++ grep '\<inet\>'
++ 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]# 

二十二、分发系统介绍

 expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。expect是在Tcl基础上创建起来的。

二十三、expect脚本远程登录

安装expect

[root@node2 ~]# yum install expect -y

远程登录脚本:

[root@node2 ~]# vim remotelogin.expect
#!/usr/bin/expect

set host "192.168.10.205"
set passwd "123456"

spawn ssh root@$host

expect {
  "yes/no" { send "yes\r";exp_continue }
  "assword:" { send "$passwd\r" }
}
interact

执行脚本:

[root@node2 ~]# chmod +x remotelogin.expect
[root@node2 ~]# ./remotelogin.expect
spawn ssh root@192.168.10.205
The authenticity of host '192.168.10.205 (192.168.10.205)' can't be established.
ECDSA key fingerprint is SHA256:bfXUezrOQimsSXepM09lXgx/Pol5MJvtvgOU7K+wdWQ.
ECDSA key fingerprint is MD5:a2:9c:64:2f:7b:2b:93:26:fa:d6:b1:48:5a:6d:d8:42.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.205' (ECDSA) to the list of known hosts.
root@192.168.10.205's password: 
Last login: Fri Jul 20 23:13:17 2018 from 192.168.10.1
[root@node1 ~]# 

OK,登录成功。

二十四、expect脚本远程执行命令

脚本如下:

[root@node2 ~]# vim expectdemo01.expect
#!/usr/bin/expect

set user "root"
set passwd "123456"
set host "192.168.10.205"

spawn ssh $user@$host

expect {
   "yes/no" { send "yes\r";exp_continue }
   "password:" { send "$passwd\r"}
}

expect "]*"
send "touch /tmp/12.txt\r"
expect "]*"
send "echo haha > /tmp/12.txt\r"
expect "]*"
send "exit\r"

执行:

[root@node2 ~]# chmod +x expectdemo01.expect
[root@node2 ~]# ./expectdemo01.expect 
spawn ssh root@192.168.10.205
root@192.168.10.205's password: 
Last login: Sat Jul 21 17:46:55 2018 from 192.168.10.206
[root@node1 ~]# touch /tmp/12.txt
[root@node1 ~]# echo haha > /tmp/12.txt
[root@node1 ~]# [root@node2 ~]# 

该脚本远程登录192.168.10.205,创建/tmp/12.txt文件,然后退出。

二十五、expect脚本传递参数

脚本:

#!/usr/bin/expect

set user [lindex $argv 0]
set host [lindex $argv 1]
set passwd "123456"
set cm [lindex $argv 2]
spawn ssh $user@$host

expect {
   "yes/no" { send "yes\r";exp_continue }
   "password:" { send "$passwd\r"}
}

expect "]*"
send "$cm\r"
set timeout 5
expect "]*"
send "exit\r"

set timeout 5:设置超时时间,如是-1则不会超时

执行脚本:

[root@node2 ~]# chmod +x expectdemo02.expect
[root@node2 ~]# ./expectdemo02.expect root 192.168.10.205 ls
spawn ssh root@192.168.10.205
Last login: Sat Jul 21 20:06:38 2018 from 192.168.10.206
[root@node1 ~]# ls
anaconda-ks.cfg              mariadb-10.3.7         php-7.2.7         zabbix-3.4.11
auto_install_zabbix_lnmp.sh  mariadb-10.3.7.tar.gz  php-7.2.7.tar.gz  zabbix-3.4.11.tar.gz
libmcrypt-2.5.8              nginx-1.14.0           py
libmcrypt-2.5.8.tar.gz       nginx-1.14.0.tar.gz    Python-3.7.0.tgz
[root@node1 ~]# [root@node2 ~]# 

OK,执行成功。

二十六、expect脚本同步文件

脚本:

[root@node2 ~]# vim expectdemo03.expect
#!/usr/bin/expect

set passwd "123456"

spawn rsync -av root@192.168.10.205:/tmp/12.txt /tmp/

expect {
    "yes/no" { send "yes\r";exp_continue }
    "password:" { send "$passwd\r" }
}

expect eof

执行:

[root@node2 ~]# chmod +x expectdemo03.expect
[root@node2 ~]# ./expectdemo03.expect
spawn rsync -av root@192.168.10.205:/tmp/12.txt /tmp/
receiving incremental file list
12.txt

sent 43 bytes  received 96 bytes  92.67 bytes/sec
total size is 5  speedup is 0.04
expect: spawn id exp6 not open
    while executing
"expect eof"
    (file "./expectdemo03.expect" line 12)
[root@node2 ~]# 

二十七、expect脚本指定host和要同步的文件

脚本:

[root@node2 ~]# vim expectdemo04.expect
#!/usr/bin/expect

set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]

spawn rsync -av $file root@$host:$file

expect {
    "yes/no" {  send "yes\r" }
    "password:" { send "$passwd\r" }
}
expect eof

测试执行:

[root@node2 ~]# chmod +x expectdemo04.expect
[root@node2 ~]# ./expectdemo04.expect  192.168.10.205 /root/for.sh 
spawn rsync -av /root/for.sh root@192.168.10.205:/root/for.sh
sending incremental file list
for.sh

sent 174 bytes  received 35 bytes  139.33 bytes/sec
total size is 82  speedup is 0.39
expect: spawn id exp6 not open
    while executing
"expect eof"
    (file "./expectdemo04.expect" line 13)
[root@node2 ~]# 

登录192.168.10.205看看:

[root@node2 ~]# ssh 192.168.10.205
Last login: Sat Jul 21 20:28:17 2018 from 192.168.10.206
[root@node1 ~]# ls
anaconda-ks.cfg              libmcrypt-2.5.8.tar.gz  nginx-1.14.0.tar.gz  Python-3.7.0.tgz
auto_install_zabbix_lnmp.sh  mariadb-10.3.7          php-7.2.7            zabbix-3.4.11
for.sh                       mariadb-10.3.7.tar.gz   php-7.2.7.tar.gz     zabbix-3.4.11.tar.gz
libmcrypt-2.5.8              nginx-1.14.0            py
[root@node1 ~]# 

OK,for.sh文件已同步过来

二十八、expect传输ssh公钥

1、生成密钥对

[root@node2 ~]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:lj4GyvqmmHzJbY4KlK2xLXP54/bXptI20iHB8xipdkQ root@node2
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|       E         |
|      o .        |
|  o    B .       |
| + .  + S        |
|. =..+ B o       |
|.=.+* . B o      |
|oo+=+= + B o     |
|oo==*+o.=.+      |
+----[SHA256]-----+
[root@node2 ~]# 

2、将公钥传给远程客户端

脚本:

#!/usr/bin/expect

set host "192.168.10.205"
set passwd "123456"
spawn ssh-copy-id $host

expect {
     "yes/no" { send "yes\r";exp_continue }
     "password:" { send "$passwd\r"}
}
interact

执行脚本:

[root@node2 ~]# chmod +x ssh.expect 
[root@node2 ~]# ./ssh.expect 
spawn ssh-copy-id 192.168.10.205
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.205's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.10.205'"
and check to make sure that only the key(s) you wanted were added.

[root@node2 ~]# 

3、测试:

[root@node2 ~]# ssh 192.168.10.205
Last login: Sat Jul 21 19:52:45 2018 from 192.168.10.206
[root@node1 ~]# 

OK,可以免密登录了。

二十九、构建文件分发系统

需求背景:对于大公司而言,肯定时不时会有网站或配置文件更新,而且使用的机器也好几台,所以,自动同步文件就至关重要了。

实现思路:首先有一台模版机器,把要分发的文件准备好,然后使用expect脚本批量把需要的文件分发到目标机器即可。

核心命令:rsync -avR --files-from=list.txt  / root@host:/

1、expect脚本:

[root@node2 ~]# vim expectdemo05.expect
#!/usr/bin/expect

set passwd "123456"
set host [lindex $argv 0]
set file [lindex $argv 1]

spawn rsync -avR --files-from=$file / root@$host:/

expect {
   "yes/no" { send "yes\r"}
   "password:" { send "$passwd\r"}
}
expect eof

[root@node2 ~]# chmod +x expectdemo05.expect

2、需要同步的文件列表:

list.txt内容:该文件的内容放的是文件的绝对路径

[root@node2 ~]# vim /tmp/list.txt
/tmp/12.txt
/root/for.sh
/root/expectdemo01.expect
/root/expectdemo02.expect
/root/expectdemo03.expect
/root/expectdemo04.expect

3、ip列表:ip.txt,存放的是ip

[root@node2 ~]# vim /tmp/ip.txt
192.168.10.205
192.168.10.200

4、创建遍历ip列表的脚本

[root@node2 ~]# vim rsync.sh
#!/bin/bash

for rip in `cat /tmp/ip.txt`
do
    echo $rip
    ./expectdemo05.expect $rip /tmp/list.txt
done

执行该脚本:

[root@node2 ~]# sh rsync.sh 
192.168.10.205
spawn rsync -av --files-from=/tmp/list.txt / root@192.168.10.205:/
building file list ... done
root/
tmp/

sent 237 bytes  received 22 bytes  518.00 bytes/sec
total size is 1,089  speedup is 4.20
expect: spawn id exp6 not open
    while executing
"expect eof"
    (file "./expectdemo05.expect" line 13)
192.168.10.200
spawn rsync -av --files-from=/tmp/list.txt / root@192.168.10.200:/
root@192.168.10.200's password: 
building file list ... done
root/
tmp/

sent 237 bytes  received 22 bytes  172.67 bytes/sec
total size is 1,089  speedup is 4.20
[root@node2 ~]# 

三十、批量远程执行命令

1、expect脚本:

[root@node2 ~]# vim exec.expect
#!/usr/bin/expect

set host [lindex $argv 0]
set passwd "123456"
set cm [lindex $argv 1]

spawn ssh root@$host

expect { 
   "yes/no" { send "yes\r"}
   "password:" { send "$passwd\r"}
}
expect "]*"
send "$cm\r"
expect "]*"
send "exit\r"
[root@node2 ~]# chmod +x exec.expect

2、shell脚本

[root@node2 ~]# vim exec.sh
#!/bin/bash

for rip in `cat /tmp/ip.txt`
do
   echo $rip
   ./exec.expect $rip "hostname"
done

执行脚本:

[root@node2 ~]# sh exec.sh
192.168.10.205
spawn ssh root@192.168.10.205
Last login: Sat Jul 21 21:01:41 2018 from 192.168.10.206
[root@node1 ~]# hostname
node1
[root@node1 ~]# 192.168.10.200
spawn ssh root@192.168.10.200
root@192.168.10.200's password: 
Last failed login: Sat Jul 21 20:59:02 CST 2018 from 192.168.10.206 on ssh:notty
There were 2 failed login attempts since the last successful login.
Last login: Fri Jul 20 23:05:56 2018 from 192.168.10.1
[root@node3 ~]# hostname
node3
[root@node3 ~]# [root@node2 ~]# 

三十一、几个脚本展示

我的博客有lamp、lnmp、zabbix一键部署脚本:www.logmm.com

© 著作权归作者所有

共有 人打赏支持
人在艹木中
粉丝 4
博文 57
码字总数 204566
作品 0
茂名
运维
“笨办法”学Bash Shell(持续更新中)

  Shell是用户与Unix/Linux操作系统沟通的桥梁。用户既可以输入命令执行,又可以利用Shell脚本编程,完成更加复杂的操作。      在GUI日益完善的今天,在系统管理等领域,Shell编程仍然...

dbtrain
2017/10/25
0
0
Linux shell 编程

shell 编程概念 (1) shell是一种命令行解释器,外壳有很多种类 (2) shell 看成是Linux内核和用户沟通的桥梁,用户默认不能直接操作内核 (3)可以通过shell外壳去操作,用户指令传递给shell,传...

zdq1992
2017/11/15
0
0
2017-12-5Linux基础知识(15)shell编程

shell编程是在Linux的基础知识中所必须掌握的语言,它也是一个命令的集合,如果学会的话,我们将会事半功倍,将重复的操作通过shell编程脚本来实现,减轻了一定的负担,那么现在就来讲一下s...

刘祥宇
2017/12/07
0
0
比较Linux系统下shell编程与c语言编程的异同_Shell编程与C语言编程的相同点_两者的差异

这是我们的Linux课程结课题目,搜索了一下,网上没有很好的这方面的解答,于是我自己整理了一份...... Shell简介:Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一...

尘世如潮
2016/04/25
142
0
Shell脚本编程30分钟入门

什么是Shell脚本 示例 看个例子吧: #!/bin/shcd ~mkdir shell_tutcd shell_tut for ((i=0; i<10; i++)); do done 示例解释 第1行:指定脚本解释器,这里是用/bin/sh做解释器的 第2行:切换到...

quanpower
2014/03/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用JDK自带的jmap和jhat监控处于运行状态的Java进程

对于处于运行状态中的Java进程,JDK自带了很多工具,允许Java开发人员监控运行进程中的各种状态,比如该进程内部创建了多少个对象实例,消耗了多少内存,等等。 本文基于JDK1.8而写成。 我下...

JerryWang_SAP
18分钟前
1
0
下单接口调优实战,性能提高10倍

概述 最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了,如果改动太大,怕有风险。另外开发成本和测试成本也非常大。对于这种...

Sam哥哥聊技术
51分钟前
4
1
rabbitMQ的安装和配置

在Windows下进行rabbitMQ的安装 第一步:软件下载 在安装rabbitMQ之前,需要先安装Erlang。 Erlang官网:http://www.erlang.org/downloads rabbitMQ官网:http://www.rabbitmq.com/download....

狼王黄师傅
今天
3
0
Vue-Element-Upload

记录一下文件上传封装Js 代码示例 封装:uploadFile.vue <template> <el-upload v-model="attachment" ref="upload" class="upload-demo" :action="uploadUrl" ......

华山猛男
今天
4
0
AWVS破解及使用手册

1.安装 因为是windows软件,比较简单,此部分略: 破解插件下载: 链接: https://pan.baidu.com/s/1x9LK9F3KvqDgTvXDjoSZnQ 提取码: 7k4u 2.创建扫描目标 2-1.Targets->Add Target 2-2.对话框...

硅谷课堂
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部