Запись в стандартный вывод и файл - PullRequest
3 голосов
/ 07 сентября 2010

У меня есть родительский процесс, который выдает дочерний элемент для выполнения execv ().

Мне нужно, чтобы вывод, передаваемый execv () в stdout, отображался на экране, а также копировался в файл журнала.

Как записать один и тот же вывод в стандартный вывод и файл, без использования каналов или тройников ?

Ответы [ 7 ]

4 голосов
/ 07 сентября 2010

Если вы не хотите использовать тройник, перед тем как записать данные, запишите их в файл, а затем отправьте на стандартный вывод.

Вы должны написать функцию ведения журнала, которая сделает это для вас, чтобысделать его чище.

2 голосов
/ 08 сентября 2010

Вы можете сделать это полностью внутри своей программы, но вам все равно нужно будет использовать анонимные каналы, созданные системным вызовом pipe().

По сути, вам потребуется подпроцесс, выполняющий эквивалент из tee, что довольно просто:

int child_pipe[2];
pid_t pid_exec_child, pid_output_child;

pipe(child_pipe);

pid_exec_child = fork();
if (pid_exec_child == 0)
{
    dup2(child_pipe[1], STDOUT_FILENO);
    close(child_pipe[0]);
    close(child_pipe[1]);
    execve(/* ... */);
    _exit(127);
}

close(child_pipe[1]);

pid_output_child = fork();
if (pid_output_child == 0)
{
    /* This child just loops around, reading from the other child and writing everything
     * to both stdout and the log file. */
    int logfd = open("logfile", O_WRONLY);
    char buffer[4096];
    ssize_t nread;

    while ((nread = read(child_pipe[0], buffer, sizeof buffer) != 0)
    {
        size_t nwritten_total;
        ssize_t nwritten;

        if (nread < 0)
        {
            if (errno == EINTR)
                continue;

            perror("read");
            _exit(1);
        }

        /* Copy data to stdout */
        nwritten_total = 0;
        while (nwritten_total < nread)
        {
            nwritten = write(STDOUT_FILENO, buffer + nwritten_total, nread - nwritten_total);

            if (nwritten < 0)
            {
                if (errno == EINTR)
                    continue;

                perror("write(stdout)");
                _exit(2);
            }

            nwritten_total += nwritten;
        }

        /* Copy data to logfile */
        nwritten_total = 0;
        while (nwritten_total < nread)
        {
            nwritten = write(logfd, buffer + nwritten_total, nread - nwritten_total);

            if (nwritten < 0)
            {
                if (errno == EINTR)
                    continue;

                perror("write(logfile)");
                _exit(3);
            }

            nwritten_total += nwritten;
        }
    }
    _exit(0);
}

close(child_pipe[0]);

/* Parent continues here */

Конечно, вероятно проще просто выполнить tee в этом втором дочернем элементе ...

(обратите внимание, что дочерние процессы используют _exit(), поскольку они унаследовали стандартное состояние ввода-вывода от родительского).

2 голосов
/ 07 сентября 2010

Вы можете использовать dup2() - эта ссылка дает пример

2 голосов
/ 07 сентября 2010

Труба через тройник .

1 голос
/ 07 сентября 2010

Также вы можете использовать fifo's. mkfifo my.fifo; в execv: program> my.fifo; и откройте fifo как обычный файл, читая из него. Таким образом, вы можете анализировать свой стандартный вывод, но он имеет незначительные недостатки с общим доступом.

0 голосов
/ 07 сентября 2010

Используйте Тройник , как это:

./myprog | tee outputfile
0 голосов
/ 07 сентября 2010

Хотите ли вы, чтобы только выход ребенка попадал в журнал?

Команда tee unix делает именно то, что вы описываете: вы передаете данные и записываете их в журнал и на стандартный вывод.

...