17

システムコールopen()では、で開くとO_CREAT | O_EXCL、システムコールにより、ファイルが存在しない場合にのみファイルが作成されるようになります。アトミック性はシステムコールによって保証されます。bashスクリプトからアトミックな方法でファイルを作成する同様の方法はありますか?

更新:2つの異なるアトミックな方法を見つけました

  1. set-onoclobberを使用します。次に、>演算子をアトミックに使用できます。
  2. mkdirを使用するだけです。Mkdirはアトミックです
4

6 に答える 6

28

100%純粋なbashソリューション:

set -o noclobber
{ > file ; } &> /dev/null

このコマンドは、という名前のファイルfileが存在しない場合にという名前のファイルを作成しますfile。、という名前のファイルがある場合fileは、何もしません(ただし、ゼロ以外の戻りコードを返します)。

touchコマンドの長所:

  • ファイルがすでに存在する場合、タイムスタンプを更新しません
  • 100%bashビルトイン
  • 期待どおりのリターンコード:fileすでに存在する場合、またはfile作成できなかった場合は失敗します。file存在せず、作成された場合の成功。

短所:

  • オプションを設定する必要がありnoclobberます(ただし、リダイレクトに注意する場合、または後で設定を解除する場合は、スクリプトで問題ありません)。

openこのソリューションは、実際には。を使用したシステムコールのbashに相当するものだと思いO_CREAT | O_EXCLます。

于 2012-12-11T21:51:09.233 に答える
5

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
于 2013-05-30T22:50:56.780 に答える
3

ランダムに生成された名前で作成し、名前を変更(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
于 2012-12-11T21:32:53.960 に答える
2

明確にするために、ファイルが存在しない場合にのみファイルが作成されるようにすることは、アトミック性と同じではありません。2つ以上の別々のスレッドが同時に同じことを行おうとしたときに、1つだけが成功し、他のすべてのスレッドが失敗する場合にのみ、操作はアトミックです。

シェルスクリプトでアトミックにファイルを作成するために私が知っている最良の方法は、このパターンに従います(そしてそれは完璧ではありません):

  1. 存在しない可能性が非常に高いファイルを作成し(適切な乱数の選択などをファイル名に使用して)、その中にいくつかの一意のコンテンツを配置します(他のスレッドにはないもの-繰り返しますが、乱数など) )。
  2. ファイルが存在し、期待する内容が含まれていることを確認してください
  3. そのファイルから目的のファイルへのハードリンクを作成します
  4. 目的のファイルに期待される内容が含まれていることを確認します

特に、touchアトミックではありません。ファイルが存在しない場合はファイルを作成するか、単にタイムスタンプを更新するためです。異なるタイムスタンプでゲームをプレイできる場合もありますが、タイムスタンプを読み取って解析し、レースに「勝った」かどうかを確認することは、上記よりも困難です。mkdirアトミックにすることもできますが、リターンコードを確認する必要があります。そうしないと、「はい、ディレクトリは作成されましたが、どのスレッドが勝ったかわかりません」としか言えないためです。ハードリンクをサポートしていないファイルシステムを使用している場合は、あまり理想的ではないソリューションを選択する必要があるかもしれません。

于 2012-12-11T21:30:54.177 に答える
0

これを行う別の方法は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ファイルのアクセス許可に関係なく、ディレクトリ自体への書き込みアクセス許可が必要です。

于 2020-06-02T22:17:19.807 に答える
-3

touch探しているコマンドです。ファイルが存在する場合は提供されたファイルのタイムスタンプを更新し、存在しない場合は作成します。

于 2012-12-11T21:13:53.133 に答える