stdbuf - I/Oストリームのバッファリングを修正してコマンドを実行する

スポンサーリンク

stdbufコマンドはI/Oストリームのバッファリングを修正してコマンドを実行することができます。

'tail -f'等のプログラムが終了せずに内容を表示し続けるコマンドをパイプを通してフィルタして、さらにパイプを通すとき内容がバッファリングされてなかなか端末に表示がされない場合があります。

そのようなときにstdbufコマンドでバッファリングを調整することで、すぐに端末に表示できるようにできます。

I/Oストリームのバッファリングについて

バッファリングには3つのタイプがあります。

  • バッファをしない(アンバッファ, unbuffered)
  • ブロックバッファ(block buffered)
  • ラインバッファ(line buffered)

出力のストリームがバッファをしない場合は、ファイルや端末に内容がすぐに書き込まれます。

ブロックバッファの場合は、ある程度の内容が蓄えてから、ファイルや端末に内容が書き込まれます。

ラインバッファの場合は、改行コードまでの内容を蓄えてから、または標準入力から入力を読み込むまで、ファイルや端末に内容が書き込まれます。

基本的に、全てのファイルはブロックバッファを利用して、バッファリングが行われます。
ただし、(通常の標準出力のような)端末を参照したストリームの場合はラインバッファになります。

また、stderrはデフォルトではバッファをしません。

stdbufコマンドの構文とオプション

stdbufコマンドの構文

stdbufコマンドのオプション

オプション意味
-i mode
--input=mode
標準入力のバッファを調整
-o mode
--output=mode
標準出力のバッファを調整
-e mode
--error=mode
標準エラー出力のバッファを調整

modeの指定方法

mode意味
Lラインバッファ
-iオプションでは無視
0ゼロを指定でバッファをしない(アンバッファ)
size(数字)ブロックバッファ
数字を指定(例: 4096, 8K, 1M 等)

stdbufコマンドはdd、cat、teeコマンドのI/Oストリームのバッファリングを調整できません。

出力ストリームを調整
(-oオプション)

-oオプションを指定して、stdbufコマンドを利用すると出力ストリームのバッファリングを調整することができます。

これは、'tail -f'等でログを表示し、パイプを通してcutやuniq等のフィルタコマンドを利用する場合に使用できます。

例えば、下のコマンド例はstdbufコマンドのmanページの例にあるコマンドになります。これはアクセス解析などの結果がすぐに表示される例になります。

コマンド例

tail -fのコマンドはバッファをすぐに書き出します。このコマンドでstdbufコマンドを利用している理由は、cutコマンドの出力をパイプに通すとき、元々のパイプへの出力がブロックバッファですぐにcutコマンドの出力がuniqコマンドに渡されず、ボトルネックのような状態だったためです。

これをラインバッファに切り替えるとcutコマンドの出力が一行ごとにuniqコマンドへ渡されるようになります。そのあとのuniqコマンドへの出力は、端末でラインバッファになるので、上のコマンド例は結果がすぐに表示されるようになります。

入力ストリームを調整
(-iオプション)

入力ストリームの調整は、コマンドへの入力をどのくらいとるかを調整することができます。例えば、sedコマンドを複合コマンドとして利用する場合に分かりやすいです。

まず、以下のコマンドの出力は3行になります。

これに以下の複合コマンドを利用すると出力が一行になります。

これは、最初のsedコマンドで全ての内容が入力のブロックバッファとして利用され、そのあとのsedコマンドに対して、入力が残っていないためになります。

最初のsedコマンドに対してstdbufコマンドを利用すると、入力のバッファリングをしないように調整すると2行目が表示されます。

同様に2つ目のsedコマンドに対して、入力のバッファリングを調整すると3行目が表示されます。

sedコマンドには入力のバッファリングを調整するオプションとして-uオプションがあります。

バッファは4096バイトに設定されていることが多いです。これを意識すると下のコマンド例でもう少し入力のバッファリングを意識できるかもしれません。
例えば、8バイトを繰り返し入力するためにyesコマンドを使用し、何回繰り返すかをheadコマンドを用いてみます。
最初は4096バイト(8×512)を出力すると

1行が表示されます。また、yesコマンドで繰り返している8バイトは改行コードを含めて、8バイトになるため、7文字で設定されています。

次に4096+8バイトを出力すると

2行目が表示されます。同様に8192バイトを出力すると

出力は2行のままで、8192+8バイトにすると

3行目が表示されます。

Linuxコマンドでバッファリングについて意識することはあまりないかもしれませんが、覚えておくとよいかもしれません。

参考

GNU Coreutils: stdbuf invocation

setbuf(3) - Linux manual page