2016-02-07 93 views
0

我目前正在創建自己的命令行shell,並且在嘗試使用管道時遇到問題。我的程序從父進程開始。它檢查用戶是否放入退出或歷史記錄。如果是這樣,它使用這些命令,但這並不重要。如果用戶輸入除退出或歷史以外的任何內容,則會創建一個執行當前任務的孩子。爲什麼不打印到標準輸出(stdout)?

但是,如果用戶輸入一個具有單個管道的命令,那麼我們從父進程開始,它創建一個子進程,調用這個子進程,子進程1.子進程1看到有一個管道並使用fork創建另一個孩子,稱這個孩子2.孩子1創建另一個孩子,稱它爲孩子3(注意:孩子2和3使用共享內存)。現在,孩子2執行第一個命令,孩子3使用孩子2的輸出執行命令。但由於某種原因我沒有得到任何輸出。

我不確定這是否是執行我的任務的最有效的方式,但這是我的教授說要做的。

如果你想看到我所有的代碼在這裏,它是:http://pastebin.com/YNTVf3XP

否則這裏是我的代碼開始在孩子1:

  //Otherwise if we have a single pipe, then do 
      else if (numPipes == 1) { 

       char *command1[CMD_MAX];  //string holding the first command 
       char *command2[CMD_MAX];  //string holding the second command 
       int fds[2];      //create file descriptors for the parent and child 
       pid_t new_pid;     //create new pid_t obj 

       onePipeSplit(tokens, command1, command2, numTokens); //Getting each command for pipe 

       if (pipe(fds) < 0) {   //use the pipe command. If < 0 
        perror("Pipe failure."); //we have an error, so exit 
        exit(EXIT_FAILURE); 
       } 

       //Creating child 2 
       new_pid = fork(); 

       //if pid < 0 then we have an error. Exit. 
       if (new_pid < 0) { 
        perror("Fork failure."); 
        exit(EXIT_FAILURE); 
       } 

       //Else we have the child (2) process 
       else if (new_pid == 0) { 

        close(fds[0]);  //Close read 

        //sending stdin to the shared file descriptor 
        if (dup2(fds[1], STDOUT_FILENO)<0) { 
         perror("Can't dup"); 
         exit(EXIT_FAILURE); 
        } 

        execvp(command1[0], command1); //Execute the next command 
        perror("Exec failure"); 
        exit(EXIT_FAILURE); 
       } 

       //Else if we have the parent process 
       else { 

        pid_t child = fork();   //Creating child 3 
        if (new_pid < 0) {    //if pid < 0, error, exit 
         perror("Fork failure."); 
         exit(EXIT_FAILURE); 
        } 

        //else if pid > 0 we have the parent wait until children execute 
        else if (new_pid > 0) { 
         wait(NULL); 
        } 

        //else we have the child (3) 
        else { 

         close(fds[1]);  //Close write 

         //Sending stdout to the shared file descriptor 
         if (dup2(fds[0], STDIN_FILENO) < 0) { 
          perror("Can't dup"); 
          exit(EXIT_FAILURE); 
         } 

         execvp(command2[0], command2); //Execute the command 
         perror("Exec failure"); 
         exit(EXIT_FAILURE); 
        } 
       } 
      } 

這裏是我的教授給我的圖像以顯示它應該如何工作。 pipe

+1

我認爲你有太多的孩子。如果你有'foo |酒吧'你需要一個管道和兩個更多的過程(除了你的程序已經是)。所以父母創建一個管道,'p'父母爲第一個孩子(這將是'bar')分叉。孩子:'close(p [1]); dup2(p [0],0); exec(「bar」);'現在父母分叉第二次(這將是'foo')。 Child:'close(p [0]); dup2(p [1],1); exec(「foo」);'Parent:'close(p [0]);靠近[P [1]);等待孩子'。 –

+0

@ J.V.A。我在問題中添加了一張圖片,顯示了我的教授給我的東西。這不意味着總共應該有3個孩子嗎?然而,我可能是錯的。 – Logan

+0

我不確定shell(1)在做什麼,但如果教授想要這樣做,那麼這就是正確的答案:) –

回答

2

的問題是在這裏:

    pid_t child = fork();   //Creating child 3 
        if (new_pid < 0) { 
     ... you keep checking `new_pid` here on down, 
     ... but you should be checking `child` here on down... 

此外,在onePipeSplit你需要把一個空的兩個命令列出的結束,因爲execvp需要這一點。

command1[i] = NULL; 

之後第二:

command2[i] = NULL; 

OK,多了一些修正:第一個循環之後添加

每個DUP2()後,你需要關閉原來的FD。舉個例子:

    if (dup2(fds[1], STDOUT_FILENO)<0) { 
         perror("Can't dup"); 
         exit(EXIT_FAILURE); 
        } 
        close(fds[1]);  /* ADD ME */ 

,並在父進程:

    //else if pid > 0 we have the parent wait until children execute 
        else if (child > 0) { 
         close(fds[0]); /* we don't use */ 
         close(fds[1]); /* the pipe */ 
         wait(NULL); 
         exit(0);   /* when 2 & 3 are done, we are too */ 
        } 
+0

感謝您的回覆。這修復了一個奇怪的錯誤,但不幸的是它仍然沒有打印出標準輸出。我會繼續尋找,但到目前爲止我不確定問題是什麼。 – Logan

+0

你得到第二個'else if(new_pid> 0){'太了吧? –

+0

是的。我試圖擺脫第二個分支,所以現在shell(2)執行第一個命令和管道到shell(1),它的工作原理。當我使用兩個孩子時,這真的很奇怪... – Logan

相關問題