質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
cron

cronは、Unix系OS上でデーモンプロセスとして動作する、スクリプトの自動実行が可能なジョブスケジューラです。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

4回答

5359閲覧

シェルスクリプトの二重起動防止を機能させたい。

710LOVER

総合スコア10

cron

cronは、Unix系OS上でデーモンプロセスとして動作する、スクリプトの自動実行が可能なジョブスケジューラです。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

0クリップ

投稿2021/06/18 06:32

編集2021/06/18 08:28

解決したいこと

動作確認時、フルパスでシェルスクリプトを実行した場合は二重起動防止が働くが、
(sh /usr/local/test/20_test.sh)
カレントディレクトリを省略してシェルスクリプトを実行すると二重起動防止が働かない。
(sh 20_test.sh)
(./20_test.sh)
※どちらも"cd /usr/local/test/"で対象シェルのカレントディレクトリに移動済み。

背景

◆対象シェルスクリプトに二重起動防止を追加し、二重起動防止が機能しているか動作確認で以下のテストを行った。
(環境はTeraterm)

  1. 対象のシェルスクリプトを手動で実行後、5秒後にまた手動で実行する。
  2. 対象のシェルスクリプトをcronで実行後、5秒後に手動で実行する。
  3. 対象のシェルスクリプトを手動で実行後、5秒後にcronで実行する。

◆各テスト結果の確認は以下を判断にした。

  1. エラーログが吐き出され、タイムスタンプが実行時であること。

 $ 2021/06/18 13:30:01 既に実行中です。
2. 実行ログのタイムスタンプが実行時であり、実行完了までログがダブってないこと。
$ 2021/06/18 13:29:55 【実行開始】



$ 2021/06/18 13:30:09 【実行終了】

対象のシェルスクリプトは以下になる。

#!/bin/bash # 自シェルのパスを取得 export BASE_DIR=$(cd $(dirname $0); pwd) #環境情報読み込み source ${BASE_DIR}/conf/environment.conf [ ! -d ${LOG_DIR} ] && mkdir ${LOG_DIR} [ ! -d ${TEMP_DIR} ] && mkdir ${TEMP_DIR} #二重で起動していないかチェックする(動作確認用にエラー時ログを吐き出す) if [ $$ != `pgrep -fo $0` ] ; then echo `date '+%Y/%m/%d %H:%M:%S'`" 既に実行中です。" | tee /usr/local/test/error.log exit 1 fi # 実行内容 echo "teratail用に変えたけど実際は色々動いてるよ。"

cronでの設定内容は以下になる。設定している時間はテスト用。

cronの内容

1#二重起動防止_動作テスト用 230 13 * * * /usr/local/test/20_test.sh

手動実行時、フルパスでシェルスクリプトを実行する分には二重起動防止の機能が働くことは証明できたが、実際に運用する作業員がシェルスクリプト実行時に"./20_test.sh"で実行するのでなるべく作業員の意に沿って実装したいのでお力をお貸し下さい。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

二重起動防止ならflockコマンドを使うのが良いかと思います。
簡単には、実行したいスクリプトをを呼び出すスクリプトを作る。

sh

1if flock --timeout=0 $0 実際に実行したいコマンド 2then echo 実行できました 3else echo 他の人が実行中でした 4fi

実行中なら、$?が1で終了する。

投稿2021/06/18 12:51

otn

総合スコア85762

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

710LOVER

2021/06/21 04:35

ご回答ありがとうございます。 flockコマンド面白そうですね、試してみます!
guest

0

参考までに…
二重起動防止というと実行中を意味するファイルを作成する方法もありますね。
(終了時に消します)
touch で作るサイズ 0 のだと負荷はあまり気にしなくていいし
実行開始したタイミングとか分かりますしね。
途中で終了したらゴミとして残るので、そのへんのケアは必要ですけど。
まあ、要件によってはこういう方法もあるってことで…

投稿2021/06/18 12:03

takasima20

総合スコア7460

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2021/06/18 12:40

任意のタイミングで実行されるコマンドの場合、ファイルを作るのでは排他制御は出来ないです。 ファイルが無いことを判断してから、ファイルを作るまでの間に、他のプロセスが同じ事をやると駄目。 mkdirだと、作る事と、それまでに無かったことのチェックが同時に出来るので、昔はmkdirでロックしてました。
takasima20

