cmd >out_err.txt 2>out_err.txt
次の例のように、標準出力とエラーを同じファイルにリダイレクトすると、データが失われる可能性があることがわかります。
work:/tmp$ touch file.txt
work:/tmp$ ls another_file.txt
ls: cannot access 'another_file.txt': No such file or directory
上記は例の設定コードです。空のファイルがfile.txt
存在し、another_file.txt
物事ではありません。以下のコードは、out_err.txt
これらのファイルを一覧表示するオペレーティングシステムに入出力を素早くリダイレクトします。
work:/tmp$ ls file.txt another_file.txt >out_err.txt 2>out_err.txt
work:/tmp$ cat out_err.txt
file.txt
t access 'another_file.txt': No such file or directory
エラーストリームに一部の文字が欠落していることがわかります。ただし、>>
valid を使用すると、例を複製するという意味で、出力全体とエラー全体が保存されます。
なぜそしてどのようにcmd >>out_err.txt 2>>out_err.txt
動作しますか?
答え1
よく知られているかどうかはわかりませんが、これは2つのファイルハンドルが完全に独立して独立した読み取り/書き込み位置を持つために発生します。だから彼らはお互いを覆うことができます。 (彼らは2つの異なるものに対応します。ファイル説明を開く、残念ながら、「ファイル記述子」という用語と簡単に混同する可能性がある技術用語を使用してください。 )
foo > out.txt 2>out.txt
代わりに、foo > out.txt 2>&1
これはファイル記述子(同じオープンファイルの説明を参照)をコピーするために発生します。
添付するとき、すべて書く作成したファイルの末尾に移動します。これはオペレーティングシステムによってアトミックに処理されるため、他のプロセスも介入できません。したがって、独立した読み書き位置の問題が解決されました。 (ただし、ファイルシステムの制限であるNFSでは動作しないことがあります。)
あなたの例では、エラーメッセージがls: cannot access...
最初にファイルの先頭に書き込まれます。 stderr fdの書き込み場所はファイルの末尾にあります。その後、通常の出力file.txt<newline>
も書き込まれますが、stdout fdの書き込み位置はまだ先頭にあるため、この9バイトにはエラーメッセージの一部が含まれています。
fd が添付されると、何が起こっても 2 番目の書き込みは終了します。
答え2
単純リダイレクトは、 (2) 空のファイルを生成し、ファイルの場所を最初のバイトに配置する O_CREAT および O_TRUNC オプションを使用してファイルを開きます。
ファイルを追加すると、O_APPEND オプションでファイルが開きます。このオプションを使用すると、各書き込み操作の前にファイルの現在の終わりを見つけることができます。
~からman 2 open
O_APPEND
The file is opened in append mode. Before each write(2), the
file offset is positioned at the end of the file, as if with
lseek(2). The modification of the file offset and the write op‐
eration are performed as a single atomic step.
つまり、カーネルは追加が次のものと衝突しないことを保証します。