利用lock檔避免程式重複執行
想直接看lock應用的腳本範例,可以略過第一個範例。
理解鎖檔概念
#!/bin/sh
LOCK_FILE=/var/lock/my.lock
if [ -f $LOCK_FILE ]; then
echo "$0 is running!" >&2
exit 0
fi
touch $LOCK_FILE
# Start to do my job.
sleep 10
echo "Done."
rm -f $LOCK_FILE
在無人使用腳本的情況下,開始時新增檔案my.lock,結束時會刪除檔案my.lock;當腳本正在執行中,若重複執行,就會因my.lock檔案存在,而直接結束程式。
使用trap指令
若在執行上方範例,在延遲10秒內,輸入Ctrl + C中斷程式,會發生什麼事呢?因為沒執行到最後一行的刪除my.lock動作,my.lock會一直存在,腳本被鎖住,不能再次執行。為避免程式不正常中斷,而被鎖住的問題,可利用trap指令來執行砍檔。
#!/bin/sh
LOCK_FILE=/var/lock/my.lock
if [ -f $LOCK_FILE ]; then
echo "$0 is running!" >&2
exit 0
fi
trap "rm -f $LOCK_FILE" EXIT
touch $LOCK_FILE
# Start to do my job.
sleep 10
echo "Done."
無論何種因素結束程式,當程式結束之前,會發送EXIT訊號,trap攔到EXIT後訊號,就會將my.lock砍掉。這樣做,就能避免程式結束,而my.lock還存在的窘境。
嘗試寫檔取代touch
有沒有一種方法,my.lock不存在時新增,my.lock存在時報錯?利用寫檔的指令能辦到,只要先設定不能覆寫檔案,有檔案存在時,寫檔就會出錯,再判斷出錯跳出程式,就能避免重複執行。
寫一個空檔案的指令為
但用此方法,若主程式想允許輸出導向可以覆寫,記得加上
寫一個空檔案的指令為
echo "" >$LOCK_FILE
或者簡化成
echo >$LOCK_FILE
甚至簡化到連echo指令都不呼叫
>$LOCK_FILE
前面再加上不能覆寫的環境設定set -C
當檔案存在時,執行會出現錯誤
$ set -C
$ >$LOCK_FILE
$ echo $?
0
$ >$LOCK_FILE
bash: $LOCK_FILE: cannot overwrite existing file
$ echo $?
1
若不希望顯示錯誤訊息
$ set -C
$ 2>/dev/null >$LOCK_FILE
$ echo $?
0
$ 2>/dev/null >$LOCK_FILE
$ echo $?
1
注意2>/dev/null的位置,因為>$LOCK_FILE已經有錯誤輸出了,若後面才設定錯誤輸出導向,就來不及了,錯誤訊息一樣會顯示。想進一步了解輸出導向,可參考「介紹輸出重新導向」。但用此方法,若主程式想允許輸出導向可以覆寫,記得加上
set +C調整回來。
#!/bin/sh
set -C
LOCK_FILE=/var/lock/my.lock
if ! 2>/dev/null >$LOCK_FILE; then
echo "$0 is running!" >&2
exit 0
fi
trap "rm -f $LOCK_FILE" EXIT
set +C
# Start to do my job.
sleep 10
echo "Done."
如果喜歡,可以將與鎖檔相關的程式碼擠在一起
#!/bin/sh
LOCK_FILE=/var/lock/my.lock
if { set -C; 2>/dev/null >$LOCK_FILE; }; then
trap "rm -f $LOCK_FILE" EXIT
set +C
else
echo "$0 is running!" >&2
exit 0
fi
# Start to do my job.
sleep 10
echo "Done."
留言
張貼留言