システムコールopen()
では、で開くとO_CREAT | O_EXCL
、システムコールにより、ファイルが存在しない場合にのみファイルが作成されるようになります。アトミック性はシステムコールによって保証されます。bashスクリプトからアトミックな方法でファイルを作成する同様の方法はありますか?
更新:2つの異なるアトミックな方法を見つけました
- set-onoclobberを使用します。次に、>演算子をアトミックに使用できます。
- mkdirを使用するだけです。Mkdirはアトミックです
100%純粋なbashソリューション:
set -o noclobber
{ > file ; } &> /dev/null
このコマンドは、という名前のファイルfile
が存在しない場合にという名前のファイルを作成しますfile
。、という名前のファイルがある場合file
は、何もしません(ただし、ゼロ以外の戻りコードを返します)。
touch
コマンドの長所:
file
すでに存在する場合、またはfile
作成できなかった場合は失敗します。file
存在せず、作成された場合の成功。短所:
noclobber
ます(ただし、リダイレクトに注意する場合、または後で設定を解除する場合は、スクリプトで問題ありません)。open
このソリューションは、実際には。を使用したシステムコールのbashに相当するものだと思いO_CREAT | O_EXCL
ます。
mv -n
トリックを使用したbash関数は次のとおりです。
function mkatomic() {
f="$(mktemp)"
mv -n "$f" "$1"
if [ -e "$f" ]; then
rm "$f"
echo "ERROR: file exists:" "$1" >&2
return 1
fi
}
例:
$ mkatomic foo
$ wc -c foo
0 foo
$ mkatomic foo
ERROR: file exists: foo
ランダムに生成された名前で作成し、名前を変更(mv -n random desired
)して目的の名前にすることができます。ファイルがすでに存在する場合、名前の変更は失敗します。
このような:
#!/bin/bash
touch randomFileName
mv -n randomFileName lockFile
if [ -e randomFileName ] ; then
echo "Failed to acquired lock"
else
echo "Acquired lock"
fi
明確にするために、ファイルが存在しない場合にのみファイルが作成されるようにすることは、アトミック性と同じではありません。2つ以上の別々のスレッドが同時に同じことを行おうとしたときに、1つだけが成功し、他のすべてのスレッドが失敗する場合にのみ、操作はアトミックです。
シェルスクリプトでアトミックにファイルを作成するために私が知っている最良の方法は、このパターンに従います(そしてそれは完璧ではありません):
特に、touch
アトミックではありません。ファイルが存在しない場合はファイルを作成するか、単にタイムスタンプを更新するためです。異なるタイムスタンプでゲームをプレイできる場合もありますが、タイムスタンプを読み取って解析し、レースに「勝った」かどうかを確認することは、上記よりも困難です。mkdir
アトミックにすることもできますが、リターンコードを確認する必要があります。そうしないと、「はい、ディレクトリは作成されましたが、どのスレッドが勝ったかわかりません」としか言えないためです。ハードリンクをサポートしていないファイルシステムを使用している場合は、あまり理想的ではないソリューションを選択する必要があるかもしれません。
これを行う別の方法はumask
、次のように、書き込み権限でファイルを作成せずに、ファイルを作成して書き込み用に開くことを試みることです。
LOCK_FILE=only_one_at_a_time_please
UMASK=$(umask)
umask 777
echo "$$" > "$LOCK_FILE"
umask "$UMASK"
trap "rm '$LOCK_FILE'" EXIT
ファイルが欠落している場合、ファイルが書き込み権限なしで作成されているにもかかわらず、スクリプトは書き込みのためにファイルを作成して開くことに成功します。すでに存在する場合、スクリプトは書き込み用にファイルを開くことができません。を使用exec
してファイルを開き、ファイル記述子を保持することができます。
rm
ファイルのアクセス許可に関係なく、ディレクトリ自体への書き込みアクセス許可が必要です。
touch
探しているコマンドです。ファイルが存在する場合は提供されたファイルのタイムスタンプを更新し、存在しない場合は作成します。