本文會不斷累積平常工做中可能涉及到的shell腳本實例,持續更新。php
shell腳本001.shnode
#!/bin/bash d=`date +Y-m-d` ##獲取日期 logfile=$d.log ##定義日誌文件名 df -h > $logfile ##向文件寫入磁盤使用狀況
日誌文件1.txtmysql
123 -sdfjukhesdjkfghjkldf 456 -jsdigkhndjfgjd 789 -dsfjkdhfjkhsdjkfhsjk 123 -sdfhfjkhsjklaj 789 -jfgduhdjkfghjkdf 123 -dhsfgjkhsdjkghjkdf
shell腳本002.shnginx
#!/bin/bash ##取文件IP|排序|去重並統計各個IP重複數量|排序 awk '{print $1}' 1.txt |sort -n |uniq -c |sort-n
#!/bin/bash sum=0 #利用for循環調取每一項進程所使用的內存,並依次求和 for mem in `ps aux |awk '{print $6}' |grep -v 'RSS'` do sum=$[$sum+$mem] ##內存求和 done echo "the usered mem $sum" ##輸出結果
#!/bin/bash #假設遠程機器IP爲114.114.114.114 ip=114.114.114.114 while循環作循環監控,"while :"爲死循環 while : do #使用ping命令,取丟包率的數值做爲存活的判斷依據 n=`ping -c2 $ip 2> /dev/null |grep 'received' |awk -F 'received, |%' '{print $2}'` n1=`echo $n |sed 's/[0-9]//g'` #判斷取值是否爲空 if [ -z "$n" ] then echo "error" exit #判斷取值是否爲數字 elif [ -n "$n1" ] then echo "error" exit #若丟包率不低於20%,則發送告警 elif [ $n -ge 20 ] then #這裏也可作外發郵件告警,詳見[郵件告警](https://my.oschina.net/u/3804357/blog/1844730 "郵件告警") echo "more loss" else echo "OK" fi #監控間隔爲30秒 sleep 30 done
#!/bin/bash #將目標文件夾下的全部指定類型文件的文件名查找存在指定文件中 find /123/ -type f -name "*.txt" > /123/txt.list #經過for循環遍歷全部文件,並依次更名 for f in `cat /123/txt.list` do mv $f $f.bak done 定義一個時間命名的目錄做爲打包文件的目錄 d=`date +%F` mkdir /123/123_$d #將全部更名文件依次拷貝到打包文件的目錄下 for f in `cat /123/txt.list` do cp $f.bak /123/123_$d/ done #進入指定目錄下進行打包 cd /123/ tar -zcvf 123.tar.gz 123_$d #還原文件名 for f in `cat /123/txt.list` do mv $f.bak $f done
注:雖然打包的文件多了一層文件名,可是對於還原文件名變得十分容易web
#!/bin/bash #判斷本機80端口是否監聽,並執行相應動做(使用命令行做爲判斷條件時,命令行正確執行即知足if條件,且用於斷定的命令行不須要加反引號) if netstat -lntp |grep -q ':80 ' then exit else #這裏也可作外發郵件告警,詳見[郵件告警](https://my.oschina.net/u/3804357/blog/1844730 "郵件告警") echo "error" /usr/local/apache2/bin/apachectl restart fi #判斷是否啓動成功,如未成功,則將錯誤信息經過郵件進行告警 n=`pgrep -l httpd |wc -l`#列出全部httpd進程的pid if [ $n -eq 0 ] then touch /tmp/apache_start.err /usr/local/apache2/bin/apachectl start 2> /tmp/apache_start.err fi if [ -s apache_start.err ] #if -s 選項,文件大小非0時爲真 then #這裏也可作外發郵件告警,詳見[郵件告警](https://my.oschina.net/u/3804357/blog/1844730 "郵件告警") fi
注:持續監控能夠採用任務計劃或while循環sql
#!/bin/bash d1=date +%w d2=date +%d bakdir=‘指定的本地備份目錄’ r_bakdir=‘遠程備份的IP地址’:‘遠程備份的目錄’ #經過ssh同步 rs_bakdir=‘遠程備份的IP地址’::‘模塊名稱’ #經過服務同步 #定義接下來的命令涉及到的全部的正確輸出記錄在正確日誌的目錄下,全部的錯誤輸出記錄在錯誤日誌的目錄下 exec 1> ‘正確日誌的目錄’ 2>‘錯誤日誌的目錄’ echo "mysql backup begin at `date +"%F %T"`" #備份到本地機器的文件以星期命名,週期爲7天,超出7天后,同名的舊文件會被新文件覆蓋 mysqldump -u’指定的用戶‘ -p‘指定的密碼’ ’指定的數據庫‘ > $bakdir/$d1.sql #備份到遠程機器的文件以日期命名,週期爲31天,超出31天后,同名的舊文件會被新文件覆蓋 rsync -az $bakdir/$d1.sql $r_bakdir/$d2.sql echo "mysql backup end at `date +"%F %T"`"
服務器環境爲lnmp,近期訪問常常出現502現象,且502錯誤在重啓php-fpm服務後消失,所以須要編寫監控腳本,一旦出現502,則自動重啓php-fpm服務shell
假設環境: 1.訪問日誌文件的路徑:/data/log/access.log 2.腳本死循環,每10秒檢測一次,10秒的日誌條數爲300條,出現502的比例不低於10%(30條)則須要重啓php-fpm服務 3.重啓命令爲:/etc/init.d/php-fpm restart
#!/bin/bash log=/data/log/access.log N=30 #設定閾值 while : do #查看訪問日誌的最新300條,並統計502的次數 err=`tail -n 300 $log |grep -c '502" '` if [ $err -ge $N ] then /etc/init.d/php-fpm restart 2> /dev/null #設定60s延遲防止腳本bug致使無限重啓php-fpm服務 sleep 60 fi sleep 10 done
#!/bin/bsah #文件名爲2.txt sed -n '1,5'p 2.txt |sed '/[a-zA-Z]/'d sed -n '6,10'p 2.txt |sed s'/[a-zA-Z]//'g sed -n '11,$'p 2.txt #最終結果只是在屏幕上打印結果,若是想直接更改文件,可將輸出結果寫入臨時文件中,再替換2.txt或者使用-i選項
示例語句: Bash also interprets a number of multi-character options. #!/bin/bash for s in Bash also interprets a number of multi-character options. do n=`echo $s|wc -c` if [ $n -lt 6 ] then echo $s fi done
#!/bin/bash echo "*cmd menu** 1-date 2-ls 3-who 4-pwd" while : do #捕獲用戶鍵入值 read -p "please input number :" n n1=`echo $n|sed s'/[0-9]//'g` #空輸入檢測 if [ -z "$n" ] then continue fi #非數字輸入檢測 if [ -n "$n1" ] then continue fi break done case $n in 1) date ;; 2) ls ;; 3) who ;; 4) pwd ;; #輸入數字非1-4的提示 *) echo "please input number is [1-4]" esac
#!/bin/bash #生成10個用戶的序列(00-09) for u in `seq -w 0 09` do #建立用戶 useradd user_$u #生成密碼 p=`mkpasswd -s 0 -l 10` #從標準輸入中讀取密碼進行修改(不安全) echo $p|passwd --stdin user_$u #常規修改密碼 echo -e "$p\n$p"|passwd user_$u #將建立的用戶及對應的密碼記錄到日誌文件中 echo "user_$u $p" >> /tmp/userpassword done
詳細需求:
1.每隔10s監控httpd的進程數,若進程數大於等於500,則自動重啓Apache服務,並檢測服務是否重啓成功
2.若未成功則須要再次啓動,若重啓5次依舊沒有成功,則向管理員發送告警郵件,並退出檢測
3.若是啓動成功,則等待1分鐘後再次檢測httpd進程數,若進程數正常,則恢復正常檢測(10s一次),不然放棄重啓並向管理員發送告警郵件,並退出檢測數據庫
#!/bin/bash #計數器函數 check_service() { j=0 for i in `seq 1 5` do #重啓Apache的命令 /usr/local/apache2/bin/apachectl restart 2> /var/log/httpderr.log #判斷服務是否重啓成功 if [ $? -eq 0 ] then break else j=$[$j+1] fi #判斷服務是否已嘗試重啓5次 if [ $j -eq 5 ] then mail.py exit fi done } while : do n=`pgrep -l httpd|wc -l` #判斷httpd服務進程數是否超過500 if [ $n -gt 500 ] then /usr/local/apache2/bin/apachectl restart if [ $? -ne 0 ] then check_service else sleep 60 n2=`pgrep -l httpd|wc -l` #判斷重啓後是否依舊超過500 if [ $n2 -gt 500 ] then mail.py exit fi fi fi #每隔10s檢測一次 sleep 10 done
#!/bin/bash logfile=/data/log/access.log #顯示一分鐘前的小時和分鐘 d1=`date -d "-1 minute" +%H%M` d2=`date +%M` ipt=/sbin/iptables ips=/tmp/ips.txt block() { #將一分鐘前的日誌所有過濾出來並提取IP以及統計訪問次數 grep '$d1:' $logfile|awk '{print $1}'|sort -n|uniq -c|sort -n > $ips #利用for循環將次數超過100的IP依次遍歷出來並予以封禁 for i in `awk '$1>100 {print $2}' $ips` do $ipt -I INPUT -p tcp --dport 80 -s $i -j REJECT echo "`date +%F-%T` $i" >> /tmp/badip.log done } unblock() { #將封禁後所產生的pkts數量小於10的IP依次遍歷予以解封 for a in `$ipt -nvL INPUT --line-numbers |grep '0.0.0.0/0'|awk '$2<10 {print $1}'|sort -nr` do $ipt -D INPUT $a done $ipt -Z } 當時間在00分以及30分時執行解封函數 if [ $d2 -eq "00" ] || [ $d2 -eq "30" ] then #要先解再封,由於剛剛封禁時產生的pkts數量不多 unblock block else block fi
示例:
10 31 53 77 105 141
數字的規律在於兩個數字的差值的差值是2的冪次方apache
#!/bin/bash a=10 b=21 echo $a for i in `seq 0 13` do #2的$i次冪 c=$[2**$i] a=$[$a+$b] b=$[$b+$c] echo $a done a=$[$a+$b] echo $a
#!/bin/bash #截取/etc/passwd文件中第三段的數字,大於1000者即爲自定義用戶 n=`awk -F ':' '$3>1000' /etc/passwd|wc -l` if [ $n -gt 0 ] then echo "there are $n custom users" else echo "no custom user" fi
監控全部磁盤分區以及inode使用率,當某個分區容量或inode使用量大於85%時,發送郵件告警安全
#!/bin/bash #將系統語言設置爲英文,若是是中文則會產生bug LANG=en log=/tmp/`date +%F.log` tag1=0 tag2=0 df -h >> $log df -i >> $log #遍歷各個磁盤利用率的數值 for h in `df -h|grep -v 'Use'|awk -F ' +|%''{print $5}'` do if [ $h -gt 85 ] then $tag1=1 fi done #遍歷各個磁盤inode的數值 for i in `df -i|grep -v 'Use'|awk -F ' +|%''{print $5}'` do if [ $i -gt 85 ] then $tag2=1 fi done #磁盤空間以及inode都沒有問題,tag=0 if [ $tag1 -eq 0 ] && [ $tag2 -eq 0 ] then tag=0 fi #磁盤空間有問題,inode沒有問題,tag=1 if [ $tag1 -eq 1 ] && [ $tag2 -eq 0 ] then tag=1 fi #磁盤空間沒有問題,inode有問題,tag=2 if [ $tag1 -eq 0 ] && [ $tag2 -eq 1 ] then tag=2 fi #磁盤空間以及inode都有問題,tag=3 if [ $tag1 -eq 1 ] && [ $tag2 -eq 1 ] then tag=3 fi #根據不一樣的tag數值,最終輸出不一樣的結果 case $tag in 0) echo "no problem." ##mail.py ;; 1) echo "disk space is not enough." ##mail.py ;; 2) echo "disk inode is not enough." ##mail.py ;; 3) echo "disk space and disk inode are not enough." ##mail.py ;; esac
用腳本每隔5分鐘監測目標目錄是否有新文件生成,如有新文件生成,則將新文件的列表輸出到一個按年、月、日、時、分爲名字的日誌裏
#!/bin/bash logfile=/data/web/`date -d "-5 min" +%Y-%m-%d-%H-%M`.log basedir=/data/web/attachment #查找修改時間少於5分鐘的文件,並將列表記錄在臨時文件中 find $basedir/ -type f -mmin -5 > /tmp/test.txt n=`wc -l /tmp/test.txt` if [ $n -gt 0 ] then mv /tmp/test.txt $logfile fi
#!/bin/bash #對歷史命令排序|查重|倒敘排列|取前10行 sort /root/.bash_history|uniq -c|sort -nr|head
每小時執行一次腳本(任務計劃),當時間爲0點或12點時,將目標目錄下的全部文件內容清空,但不刪除文件,其餘時間則只統計各個文件的打小,一個文件一行,輸出到以時間和日期命名的文件中,須要考慮目標目錄下二級、三級等子目錄的文件
#!/bin/bash logfile=/tmp/`date +%H-%F`.log n=`date +%H` if [ $n -eq 00 ] || [ $n -eq 12 ] then #經過for循環,以find命令做爲遍歷條件,將目標目錄下的全部文件進行遍歷並作相應操做 for i in `find /data/log/ -type f` do true > $i done else for i in `find /data/log/ -type f` do du -sh $i >> $logfile done fi
#!/bin/bash #wc -l選項直接接文檔名稱會將文檔行數以及文檔名稱都進行輸出,所以須要使用awk只輸出文檔行數(截取第一段) n=`wc -l a.txt|awk '{print $1}'` sum=0 #文檔中每一行可能存在空格,所以不能直接用文檔內容進行遍歷 for i in `seq 1 $n` do #輸出的行用變量表示時,須要用雙引號 line=`sed -n "$i"p a.txt` #wc -L選項,統計最長行的長度 n_n=`echo $line|sed s'/[^0-9]//'g|wc -L` echo $n_n sum=$[$sum+$n_n] done echo "sum:$sum"
#!/bin/bash #經過對比兩臺服務器上文件的md5值,達到檢測一致性的目的 dir=/data/web b_ip=192.168.88.10 #將指定目錄下的文件所有遍歷出來並做爲md5sum命令的參數,進而獲得全部文件的md5值,並寫入到指定文件中 find $dir -type f|xargs md5sum > /tmp/md5_a.txt ssh $b_ip "find $dir -type f|xargs md5sum > /tmp/md5_b.txt" scp $b_ip:/tmp/md5_b.txt /tmp #將文件名做爲遍歷對象進行一一比對 for f in `awk '{print 2} /tmp/md5_a.txt'` do #以a機器爲標準,當b機器不存在遍歷對象中的文件時直接輸出不存在的結果 if grep -qw "$f" /tmp/md5_b.txt then md5_a=`grep -w "$f" /tmp/md5_a.txt|awk '{print 1}'` md5_b=`grep -w "$f" /tmp/md5_b.txt|awk '{print 1}'` #當文件存在時,若是md5值不一致則輸出文件改變的結果 if [ $md5_a != $md5_b ] then echo "$f changed." fi else echo "$f deleted." fi done
規定一分鐘記錄一次 日誌格式以下所示: 2018-08-12 23:40 ens33 input: 1234bps ens33 output: 1235bps ################## 2018-08-12 23:41 ens33 input: 1234bps ens33 output: 1235bps
代碼以下: #!/bin/bash while : do 設置語言爲英文,保障輸出結果是英文,不然會出現bug LANG=en logfile=/tmp/`date +%d`.log 將下面執行的命令結果輸出重定向到logfile日誌中 exec >> $logfile date +"%F %H:%M" #sar命令統計的流量單位爲kb/s,日誌格式爲bps,所以要*1000*8 sar -n DEV 1 59|grep Average|grep ens33|awk '{print $2,"\t","input:","\t",$5*1000*8,"bps","\n",$2,"\t","output:","\t",$6*1000*8,"bps"}' echo "####################" #由於執行sar命令須要59秒,所以不須要sleep done
有一些腳本加入到了cron之中,存在腳本還沒有運行完畢又有新任務須要執行的狀況,致使系統負載升高,所以可經過編寫腳本,篩選出影響負載的進程一次性所有殺死。
#!/bin/bash ps aux|grep 指定進程名|grep -v grep|awk '{print $2}'|xargs kill
#!/bin/bash #捕獲監聽80端口的服務名稱 netstat -lntp|grep ":80"|awk -F '/' '{print $2}'|sort|uniq > /tmp/80.log n=`wc -l /tmp/80.log|awk '{print $1}'` s1=`cat /tmp/80.log` #判斷服務種類函數 judge_server() { case $1 in httpd) echo "this server is apache" ;; nginx) echo "this server is nginx" ;; *) echo "this server is other" ;; esac } if [ $n -eq 0 ] then echo "no web server!" exit fi if [ $n -eq 1 ] then judge_server $s1 else echo "there are $n web servers" for web in `cat /tmp/80.log` judge_server $web fi
#!/bin/bash mysqlcmd="mysql -uroot -p123456" #判斷MySQL服務是否正常(正確執行MySQL命令) $mysqlcmd -e "show processlist" if [ $? -gt 0 ] then echo "this mysql is wrong." else #若是是從庫則有返回值 $mysqlcmd -e "show slave status\G" > /tmp/sql.log n=`wc -l /tmp/sql.log|awk '{print $1}'` if [ $n -gt 0 ] then y1=`grep 'Slave_IO_Running:' /tmp/sql.log`|awk -F ':' '{print $2}'|sed 's/ //g'` y2=`grep 'Slave_SQL_Running:' /tmp/sql.log`|awk -F ':' '{print $2}'|sed 's/ //g'` if [ $y1 == "yes" ] && [ $y2 == "yes" ] then echo "the slave is ok" else echo "the slave is wrong" fi fi fi
cat 028.sh #!/bin/bash sum=0 for i in {1..100} do #求餘數 n=$[$i%3] if [ $n -eq 0 ] then sum=$[$sum+$i] fi done echo "sum:$sum"