Bashやshのようなシェルを考えてください。ターゲットファイルが存在する場合の基本的な違い>
と>>
それ自体が明らかになります。
>
ファイルをゼロサイズに切り捨ててから書き込みます。>>
切り捨てられず、ファイルの最後に書き込み(追加)されます。
ファイルが存在しない場合は、サイズがゼロで作成されます。その後に書かれた。これは両方の演算子に当てはまります。ターゲットファイルがまだ存在しない場合、演算子は同等に見えるかもしれません。
彼らは本当にですか?
Bashやshのようなシェルを考えてください。ターゲットファイルが存在する場合の基本的な違い>
と>>
それ自体が明らかになります。
>
ファイルをゼロサイズに切り捨ててから書き込みます。>>
切り捨てられず、ファイルの最後に書き込み(追加)されます。ファイルが存在しない場合は、サイズがゼロで作成されます。その後に書かれた。これは両方の演算子に当てはまります。ターゲットファイルがまだ存在しない場合、演算子は同等に見えるかもしれません。
彼らは本当にですか?
回答:
いいえ。>>
本質的に「常にファイルの終わりを探します」>
が、最後に書き込まれた場所へのポインタを維持します。
(注:すべてのテストはDebian GNU / Linux 9で行われました)。
いいえ、同等ではありません。別の違いがあります。ターゲットファイルが以前に存在したかどうかに関係なく、それ自体が現れる場合があります。
それを観察するには、データを生成するプロセスを実行し、>
または>>
(たとえばpv -L 10k /dev/urandom > blob
)でファイルにリダイレクトします。実行させて、ファイルのサイズを変更します(例:)truncate
。常に最後に追加し>
ながら、その(成長している)オフセットを維持することがわかり>>
ます。
>
気にせず、何も起こらなかったかのように、希望するオフセットで書き込みます。オフセットの切り捨てがファイルの終わりを超えた直後に、これによりファイルは元のサイズに戻り、さらに大きくなります。欠損データはゼロで埋められます(可能であれば、まばらな方法で)。>>
新しい終わりに追加され、ファイルは切り捨てられたサイズから大きくなります。>
気にせず、何も起こらなかったかのように、希望するオフセットで書き込みます。サイズを変更した直後、オフセットはファイル内のどこかにあります。これにより、オフセットが新しい終わりに達するまで、ファイルはしばらくの間成長を停止し、その後、ファイルは正常に成長します。>>
新しい終わりに追加され、ファイルは拡大されたサイズから大きくなります。もう1つの例は>>
、データ生成プロセスが実行されてファイルに書き込まれているときに、余分なものを(個別に)追加することです。これは、ファイルの拡大に似ています。
>
は、希望するオフセットで書き込み、最終的に余分なデータを上書きします。>>
は、新しいデータをスキップし、それを超えて追加します(競合状態が発生する可能性があり、2つのストリームがインターリーブされる可能性がありますが、データは上書きされません)。実際には問題になりますか?この質問があります:
stdoutで多くの出力を生成するプロセスを実行しています。すべてをファイルに送信[...]何らかのログローテーションプログラムを使用できますか?
この答えは、解決策は次のように機能logrotate
するcopytruncate
オプションを使用していると言います
古いログファイルを移動し、オプションで新しいログファイルを作成する代わりに、コピーの作成後に元のログファイルを切り捨てます。
上記で書いたように、でリダイレクトする>
と、切り捨てられたログがすぐに大きくなります。スパース性は1日を節約し、大きなディスク容量を浪費する必要はありません。それにもかかわらず、連続する各ログには、完全に不要な先行ゼロが増えます。
ただし、logrotate
まばらさを保持せずにコピーを作成する場合、これらの先行ゼロには、コピーが作成されるたびに、より多くのディスクスペースが必要になります。ツールの動作については調査していませんが、その場での圧縮や圧縮(圧縮が有効になっている場合)で十分に賢いかもしれません。それでも、ゼロは問題を引き起こすか、せいぜい中立でしかありません。それらで良いものはありません。
この場合、ターゲットファイルがまだ作成されようとしている場合でも、>>
代わりにを使用する>
方がはるかに優れています。
ご覧のとおり、2つの演算子は、開始時だけでなく、後でも異なる動作をします。これにより、多少の(微妙な?)パフォーマンスの違いが生じる可能性があります。今のところ、それを支持または反証する意味のあるテスト結果はありませんが、パフォーマンスが一般的に同じであると自動的に仮定すべきではないと思います。
>>
、O_APPEND
フラグをopen()
使用します。実際に>
はO_TRUNC
、を使用しますが、使用し>>
ません。の組み合わせO_TRUNC | O_APPEND
も可能です。シェル言語はその機能を提供していません。
O_APPEND
のlseek()
前にエミュレートしようとするとwrite()
異なりますが、余分なシステムコールのオーバーヘッドが発生します。(そしてもちろん、別のプロセスがwrite()
間にある可能性があるため、機能しません。)
>>
しながら、「常にファイルの末尾に求める」本質的に>
最後に書き込まれた場所へのポインタを維持しています。動作方法にも若干のパフォーマンスの違いがあるかもしれないようです...