0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ShellScriptで多重起動防止を実装する

0
Last updated at Posted at 2023-04-11

同僚が多重起動防止を実装するのに苦労していたので

以前書いた多重起動防止コードをブラッシュアップして公開します。
flockは使っていません。

多重起動防止.bash
#!/bin/bash
myDIR=$(cd $(dirname $0); pwd) # 自身のディレクトリを取得
LOCK_FILE=$myDIR/lock # 自身のディレクトリにロックファイルのファイル名を指定

# ロックファイルが存在していたらその中に書かれたLOCK_FILEのプロセスが走っているかどうか確認
if [ -r $LOCK_FILE ]; then
  # ロックファイルからPIDを取得
  pid=$(cat $LOCK_FILE)
  # 同じPIDを持つプロセスが走っているかどうか確認。
  # ロックファイルの中身が空の時にはエラーが発生してしまうので、-eオプションを付けていると停止します。注意!
  result=$(ps -p $pid 2> /dev/null | grep -v PID)
  if [ "$result" != "" ]
  then
      echo "Another process is running"
      exit
  fi
fi

# ここまでたどり着いたら実行していいのでロックファイルに自身のLOCK_FILEを書き込む
echo "$(date) Process started"
PID=$$
echo $PID > $LOCK_FILE

#
# 好きな処理を行う
#


# 処理が終了したらロックファイルを削除してロック解除
# 多重起動確認にPIDを確認しているのでロックファイルが残っていても問題ない
# ただし、PIDが一周して戻ってきた場合にはデッドロック発生の恐れあり
echo "$(date) Process finished"
rm $LOCK_FILE

以下、chatGPT先生の解説です

このスクリプトは、複数のインスタンスが同時に実行されないようにするためにロックファイルを使用する簡単な方法を提供しています。以下のような流れで動作します。

自身のディレクトリを取得して、ロックファイルのパスを作成する
ロックファイルが存在する場合は、ロックファイルに書かれたプロセスが実行中かどうかを確認し、実行中であればスクリプトを終了する
ロックファイルが存在しない場合は、ロックファイルを作成して自身のプロセスIDを書き込む
処理が完了したらロックファイルを削除してロックを解除する

実は同時に起動すると多重起動できてしまうそうです

コメントをいただきました。
確かに、PIDをファイルに書き込む前に次のを起動してしまうと多重起動できてしまうそうです。

chatGPT先生のコメントをよく読んでみたら確かにこんなことも書かれていました。
スクリプトの動作には問題はないように見えますが、いくつかの改善点があります。

ロックファイルを作成する前に、別のプロセスが既にロックファイルを作成している可能性があります。ロックファイルの作成に失敗する場合があります。ロックファイルを作成する前に、ファイルが存在しないことを確認する必要があります。
ロックファイルの作成に失敗した場合でも、スクリプトは処理を続行します。ロックファイルの作成に失敗した場合は、エラーメッセージを表示してスクリプトを終了する必要があります。
ロックファイルを削除する前に、ファイルが存在するかどうかを確認する必要があります。ファイルが存在しない場合は、削除する必要がありません。
プロセスIDをロックファイルに書き込む前に、ロックファイルを作成することを確認する必要があります。

もう一つ別の多重起動防止コードです

こちらはネット検索したら見つけたコードですが、出展が分からなくなってしまいました。これだとPIDファイルを書く必要がないので便利ですが、a.outみたいな別のプログラムだけどファイル名が同じインスタンスが動いている場合は大丈夫かなぁと気になっています。

多重起動防止2.bash
myName=$0
PID=$$
running=$(pidof -x $myName)
echo "$myName '$PID'='$running'"
if [ "$PID" != "$running" ]; then
    echo "多重起動中"
    exit
fi
sleep 10

以下、chatGPT先生のコメントです
スクリプトは、プロセスIDを取得するために pidof コマンドを使用しています。このコマンドは、実行中のプロセスのPIDを取得するために使用されます。スクリプトが実行される前に同じスクリプトが起動されている場合、スクリプトは終了します。この方法は、単一のスクリプトを使用して、他のスクリプトでの多重起動も防止できます。

改善点としては、pidof コマンドがない場合にスクリプトが動作しないため、代替の方法を用意する必要があります。また、プロセスIDの比較は文字列として行われているため、PIDが数値ではない場合に不具合が生じる可能性があります。PIDの比較には、-eq オプションを使用するとよいでしょう。また、スクリプトが動作している間、pidof コマンドが実行され続けるため、余分なリソースを消費する可能性がある点にも注意する必要があります。

0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?