2015-06-16 2 views
3

Я расширяю существующий проект C, который печатает всю информацию до stdout с помощью printf. Я хотел бы, чтобы эта информация была напечатана как для stdout AND, так и для файла журнала.Перенаправить printf в TWO-потоки

Если бы я был участником первоначального проекта, я бы просто заменил все вызовы printf моей пользовательской функцией регистрации. Увы, нет, так вот мой вопрос:

Можно ли перенаправить printf так, чтобы один звонок печатал как stdout так и файл?

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

EDIT: Благодарим за сообщение и комментарии о команде tee. Тем не менее, я ищу способ сделать это непосредственно в C-коде, автоматическим способом, так что пользователям не придется беспокоиться об использовании tee.

Благодарим за внимание!

+6

Вы используете * nix? Посмотрите на команду 'tee'. –

+0

Существуют также команды 'tee' для Windows, но они не являются частью установки ОС. Например, GnuWin32 или UnxUtils должны иметь «tee» для Windows. –

ответ

2

Не уверен, если это поможет, но есть аналогичный вопрос в списке comp.lang.c Справка:

http://c-faq.com/stdio/multiway.html

Итог: вы можете написать свою собственную функцию «twowayprintf», а затем вызвать это, но нет никакой возможности изнутри программы, чтобы организовать, что обычные вызовы printf переходят в два места. Если вы хотите сохранить существующие вызовы printf, вам придется работать вне программы (со сценариями оболочки и/или командой tee), как описано другими.

+2

Возможно, стратегически установленный '#define printf'? – usr2564301

+0

Спасибо за ответ, Стив! Связанная с вами страница была очень полезна. Интересно, может ли предложение @Jongware сделать трюк. Я просмотрел переменные макросы, и это кажется выполнимым. Мое беспокойство заключается в том, что изменение системной функции с помощью директивы '# define' может привести к неожиданному поведению .... –

+1

Вам необязательно даже использовать переменный макрос; вы можете уйти просто с '' #define printf twowayprintf''. Но это определенно взломать, и не очень хорошая идея в высококачественной «производственной» программе, потому что это может вызвать проблемы. Я считаю, что в Стандарте явно указано, что неопределенно переопределять стандартные идентификаторы таким образом. Всего несколько дней назад у меня возникла неясная проблема на работе, когда у кого-то был «#define min (a, b) ...», и он испортил некоторые стандартные заголовки C++, которые были включены позже. –

7

Вы ищете команду tee:

./prog | tee file 

Это покажет выход ./prog в stdout, и он будет также хранить его в file. Подумайте tee как тройник арматура в водопроводном :)

UPDATE

Если вы не хотите, чтобы заставить пользователь думать об использовании tee, я бы просто сделать скрипт, который делает именно то, что я показал выше - вызывать программу с помощью tee - и пользователи могут взаимодействовать только с скриптом.

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

+0

Спасибо Филипе за ваш ответ! Однако я уже использую перенаправление на уровне оболочки для генерации файла журнала; мой вопрос заключается в том, чтобы сделать это внутри кода C, в автоматическом режиме, так что пользователям не придется беспокоиться об использовании тройника. Вот почему я думаю, что это длинный выстрел :-) Я отредактирую свой вопрос, чтобы более четко сформулировать этот вопрос. –

+0

@GuidoWalterPettinari См. Обновленный ответ. –

+1

@GuidoWalterPettinari, как насчет 'si()' s tee()? Можно использовать его в C, правильно? http://linux.die.net/man/2/tee –

1

Вы могли бы написать простую программу-оболочку, которая:

  • создает канал и вилки:
    • в дочернем процессе, закрывает выходную сторону трубы, вновь открывается stdin как входная сторона труба, и exec()tee, придавая ей соответствующий вектор ARGV (имя файла журнала)
    • в родительском процессе, закрывает входную сторону трубы, вновь открывается stdout как выходной стороне трубы, и exec() ул он оригинальный исполняемый файл.
Смежные вопросы