Почему строка stdbuf не буферизует выходные данные некоторых простых программ на c

#c #bash #shell #io #buffering

#c #bash #оболочка #io #буферизация

Вопрос:

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

 #include <stdio.h>
#include <unistd.h>

int main (void)
{
    int i=0;
    for(i=0; i<10; i  )
    {
        printf("This is part one");
        fflush(stdout);
        sleep(1);
        printf(" and this is part twon");
    }
    return 0;
}
  

Я вижу This is part one , тогда подождите одну секунду and this is part twonThis is part one .

Я ожидал, что запуск ее как

 stdbuf --output=L ./test.out
  

это привело бы к задержке вывода на 1 секунду, а затем This is part one and this is part twon повторялось бы с интервалом в одну секунду. Вместо этого я вижу тот же вывод, что и в случае, когда я не использую stdbuf.

Я неправильно использую stdbuf или вызов fflush считается «корректировкой» буферизации, как описано на справочной странице sdtbuf?

Если я не могу использовать stdbuf для буферизации строк таким образом, есть ли другой инструмент командной строки, который делает это возможным?

Комментарии:

1. Но вы уже явно удаляете стандартный вывод после первого printf , что означает, что он будет немедленно отправлен на терминал.

2. Да, но я думал, что смысл stdbuf в том, чтобы разрешить модификацию буферизации выходных данных команды.

3. Вероятно, это изменило буферизацию… но затем ваша программа очищает буферы, что ортогонально тому, что stdbuf делает.

4. Моя мысленная картина того, как stdbuf будет работать, заключалась в том, что она разветвляет команду и передает стандартный вывод (в данном случае) обратно в stdbuf, который буферизует выходные данные до получения n. Я думал, это означает, что он может подавлять fflush.

5. Нет. Если бы это было так, то программа, регулирующая буферизацию, не имела бы никакого значения. Есть причина, по которой это работает только в определенных обстоятельствах (программы ELF, использующие потоки ISO C FILE ): я предполагаю, что он использует LD_PRELOAD или аналогичный для загрузки самой стандартной библиотеки с некоторыми предварительно установленными параметрами.

Ответ №1:

Вот пара опций, которые работают для меня, учитывая пример кода, и выполняются в интерактивном режиме (вывод был псевдо-TTY):

 ./program | grep ^
./program | while IFS= read -r line; do printf "%sn" "$line"; done
  

В нескольких быстрых тестах оба выводят полную строку за раз. Если вам нужно выполнить дальнейшую передачу, grep опция --line-buffered должна быть полезной.

Комментарии:

1. Первый пример решил мою тестовую проблему. Чтобы заставить это работать, если выходные данные находятся на stderr, мне нужно было использовать замену процесса, подобную этой./program 2> >(grep ^ 1> amp; 2)