1. 程式人生 > >Shell-case:服務nginx的安裝指令碼

Shell-case:服務nginx的安裝指令碼

     之前分享了不少指令碼中的使用的小技巧,今天拿出點實打實的東西來,在我的 github https://github.com/SmartLyu/shell 裡有 nginx 的一個安裝配置包,還有一個關於安裝 nginx 的指令碼,今天就來和大家分享一下我寫的nginx相關的指令碼,大致分為  安裝指令碼、服務控制指令碼、自動同步等。

先來說說安裝指令碼nginx_install
     大家解壓我的nginx軟體包就可以看到使用手冊,具體的指令碼如何使用就不和大家一一贅述了,我就來和大家分享一下,指令碼編寫的過程,和大家聊聊我是怎麼寫出這個指令碼的,希望大家看完後能有所收益。
     裡面有進度條等用於美化的操作,我就不做介紹了,我就講講裡面的核心部分,最核心的當然就是解壓編譯安裝了,我們用命令如何做呢,tar解壓後用configure配置再是make編譯最後make install進行安裝,那指令碼中也這麼寫,不過有個小問題,就是我們配置或者編譯安裝都需要到解壓出的目錄下,如何做到呢?一般壓縮包命名是在被壓縮的目錄名後新增上應該新增的字尾 如.tar.gz,而目錄命令規範中目錄名中沒有 . ,那麼我們就可以以 . 為分隔的標識,然後進行去尾操作,這樣就可以得到目錄名了,這樣用 ${file%%.*}就可以得到目錄名了,但是這時候解壓的問題來了,我怎麼知道這是什麼壓縮的,如何分辨呢?總不能用tar解壓zip壓縮包吧,那我們就獲取一下壓縮包的字尾名判斷一下好了[ ${file##*.} == 'zip' ],預設是tar包,如果是zip包再特殊處理。進入目錄後就可以進行配置編譯安裝了,最後判斷一下nginx有沒有安裝好,看一下目標位置下所以,基本的主框架就出來了:

file=壓縮包名
nginx_path=選擇nginx安裝位置
w=需要nginx具備的模組
[ ${file##*.} == 'zip' ]  && unzip $file -d $path || tar -xf $file -C $path
cd ${file%.*.*}
useradd -s /sbin/nologin nginx
./configure --prefix=$nginx_path --user=nginx --group=nginx $w &>/dev/null
[ $? -ne 0 ] && echo 'configure has problem' && kill $! && exit 4
make &>/dev/null
[ $? -ne 0 ] && echo 'make has problem' && kill $! && exit 5
make install &>/dev/null
[ ! -e $nginx_path/sbin/nginx ] && echo -e "\nnginx has problem" && exit 6

     這樣的指令碼已經初步完成的既定的功能,不過,還有不少問題,首先,很多時候我們不是要安裝nginx,有的時候是要升級,那麼我們這個指令碼能不能兼顧完成升級操作呢?當然是可以的,首先我們先清除,什麼時候應該升級,怎麼升級,先回答第一個問題,什麼時候升級,答案就是當nginx已經被安裝了,我們就檢查一下,nginx目錄下有沒有基本的檔案,有就說明要升級,沒有就是安裝,用著判斷解決:[ -e $nginx_path/sbin/nginx ]  ,再看怎麼升級,升級和安裝唯一的區別就是最後一步,安裝是make install 升級是吧原來sbin下的檔案刪掉,把新的複製過去即可,那就簡單了,我們只需要把剛剛make install 一步改一下,即可:

if [ -e $nginx_path/sbin/nginx ];then
  rm -f $nginx_path/sbin/nginx
  cp objs/nginx $nginx_path/sbin/
else
  make install &>/dev/null
fi

     現在功能是很全面了,可以兼顧升級安裝了,下面我們就要再加功能了,我們希望我們的指令碼可變通更多一點,那我們就希望使用者可以通過變數來控制,這時候問題來了,我們有三個型別引數,壓縮包、安裝位置、需要安裝的模組,那麼問題來了,每個都是有一定預設值的,使用者不輸入,我們就按預設值來,但是,我們怎麼知道使用者輸入的是哪個型別引數呢?按照位置來肯定不行,因為加入我們第一個位置設定為壓縮包,第二個是安裝位置,後面都是安裝模組,看似可行,可問題也很大,那就是使用者必須每次都具體寫清楚壓縮包是什麼,安裝位置是哪裡,安裝模組是什麼,預設值也就無稽之談了,因為如果使用者不寫壓縮包,那使用者寫的安裝位置就被計算機當成了壓縮包的位置,導致程式崩潰,這肯定是不可以的,這該怎麼辦呢,我們人能分出那個是哪個,那我們想辦法讓計算機也能分出來,具體操作其實很簡單,還是按照一般演算法的思維考慮,從問題出發,如何讓計算機分出這引數屬於什麼型別,試問人是怎麼分的呢?我們看到 -- 開頭的就知道這是模組,不是 -- 開頭的就是一個路徑,有 / 開頭的就是絕對路徑,沒有就是相對路徑,而壓縮包一定是 路徑/包名 ,安裝位置一定是一個路徑,那就好辦了,我們也這麼讓計算機判斷,吧所有引數進行識別,用 for 迴圈吧 $* 中所有引數依次進行檢測, 如果是--開頭的就追加到 w 後面,反正我們配置的時候多個模組間用空格分隔,我們也這麼寫 w 引數即可,把多個模組寫到一個引數中就是了,如果是絕對路徑就判斷,該引數是否代表一個檔案,不是那就當做安裝路徑,最後就可以得到篩選稽核引數的程式碼:

w=''
for i in $*
do
  echo $i | grep '\-\-.*' &>/dev/null
  if [ $? -eq 0 ];then
    w=$w' '$i
  else
    [ -f $i ] && a=$i && continue
    nginx_path=$i
    echo $nginx_path | grep '^/' &>/dev/null
    [ $? -ne 0 ] && nginx_path=$PWD/$nginx_path
  fi
done

     再之就是之前我blog中寫的,一般指令碼不單單是自己一個指令碼完成的,還有其他的指令碼,可能要相互協作,如果使用者自定義了自己nginx的位置,而我又寫了一些控制服務啊什麼的指令碼,這些指令碼就需要修改裡面的nginx安裝位置,這時候就需要獲取指令碼所在位置,這個大家可以參考我的一個專門的blog 《獲取執行的指令碼所在目錄的位置》--> https://blog.csdn.net/Yu1543376365/article/details/82937512
然後獲取位置後,我們就可以修改我們其他的一些服務的指令碼中nginx的安裝位置了,用sed進行修改,具體怎麼修改涉及到其他指令碼的撰寫,大家可以閱讀我的指令碼程式碼然後進行理解分析。

     最後還有檢查yum,檢查安裝包是否存在等等基本操作,因為沒有複雜演算法,在之前的blog中都有具體贅述,就不在這裡詳細描繪了。


再來說說nginx的服務控制指令碼
    首先我們要先了解服務控制指令碼一般怎麼寫,一般格式是

start(){ 指令碼啟動 }
stop(){ 指令碼關閉 }

choice=${1:-0}
case $choice in
start)
  start ;;
stop)
  stop ;;
restart)
  stop 
  start ;;
*)
  echo 'Error'
  exit 6
