歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> SHELL編程

如何避免shell腳本被同時運行多次

比如說有一個周期性(cron)備份mysql的腳本,或者rsync腳本,
如果出現意外,運行時間過長,
很有可能下一個備份周期已經開始了,當前周期的腳本卻還沒有運行完,
顯然我們都不願意看到這樣的情況發生。

其實只要對腳本自身做一些改動,就可以避免它被重復運行。


#!/bin/bash

LOCK_NAME="/tmp/my.lock"
if [[ -e $LOCK_NAME ]] ; then
echo "re-entry, exiting"
exit 1
fi

### Placing lock file
touch $LOCK_NAME
echo -n "Started..."

### 開始正常流程
### 正常流程結束

### Removing lock
rm -f $LOCK_NAME

echo "Done."
 

當腳本開始運行時, 創建 /tmp/my.lock文件,
這時如果再次運行此腳本,發現存在my.lock,就退出,
腳本運行結束時刪除這個文件。

大多數情況下,這樣做都沒有什麼問題。
意外1) 如果同時運行二次此腳本, 二個進程都會發現my.lock不存在,然後都可以繼續執行。
意外2) 如果腳本在運行過程中意外退出, 沒有來得及刪除 my.lock文件, 那麼就悲劇了。

修改如下:


#!/bin/bash

LOCK_NAME="/tmp/my.lock"
if ( set -o noclobber; echo "$$" > "$LOCK_NAME") 2> /dev/null;
then
trap 'rm -f "$LOCK_NAME"; exit $?' INT TERM EXIT

### 開始正常流程
### 正常流程結束

### Removing lock
rm -f $LOCK_NAME
trap - INT TERM EXIT
else
echo "Failed to acquire lockfile: $LOCK_NAME."
echo "Held by $(cat $LOCK_NAME)"
exit 1
fi



echo "Done."
 

set -o noclobber 的意思:


If set, bash does not overwrite an existing file with the >, >&, and <> redirection operators.
 

這樣就能保證my.lock只能被一個進程創建出來。比touch靠譜多了。

trap 可以捕獲各種信號,然後做出處理:
INT 用來處理 ctrl+c取消腳本執行的情況。
TERM 用來處理 kill -TERM pid 的情況。
EXIT 不清楚

另外,對於 kill -9 無效。。

還記得N年前,在php群裡面,草人也問過這個問題,
我們給的答案是 ps aux|grep filename |wc -l ,哈哈,真2。
 

Copyright © Linux教程網 All Rights Reserved