Contents

Linux 防止程式同時執行方法

最進工作在 Windows 伺服器,有些 Linux 東西想在 Windows 實現,但這邊做個 Linux 回顧整理,以後想要用的話可以回來看個筆記。

實作方法

以下參照Linux 防止 Shell 指令稿重複執行教學 - G. T. Wang實作,有些我之前有用過,但有幾個沒看過方法,我覺得還滿有趣的,這邊就簡單操作。

鎖定檔案(lock file)

這邊注意,鎖定檔案不是指檔案被鎖定(lock),怎麼感覺有點繞口令😅,這邊建立檔案但檔案還是可以被刪除。這邊假如你 Script 當掉強制關掉或直接重開機,這邊檔案可能還會存在,存在的話程式就無法打開,可能要注意這個問題。這個方法我之前有一個專案也有類似用這個方法,但這個方法缺點如剛剛所說,所以我每次程式執行錯誤都要刪除 lock file 才能執行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/sh

# 鎖定檔案路徑
LOCK_FILE=/home/gtwang/my_script.lock

# 檢查鎖定檔案
if [ -f $LOCK_FILE ]; then
  echo "This script is already running!"
  exit 1
fi

# 建立 lock file
touch $LOCK_FILE

# 檢查鎖定檔案是否成功被建立
if [ ! -f $LOCK_FILE ]; then
  echo "Cannot create lock file!"
  exit 1
fi

# 主要工作
echo "Doing my job."
sleep 30
echo "Done."

# 刪除鎖定檔案
rm -f ${LOCK_FILE}

實作真的很簡單,執行程式。Ctrl+C 就會中斷程式但你就會發現你程式不能執行了。刪掉就能解決。

https://i.imgur.com/7KF31iA.png

行程 ID 檔案(PID file) 推薦!!!

大多數 Linux 很多都用這種方式,當然有些 pid 是用上面方式去實作,沒有檢查 pid 程式是否有真的執行,我很推薦用這個方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/sh

# 行程 ID 檔案路徑
PID_FILE=/home/gtwang/my_script.pid

# 檢查行程 ID 檔案是否存在
if [ -f $PID_FILE ]; then
  # 取得行程 ID
  PID=$(cat $PID_FILE)

  # 檢查行程是否有在執行
  ps -p $PID > /dev/null 2>&1
  if [ $? -eq 0 ]; then
    echo "This script is already running!"
    exit 1
  fi
fi

# 行程沒有在執行,將目前行程 ID 寫入檔案
echo $$ > $PID_FILE

# 檢查行程 ID 檔案是否成功被建立
if [ $? -ne 0 ]; then
  echo "Could not create PID file."
  exit 1
fi

# 主要工作
echo "Doing my job."
sleep 30
echo "Done."

# 刪除鎖定檔案
rm -f ${PID_FILE}

https://i.imgur.com/FH4kzMV.png

Pid 檔案也沒被鎖住,這邊不能手動刪掉,就算程式中斷不會像上一個方法(flock)卡住。

flock

多年前有寫過這篇flock 防止重新執行方法 - 程式狂想筆記 - 記錄著我接觸程式藝文,我之前公司有用過,寫在Crontab 不須寫 Script 就能控制防止同時執行。
這邊我還是推薦使用 Pid 檔案檢查方式,原因是 flock 是真的鎖住檔案,理論上應該會佔掉一個 CPU 工作序。我使用覺得還滿穩的,僅次推薦。

1
2
3
4
5
# 以 /home/gtwang/my_script.lock 為鎖定檔案,
# 讓 /home/gtwang/my_script.sh 同一時間只執行一次
flock -x /home/gtwang/my_script.lock -c /home/gtwang/my_script.sh
# 若發現重複執行,則直接離開
flock -nx /home/gtwang/my_script.lock -c /home/gtwang/my_script.sh

solo

這個方法我覺得很有趣,但使用可能會佔住 127.0.0.1 的 Port,理論上不影響對外 Port,但假如你的服務針對所以對外 Port 還是會有衝突可能,你這樣玩可能 SE 工程師在你背後很火,所以不是很推薦這樣用,但這招我覺得滿實用。

https://i.imgur.com/ZLiavS0.png

程式檔名檢查大法

用檔名去 ps去做檢查,但這樣程式不能取相同名子,不然會撞到不能執行,理論上可能會存在漏洞,但率比較低,我有遇過有公司這樣做檢查。這邊要注意,不同程式相同名稱就會有問題,這邊就不實作了。

可參考: 【shell】防止脚本重复运行_q3dxdx的博客-CSDN博客

彩蛋