esac

     其中使用者輸入要做什麼操作,一般而言,這個服務控制是一定要使用者做出選擇的,所以,理論上講,我們需要在指令碼開始做一次判斷,然後報錯,但是我沒有這麼做,我思考了一下,發現,使用者沒輸入和輸入不合法,都要報錯,他只能輸入start、stop這樣的關鍵詞,如果輸入錯了,我們也要報錯提示他這麼輸入,不輸入也是一樣,那我們為什麼不一起處理呢,我就把沒輸入變成輸錯了就是了,所以,我給輸入設定了一個初始值,這初始值就是一個隨便的不合法輸入,然後就簡化了指令碼。

     然後具體如何啟動關閉nginx就不詳細贅述了,我來說兩個問題,第一個,如何判斷nginx有沒有啟動,第二個啟動nginx必須要求80埠是空閒的,如何檢查,並且釋放80埠

     先解決如何判斷nginx是否啟動,正如大家所知道的Linux中所有的程式都是以程序的形式展現出來的,那我們檢查有沒有nginx這個程序即可,有就說明已經開啟,反之沒有開啟,那命令就是
netstat -ntlup,也可以用 ss -ntlup,前者是用於rhel6的,後者是rhel7開始使用的,現在兩個都還是可以用的,我們只要從中過濾nginx,如果有就說明開了,沒有就說明沒有開啟,那就好辦了。

     再看第二個問題,檢查80埠很簡單,用剛剛命令檢索80即可,可是怎麼關閉,我們都知道結束程序用命令kill或者killall ,那我們要獲取80埠的程序名,怎麼辦呢,可以用awk,也可以用去尾法,吧程序名摳出來,port80=$(netstat -ntulp | egrep ':80\b') ;[ $? -eq 0 ] && killall ${port80##*/} 這樣就好了,設定了一個path用來記錄nginx的安裝位置,這就和nginx_install遙相呼應了。

path=/usr/local/nginx
start(){

   # check nginx
   netstat -ntlup | grep -q nginx
   [ $? -eq 0 ] && status && exit 0

   # check httpd 
   port80=$(netstat -ntulp | egrep ':80\b')
   [ $? -eq 0 ] && killall ${port80##*/} && echo if you want to start ngix you need to stop apache , now I try to stop it || echo 'port 80 is ready'

   # 只有當apache啟動了,但是關不了的時候會執行下面的命令
   [ $? -ne 0 ] && echo 'your port cannot be stopped' && exit 1

   # start nginx
   sleep 0.5
   $path/sbin/nginx

   status
}

stop(){
   # stop nginx
   netstat -ntlup | grep -q nginx
   [ $? -eq 0 ] && $path/sbin/nginx -s stop
}

choice=${1:-0}
case $choice in
start)
  start ;;
stop)
  stop ;;
restart)
  stop 
  start ;;
*)
  echo 'Error: you can try nginx_server start|stop|restart|status|virsion|test'
  exit 6
esac