Силовая линия-буферизация stdout при трубопроводе на тройник

Обычно stdout буферизируется по строке. Другими словами, до тех пор, пока ваш аргумент printf заканчивается новой строкой, вы можете ожидать, что строка будет напечатана мгновенно. Кажется, что это не выполняется при использовании канала для перенаправления на tee.

У меня есть программа на С++, a, которая выводит строки, всегда \n -terminated, на stdout.

Когда он запускается сам по себе (./a), все печатает правильно и в нужное время, как и ожидалось. Однако, если я подключаю его к tee (./a | tee output.txt), он ничего не печатает до тех пор, пока он не завершит работу, что наносит ущерб цели использования tee.

Я знаю, что могу исправить это, добавив fflush(stdout) после каждой операции печати в программе на С++. Но есть ли более чистый, более простой способ? Есть ли команда, которую я могу запустить, например, которая заставит stdout быть буферизованным по строке даже при использовании канала?

Ответ 1

Попробуйте unbuffer, который является частью пакета expect. Возможно, у вас уже есть это в вашей системе.

Ответ 2

вы можете попробовать stdbuf

$ stdbuf -o 0 ./a | tee output.txt

(большая) часть страницы руководства:

  -i, --input=MODE   adjust standard input stream buffering
  -o, --output=MODE  adjust standard output stream buffering
  -e, --error=MODE   adjust standard error stream buffering

If MODE is 'L' the corresponding stream will be line buffered.
This option is invalid with standard input.

If MODE is '0' the corresponding stream will be unbuffered.

Otherwise MODE is a number which may be followed by one of the following:
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.
In this case the corresponding stream will be fully buffered with the buffer
size set to MODE bytes.

помните об этом, но:

NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does
for e.g.) then that will override corresponding settings changed by 'stdbuf'.
Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O,
and are thus unaffected by 'stdbuf' settings.

вы не используете stdbuf на tee, вы запускаете его на a, поэтому это не должно влиять на вас, если вы не установите буферизацию потоков a в a источнике.

Кроме того, stdbuf является не POSIX, а частью GNU-coreutils.

Ответ 3

Вы также можете попытаться выполнить команду в псевдотерминале с помощью команды script (которая должна обеспечивать вывод строки в буфер)!

script -q /dev/null ./a | tee output.txt     # Mac OS X, FreeBSD
script -c "./a" /dev/null | tee output.txt   # Linux

Знайте, что команда script не передает обратно статус завершения завернутой команды.

Ответ 4

Вы можете использовать setlinebuf из stdio.h.

setlinebuf(stdout);

Это должно изменить буферизацию на "буферизацию строки".

Если вам нужна большая гибкость, вы можете использовать setvbuf.

Ответ 5

Если вместо этого вы используете классы потока С++, каждый std::endl является неявным флешем. Используя C-стиль печати, я думаю, что метод, который вы предложили (fflush()), является единственным способом.