shell編程 原

shell是什麼?

shell是一種腳本語言

可以使用邏輯判斷、循環等語法

可以自定義函數

shell是系統命令的集合

shell腳本可以實現自動化運維,能大大增加我們的運維效率

shell腳本結構和執行方法

開頭需要加#!/bin/bash

以#開頭的行作爲解釋說明

腳本的名字以.sh結尾,用於區分這是一個shell腳本

執行方法有兩種 chmod +x 1.sh; ./1.sh bash 1.sh

查看腳本執行過程 bash -x 1.sh

查看腳本是否語法錯誤 bash -n 1.sh

date命令的用法

 date  +%Y-%m-%d, date +%y-%m-%d //年月日
 date  +%H:%M:%S = date +%T //時間
 date +%s  //時間戳
 date -d @1504620492
 date -d "+1day"  //一天後
 date -d "-1 day"  //一天前
 date -d "-1 month" //一月前
 date -d "-1 min"  //一分鐘前
 date +%w, date +%W //星期

shell腳本中的變量

當腳本中使用某個字符串較頻繁並且字符串長度很長時就應該使用變量代替

使用條件語句時,常使用變量 if [ $a -gt 1 ]; then … ; fi

引用某個命令的結果時,用變量替代 n=`wc -l 1.txt`

寫和用戶交互的腳本時,變量也是必不可少的 read -p "Input a number: " n; echo $n 如果沒寫這個n,可以直接使用$REPLY

內置變量 $0, $1, $2… $0表示腳本本身,$1 第一個參數,$2 第二個 …. $#表示參數個數

數學運算a=1;b=2; c=$(($a+$b))或者$[$a+$b]

shell中的邏輯判斷

 格式1:if 條件 ; then 語句; fi
 格式2:if 條件; then 語句; else 語句; fi
 格式3:if …; then … ;elif …; then …; else …; fi
 邏輯判斷表達式:if [ $a -gt $b ]; if [ $a -lt 5 ]; if [ $b -eq 10 ]等 -gt (>); -lt(<); -ge(>=); -le(<=);-eq(==); -ne(!=) 注意到處都是空格
 可以使用 && || 結合多個條件
 if [ $a -gt 5 ] && [ $a -lt 10 ]; then
 if [ $b -gt 5 ] || [ $b -lt 3 ]; then

if 判斷文件、目錄屬性

 [ -f file ] 判斷是否是普通文件,且存在
 [ -d file ] 判斷是否是目錄,且存在
 [ -e file ] 判斷文件或目錄是否存在
 [ -r file ] 判斷文件是否可讀
 [ -w file ] 判斷文件是否可寫
 [ -x file ] 判斷文件是否可執行

if判斷的一些特殊用法

 if [ -z "$a" ]  這個表示當變量a的值爲空時會怎麼樣
 if [ -n "$a" ] 表示當變量a的值不爲空
 if grep -q '123' 1.txt; then  表示如果1.txt中含有'123'的行時會怎麼樣
 if [ ! -e file ]; then 表示文件不存在時會怎麼樣
 if (($a<1)); then …等同於 if [ $a -lt 1 ]; then… 
 [ ] 中不能使用<,>,==,!=,>=,<=這樣的符號

shell中的case判斷

 格式 case  變量名 in 
          value1)                         
            command
            ;;
          value2)
            command
            ;;
          *)           
            commond
            ;;
         esac
在case程序中,可以在條件中使用|,表示或的意思, 比如    
2|3) 
 command
 ;;

shell腳本案例

 #!/bin/bash
read -p "Please input a number: " n
if [ -z "$n" ]
then
    echo "Please input a number."
    exit 1
fi

n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
 echo "Please input a number."
 exit 1
fi

if [ $n -lt 60 ] && [ $n -ge 0 ]
then
    tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
then
    tag=2
elif [ $n -ge 80 ]  && [ $n -lt 90 ]
then
    tag=3
elif [ $n -ge 90 ] && [ $n -le 100 ]
then
    tag=4
else 
    tag=0
fi
case $tag in
    1)
    echo "not ok"
        ;;
    2)
        echo "ok"
        ;;
    3)
        echo "ook"
        ;;
    4)
        echo "oook"
        ;;
    *)
        echo "The number range is 0-100."
        ;; 
esac

for循環

語法:for 變量名 in 條件; do …; done

案例1(1到100累加)

#!/bin/bash
sum=0
for i in `seq 1 100`
do
  sum=$[$sum+$i]
  echo $i
done
echo $sum

案例2 (文件列表循環)

#!/bin/bash
cd /etc/
for a in `ls /etc/`
do
 if [ -d $a ]
  then
    ls -d $a
 fi
done

while循環

**語法 while 條件; do … ; done **

案例1

