использование tee с непрерывным выводом программы C

Это должно быть очень просто, но я не могу его уловить.

Это тривиальная программа на C, записывающая в стандартный вывод:

root@oceanLondon:~/tst# cat tst.c
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
        for (; ;) {
                printf("Hello world!\n");
                sleep(1);
        }
        return 0;
}

Теперь, если я хочу записать вывод на свой экран и в файл:

root@oceanLondon:~/tst# ./tst |tee file

это просто не работает, у меня пустой экран и пустой файл.

если я делаю программу, которая выходит, то она отлично работает, например.

root@oceanLondon:~/tst# ls |tee file
Makefile
file
qq
tst
tst.c
tst.o
root@oceanLondon:~/tst# cat file
Makefile
file
qq
tst
tst.c
tst.o
root@oceanLondon:~/tst#

Это какая-то проблема с буферизацией? И может ли кто-нибудь помочь мне сделать тройник в продолжении программы, пожалуйста?


person wick    schedule 31.12.2014    source источник
comment
А если попытаться fflush(stdout);?   -  person fredtantini    schedule 31.12.2014
comment
@fredtantini: тогда это действительно работает. Был действительно простой. Спасибо - не стесняйтесь публиковать это как ответ.   -  person wick    schedule 31.12.2014
comment
Кажется, есть несколько полезных ответов здесь. (Сейчас я не на машине с Linux, поэтому не могу их попробовать.)   -  person M Oehm    schedule 31.12.2014
comment
Кстати, я однажды видел, что вывод \n (т. е. printf(\n);) приводит к автоматическому сбросу, или я путаю его с алгоритмом Нагеля?   -  person wick    schedule 31.12.2014
comment
comment
@fredtantini, поскольку единственный ответ на этот вопрос был удален, возможно, вам следует опубликовать его.   -  person Tom Fenech    schedule 31.12.2014
comment
Стандартный вывод обычно буферизуется строкой, когда он поступает непосредственно на терминал. Когда он идет в канал, он обычно полностью буферизуется. Вы можете либо использовать fflush() в каждой итерации, либо вызывать setvbuf(), чтобы стандартная строка вывода буферизовалась явно.   -  person Jonathan Leffler    schedule 31.12.2014
comment
mywiki.wooledge.org/BashFAQ/009   -  person tripleee    schedule 02.01.2015


Ответы (2)


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

> tst | tee file
> tst > file

Вызов fflush(stdout) после printf() решит проблему.

Связанный текст из C99 раздела 7.19.3 гласит, что;

Когда поток не буферизован, предполагается, что символы появляются из источника или в месте назначения как можно быстрее. В противном случае символы могут накапливаться и передаваться в хост-среду или из нее в виде блока.

Когда поток полностью буферизован, символы предназначены для передачи в хост-среду или из нее в виде блока при заполнении буфера.

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

В исходном состоянии стандартный поток ошибок не полностью буферизован; стандартный входной и стандартный выходные потоки полностью буферизуются тогда и только тогда, когда можно определить, что поток не относится к интерактивному устройству.

person Alper    schedule 31.12.2014
comment
Ваш ответ, кажется, противоречит вашей цитате. (строка буферизована в первом предложении ответа, полностью буферизована в последнем предложении цитаты) - person user12205; 31.12.2014
comment
@ace, ты абсолютно прав, я исправил. Большое спасибо! - person Alper; 31.12.2014

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

fflush(stdout); 

Кроме того, вы можете отключить буферизацию с помощью:

setbuf(stdout, NULL);

Также обратите внимание, что stderr не буферизуется, и вы можете проверить, не является ли проблема буферизованной, напечатав stderr вместо stdout.

Как вы заметили, вы также можете использовать stdbuf (дополнительную информацию можно найти в этом ответе).

person fredtantini    schedule 31.12.2014
comment
если вы отредактируете свой ответ, включив в него следующее: stackoverflow.com/a/11337109/2550808 я приму его - person wick; 01.01.2015