連鎖コマンドはアトミックですか?


8

ファイルに継続的に書き込むプロセスがあり、ルートでファイルを制御したい場合は、次のようなことができます。

sudo rm somefile; sudo touch somefile

追加プロセスがこれらの2つのコマンドの間にファイルに追加することは可能ですか?もしそうなら、その間に他のコマンドが実行されないようにする方法はありますか?


4
これはXYの問題である可能性があります。解決しようとしている根本的な問題を説明できますか?
Nate Eldredge 2015

1
@NateEldredge:まったく違います。私の考案した仮説に基づいて、なぜそのように見えるのか理解できません。問題もありません。ちょっと興味があるんだけど。
Darth Egregious

5
プロセスはおそらく、削除されたファイルへの書き込みを続け、新しいファイルを開こうとはしません。
Random832

仮説での私の仮定は少し間違っていることがわかりましたが、「追加」を「オープン」または「タッチ」に変更しても、それでも意味があると思います。
Darth Egregious

回答:


12

チェーンされたコマンドラインは基本的に小さなシェルスクリプトです。通常のfork + execプロシージャを使用して最初のコマンドを実行し、それが終了するのを待ってから、2番目のコマンドを同じ方法で実行します。2つのコマンドの間には、シェルが簿記と処理にかかる任意の時間があり、その間に通常のマルチプロセッシングが行われ、他の任意のプロセスが他の任意のことを行う可能性があります。したがって、答えは「いいえ」です。(実際にこれを行うとsomefile、ファイルのディレクトリエントリは消えますが、ファイル自体は(プロセスによって開かれているため)閉じられるまで残ります。ファイルが使用するディスク領域は、それが発生するまで再利用されません。 、touchコマンドは、同じ名前とパスで、無関係な新しいファイルを作成します。

ファイルの所有権をrootに変更したい場合は、変更してくださいsudo chown root:root somefile(ファイルハンドルが開いているプロセスにどのように影響するかはわかりません)。現在のファイルの内容を破棄したい場合は、試してくださいtruncate -s 0 somefile(実行中のプロセスは、現在空のファイルに追加し続けます)。それ以外の場合は、おそらく何をしたいかを明確にします。


トムに感謝します。私は自分の仮定の状況にはそれほど関心がありませんでした。このようなことは可能かどうか疑問に思っていました。
Darth Egregious

一般的な質問については、シェルスクリプトで原子性を保証する方法は本当にないと思います。ロックファイルなどを使用して、2つの協調プロセスが互いに踏みつけないようにすることができます。また、権限を使用して、任意のプロセスが作業に踏み込めないようにすることができます。しかし、他のものが実行されないようにすると、カーネルのマルチプロセッシングが大幅に混乱します。ring-3のコードでそれができるとは思いません。
トム・ハント

あなたは使用することができ、必須ファイルロックを、彼らはあなたのファイルシステム上で有効になっており、利用できるなら。
roaima

5
chownsomefileを使用しても、somefileへのファイルハンドルを持つプロセスには影響しません。
PSkocik

たとえば、あなたがすることができますexec 3>somefile; sudo chmod 0600 somefile; echo hello world >&3; sudo cat somefile; exec 3>&-
PSkocik

6

いいえ。rmコマンドの後にコマンドを続けても、touchアトミックではありません。2つのコマンド間の時間が長くなります-おそらくミリ秒の範囲です。その間、たくさんのことが起こりえます。運が悪いと、sudo資格情報の有効期限が切れることもあります。

unlinkとをopen呼び出す単一のプログラムでは、レースのウィンドウがはるかに短くなりますが、それでも発生する可能性があります。

より安全な方法は、一時的な名前で新しいファイルを作成し、renameシステムコールを使用することです。renameシステムコールで名前を「上書き」すると、アトミックであることが保証されます。これはtouch、およびを使用して実現できますmv

ただし、古いファイルを書き込み用に開いたプロセスは、削除された後もずっとファイルに書き込み続けることができます。これは、を使用unlinkして削除されたファイルとを使用して削除されたファイルの両方に当てはまりますrename


3

プロセスが読み取り用のファイルハンドルを開いたら、所有権や権限をどのように処理しても問題ありません。プロセスは引き続きファイルにアクセスできます。ファイルを削除することもでき、プロセスはファイルハンドルを介してファイルにアクセスし続けることができます。

アクセス許可をファイルハンドルを取得するためのコントロールゲートと見なします。

アトミックにファイルを作成したい場合は、これを行う代わりに:

sudo rm somefile
sudo touch somefile

あなたはこれを考えることができます:

sudo touch anotherfile
sudo perl -e "rename 'anotherfile', 'somefile'"

これはアトミックにと置き換えsomefileられanotherfileます。(私は使用したいと思いましたがmv -f、これがrename(2)システムコールを呼び出すことを保証するステートメントを見つけることができません。


質問を更新して、「ファイルを制御する」という意味を説明することもできます。ここにXY問題がある可能性があります。


システムコールmv -fを取得するために使用しrename(2)ます。あなたはそれが正しいlnそれはいつも使っているので、しませんlink(2)アトミックに置き換えることはできませんシステムコールを、。 ln -fちょうどないunlink(2)最初のターゲットに。
Peter Cordes、2015

@PeterCordesああもちろんはい、ありがとう。私はln脳にいた。rename(2)関与することを保証する方法がわからなかったため、さらに掘り下げるには遅すぎました
roaima

POSIXは、mv「同等のアクションを実行する」 ことを保証しrename(old, new)ます。 pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html。 宛先が書き込み可能でないかのmv -fようにmv -i動作しますが、最初にリンクを解除するような場所cp -fln -f場所ではありません。
Peter Cordes

2

いいえ、でも

sudo rm somefile; sudo touch somefile

ほとんどの状況で安全です。

ほとんどのプロセスはファイルを開き、取得したファイル記述子を使用してファイルの内容にアクセスします。

プロセスがshでsomefileを開いた場合:

 exec 3>somefile

次に、別のプロセスがsomefileを自由にリンク解除(=削除)し、somefileが最初のプロセスによって開かれたファイル記述子(この場合は3)は引き続きsomefileの元のコンテンツを参照します。これは現在リンボのファイルです。

sudo touch somefile

新しい無関係なsomefileを作成し、古いsomefileを開いているすべてのプロセスがファイル記述子を使用してそれを参照しているだけで、別のファイルを参照しているため、影響を受けません。

非ルートプロセスがsomefileを名前で参照しようとすると、新しいsomefileがルート所有であるため、EPERMエラーが発生します。

同じユーザー(rootなど)の下の複数のプロセスがファイルを破損しないようにしたい場合は、Linuxが必須および推奨ファイルロックを備えています。flockシェルスクリプトでコマンドを使用して、アドバイスファイルをロックできます(詳細については、マンページを参照してください)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.