shell腳本實例【持續更新】

本文會不斷累積平常工做中可能涉及到的shell腳本實例,持續更新。php

1.文件以日期命名,並寫入磁盤使用狀況

shell腳本001.shnode

#!/bin/bash 
d=`date +Y-m-d`    ##獲取日期
logfile=$d.log     ##定義日誌文件名
df -h > $logfile   ##向文件寫入磁盤使用狀況

2.統計日誌文件中各個IP的訪問量


日誌文件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

3.計算Linux系統全部進程佔用內存之和

#!/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"  ##輸出結果

4.監控遠程機器的存活,發現宕機示警

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

5.批量修改指定目錄下文件名、打包並還原文件名

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


6.判斷本機80端口是否監聽(假設服務爲httpd),若是不存在,則重啓服務併發送郵件告警

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


7.多地備份數據庫(本地保留一週、遠程保留一月)

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

8.監測Nginx訪問日誌502狀況,並作相應動做

服務器環境爲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

9.把一個文檔前五行中包含字母的行刪掉,同時刪除6到10行包含的全部字母

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

10.用shell打印示例語句中字母數小於6的單詞

示例語句:
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

11.輸入數字運行相應命令

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

12.建立10個用戶,並分別設置密碼,密碼要求10位且包含大小寫字母以及數字,最後須要把每一個用戶的密碼存在指定文件中

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

13.監控httpd的進程數,根據監控狀況作相應處理


詳細需求:
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

14.根據web訪問日誌,封禁請求量異常的IP,如IP在半小時後恢復正常,則解除封禁

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

15.觀察下列數字,輸出包含前6個數字在內的16個數字


示例:
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

16.查看Linux系統中是否存在自定義用戶,並統計自定義用戶數量

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

17.監控磁盤分區以及inode使用率並告警


監控全部磁盤分區以及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

18.監測目標目錄的文件生成狀況


用腳本每隔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

19.查看經常使用命令,並列出TOP10

#!/bin/bash
#對歷史命令排序|查重|倒敘排列|取前10行
sort /root/.bash_history|uniq -c|sort -nr|head

20.定時清空文件內容,定時記錄文件大小


每小時執行一次腳本(任務計劃),當時間爲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

21.計算文檔每行出現的數字個數,並計算整個文檔的數字總數

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

22.檢測兩臺服務器指定目錄下的文件一致性

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

23.檢測網卡流量,並按規定格式記錄在日誌中


規定一分鐘記錄一次
日誌格式以下所示:
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

24.殺死全部腳本

有一些腳本加入到了cron之中,存在腳本還沒有運行完畢又有新任務須要執行的狀況,致使系統負載升高,所以可經過編寫腳本,篩選出影響負載的進程一次性所有殺死。

#!/bin/bash
ps aux|grep 指定進程名|grep -v grep|awk '{print $2}'|xargs kill

25.檢測服務器是否開啓web服務(監聽80),並判斷服務種類

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

26.檢測MySQL服務是否正常,判斷是主庫仍是從庫,如是從庫判斷主從服務是否正常

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

27.

28.計算100之內全部能被3整除的正整數的和

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"
相關文章
相關標籤/搜索