このスクリプトは、独自のインスタンスが1つだけ実行されることをどのように保証しますか?

このスクリプトは、独自のインスタンスが1つだけ実行されることをどのように保証しますか?

2013年8月19日ランダルシュワルツ解放するこれLinuxでは、「スクリプトインスタンスが1つだけ実行され、競合状態やロックファイルをクリーンアップする必要はありません」を保証するように設計されたシェルスクリプト:

#!/bin/sh
# randal_l_schwartz_001.sh
(
    if ! flock -n -x 0
    then
        echo "$$ cannot get flock"
        exit 0
    fi
    echo "$$ start"
    sleep 10 # for testing.  put the real task here
    echo "$$ end"
) < $0

広告されたとおりに動作するようです。

$ ./randal_l_schwartz_001.sh & ./randal_l_schwartz_001.sh
[1] 11863
11863 start
11864 cannot get flock
$ 11863 end

[1]+  Done                    ./randal_l_schwartz_001.sh
$

これが私の理解です:

  • スクリプトは、独自<の内容のコピーをサブシェルの$0STDIN(ファイル記述子など)にリダイレクトします()。0
  • flock -n -xサブシェル内では、スクリプトはファイル記述子の非ブロック排他ロック()を取得しようとします0
    • この試みが失敗すると、サブシェルは終了します(他に何もしないので、デフォルトのスクリプトも同じです)。
    • 試行が成功すると、サブシェルが必要なタスクを実行します。

私の質問は次のとおりです。

  • スクリプトが次のコピーをサブシェルの継承されたファイル記述子にリダイレクトする必要があるのはなぜですか。それ自体のコンテンツ他のファイルの内容ではない? (上記のように他のファイルからリダイレクトして再実行してみましたが、実行順序が変更されました。非バックグラウンドジョブがバックグラウンドジョブよりも先にロックされます。したがって、ファイル自体の内容を使用すると競合状態を回避できます。しかし、どうなりますか?)
  • とにかく、スクリプトがファイルの内容のコピーをサブシェルの継承されたファイル記述子にリダイレクトする必要があるのはなぜですか?
  • あるシェルのファイル記述子の排他的ロックを維持すると、他のシェルで実行されているのと0同じスクリプトのコピーがファイル記述子の排他的ロックを取得できないのはなぜですか0?シェルには、標準のファイル記述子(0、、、1および2STDIN、STDOUT、およびSTDERR)の独自の独立したコピーはありませんか?

ベストアンサー1

スクリプトが他のファイルの内容ではなく、独自の内容のコピーをサブシェルが継承したファイル記述子にリダイレクトする必要があるのはなぜですか。

スクリプトのすべてのコピーが同じファイルを使用する限り、すべてのファイルを使用できます。 just を使用すると、$0ロックはスクリプト自体にバインドされます。スクリプトをコピーして他の目的に変更する場合は、ロックファイルの新しい名前を作成する必要はありません。これはとても便利です。

スクリプトがシンボリックリンクを介して呼び出されると、リンクではなく物理ファイルにロックが設定されます。

(もちろん、一部のプロセスがスクリプトを実行し、実際のパスではなく0番目の引数で構成された値を指定すると、中断されますが、これはほとんど発生しません。)

(上記のように別のファイルを使ってやり直してみると、実行順序が変わりました)

これはランダムな変更ではなく、使用されたファイルが原因であると確信していますか?パイプと同様に、実際にコマンドがどこにあるかを確認する方法はありませんcmd1 & cmd。これは主にオペレーティングシステムのスケジューラによって異なります。私のシステムにランダムな変更が発生しています。

とにかく、スクリプトがファイルの内容のコピーをサブシェルの継承されたファイル記述子にリダイレクトする必要があるのはなぜですか?

flockロックを維持するユーティリティだけでなく、ロックを維持するファイル記述のコピーもシェル自体に保存するようです。flock(2)ロックを使用して作成されたロックは、ロックを保持するファイル記述子が閉じられると解放されます。

flock2つのモードがあります。ファイル名に基づいてロックを取得し、外部コマンドを実行するか(この場合はflock必要な開かれたファイル記述子が保存されます)、ファイル記述子を外部から取得するため、外部プロセスは保存を担当します。 。

この文書の内容はここに関連しておらず、コピーは作成されませんでした。サブシェル自体へのリダイレクトは、データをコピーせずにファイルへのハンドルのみを開きます。

あるシェルでファイル記述子 0 の排他的ロックを維持すると、他のシェルで実行される同じスクリプトのコピーがファイル記述子 0 の排他的ロックを取得できないのはなぜですか?シェルには、標準ファイル記述子(0、1、2、STDIN、STDOUT、およびSTDERR)の独自の独立したコピーはありませんか?

はい、しかしロックされています文書、ファイル記述子ではありません。一度に1つのオープンファイルインスタンスのみロックを保持できます。


ロックされたファイルへのハンドルを開き、サブシェルなしでexec同じことができるはずです。

$ cat lock.sh
#!/bin/sh

exec 9< "$0"

if ! flock -n -x 9; then
    echo "$$/$1 cannot get flock" 
    exit 0
fi

echo "$$/$1 got the lock"
sleep 2
echo "$$/$1 exit"

$ ./lock.sh bg & ./lock.sh fg ; wait; echo
[1] 11362
11363/fg got the lock
11362/bg cannot get flock
11363/fg exit
[1]+  Done                    ./lock.sh bg

おすすめ記事