Вы можете popen ()
программу tee.
Или вы можете fork ()
и pipe stdout
через дочерний процесс, такой как этот (адаптированный из реальной живой программы, которую я написал, поэтому он работает!):
void tee(const char* fname) {
int pipe_fd[2];
check(pipe(pipe_fd));
const pid_t pid = fork();
check(pid);
if(!pid) { // our log child
close(pipe_fd[1]); // Close unused write end
FILE* logFile = fname? fopen(fname,"a"): NULL;
if(fname && !logFile)
fprintf(stderr,"cannot open log file \"%s\": %d (%s)\n",fname,errno,strerror(errno));
char ch;
while(read(pipe_fd[0],&ch,1) > 0) {
//### any timestamp logic or whatever here
putchar(ch);
if(logFile)
fputc(ch,logFile);
if('\n'==ch) {
fflush(stdout);
if(logFile)
fflush(logFile);
}
}
putchar('\n');
close(pipe_fd[0]);
if(logFile)
fclose(logFile);
exit(EXIT_SUCCESS);
} else {
close(pipe_fd[0]); // Close unused read end
// redirect stdout and stderr
dup2(pipe_fd[1],STDOUT_FILENO);
dup2(pipe_fd[1],STDERR_FILENO);
close(pipe_fd[1]);
}
}
Вы можете использовать forkpty ()
с exec ()
для выполнения отслеживаемая программа с ее параметрами. forkpty ()
возвращает дескриптор файла, который перенаправляется в программы stdin и stdout. Все, что записывается в файловый дескриптор, является вводом программы. Все, что написано программой, можно прочитать из файлового дескриптора.
Вторая часть - прочитать в цикле вывод программы и записать его в файл, а также распечатать его в stdout.
Пример:
pid = forkpty(&fd, NULL, NULL, NULL);
if (pid<0)
return -1;
if (!pid) /* Child */
{
execl("/bin/ping", "/bin/ping", "-c", "1", "-W", "1", "192.168.3.19", NULL);
}
/* Parent */
waitpid(pid, &status, 0);
return WEXITSTATUS(status);
Вы можете использовать pipe (2)
и dup2 (2)
, чтобы связать ваш стандартный выход с файловым дескриптором, из которого вы можете читать. Затем вы можете иметь отдельный поток, отслеживающий этот дескриптор файла, записывая все, что он получает, в файл журнала и исходный стандартный вывод (сохраненный avay в другом файловом дескрипторе с помощью dup2
перед подключением канала). Но вам понадобится фоновый поток.
На самом деле, я думаю, что метод popen tee, предложенный vatine, вероятно, проще и безопаснее (если вам не нужно делать что-либо дополнительно с файлом журнала, например, метки времени или кодирование или что-то в этом роде).
Нет тривиального способа сделать это в C. Я подозреваю, что проще всего было бы вызвать popen (3) с tee как командой и желаемым файлом журнала как arument,