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 當一個腳本語法有錯誤時他會有一個提示,若是沒有任何輸出證實他沒有錯誤。
date命令使用方法
data顯示當前系統的日期和時間
data +%Y表示四位的年
data +%y兩位的年
data +%M分鐘
data +%m月份
data +%d日期
data +%D月/日/年
data +%Y%m%d年0月0日
data +%F年-月-日
data +%H小時
data +%S秒
data +%H:%M:%S 小時分鐘秒=data +%T
data +%h英文月份
data +%w周幾
data +%W今年的第幾周
cal顯示日曆
data +%s時間戳
時間戳換算日期date -d @1504620492
日期換算時間戳 date +%s -d "2019-2-14 22:35:49"
查看之前的日期-d
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
-gt大於 -lt小於
也能夠用大於小於號,可是必須加雙括號:(($a>3));(($a<3))
舉例:
a=5
若是$a大於3
則輸出ok
fi結尾
格式2:if 條件; then 語句; else 語句; fi
舉例:
a=5
若是a>3
則輸出就ok
不然輸出nook
格式3:if …; then … ;elif …; then …; else …; fi
舉例:
a=4
若是$a大於4
則輸出a大
在若是$a小於4
則輸出大於1&&小於4
不然輸出無效
邏輯判斷表達式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 ] 判斷是不是目錄且存在
[ -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
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
}
解釋: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"
事例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程序來實現它能夠定義發郵件的服務器、發郵件人以及發件人密碼
輸出日誌整個監控系統要有日誌輸出。
要求:咱們的機器角色多種多樣可是全部機器上都要部署一樣的監控系統也就說全部機器無論什麼角色整個程序框架都是一致的不一樣的地方在於根據不一樣的角色定製不一樣的配置文件。
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