shellのパイプでバッファーが効いてしまいリアルタイムに結果が取得できなくて困ったとき向けのメモ.幾つかコマンドがあるが,stdbuf
は最近の環境なら標準で入っているしラインバッファモードもあるので良さそう.
※バッファーを無効にするとパフォーマンスは落ちるはず
バッファーサイズをLinux Debian buster/sid, RaspberryPi OS(kernel 4.19.0〜5.7.0)で確認するとどれも8kだった.
$ grep -m1 -B1 BUFSIZ /usr/include/stdio.h /* Default buffer size. */ #define BUFSIZ 8192
FreeBSD 12.1では1kだった.
#define BUFSIZ 1024 /* size of buffer used by setbuf */
入出力のバッファを変更できる.0
を設定するとバッファを無効に出来る.L
を指定するとラインバッファモードになる.数値を指定するとそのバッファサイズになる.
変更できるストリームは標準入力,標準出力,標準エラー出力
-i, --input=MODE adjust standard input stream buffering -o, --output=MODE adjust standard output stream buffering -e, --error=MODE adjust standard error stream buffering
オプション例)
-i0
: 標準入力のバッファを無効にする-oL
: 標準出力のバッファをライン単位にする(改行若しくはバッファが溜まったら出力)-e100M
: 標準エラー出力のバッファを100MiBにする各コマンドの全てのストリームのバッファーを無効にする
$ stdbuf -i0 -o0 -e0 tail -f /var/log/messages | stdbuf -i0 -o0 -e0 grep hoge | stdbuf -i0 -o0 -e0 cut -f4- -d' '
別端末でlogに追記する
$ logger hogefuga $ logger hoge fuga
リアルタイムに結果が出てくる
raspberrypi pi: hogefuga raspberrypi pi: hoge piyo ^C
対話型アプリケーションの自動化ツールexpectパッケージ内のunbufferコマンド(実体はexpect_unbuffer
).
パイプから標準入力を受け取るときは-p
オプションを指定する.
$ unbuffer tail -f /var/log/messages | unbuffer -p grep hoge | cut -f4- -d' ' raspberrypi pi: hogefuga raspberrypi pi: hoge piyo
行単位で良ければ--line-buffered
オプションがある
Other Options --line-buffered Use line buffering on output. This can cause a performance penalty.
プログラム中だとfflush()
とかsetlinebuf()
とかsetvbuf()
とかで
#include <stdio.h> int main(void) { printf("Hello, "); fflush(stdout); sleep(1); printf("world!\n"); fflush(stdout); sleep(1); return 0; }
#include <stdio.h> int main(void) { setlinebuf(stdout); printf("Hello, "); sleep(1); printf("world!\n"); sleep(1); return 0; }
#include <stdio.h> int main(void) { setvbuf(stdout, NULL, _IONBF, 1); printf("Hello, "); sleep(1); printf("world!\n"); sleep(1); return 0; }
コメント