同じスクリプトの 2 つのインスタンスが同時に実行されるのを回避する一般的な方法は、次のようになります。
[ -f ".lock" ] && exit 1
touch .lock
# do something
rm .lock
競合状態を回避して、シェルスクリプトからファイルをロックするより良い方法はありますか? 代わりにディレクトリを使用する必要がありますか?
はい、実際にサンプル スクリプトには競合状態があります。別のnoclobber
スクリプトが-f
テストとtouch
.
以下は、メカニズムを説明するサンプル コード スニペット (この記事に触発されたもの) です。
if (set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null;
then
# This will cause the lock-file to be deleted in case of a
# premature exit.
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# Critical Section: Here you'd place the code/commands you want
# to be protected (i.e., not run in multiple processes at once).
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Failed to acquire lock-file: $lockfile."
echo "Held by process $(cat $lockfile)."
fi
flock コマンドを試してください:
exec 200>"$LOCK_FILE"
flock -e -n 200 || exit 1
ロックファイルがロックされている場合は終了します。これはアトミックであり、最近のバージョンの NFS で動作します。
私はテストをしました。0 を含むカウンター ファイルを作成し、2 つのサーバーで同時に 500 回のループで次のコマンドを実行しました。
#!/bin/bash
exec 200>/nfs/mount/testlock
flock -e 200
NO=`cat /nfs/mount/counter`
echo "$NO"
let NO=NO+1
echo "$NO" > /nfs/mount/counter
1 つのノードがロックを求めて他のノードと競合していました。両方の実行が終了したとき、ファイルの内容は 1000 でした。何度も試しましたが、常に機能します。
注: NFS クライアントは RHEL 5.2 で、使用されるサーバーは NetApp です。
私はもっと簡単な解決策を見つけたようです:man lockfile