掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
作者:守望,linux應(yīng)用開發(fā)者,目前在公眾號【編程珠璣】 分享Linux/C/C++/數(shù)據(jù)結(jié)構(gòu)與算法/工具等原創(chuàng)技術(shù)文章和學(xué)習(xí)資源。

成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供龍安網(wǎng)站建設(shè)、龍安做網(wǎng)站、龍安網(wǎng)站設(shè)計、龍安網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、龍安企業(yè)網(wǎng)站模板建站服務(wù),十余年龍安做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
假設(shè)你的一個腳本已經(jīng)在運行了,如果避免再次被執(zhí)行呢?也就是如何實現(xiàn)單例運行?
看起來可行的方法
一個非常簡單的思路就是,新的腳本被執(zhí)行時,先檢測當(dāng)前腳本是否有其他實例正在運行,如果有則直接退出。
- #!/usr/bin/env bash
- #test.sh 來源:公眾號編程珠璣
- #獲取當(dāng)前運行的test.sh腳本數(shù)
- runCount=$(ps -ef|grep test.sh | grep -v grep -c)
- if [ "${runCount}" -ge 1 ]
- then
- echo -e "test.sh already running,num:${runCount}"
- exit 1;
- fi
- while true
- do
- echo "test.sh run"
- sleep 1
- done
這里通過ps獲取到當(dāng)前在運行的test.sh腳本數(shù),如果大于1,說明已經(jīng)有在運行的了。
但是你運行會發(fā)現(xiàn),其程序數(shù)量不只是一個。
- $ ./test.sh
- test.sh already running,num:2
驚不驚喜?為什么為這樣呢?原因在于,shell腳本中一個命令執(zhí)行相當(dāng)于fork了一個進程執(zhí)行,這里執(zhí)行的是查找tesh.sh并grep的程序,另外還有一個就是當(dāng)前運行的腳本程序,這樣的方式自然就會出現(xiàn)每次都有兩個了。
當(dāng)然判斷條件這里你可以換一下,例如數(shù)量大于2,但終歸不太好。
文件鎖
實際上這種方法你已經(jīng)在《如何讓你的程序同時只有一個在運行》介紹過了,只不過之前是用于編寫C/C++程序,而這里是用于shell腳本。
我們來回顧一下,這是一個怎樣的過程:
解釋一下第一條,為什么一定要確定鎖文件中的進程正在運行,因為,有些情況下如果運行的時候退出沒有刪除該文件,則會導(dǎo)致新的實例永遠無法運行。
- #!/usr/bin/env bash
- #來源:公眾號編程珠璣
- LOCKFILE=/tmp/test.lock
- if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
- echo " $0 already running"
- exit
- fi
- # 確保退出時,鎖文件被刪除
- trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
- #將當(dāng)前程序進程id寫入鎖文件
- echo $$ > ${LOCKFILE}
- # 做你需要的事情
- sleep 1000
- # 刪除鎖文件
- rm -f ${LOCKFILE}
我們試著運行其中一個,然后另外一個窗口嘗試運行:
- $ ./test.sh
- ./test.sh already running
由于已經(jīng)有實例在運行,發(fā)現(xiàn)新的程序無法運行了。而等舊的腳本運行完之后,新的就可以運行了。
實際上這里面有幾個點非常巧妙:
flock
說到鎖文件,這里就不得不提flock命令了。沒有前面的一些巧妙處理,我們很多時候會很難刪除原先創(chuàng)建的鎖文件,比如:
因此我們可以考慮使用flock:
- #!/usr/bin/env bash
- #來源:公眾號編程珠璣
- LOCK_FILE=/tmp/test.lock
- exec 99>"$LOCK_FILE"
- flock -n 99
- if [ "$?" != 0 ]; then
- echo "$0 already running"
- exit 1
- fi
- #腳本要做的其他事情
- sleep 1024
解釋一下:
因此這里避免了鎖沒有釋放的情況。
另一種做法
查看flock的man手冊,我們發(fā)現(xiàn)它還有一個例子是這么做的:
- [ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
在腳本開頭加上上面這么一行就可以了。例如:
- #!/usr/bin/env bash
- #來源:公眾號編程珠璣
- [ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
- #腳本要做的其他事情
- sleep 1024
解釋一下:
總結(jié)
單例運行本身思路是很簡單的,就是探測當(dāng)前是否有實例在運行,如果有,則退出,但是這里如何判斷,卻并不是那么容易。
最后,總結(jié)一下本文出現(xiàn)的一些該掌握的信息
本文轉(zhuǎn)載自微信公眾號「 編程珠璣」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 編程珠璣公眾號。
分享文章:怎么正經(jīng)的實現(xiàn)Shell腳本單例運行?
文章地址:http://uogjgqi.cn/article/dpdpjce.html

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流