#!/bin/bash
while :
do
  load=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d. -f1`
  if [ $load -gt 10 ]
   then
     top|mail -s "load is high: $load" [email protected]
  fi
   sleep 30
done

案例2

#!/bin/bash
while :
do
    read -p "Please input a number: " n
    if [ -z "$n" ]
    then
        echo "you need input sth."
        continue
    fi
    n1=`echo $n|sed 's/[0-9]//g'`
    if [ -n "$n1" ]
    then
        echo "you just only input numbers."
        continue
    fi
    break
done
echo $n

break跳出循環

#!/bin/bash
for i in `seq 1 5`
do
    echo $i
    if [ $i == 3 ]
    then
        break
    fi
    echo $i
done
echo aaaaaaa

continue結束本次循環

忽略continue之下的代碼,直接進行下一次循環

#!/bin/bash
for i in `seq 1 5`
do
    echo $i
    if [ $i == 3 ]
    then
        continue
    fi
    echo $i
done
echo $i

exit直接退出腳本

#!/bin/bash
for i in `seq 1 5`
do
    echo $i
    if [ $i == 3 ]
    then
        exit
    fi
    echo $i
done
echo aaaaaaa

shell腳本中的函數

函數就是把一段代碼整理到了一個小單元中,並給這個小單元起一個名字,當用到這段代碼時直接調用這個小單元的名字即可。

格式: function f_name() {

                command          

         }

函數必須要放在最前面

示例1

#!/bin/bash
input() {
    echo $1 $2 $# $0
}

input 1 a b

示例2

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

示例3

#!/bin/bash
ip() {
    ifconfig |grep -A1 "$1" |tail -1 |awk '{print $2}'
}
read -p "Please input the eth name: " e
myip=`ip $e`
echo "$e address is $myip"

shell中的數組1

 定義數組 a=(1 2 3 4 5); echo ${a[@]}
 echo ${#a[@]} 獲取數組的元素個數 
 echo ${a[2]} 讀取第三個元素,數組從0開始
 echo ${a[*]} 等同於 ${a[@]}  顯示整個數組
 數組賦值
 a[1]=100; echo ${a[@]}
 a[5]=2; echo ${a[@]} 如果下標不存在則會自動添加一個元素
 數組的刪除
 uset a; unset a[1]

shell中的數組2

 數組分片
 a=(`seq 1 5`)
 echo ${a[@]:0:3} 從第一個元素開始,截取3個
 echo ${a[@]:1:4} 從第二個元素開始,截取4個
 echo ${a[@]:0-3:2} 從倒數第3個元素開始,截取2個
 數組替換
 echo ${a[@]/3/100}
 a=(${a[@]/3/100})

shell項目-告警系統

需求:使用shell定製各種個性化告警工具,但需要統一化管理、規範化管理。

思路:指定一個腳本包,包含主程序、子程序、配置文件、郵件引擎、輸出日誌等。

主程序:作爲整個腳本的入口,是整個系統的命脈。

配置文件:是一個控制中心,用它來開關各個子程序,指定各個相關聯的日誌文件。

子程序:這個纔是真正的監控腳本,用來監控各個指標。

郵件引擎:是由一個python程序來實現,它可以定義發郵件的服務器、發郵件人以及發件人密碼

輸出日誌:整個監控系統要有日誌輸出。

要求:我們的機器角色多種多樣,但是所有機器上都要部署同樣的監控系統,也就說所有機器不管什麼角色,整個程序框架都是一致的,不同的地方在於根據不同的角色,定製不同的配置文件。  

程序架構

bin下是主程序

conf下是配置文件

shares下是各個監控腳本

mail下是郵件引擎

log下是日誌。

存放路徑:

cd /usr/local/sbin/

mkdir mon

cd mon

mkdir  bin conf shares log mail

main.sh內容 /bin/下

#!/bin/bash
# 是否發送郵件的開關
export send=1
# 過濾ip地址
export addr=`/sbin/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
#先檢查配置文件中是否需要監控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

mon.conf內容 /conf/下

## to config the options if to monitor
## 定義mysql的服務器地址、端口以及user、password
to_mon_cdb=0   ##0 or 1, default 0,0 not monitor, 1 monitor
db_ip=10.20.3.13
db_port=3315
db_user=username
db_pass=passwd
## httpd   如果是1則監控,爲0不監控
to_mon_httpd=0
## php 如果是1則監控,爲0不監控
to_mon_php_socket=0
## http_code_502  需要定義訪問日誌的路徑
to_mon_502=1
logfile=/data/log/xxx.xxx.com/access.log
## request_count   定義日誌路徑以及域名
to_mon_request_count=0
req_log=/data/log/www.discuz.net/access.log
domainname=www.discuz.net

 load.sh內容 

#! /bin/bash
load=`uptime |awk -F 'average:' '{print $2}'|cut -d',' -f1|sed 's/ //g' |cut -d. -f1`
if [ $load -gt 10 ] && [ $send -eq "1" ]
then
    echo "$addr `date +%T` load is $load" >../log/load.tmp
    /bin/bash ../mail/mail.sh [email protected] "$addr\_load:$load" `cat ../log/load.tmp`
fi
echo "`date +%T` load is $load"

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"

disk.sh內容

#! /bin/bash
##Writen by aming##
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/mail.sh $addr\_disk $r ../log/disk.tmp
    echo "`date +%T` disk useage is nook"
else
    echo "`date +%T` disk useage is ok"
fi

 mail.sh內容

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.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.py  $1 "trouble continue 10 min $2" "$3"
         echo "0" > /tmp/$log.txt
    fi
fi  

 mail.py內容

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
import sys
mail_user = '[email protected]'   #填自己的郵箱地址
mail_pass = 'xxxxxxxxxx'         #填寫授權碼

def send_mail(to_list,subject,content):
	me = "zabbix 監控告警平臺"+"<"+mail_user+">"
	msg = MIMEText(content, 'plain', 'utf-8')
	msg['Subject'] = subject
	msg['From'] = me
	msg['to'] = to_list
	try:
		s = smtplib.SMTP("smtp.163.com", 25)
		s.login(mail_user,mail_pass)
		s.sendmail(me,to_list,msg.as_string())
		s.close()
		return True

	except Exception,e:
		print str(e)
		return False
	
	if __name__ == "__main__":
		send_mail(sys.argv[1], sys.argv[2], sys.argv[3])

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章