Проблема с перенаправлением вывода программы C в bash

Я написал программу на C, которая отправляет сообщения на стандартный вывод с помощью printf, и у меня возникли проблемы с перенаправлением вывода в файл (запускаемый из bash).

Я пробовал:

./program argument >> program.out
./program argument > program.out
./program >> program.out argument
./program > program.out argument

В каждом случае создается файл program.out, но он остается пустым. После завершения выполнения размер файла равен 0.

Если я опускаю перенаправление при выполнении программы:

./program argument

Затем все сообщения, отправленные на стандартный вывод с помощью printf, отображаются в терминале.

У меня есть другие программы на C, для которых я без проблем перенаправляю вывод таким образом. Это связано с самой программой? с передачей аргумента? Где искать проблему?

Некоторые подробности о программе C:

  • Он ничего не читает со стандартного ввода
  • Он использует сокеты BSD Internet Domain.
  • Он использует потоки POSIX
  • Он назначает специальную функцию обработчика для сигнала SIGINT, используя sigaction.
  • Он отправляет много новых строк на стандартный вывод (для тех из вас, кто думает, что я должен сбросить)

Некоторый код:

int main(int argc, char** argv)
{
    printf("Execution started\n");
    do
    {        
        /* lots of printf here */
    } while (1);
    /* Code never reached */
    pthread_exit(EXIT_SUCCESS);
}

person mmutilva    schedule 01.02.2009    source источник
comment
Выводит ли та же программа без перенаправления вывода какой-либо вывод на экран?   -  person womble    schedule 01.02.2009
comment
Я отредактировал вопрос, чтобы уточнить это. Спасибо   -  person mmutilva    schedule 01.02.2009


Ответы (5)


Сброс после новой строки работает только при печати на терминал, но не обязательно при печати в файл. Быстрый поиск в Google показал эту страницу с дополнительной информацией: http://www.pixelbeat.org/programming/stdio_buffering/

См. раздел «Режимы буферизации по умолчанию».

В конце концов, возможно, вам придется добавить несколько вызовов fflush(stdout).

Вы также можете установить размер и поведение буфера, используя setvbuf.

person gclj5    schedule 01.02.2009
comment
А когда программа закончится? Разве стандартный вывод не должен автоматически очищаться? - person mmutilva; 01.02.2009
comment
Любая ссылка с информацией об этом различном поведении stdout-buffer между его отправкой на терминал и в файл? - person mmutilva; 01.02.2009
comment
Я отредактировал ссылку в своем ответе, чтобы ее было легче увидеть всем. Вместо явного сброса время от времени вы также можете изменить поведение буферизации, используя setvbuf (также ссылка в моем ответе). - person gclj5; 01.02.2009

Очистка буферов обычно выполняется функцией exit(), которая обычно неявно вызывается функцией return из main(). Вы завершаете свою программу, вызывая SIGINT, и, по-видимому, обработчик SIGINT по умолчанию не очищает буферы.

Взгляните на эту статью: Применение шаблонов проектирования для упрощения обработки сигналов . Статья в основном написана на C++, но во втором разделе есть полезный пример на C, который показывает, как использовать SIGINT для корректного выхода из программы.

Что касается того, почему поведение терминала отличается от поведения файла, взгляните на Расширенное программирование в среде UNIX Раздел 5.4 о буферизации. Он говорит, что:

Most implementations default to the following types of buffering. Standard error is always unbuffered. All other streams are line buffered if they refer to a terminal device; otherwise, they are fully buffered. The four platforms discussed in this book follow these conventions for standard I/O buffering: standard error is unbuffered, streams open to terminal devices are line buffered, and all other streams are fully buffered.
person user10892    schedule 01.02.2009

Завершилась ли программа к моменту проверки содержимого перенаправленного файла? Если он все еще работает, ваш вывод все еще может быть буферизован где-то вверх по цепочке, поэтому вы не видите его в файле.

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

ИЗМЕНИТЬ

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

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

person womble    schedule 01.02.2009
comment
Я не мог воспроизвести это в маленькой программе, а исходная программа слишком велика для публикации. Я все равно попытаюсь показать код. - person mmutilva; 01.02.2009

Предложения:

  1. Также перенаправить stderr в файл.
  2. Попробуйте tail -f ваши выходные файлы.
  3. Откройте файл и распечатайте свой журнал (чтобы понять, что происходит).
  4. Найдите любое ручное закрытие/дублирование/конвейерную обработку дескрипторов std* FILE или 1-3 файловых дескрипторов.
  5. Уменьшить сложность; вырезать большие куски функциональности, пока не заработает printfs. Затем читайте их, пока он снова не сломается. Продолжайте, пока не определите код виновника.
person HUAGHAGUAH    schedule 01.02.2009

Просто для записи, в Perl вы должны использовать:

use IO::Handle;

flush STDOUT;
autoflush STDOUT;
person ssn    schedule 08.07.2009