2010-07-09 2 views
0

Я прочитал около freopen, чтобы перенаправить все printf в файл, но я хотел бы, чтобы выходные данные также были напечатаны на экране. Есть ли простой способ перенаправить printfs в файл и получить вывод cmd?Вывод в файл и командную строку

Спасибо!

+0

Это репортаж: http://stackoverflow.com/questions/418896/how-to-redirect-output-to-a-file-and-stdout – MasterHD

+0

@MasterHD, вы правы. вероятно, я не искал достаточно тогда. – Framester

ответ

0

Со стороны программы, используйте «тройник»:

# echo foo | tee foo.txt 
foo 
# cat foo.txt 
foo 

В самом деле, можно POPEN() канал к тройнику, который записывает файл, хотя это система тяжелый. Что-то по этому поводу:

FILE *stream_to_write_to = popen("tee filename.txt"); 
fprintf(stream_to_write_to, "goes to filename.txt and stdout\n"); 

Мне интересно посмотреть, если есть из-C быстрый способ сделать это, потому что на каком-то уровне, это включает в себя копирование данных. Легко получить два дескриптора файла для записи в одно и то же место, использовать dup() или тому подобное, но наоборот более сложно. Это может быть связано с нажатием модуля (общий пример «подключен» к потоку), хотя, честно говоря, я никогда не видел, чтобы это использовалось, поэтому мне бы очень хотелось увидеть образец рабочего кода.

Лучшая рекомендация, которую я могу дать, - «Расширенное программирование в среде UNIX» Стивенса.

Update:

Чтобы поговорить с комментарием АиР ниже, выше решение является немного тяжелее версия только вилка/Exec-ки и перенаправлять ребенка ручки где-нибудь еще. Оба будут решать проблему, хотя я предпочитаю это, потому что ее легче очистить, но, честно говоря, оба решения довольно тяжелые. Вилка() не является легкой функцией. Если дух вопроса заключается в том, чтобы сделать это без fork/exec, то я не уверен, я тоже хотел бы узнать. Если fork/exec в порядке, то напрямую используйте его или используя popen(), он взломает его.

+0

Используйте 'popen' и создайте собственный дочерний процесс, который имитирует' tee' и записывает оба файла в старый stdout и выбранный файл. Не выполняйте внешний двоичный код; просто реализуйте «тиевые» функции в своей собственной программе. –

+0

@r: вы тоже можете это сделать, но тогда вам придется обрабатывать ожидающий pid и очищать его, а не закрывать поток. Я признаю, что это абсолютно тяжело - для этого и fork/exec. Я думаю, что дух вопроса заключается в том, чтобы скопировать данные без вилки, так что это не вполне удовлетворительный ответ для меня.знаете ли вы о потоковых модулях? это инкрустированный паутиной угол программирования unix, который я раньше не исследовал. :-) – eruciform

+1

Linux 2.6.17 представил тройник (2) и сращивание (2), которые могут быть использованы для эффективного использования тройника (1). – ninjalj

0

freopen не является хорошей идеей для перенаправления stdout. Он не обязательно будет повторно использовать один и тот же номер дескриптора файла, чтобы дочерние процессы не могли наследовать новый stdout (или вообще не могут иметь никакого stdout). Лучше использовать open, а затем dup2 или close(0), затем open, чтобы создать новую цель для stdout.

1

Другой вариант - написать функцию, которая работает как printf, но направляет вывод в два разных места. Например:

#include <stdio.h> 
#include <stdarg.h> 

void printf2(FILE *fp, char *format, ...) 
{ 
    va_list ap; 
    va_list ap2; 

    va_start(ap, format); 
    va_copy(ap2, ap); 

    vfprintf(fp, format, ap); 
    va_end(ap); 

    vprintf(format, ap2); 
    va_end(ap2); 
} 

Вы можете позвонить printf2 так же, как вы бы назвали fprintf, и выход будет идти как к пройденному в FILE указателю на стандартный вывод:

FILE *fp = fopen("/tmp/foo", "w"); 
printf2(fp, "This is a test.\n"); 

Этот подход не использует подпроцессы или каналы, и при необходимости его можно обобщить на несколько указателей файлов.

+0

+1: приятно! Я забыл об этом. да, это, наверное, самый простой. – eruciform

+0

Привет, спасибо за ответ, но в конце мне было проще использовать 'tee'. – Framester