筆記16(shell編程)

shell是什麼php

shell是一種腳本語言  aming_linux  blog.lishiming.netpython

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

 能夠自定義函數linux

 shell是系統命令的集合git

 shell腳本能夠實現自動化運維能大大增長咱們的運維效率sql


shell腳本結構和執行方法shell

 開頭須要加#!/bin/bash固有的格式數組

意思就是接下來的文件是由/bin/bash解析的瀏覽器

 以#開頭的行做爲解釋說明bash

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

執行方法有兩種:

(1)先給這個文件加一個執行權限'x' 

例如:chmod a+x 1.sh 這樣就能夠在相對路徑下用./1.sh來執行它。

(2)bash 1.sh

(3)sh 1.sh

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

 查看腳本是否語法錯誤  bash -n 1.sh 當一個腳本語法有錯誤時他會有一個提示,若是沒有任何輸出證實他沒有錯誤。

image.png


date命令使用方法

data顯示當前系統的日期和時間

data +%Y表示四位的年 

data +%y兩位的年

data +%M分鐘 

data +%m月份

data +%d日期 

data +%D月/日/年

wKioL1m84XqTDS__AABBRzDIEwA104.png

data +%Y%m%d年0月0日

wKiom1m84b3yvPtLAABMPg0U_VU274.png

data +%F年-月-日

wKioL1m84aKCM_yfAABFNDdX0BI383.png

data +%H小時 

data +%S

data +%H:%M:%S 小時分鐘秒=data +%T

wKioL1m84c-QobUNAACKcywwSLM404.png

data +%h英文月份

data +%w周幾

data +%W今年的第幾周

cal顯示日曆

data +%s時間戳

時間戳換算日期date -d @1504620492

wKiom1m84lOABU-JAADWREHBMCM142.png

日期換算時間戳 date +%s -d "2019-2-14 22:35:49"

image.png

查看之前的日期-d

 date -d "+1day"  一天後

 date -d "-1 day"  一天前

 date -d "-1 month" 一月前

 date -d "-1 min"  一分鐘前

 date +%w, date +%W 星期

wKiom1m84tHQO-BCAAIZgqFe3uQ293.png


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

-gt大於  -lt小於

也能夠用大於小於號,可是必須加雙括號:(($a>3));(($a<3))

舉例:

a=5

若是$a大於3

則輸出ok

fi結尾

wKiom1m852TDm2VDAAA3-yq4dWY580.png

格式2:if 條件; then 語句; else 語句; fi

舉例:

a=5

若是a>3

則輸出就ok

不然輸出nook

wKiom1m86XviC3i1AABY0620Oz4608.png

格式3:if …; then … ;elif …; then …; else …; fi

舉例:

a=4

若是$a大於4

則輸出a大

在若是$a小於4

則輸出大於1&&小於4

不然輸出無效

QQ瀏覽器截圖20190218214409.png

邏輯判斷表達式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

解釋:若是$a大於5而且$a小於10,則輸出...

if [ $b -gt 5 ] || [ $b -lt 3 ]; then

解釋:若是$b大於5或者$b小於3,則輸出...


if判斷文件、目錄屬性

 [ -f file ]判斷是不是普通文件且存在

 [ -d file ] 判斷是不是目錄且存在

 wKioL1m-NIXhmcrUAAB-oHx-Jkk190.png

 [ -e file ] 判斷文件或目錄是否存在

 [ -r file ] 判斷文件是否可讀

 [ -w file ] 判斷文件是否可寫

 [ -x file ] 判斷文件是否可執行

f="/usr/xjw"

[ -f $f ] && rm-rf $f

等同於

if [ -f $f ]

then

rm -rf $f


[ -f $f ] || touch $f

等同於

if [ ! -f $f ]

then

touch $f


shell中的case判斷


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


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


for循環案例2

文件列表循環把etc下每一個文件ls列一下

 #!/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" asldkfls@11.com

    fi

    sleep 30

done

注:(while:死循環的意思)跟while true同樣


案例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

continue:結束本次循環,若是沒達到目的會直接忽略continue下邊的代碼,直接進行下一次循環

continue是跳出當前條件循環,繼續下一輪條件循環

break:跳出來,退出這個循環

break是立馬跳出循環;continue是跳出當前條件循環,繼續下一輪條件循環;

exit是直接退出整個腳本

若是寫腳本的時候輸入漢字發現是亂碼,那證實系統變量語言不對LANG

用echo $LANG或者env|grep LANG看一下變量值若是是LANG=en就把他改爲LANG=zh_CN.UTF-8


