GNU/Linux >> Linux の 問題 >  >> Linux

シェルスクリプトの正しいロック?

シェルスクリプトの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メソッドが適しているはずです。


Linux
  1. シェルスクリプトの連想配列?

  2. シェルスクリプトでルート権限を削除する方法は?

  3. Webサイトからシェルスクリプトを実行しますか?

  1. シェルスクリプトでパスワードを隠す?

  2. Unixシェルスクリプトのファイル拡張子?

  3. 複数のシェルスクリプト間で変数を共有しますか?

  1. シェルスクリプトのPosixコンプライアンスをテストする方法は?

  2. シェルスクリプトで長いコマンドを分割しますか?

  3. シェル スクリプトのコマンド ライン パラメータ