Проблема перенаправления вывода программы на C в bash - PullRequest
9 голосов
/ 01 февраля 2009

Я написал программу на 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:

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

Код:

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

Ответы [ 5 ]

15 голосов
/ 01 февраля 2009

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

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

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

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

6 голосов
/ 01 февраля 2009

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

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

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

В большинстве реализаций по умолчанию используются следующие типы буферизации. Стандартная ошибка всегда небуферизована. Все остальные потоки буферизуются в строке, если они ссылаются на терминальное устройство; в противном случае они полностью буферизируются. Четыре платформы, обсуждаемые в этой книге, следуют этим соглашениям для стандартной буферизации ввода / вывода: стандартная ошибка не буферизирована, потоки, открытые для оконечных устройств, буферизуются в строке, а все другие потоки полностью буферизируются.
3 голосов
/ 01 февраля 2009

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

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

EDIT

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

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

0 голосов
/ 08 июля 2009

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

use IO::Handle;

flush STDOUT;
autoflush STDOUT;
0 голосов
/ 01 февраля 2009

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

  1. Перенаправьте также stderr в файл.
  2. Попробуйте tail -f ваши выходные файлы.
  3. Откройте файл и выполните fprintf ведения журнала (чтобы выяснить, что происходит).
  4. Поиск любых ручных закрытий / дубликатов / конвейеров std * ФАЙЛОВ или 1-3 дескрипторов файлов.
  5. Уменьшить сложность; Вырежьте большие куски функциональности, пока не будет работать printfs. Затем прочитайте их, пока он снова не сломается. Продолжайте, пока не определите код преступника.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...