2016-09-28 4 views
0

У меня есть приложение, которое порождает дочерний процесс. Этот дочерний процесс выводит информацию о том, что он делает, печатая на stdout. Родительский процесс делает то же самое (например, prints to stdout).Подготовить выход консольного дочернего процесса

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

Я думал, что было бы разумнее иметь родительский процесс, чтобы получить выход из дочернего процесса, что он forks/exec. Я не хочу перенаправлять вывод, потому что просмотр вывода inline с родительским процессом является полезным. Как мне это сделать? Я использую fork/exec в родительском.

Должен ли я читать выходные данные и добавлять каждую строку вручную или есть более простой подход?


Update:

Благодаря Barmar. Вот как я это делаю. Я также мог читать байты по байтам в родительском процессе из канала до конца строки. Но я решил не использовать этот подход по причинам сложности в моем однопоточном приложении lua + C.

// Crude example of output filtering using sed to 
// prepend child process output text 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <libgen.h> 
#include <string.h> 


pid_t spawn(int fd[2], const char* path) 
{ 
    printf("Create child\n"); 
    pid_t pid = fork(); 
    switch(pid){ 
    case -1: 
     printf("Create process failed"); 
     return -1; 
    case 0: 
     dup2(fd[1], STDOUT_FILENO); 
     close(fd[0]); 
     close(fd[1]); 
     execl(path, path, NULL); 
     return 0; 
    default: 
     return pid; 
    } 
} 

pid_t spawnOutputFilter(int fd[2]) 
{ 
    printf("Create sed\n"); 
    pid_t pid = fork(); 
    switch(pid){ 
    case -1: 
     printf("Create sed failed"); 
     return -1; 
    case 0: 
     dup2(fd[0], STDIN_FILENO); 
     close(fd[0]); 
     close(fd[1]); 
     execlp("sed", "sed", "s/^/Engine: /", (char *)NULL); 
     return -1; 
    default: 
     return pid; 
    } 
} 


int main(int argc, char* argv[]) 
{ 
    if (argc > 1){ 
    int options; 
    int fd[2]; 
    pipe(fd); 
    pid_t pid = spawn(fd, argv[1]); 
    pid_t sed_pid = spawnOutputFilter(fd); 

    close(fd[0]); 
    close(fd[1]); 
    waitpid(pid, NULL, 0); 
    waitpid(sed_pid, NULL, 0); 
    } 

    return 0; 
} 
+1

В зависимости от того, как вы структурируете свой код, вы можете сделать что-то вроде этого: '#define printf printf (" preend "); printf' – Riley

ответ

2

Вы можете создать второй дочерний процесс, который выполняет

execlp("sed", "sed", "s/^/PREFIX: /", (char *)NULL); 

Подключите стандартный вывод первого ребенка на стандартный ввод этого процесса с трубой.

+1

nit: '' s/^/PREFIX:/"' else ожидать 'unterminated '' command' –

+0

Кажется, что это работает, и неплохо. – Matt

0

не мог бы вы определить #define printf(a) printf("your text:" a).

Другой альтернативы я могу думать использует dup

Вы открываете тот же файл войдите в своем дочернем процессе и dup вашего stdout к новому дескриптору.

+0

Я не думаю, что он будет работать с несколькими параметрами' printf' ... –

+0

Возможно. Это технически сочетание C & Lua, поэтому выход поступает из нескольких мест. #define не будет работать в lua, но я мог бы заменить каждый вызов на печать другой программой, я полагаю. Это все еще утомительно. – Matt

+0

Неужели? Зачем? Единственной альтернативой было бы привязать кэш-память 'write', проверить pid и обрабатывать ее по-разному для разных процессов. * Это * утомительно. –

2

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

Я думаю, это зависит от того, как вы судите о «умных». Это может быть проще, чтобы заставить ребенка добавить текст к выходу.

Я не хочу перенаправлять вывод, потому что просмотр выходного потока с родительским процессом является полезным. Каков наилучший способ сделать это?

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

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

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

Смежные вопросы