2015-08-15 2 views
0

У меня проблема с трубами. Я пытаюсь выполнить, например, ls | grep test и моя программа зависает. Моя программа - это оболочечная программа, и я получил перенаправление и другие функции для работы, но я не могу заставить трубы работать ... Что я делаю неправильно? У меня есть поиск ответов, но я не могу найти какие-либо исправления моей проблемы.Проблемы с трубами в c

if(pipe(fd_pipe) < 0) 
     perror("pipe error..."); 

    if ((pid = fork()) < 0) /* fork a child process */ 
    {  
     perror("ERROR: forking child process failed\n"); 
     exit(1); 
    } 
    else if (pid == 0) /* the child process, do the first command */ 
    { 
     printf("In first child...\n"); 
     //dupPipe(fd_pipe, 1, STDOUT_FILENO); /* send to write end of pipe */ 

     fflush(stdout); 
     std_out = dup(1); // for later restore... 
     close(fd_pipe[0]); 
     dup2(fd_pipe[1], 1); 


     printf("exec %s in first child...\n", comline[0].argv[0]);   
     if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 

    } 
    else /* parent process*/ 
    { 
     while (wait(&status) != pid) //wait for child to completion 
      ; 

     fflush(stdin); 
     std_in = dup(0); // for later restore... 
     close(fd_pipe[1]); 
     dup2(fd_pipe[0], 0); 


     if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command */ 
      { 
       fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
       fflush(stderr); 
       perror(""); 
      } 
+2

Технически, вызов 'fflush' на' stdin' не определен. Если вы хотите быть переносным, не делайте этого. –

+0

«У меня есть поиск ответа» - поиск сложнее. [Вы видели этот вопрос?] (Https://stackoverflow.com/questions/19356075/toy-shell-not-piping-correctly)? – WhozCraig

+0

Обратите внимание, что вам не нужно проверять возвращаемое значение 'execvp()' или любого его семейства. Если функция возвращается, она не удалась; если он преуспеет, он не возвращается. Ваш комментарий о «для последующего восстановления» нечетный; не будет никаких «позже» для восстановления, если «execvp()» будет успешным. Более четкий комментарий будет «для восстановления, если команда не выполняется», но было бы более убедительно, если бы вы показали код. –

ответ

0

Обратите внимание, что комментарии в Andrew Henle «s answer применяются в долгосрочной перспективе - вы должны запустить все программы в трубопроводе по совместительству чтобы гарантировать, что нет никаких тупиков, потому что один процесс пытается записать в полную трубу а другой ожидает завершения одного процесса перед выполнением кода (или программы), который читается из канала. Также применяются комментарии, сделанные непосредственно по этому вопросу.

Однако, этот код, полученный с вашей стороны с минимальным помощником (я прокомментировал неиспользованные переменные std_in и std_out, хотя), компилируется чисто и работает и дает правдоподобный вывод.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 

struct cmd 
{ 
    char **argv; 
}; 

int main(void) 
{ 
    int fd_pipe[2]; 
    int pid; 
    //int std_in; 
    //int std_out; 
    int status; 
    char *cmd1[] = { "ls", 0 }; 
    char *cmd2[] = { "grep", "test", 0 }; 
    struct cmd comline[2] = { { cmd1 }, { cmd2 } }; 

    if(pipe(fd_pipe) < 0) 
     perror("pipe error..."); 

    if ((pid = fork()) < 0) /* fork a child process */ 
    {  
     perror("ERROR: forking child process failed\n"); 
     exit(1); 
    } 
    else if (pid == 0) /* the child process, do the first command */ 
    { 
     printf("In first child...\n"); 
     //dupPipe(fd_pipe, 1, STDOUT_FILENO); /* send to write end of pipe */ 

     fflush(stdout); 
     //std_out = dup(1); // for later restore... 
     close(fd_pipe[0]); 
     dup2(fd_pipe[1], 1); 

     printf("exec %s in first child...\n", comline[0].argv[0]);   
     if (execvp(comline[0].argv[0], comline[0].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 
     exit(EXIT_FAILURE); 

    } 
    else /* parent process*/ 
    { 
     while (wait(&status) != pid) //wait for child to completion 
      ; 

     fflush(stdin); 
     //std_in = dup(0); // for later restore... 
     close(fd_pipe[1]); 
     dup2(fd_pipe[0], 0); 

     if (execvp(comline[1].argv[0], comline[1].argv) < 0) /* execute the command */ 
     { 
      fprintf(stderr,"-mish: Exe of %s failed...",comline[0].argv[0]); 
      fflush(stderr); 
      perror(""); 
     } 
     exit(EXIT_FAILURE); 
    } 
    printf("Exiting from %d\n", (int)getpid()); 
    return 0; 
} 

В директории с 130-нечетные файлы (дает около 1,5 KiB выхода из ls), я получаю:

$ ./p97 
In first child... 
chk-utf8-test.sh 
chk-wchar-test.sh 
pbb-test.data 
test-fstatat.c 
test-rename.c 
utf8-test.c 
wchar-test.c 
$ 

Это то, что я получаю из командной строки работает ls | grep test друг от друга (от курс) из диагностического сообщения.

Мое подозрение, однако, в том, что вы не показали нам весь код. Переменные std_in и std_out заставляют меня подозревать, что на самом деле есть какой-то другой код, и, возможно, операция pipe() происходит в родительском процессе, который затем вилки, а потом потом пробегает остальную часть кода, показанного в вопросе. Если есть такой сценарий, тогда могут быть проблемы с командами, которые не завершаются, потому что канал закрыт неправильно.

+0

Спасибо за ответ, сейчас он работает :). Std_in и std_out должны были восстановить его обратно в STDIN и STDOUT для последующего использования. Еще раз спасибо!! – Christer

0

Вы звоните wait(), пока первый дочерний процесс все еще работает. Это означает, что ничего не читается, когда первый ребенок записывает свой stdout - если труба заполняется, первый дочерний процесс блокирует запись до stdout. Но так как родительский процесс wait() 'для того, чтобы первый ребенок закончил, вы завершаетесь в тупике.

+0

Это (по крайней мере) потенциальная проблема; его необходимо будет решить. Элементы конвейера должны выполняться одновременно. Я не уверен, что это единственная проблема, и не будет проблемой, если вывод 'ls' меньше, чем около 5 килобайт, что является довольно большим списком каталогов. –

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