break跳出循環

#!/bin/bash

for i in `seq 1 5`

do

    echo $i//輸出i的值

    if [ $i == 3 ]//當i等於三的時候跳循環就是跳出for循環

    then

        break

    fi

    echo $i

done

echo aaaaaaa

wKiom1m_nnGxwhvSAAB6G6Ix-kE067.png


continue結束本次循環

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

#!/bin/bash

for i in `seq 1 5`

do

    echo $i

    if [ $i == 3 ]

    then

        continue

    fi

    echo $i

done

echo $i

wKioL1m_nlTBm5N-AABy2FIaCWc229.png


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             

     }

解釋:function後邊跟函數的名字,或者能夠不寫function,直接寫函數的名字:函數名()

函數必需要放在最前面

 示例1 (打印一個參數

#!/bin/bash

input() {

    echo $1 $2 $# $0

}


input 1 a b


示例2 

#!/bin/bash

sum() {

    s=$[$1+$2]

    echo $s

}

sum 1 2

解釋:首先定義一個函數sum,函數裏邊定義一個變量s,變量的內容是第一個參數與第二個參數相加,而後輸出函數的結果,最下邊sum是用來引用它,sum 1 2意思就是說1+2


示例3 輸入網卡的名字顯示網卡的IP0

#!/bin/bash

ip() {

    ifconfig |grep -A1 "$1 " |tail -1 |awk '{print $2}'|awk -F':' '{print $2}'

}

read -p "Please input the eth name: " e

myip=`ip $e`

echo "$e address is $myip"


image.png

事例4:

#!/bin/bash

read -p "please inpute the ent name:" n

ip()

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

}

ip $n


shell中的數組1

定義數組 

格式:

a=(1 2 3 4 5); echo ${a[@]}

[root@localhost ~]# a=(1 2 3 4 5); echo ${a[@]}
1 2 3 4 5

a=(1 2 3 4 5); echo ${a[*]}

[root@localhost ~]# a=(1 2 3 4 5); echo ${a[*]}
1 2 3 4 5

查看指定某一元素的值:更改[ ]裏邊的值就能夠

數組特性從零開始,0表明第一個,1表明第二個,依次日後排列

[root@localhost ~]# a=(1 2 3 4 5); echo ${a[0]}
1
[root@localhost ~]# a=(1 2 3 4 5); echo ${a[1]}
2
[root@localhost ~]# a=(1 2 3 4 5); echo ${a[2]}
3

