提醒:本文為合集文章,後續會持續更新!
關注我,持續學習shell腳本,每日提升!
誰一開始寫shell腳本不是從流水賬開始的?寫着寫着你就會發現,需要在哪裡加判斷,在哪裡抛出異常。寫着寫着就知道何時用函數,何時用變量。寫着寫着你就會說,shell腳本也就那麼回事。
【需求】
将如下部署文檔用一個shell腳本實作。
1)下載下傳源碼
cd /usr/local/src
sudo curl -O http://nginx.org/download/nginx-1.23.0.tar.gz
2)解壓
sudo tar zxf nginx-1.23.0.tar.gz
cd nginx-1.23.0
3)安裝依賴
## RHEL/Rocky
sudo yum install -y gcc make pcre-devel zlib-devel openssl-devel
##ubuntu
sudo apt install -y gcc make libpcre++-dev libssl-dev zlib1g-dev
4)配置
sudo ./configure --prefix=/usr/local/nginx --with-http_ssl_module
5)編譯和安裝
sudo make && sudo make install
6)編輯system服務管理腳本
sudo vi /lib/systemd/system/nginx.service #寫入如下内容
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /usr/local/nginx/logs/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /usr/local/nginx/logs/nginx.pid)"
[Install]
WantedBy=multi-user.target
7)加載服務
sudo systemctl daemon-reload
8)啟動服務
sudo systemctl start nginx
【參考腳本】
#!/bin/bash
ck_ok()
{
if [ $? -ne 0 ]
then
echo "$1 error."
exit 1
fi
}
download_ng()
{
cd /usr/local/src
if [ -f nginx-1.23.0.tar.gz ]
then
echo "目前目錄已經存在nginx-1.23.0.tar.gz"
echo "檢測md5"
ng_md5=`md5sum nginx-1.23.0.tar.gz|awk '{print $1}'`
if [ ${ng_md5} == 'e8768e388f26fb3d56a3c88055345219' ]
then
return 0
else
sudo /bin/mv nginx-1.23.0.tar.gz nginx-1.23.0.tar.gz.old
fi
fi
sudo curl -O http://nginx.org/download/nginx-1.23.0.tar.gz
ck_ok "下載下傳Nginx"
}
install_ng()
{
cd /usr/local/src
echo "解壓Nginx"
sudo tar zxf nginx-1.23.0.tar.gz
ck_ok "解壓Nginx"
cd nginx-1.23.0
echo "安裝依賴"
if which yum >/dev/null 2>&1
then
## RHEL/Rocky
for pkg in gcc make pcre-devel zlib-devel openssl-devel
do
if ! rpm -q $pkg >/dev/null 2>&1
then
sudo yum install -y $pkg
ck_ok "yum 安裝$pkg"
else
echo "$pkg已經安裝"
fi
done
fi
if which apt >/dev/null 2>&1
then
##ubuntu
for pkg in make libpcre++-dev libssl-dev zlib1g-dev
do
if ! dpkg -l $pkg >/dev/null 2>&1
then
sudo apt install -y $pkg
ck_ok "apt 安裝$pkg"
else
echo "$pkg已經安裝"
fi
done
fi
echo "configure Nginx"
sudo ./configure --prefix=/usr/local/nginx --with-http_ssl_module
ck_ok "Configure Nginx"
echo "編譯和安裝"
sudo make && sudo make install
ck_ok "編譯和安裝"
echo "編輯systemd服務管理腳本"
cat > /tmp/nginx.service <<EOF
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP \$(/bin/cat /usr/local/nginx/logs/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM \$(/bin/cat /usr/local/nginx/logs/nginx.pid)"
[Install]
WantedBy=multi-user.target
EOF
sudo /bin/mv /tmp/nginx.service /lib/systemd/system/nginx.service
ck_ok "編輯nginx.service"
echo "加載服務"
sudo systemctl unmask nginx.service
sudo systemctl daemon-reload
sudo systemctl enable nginx
echo "啟動Nginx"
sudo systemctl start nginx
ck_ok "啟動Nginx"
}
download_ng
install_ng
【解析】
其實腳本思路,大家也都沒啥問題,畢竟給出了文檔。有的同學,直接将文檔,改成了腳本,這沒錯啊,shell腳本就是這樣,将手動的操作改成自動。
但是,大家也要考慮,每一步執行中是否遇到問題,遇到問題了,你怎麼去處理。腳本寫的好不好,就在于細節你處理是否到位,很有可能一個小細節,那就是非常大的bug。
比如,變量擷取值和我們預期不符合,然而你卻拿這個不符合預期的值進行了比較或者判斷,那最終結果肯定也會不符合我們的預期,甚至是會報錯。
腳本分成了幾個函數,其中有一個專門用來判斷上一步有沒有錯的,就是這個ck_ok 。為什麼将它包裝成了函數呢,因為整個腳本裡,很多地方都需要做判斷。
下載下傳包,這裡,需要判斷是否已經下載下傳過了,而如果下載下傳過了,還要判斷下載下傳的包是不是我們想要的,怎麼判斷呢?
用 [ -f filename ]來判斷檔案是否存在,檔案存在,還需要計算它的md5值來判斷是否符合我們的預期。是以,這裡有一個點就是說,你必須要知道正确檔案的md5值。
當然,有的官網會給出檔案的正确md5。下載下傳過,就不要重複下載下傳了,因為下載下傳檔案不僅耗費時間還耗費帶寬。
你腳本執行過程中出現了問題可能需要反複執行多次腳本,如果不判斷是否下載下傳過,那豈不是每次都要下載下傳一次了。下載下傳後,就需要安裝啦。
安裝過程,根據文檔,其實核心就三個大的步驟:configure,make,make instal。
每一步都需要判斷是否正确執行,因為它們是環環相扣的。為了讓腳本更加完美 ,最好是每一個關鍵步驟都需要去做一個判斷。
文檔裡有一步,是需要安裝依賴的。為了讓腳本更加通用,是以你最好是根據系統來判斷是使用yum還是apt來安裝對應的包。
我這裡偷懶了,直接判斷是否有yum或者apt指令,但實際上這樣并不是最優的方案。最優方案是需要根據特定指令來判定系統是啥。
比如是 CentOS,是 RHEL,還是Rocky?當然,甚至連它們的版本也要做判斷。不過話說回來,我們還不需要搞到那麼那麼完美。包括大家以後工作中寫腳本時,肯定是需要有一個前提的,比如,針對CentOS7寫的腳本,或者針對Rocky8寫的腳本。是以呢,腳本就不需要整那麼複雜了。
說到安裝依賴,和下載下傳包一樣 ,也需要考慮 是否已經安裝過。是以,這一步需要大家先判斷對應的包是不是已經安裝過了,安裝過就不需要再安裝。
我腳本裡其實也有缺陷,比如安裝完包後沒有去檢測這個包是否安裝成功。其實,這是有必要做的,因為依賴包安裝不成功,直接影響到了能否make成功。
make 和 make instll 兩個可以合并,比如:make && make install。寫成一行也是可以的,最終隻做一個判斷。
install完成後,就該編輯systemd服務管理腳本裡,這裡有好幾個同學都有問題,大家有的使用echo有的使用 EOF這種,都可以實作。
但是,大家忽略了一個問題,就是你echo的文本裡是有$符号的。它在shell腳本裡是會被當成調用變量的符号的。是以,這裡需要特殊處理一下,加個 \,即\$,它會将$符号脫義。
再往後就是daemon-reload和start服務了,這裡同樣也要做個檢測。
關注"阿銘linux",持續提升!