中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何正經的實現shell腳本單例運行

發布時間:2021-10-27 16:29:22 來源:億速云 閱讀:270 作者:小新 欄目:系統運維

這篇文章將為大家詳細講解有關如何正經的實現shell腳本單例運行,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

看起來可行的方法

一個非常簡單的思路就是,新的腳本被執行時,先檢測當前腳本是否有其他實例正在運行,如果有則直接退出。

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獲取到當前在運行的test.sh腳本數,如果大于1,說明已經有在運行的了。

但是你運行會發現,其程序數量不只是一個。

$ ./test.sh test.sh already running,num:2

驚不驚喜?為什么為這樣呢?原因在于,shell腳本中一個命令執行相當于fork了一個進程執行,這里執行的是查找tesh.sh并grep的程序,另外還有一個就是當前運行的腳本程序,這樣的方式自然就會出現每次都有兩個了。

當然判斷條件這里你可以換一下,例如數量大于2,但終歸不太好。

文件鎖

實際上這種方法你已經在《如何讓你的程序同時只有一個在運行》介紹過了,只不過之前是用于編寫C/C++程序,而這里是用于shell腳本。

我們來回顧一下,這是一個怎樣的過程:

  • 運行前檢查是否有該鎖文件,并且文件中的進程正在運行

  • 如果有并且程序正在運行,則已經有實例在運行

  • 否則,無實例,創建鎖文件,寫入進程id

  • 退出時,刪除鎖文件

解釋一下第一條,為什么一定要確定鎖文件中的進程正在運行,因為,有些情況下如果運行的時候退出沒有刪除該文件,則會導致新的實例永遠無法運行。

#!/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 #將當前程序進程id寫入鎖文件 echo $$ > ${LOCKFILE}  # 做你需要的事情 sleep 1000  # 刪除鎖文件 rm -f ${LOCKFILE}

我們試著運行其中一個,然后另外一個窗口嘗試運行:

$ ./test.sh  ./test.sh already running

由于已經有實例在運行,發現新的程序無法運行了。而等舊的腳本運行完之后,新的就可以運行了。

實際上這里面有幾個點非常巧妙:

  • kill -0 `cat \${LOCKFILE}` 這里用于檢測該進程是否存在,避免進程不在了,但是鎖文件還在,導致后面的腳本無法運行。

  • trap "rm -f \${LOCKFILE}; exit" INT TERM EXIT 用于確保腳本退出時,鎖文件會被刪除。

  • rm -f {LOCKFILE} 腳本最后需要刪除鎖文件

flock

說到鎖文件,這里就不得不提flock命令了。沒有前面的一些巧妙處理,我們很多時候會很難刪除原先創建的鎖文件,比如:

  • 腳本被意外中斷,沒來得及執行刪除

  • 多個腳本產生競爭,導致判斷異常,比如前面有一個腳本運行,判斷沒有鎖文件,下一步準備創建,但是另外一個腳本又先創建了,就會導致異常了。

因此我們可以考慮使用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

解釋一下:

  • exec 99>"$LOCK_FILE"  表示創建文件描述符99,指向鎖文件,為何是99?110其實也是可以的,只是為了和當前腳本可能打開的文件描述符沖突(例如和0,1,2沖突)。

  • flock -n 99 嘗試對該文件描述符加鎖,由操作系統保證原子性

  • 一旦flock失敗了,我們這里可以退出

  • 而即使鎖定了,腳本退出后,也會自動釋放

因此這里避免了鎖沒有釋放的情況。

另一種做法

查看flock的man手冊,我們發現它還有一個例子是這么做的:

[ "${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

解釋一下:如果${FLOCKER}環境變量沒有設置,則嘗試將腳本本身加鎖,如果加鎖成功,則運行當前腳本,(并且帶上原有的參數),否則的話靜默退出。

總結

單例運行本身思路是很簡單的,就是探測當前是否有實例在運行,如果有,則退出,但是這里如何判斷,卻并不是那么容易。

最后,總結一下本文出現的一些該掌握的信息:

  • $0 腳本名稱

  • $@ 腳本參數

  • $$ 當前腳本進程id

  • $? 上一條命令執行結果

  • 描述符0 標準輸入

  • 描述符1 標準輸出

  • 描述符2 標準錯誤

  • > 重定向

關于“如何正經的實現shell腳本單例運行”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

合山市| 凤山市| 沧州市| 灌南县| 乌审旗| 洱源县| 张家港市| 大宁县| 昌都县| 双鸭山市| 广州市| 应用必备| 南丹县| 奇台县| 扎兰屯市| 阳山县| 盐亭县| 湘西| 昭苏县| 乡宁县| 延边| 治多县| 三台县| 微山县| 三明市| 灵石县| 武清区| 永仁县| 绍兴县| 大同县| 盐亭县| 石台县| 礼泉县| 阿巴嘎旗| 西充县| 苏尼特左旗| 白城市| 宿州市| 石阡县| 深水埗区| 会昌县|