echo ${#a[@]} 獲取數組的元素個數 

[root@localhost ~]# echo ${#a[@]}
5

 

數組賦值

 a[1]=100; echo ${a[@]}若是下標或者說賦值的元素存在那麼就會被替換或者說覆蓋掉以前的

[root@localhost ~]# echo ${a[@]} //數組內容爲1 2 3 4 5 a
1 2 3 4 5 a
[root@localhost ~]# a[1]=100     //重新給元素賦值100
[root@localhost ~]# echo ${a[@]} //由於存在就會被替換掉,變成1 100 3 4 5 a
1 100 3 4 5 a
[root@localhost ~]#

 a[5]=a; echo ${a[@]} 若是下標不存在則會自動添加一個元素

[root@localhost ~]# a=(1 2 3 4 5) //a賦值爲1 2 3 4 5
[root@localhost ~]# echo ${a[@]}  //打印a數組
1 2 3 4 5
[root@localhost ~]# a[5]=a        //給第五個元素賦值爲a
[root@localhost ~]# echo ${a[@]}  //由於第五個元素不存在因此會增長一個
1 2 3 4 5 a


 數組的刪除

unset a 刪除整個數組,其實跟取消賦值相似

[root@localhost ~]# echo ${a[@]}
1 100 4 5 a
[root@localhost ~]# unset a
[root@localhost ~]# echo ${a[@]}

[root@localhost ~]#

unset a[2] 刪除指定的下標元素

[root@localhost ~]# echo ${a[@]}
1 100 3 4 5 a
[root@localhost ~]# unset a[2]
[root@localhost ~]# echo ${a[@]}
1 100 4 5 a


數組分片

以 分割,第一個冒號後邊表示你要從第幾個元素開始截取,第二個冒號後邊表示你要截取幾個

 a=(`seq 1 10`)

 echo ${a[@]:0:3} 從第三個元素開始截取4個

[root@localhost ~]# a=(`seq 1 10`)
[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo ${a[@]:3:4}
4 5 6 7

 echo ${a[@]:1:4} 從第二個元素開始截取4個

[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo ${a[@]:1:4}
2 3 4 5

 echo ${a[@]:0-3:2} 從倒數第3個元素開始截取2個

[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo ${a[@]:0-3:2}
8 9

echo ${a[@]:0-4:4} 從倒數第4個元素開始截取4個

[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo ${a[@]:0-4:4}
7 8 9 10


數組替換

用/分割,第一個/後邊表示被替換的元素,第二個/後邊表示要替換的元素

好比把數組中的3替換成100

 echo ${a[@]/3/100}輸出時替換

[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo ${a[@]/3/100}
1 2 100 4 5 6 7 8 9 10

 a=(${a[@]/3/100})永久替換,其實就是賦值

[root@localhost ~]# a=(${a[@]/3/100})
[root@localhost ~]# echo ${a[@]}
1 2 100 4 5 6 7 8 9 10


shell項目-告警系統

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

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

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

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

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

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

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

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

image.png

bin下是主程序

conf下是配置文件

shares下是各個監控腳本

mail下是郵件引擎

log下是日誌。



shell項目-告警系統main.sh 

main.sh內容

 #!/bin/bash

#Written by aming.

# 是否發送郵件的開關

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


shell項目-告警系統mon.conf 

 mon.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


shell項目-告警系統load.sh

load.sh內容

 #! /bin/bash

##Writen by aming##

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 aming_test@163.com "$addr\_load:$load" `cat ../log/load.tmp`

fi

echo "`date +%T` load is $load"


shell項目-告警系統502.sh

 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"


shell項目-告警系統disk.sh

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

註釋:'[ %]+'以空格或者百分號爲分隔符,+表示一個或者多個,結合起來就是以一個或多個空格或者百分號爲分隔符(相似:'[:#]+'以冒號或者警號)

shell項目-告警系統mail.sh

 mail.sh內容 //其中mail.py內容到這裏下載https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py

  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  


shell項目-分發系統-expect講解

yum install -y expect

  自動遠程登陸

 #! /usr/bin/expect

set host "192.168.133.132"

set passwd "123456"

spawn ssh root@$host

expect {

"yes/no" { send "yes\r"; exp_continue}

"assword:" { send "$passwd\r" }

}

interact


shell項目-分發系統-expect講解

自動遠程登陸後執行命令並退出

#!/usr/bin/expect

set user "root"

set passwd "123456"

spawn ssh $user@192.168.133.132


expect {

"yes/no" { send "yes\r"; exp_continue}

"password:" { send "$passwd\r" }

}

expect "]*"

send "touch /tmp/12.txt\r"

expect "]*"

send "echo 1212 > /tmp/12.txt\r"

expect "]*"

send "exit\r"


shell項目-分發系統-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"}

"password:" { send "$passwd\r" }

}

expect "]*"

send "$cm\r"

expect "]*"

send "exit\r"


shell項目-分發系統-expect講解

自動同步文件 

#!/usr/bin/expect

set passwd "123456"

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

expect {

"yes/no" { send "yes\r"}

"password:" { send "$passwd\r" }

}

expect eof


shell項目-分發系統-expect講解

指定host和要同步的文件

#!/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


shell項目-分發系統-構建文件分發系統

需求背景對於大公司而言確定時不時會有網站或者配置文件更新並且使用的機器確定也是好多臺少則幾臺多則幾十甚至上百臺。因此自動同步文件是相當重要的。

 實現思路首先要有一臺模板機器把要分發的文件準備好而後只要使用expect腳本批量把須要同步的文件分發到目標機器便可。

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


shell項目-分發系統-構建文件分發系統

 文件分發系統的實現

 rsync.expect 內容

#!/usr/bin/expect

set passwd "123456"

set host [lindex $argv 0]

set file [lindex $argv 1]

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

expect {

"yes/no" { send "yes\r"}

"password:" { send "$passwd\r" }

}

expect eof

 ip.list內容

192.168.133.132

192.168.133.133

......


shell項目-分發系統-構建文件分發系統

 rsync.sh 內容

#!/bin/bash

for ip in `cat ip.list`

do

    echo $ip

    ./rsync.expect $ip list.txt

done


shell項目-分發系統-命令批量執行

 exe.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"


shell項目-分發系統-命令批量執行

exe.sh 內容

#!/bin/bash

for ip in `cat ip.list`

do

    echo $ip

    ./exe.expect $ip "w;free -m;ls /tmp"

done

相關文章
相關標籤/搜索