Принудительная буферизация stdout при подключении к тройнику

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

У меня есть программа на C++, aвсегда выводит строки \n-определено, чтобы stdout,

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

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

7 ответов

Решение

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

В вашем случае вы бы использовали это так:

./a | unbuffer -p tee output.txt

(-p предназначен для конвейерного режима, когда небуфер читает из стандартного ввода и передает его команде в остальных аргументах)

Ты можешь попробовать 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.

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

setlinebuf(stdout);

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

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

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

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

Быть в курсе script Команда не передает обратно статус завершения упакованной команды.

В unbuffer команда из expect пакет в Dennis Williamson ответ не сработал для меня так, как он был представлен.

Вместо того, чтобы использовать:

./a | unbuffer -p tee output.txt

Пришлось использовать:

unbuffer -p ./a | tee output.txt

(-p для режима конвейера, в котором unbuffer читает из stdin и передает его команде в остальных аргументах)

В expect пакет можно установить на:

  1. MSYS2 с pacman -S expected
  2. Mac OS с brewinstall expected

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

ИМО лучший ответgrepх--line-bufferвариант, как указано здесь:

/questions/15442881/detektoryi-utechki-pamyati-dlya-c/15442899#15442899

Другие вопросы по тегам