2021/06/18 20:58

なるほどです。アドバイスありがとうございます。
otn

2021/06/18 23:00

trap "rmdir $LOCKDIR 2>/dev/null" 0 1 2 3 ・・・シグナルを並べる if mkdir $LOCKDIR 2>/dev/null then echo ロックが取れた else echo ロックが取れなかった fi
takasima20

2021/06/19 12:04

あー、trap でフォローしてるんスねえ。そこまで厳密にはやったことないですわ(汗
guest

0

うまく再現できないので、ただの思いつきを書きますが、こうしてみたらどうですか?

sh

1fullpath=`readlink -f $0` 2if [ $$ != `pgrep -fo $fullpath` ] ; then

あと、質問者さんが言っている「シェル」は「シェルスクリプト」のことですよね。
「シェルスクリプト」を「シェル」と呼んではなかなか伝わりませんので気をつけてください。

投稿2021/06/18 07:37

itagagaki

総合スコア8402

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

710LOVER

2021/06/18 08:40

ご回答ありがとうございます。 「シェル」は「シェルスクリプト」に修正しました。 いったん原文のまま張り替えてシェルスクリプト単体の動作確認しましたが、二重起動防止が働いて動作しませんでした。 readlinkを選んだのはシンボリックリンクのリンク先とプロセスIDが同一セットかどうか判断させるのが狙いでしょうか?
itagagaki

2021/06/18 09:09

問題なのは、最初に実行したシェルスクリプトがフルパスでない場合なのでしょうか? それとも二重に実行したシェルスクリプトがフルパスでない場合なのでしょうか? 後者なのかなと思って、$0を常にフルパスに置き換えたらどうなのかなと思い、その手段として readlinkを使ってみました。 まあreadlinkの本来の用途とは違いますけどね。 以下が私のUbuntu 20.04でのテスト結果です。参考になれば幸いです。 ~$ cat test.sh #!/bin/bash -x echo $$ echo $0 fullpath=`readlink -f $0` echo $fullpath pgrep -f $0 pgrep -f $fullpath ~$ sh -x ./test.sh + echo 483 483 + echo ./test.sh ./test.sh + readlink -f ./test.sh + fullpath=/home/ita/test.sh + echo /home/ita/test.sh /home/ita/test.sh + pgrep -f ./test.sh 483 + pgrep -f /home/ita/test.sh ~$ sh -x /home/ita/test.sh + echo 487 487 + echo /home/ita/test.sh /home/ita/test.sh + readlink -f /home/ita/test.sh + fullpath=/home/ita/test.sh + echo /home/ita/test.sh /home/ita/test.sh + pgrep -f /home/ita/test.sh 487 + pgrep -f /home/ita/test.sh 487 ~$ ./test.sh + echo 491 491 + echo ./test.sh ./test.sh ++ readlink -f ./test.sh + fullpath=/home/ita/test.sh + echo /home/ita/test.sh /home/ita/test.sh + pgrep -f ./test.sh 491 + pgrep -f /home/ita/test.sh ~$ /home/ita/test.sh + echo 495 495 + echo /home/ita/test.sh /home/ita/test.sh ++ readlink -f /home/ita/test.sh + fullpath=/home/ita/test.sh + echo /home/ita/test.sh /home/ita/test.sh + pgrep -f /home/ita/test.sh 495 + pgrep -f /home/ita/test.sh 495
710LOVER

2021/06/18 09:50

問題なのは、最初に実行したシェルスクリプトがフルパスでない場合なのでしょうか? それとも二重に実行したシェルスクリプトがフルパスでない場合なのでしょうか? →両方です。 提示していただいたテスト結果をみるに、同じシェルスクリプトでも実行の仕方によってプロセスIDが異なってしまうのですね。
guest

0

ベストアンサー

起動の仕方によってpgrep -fの対象の文字列が違ってくるので、考えられる全パターンにマッチする正規表現を書かなければならないわけですね。

これでどうでしょう。

if [ $$ != `pgrep -fo '([a-z/]*sh )?20_test.sh'` ] ; then

投稿2021/06/18 10:23

itagagaki

総合スコア8402

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

710LOVER

2021/06/18 11:08

フルパスの有無に関わらず、動作確認ができました! 発想力が富んでて、とても学びになりました。 お時間いただきありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問