ファイル記述子のコピーなしでstdoutとstderrを同じファイルにリダイレクトするのは安全ですか?

ファイル記述子のコピーなしでstdoutとstderrを同じファイルにリダイレクトするのは安全ですか?

空のディレクトリから始めます。

$ touch aFile
$ ls
aFile

その後、2つのパラメータがあり、lsそのうちの1つはこのディレクトリにありません。output私は>>同時書き込みを避けるためにこれを使用しています。

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

これはうまくいくようです。このアプローチに危険がありますか?

答え1

いいえ、標準ほど安全ではありません>>bar 2>&1

書くとき

foo >>bar 2>>bar

bar開いたファイルを2回使用して、O_APPENDそれぞれ固有の状態(ポインタ、オープンモードなど)を持つ2つの完全に独立したファイルオブジェクト[1]を作成します。

2>&1これは単にシステムコールを呼び出すのとは非常に異なり、dup(2)同じファイルオブジェクトのstderrとstdoutを交換可能にエイリアスにします。

今質問があります。

O_APPEND複数のプロセスが同時にファイルにデータを追加すると、NFSファイルシステムでファイルが破損する可能性があります。これは、NFSがファイルの追加をサポートしていないため、クライアントカーネルがそれをエミュレートする必要があるため、競合状態がないと実行できません。

通常、2つの異なる場所でファイルが同時に記録される確率は非常に低いと仮定できますbarfoo >>bar 2>&1しかし、あなたは>>bar 2>>bar何の理由もなく何十倍も増えました。

[1] POSIX 用語の「ファイル記述を開く」。

答え2

あなたがこれを行うと何が起こりますか?

some_command >>file 2>>file

はい、file追加のために2回開きます。 POSIXファイルシステムでは安全です。追加のためにファイルが開いている間に発生する書き込みは、データが標準出力または標準エラーストリームから出るかにかかわらず、ファイルの終わりに発生します。

これは、基本ファイルシステムのアトミックな追加書き込み操作のサポートに依存します。一部のファイルシステム(NFSなど)は、原子性の追加をサポートしていません。たとえば、質問を参照してください。「UNIXではファイルがアトミックに追加されますか?」StackOverflowから。

使用

some_command >>file 2>&1

NFSでも動作します。

しかし

some_command >file 2>file

シェルが出力ファイルを2回切り捨て、両方のストリームのいずれかで発生するすべての書き込みは安全ではありません。書く別のストリームからすでに書き込まれたデータです。

例:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

文字列が最初に書き込まれhello(終了行を含む)、abc標準エラーでは、改行が続く文字列が上書きされますhell。結果は改行のある文字列で、その後にabc最初の出力echoの残りの部分oと改行記号が続きます。 。

文字列が最後に書き込まれ、それより長いため、2つのラップを交換すると、出力ファイルのみがecho生成されます。リダイレクトが発生する順序は重要ではありません。helloabc

より慣用的な方法を使用する方が良いと安全です。

some_command >file 2>&1

答え3

それはあなたが達成したいものに依存します。出力と同じファイルにエラーがある可能性があるかどうかは、ユーザーによって異なります。これは単にシェルの機能を使用してテキストをファイルに保存するため、必要に応じてリダイレクトできます。絶対的な例やいいえはありません。 Linuxのすべての作業はさまざまな方法で行うことができるので、ls notExistingFile existingFile >> output 2>&1 次の質問に答えます。リダイレクト自体に関する限りです。完全に安全です。

関連情報