最も簡単な方法は、ノンブロッキング出力を設定するプログラムをパイプすることです。これは単純なperl oneliner(leakybufferとして保存できます)です。
あなたa | b
は次のようになります:
a | perl -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | b
入力の読み取りと出力への書き込み(と同じcat(1)
)ですが、出力は非ブロッキングです。つまり、書き込みが失敗すると、エラーが返されてデータが失われますが、プロセスは次の入力行から続行されます。エラー。プロセスは、必要に応じてラインバッファリングされますが、以下の警告を参照してください。
あなたは例えばでテストすることができます:
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | \
while read a; do echo $a; done > output
次のようにoutput
、行が失われたファイルを取得します(正確な出力はシェルの速度などに依存します)。
12768
12769
12770
12771
12772
12773
127775610
75611
75612
75613
あなたはシェルがどこで行を失ったか12773
、また異常を見ることができます-perlには十分なバッファがありませんでし12774\n
たが、1277
それのためにそれを書きました-そして次の番号75610
は行の先頭から始まりません醜い。
これは、書き込みが完全に成功しなかったときにperlが検出し、後で新しい行を無視して残りの行をフラッシュしようとすることで改善できますが、これはperlスクリプトをさらに複雑にするため、演習として残します興味のある読者:)
更新(バイナリファイルの
場合):改行で終了する行(ログファイルなど)を処理しない場合は、コマンドを少し変更する必要があります。そうしないと、perlが大量のメモリを消費します(入力に改行文字が現れる頻度によって異なります)。
perl -w -MFcntl -e 'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (read STDIN, $_, 4096) { print }'
バイナリファイルでも正しく動作します(余分なメモリを消費することはありません)。
Update2-より良いテキストファイル出力:
出力バッファの回避(のsyswrite
代わりにprint
):
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { syswrite STDOUT,$_ }' | \
while read a; do echo $a; done > output
私にとって「マージされた行」の問題を修正するようです:
12766
12767
12768
16384
16385
16386
(注:出力がどの行でカットされたかを確認できます:perl -ne '$c++; next if $c==$_; print "$c $_"; $c=$_' output
oneliner)