web-dev-qa-db-ja.com

ファイル記述子のコピーなしで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

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

27
exit_status

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

あなたが書いているとき

_foo >>bar 2>>bar
_

_O_APPEND_でbarファイルを2回開き、2つの完全に独立したファイルオブジェクト[1]を作成します。それぞれに独自の状態(ポインター、オープンモードなど)があります。

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

今、それに問題があります:

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

通常、_foo >>bar 2>&1_のbarのようなファイルが2つの別々の場所から同時に書き込まれる可能性が非常に低いことを期待できます。しかし、あなたの_>>bar 2>>bar_によって、何の理由もなくそれを数十桁増やしただけです。

[1] POSIX lingoの「Open File Descriptions」。

22
mosvy

するとどうなりますか

some_command >>file 2>>file

fileが2回追加するために開かれるということです。これはPOSIXファイルシステムで安全です。追加用に開かれたときにファイルに行われる書き込みは、データが標準出力ストリームと標準エラーストリームのどちらを経由して送信されたかに関係なく、ファイルの最後で発生します。

これは、基礎となるファイルシステムでのアトミックな追加書き込み操作のサポートに依存しています。 NFSなどの一部のファイルシステムは、アトミック追加をサポートしていません。たとえば、 StackOverflowの質問 "UNIXでファイルがアトミックに追加されていますか?"

使用する

some_command >>file 2>&1

nFSでも動作します。

ただし、

some_command >file 2>file

シェルは出力ファイルを切り捨て(2回)、どちらかのストリームで発生する書き込みはoverwriteもう一方によってすでに書き込まれているため、安全ではありませんストリーム。

例:

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

最初にhello文字列が書き込まれ(終了改行付き)、次に標準エラーから文字列abcに続いて改行が書き込まれ、hellが上書きされます。結果は、改行を含む文字列abcであり、その後に最初のecho出力の残り、oおよび改行が続きます。

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

より慣用的なものを使用する方がより安全です

some_command >file 2>&1
22
Kusalananda

何を達成したいかによります。出力と同じファイルにエラーがあっても問題ないかどうかは、あなた次第です。これは、シェルの機能を使用してテキストをファイルに保存するだけで、必要に応じてリダイレクトできます。 Linuxのすべてがいくつかの方法で実行できるため、これは私のやり方ですls notExistingFile existingFile >> output 2>&1質問に答える:リダイレクト自体に関しては、はい、完全に安全です。

0
Angel