シェルスクリプトの1つのインスタンスのみが同時に実行されていることを確認する必要がある場合があります。
たとえば、独自にロックを提供しないcrondを介して実行されるcronジョブ(たとえば、デフォルトのSolaris crond)。
ロックを実装するための一般的なパターンは、次のようなコードです。
#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then # 'test' -> race begin
echo Job is already running!
exit 6
fi
touch $LOCK # 'set' -> race end
# do some work
rm $LOCK
もちろん、そのようなコードには競合状態があります。
2つのインスタンスの実行は、3行目以降、一方が$LOCK
に触れる前に
進むことができる時間枠があります。 ファイル。
cronジョブの場合、2つの呼び出しの間に
分の間隔があるため、これは通常問題にはなりません。
ただし、問題が発生する可能性があります。たとえば、ロックファイルがNFSサーバー上にある場合は
ハングします。その場合、いくつかのcronジョブが3行目でブロックされ、キューに入れられる可能性があります。
NFSサーバーが再びアクティブになると、並列実行中のジョブの群れが雷鳴になります。
Webで検索すると、その問題の良い解決策のように見えるツールlockrunが見つかりました。
これを使用して、
次のようなロックが必要なスクリプトを実行します:
$ lockrun --lockfile=/var/tmp/mylock myscript.sh
これをラッパーに入れるか、crontabから使用できます。
lockf()
を使用します (POSIX)利用可能な場合、flock()
にフォールバックします (BSD)。そしてlockf()
NFSを介したサポートは比較的広範囲に及ぶはずです。
lockrun
に代わるものはありますか ?
他のcronデーモンはどうですか?
正常な方法でロックをサポートする一般的なcrondはありますか? Vixie Crond(デフォルトは
Debian / Ubuntuシステム)のマニュアルページをざっと見ても、ロックについては何もわかりません。
lockrun
のようなツールを含めるのは良い考えでしょうか coreutilsに?
私の意見では、timeout
と非常によく似たテーマを実装しています。 、nice
と友達。
承認された回答:
上記で説明した競合状態を防ぐことができるシェルスクリプトをロックする別の方法を次に示します。この場合、2つのジョブが両方とも3行目を通過する可能性があります。noclobber
オプションはkshとbashで機能します。 set noclobber
は使用しないでください csh/tcshでスクリプトを作成するべきではないからです。 😉
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
NFSをロックするYMMV(NFSサーバーに到達できない場合)が、一般的には以前よりもはるかに堅牢です。 (10年前)
複数のサーバーから同時に同じことを行うcronジョブがあり、実際に実行する必要があるのは1つのインスタンスだけである場合、このようなものが機能する可能性があります。
関連:単純なMacOS Bluetooth Toggle Shellコマンド?私はlockrunの経験がありませんが、スクリプトが実際に実行される前に事前設定されたロック環境があると役立つ場合があります。またはそうではないかもしれません。スクリプトの外部でラッパーのロックファイルのテストを設定しているだけです。理論的には、2つのジョブがlockrunによってまったく同時に呼び出された場合、'inside-の場合と同様に、同じ競合状態に陥ることはありません。スクリプトの解決策?
いずれにせよ、ファイルロックはシステムの動作をほぼ尊重し、実行前にロックファイルの存在をチェックしないスクリプトは、実行しようとしていることをすべて実行します。ロックファイルテストと適切な動作を行うだけで、100%ではないにしても、99%の潜在的な問題を解決できます。
ロックファイルの競合状態に頻繁に遭遇する場合は、ジョブのタイミングが正しくないなど、より大きな問題の兆候である可能性があります。または、間隔がジョブの完了ほど重要でない場合は、ジョブをデーモン化するのに適している可能性があります。 。
以下の編集– 2016-05-06(KSH88を使用している場合)
以下の@ClintPachlのコメントに基づいて、ksh88を使用する場合は、mkdir
を使用してください。 noclobber
の代わりに 。これは主に潜在的な競合状態を緩和しますが、それを完全に制限するわけではありません(リスクはごくわずかですが)。詳細については、Clintが以下に投稿したリンクをお読みください。
lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid
if ( mkdir ${lockdir} ) 2> /dev/null; then
echo $$ > $pidfile
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -rf "$lockdir"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi
また、追加の利点として、スクリプトでtmpfileを作成する必要がある場合は、lockdir
を使用できます。 スクリプトが終了したときにクリーンアップされることを知っている、それらのディレクトリ。
より現代的なバッシュには、上部のnoclobberメソッドが適しているはずです。