シェルスクリプトのエラー処理

シェルスクリプトのエラー処理

run_script.sh私は空のファイルを生成するステップを含むシェルスクリプトを書いていますrun_script.lck。 cronjobはシェルスクリプトを呼び出すたびに確認しますrun_script.lck。ロックがある場合は、プログラムがrun_script.shすでに実行されており、まだ完了していないことを意味します。ファイルはrun_script.lckプログラムの終わりに削除されます。

問題は、シェルスクリプトがクラッシュしたときに終了する前にロックファイルを削除することです。

私は次の行を書きました:

trap "rm -f run_script.lck" EXIT

ただし、次のように不要にロックされたファイルを削除します。

シェルAで実行しrun_script.shて実行している場合は、ロックファイルが生成されます。その後、シェルBで再度実行すると、スクリプトはすでに実行中であるため、スクリプトが中断されるというメッセージが表示されます。ただし、トラップはシェルB(中断されたスクリプトを終了する)からのシグナルを含むEXITシグナルを受け取り、ロックファイルを削除します。シェルAのスクリプトはまだ実行中ですが、ロックは削除されており、run_script.sh他のスクリプトがすでに実行されている間は誰でも他のスクリプトを再度呼び出すことができます。

この問題を解決する方法を知っていますか?

答え1

ロックが存在することを確認する今後トラップを設定してください。

答え2

Ignacioの答えを説明するために(次のプロトコルを使用する:まずロックファイルがあることを確認してからトラップをインストールする)、次のように問題を解決できます。

$ cat test2.sh
if [ -f run_script.lck ]; then
  echo Script $0 already running
  exit 1
fi
trap "rm -f run_script.lck" EXIT
# rest of the script ...

答え3

これはエラートラップを設定し、shエラーが発生したときにスクリプトを中断することによって行われます(set -e)。例えば

$ cat test.sh
set -e
trap "echo foo" ERR
if [ $# == 1 ]; then
  exit 0
fi
false
$ bash test.sh
foo
$ bash test.sh 1
$

$#パラメータ数はどこにありますか?)

スクリプトは、スクリプトが正常に実行されたとき(つまり、通常のプログラムフローの終わりなどの競合が発生しない)、トラップコマンドが実行されていることを確認するだけです。

set -e終了ステータスが同じでない場合は常に0スクリプトの実行が終了することを示します。同様に、set -u未定義変数を(偶発的に)使用するたびに実行が終了します。

したがって、このアイデアを元のユースケースに切り替えると、ソリューションは次のようになります。

$ cat test.sh
set -e
trap "rm -f run_script.lck" ERR
if [ -f run_script.lck ]; then
  echo Script $0 is already running
  exit 1
fi
#
# do all the work ...
#
# no error until now
rm -f run_script.lck

関連情報